diff options
author | zakk <zakk@edf5b092-35ff-0310-97b2-ce42778d08ea> | 2005-08-26 17:39:27 +0000 |
---|---|---|
committer | zakk <zakk@edf5b092-35ff-0310-97b2-ce42778d08ea> | 2005-08-26 17:39:27 +0000 |
commit | 6bf20c78f5b69d40bcc4931df93d29198435ab67 (patch) | |
tree | e3eda937a05d7db42de725b7013bd0344b987f34 /code/botlib/be_ai_move.c | |
parent | 872d4d7f55af706737ffb361bb76ad13e7496770 (diff) | |
download | ioquake3-aero-6bf20c78f5b69d40bcc4931df93d29198435ab67.tar.gz ioquake3-aero-6bf20c78f5b69d40bcc4931df93d29198435ab67.zip |
newlines fixed
git-svn-id: svn://svn.icculus.org/quake3/trunk@6 edf5b092-35ff-0310-97b2-ce42778d08ea
Diffstat (limited to 'code/botlib/be_ai_move.c')
-rwxr-xr-x | code/botlib/be_ai_move.c | 7220 |
1 files changed, 3610 insertions, 3610 deletions
diff --git a/code/botlib/be_ai_move.c b/code/botlib/be_ai_move.c index 210d4d9..1f3b8ee 100755 --- a/code/botlib/be_ai_move.c +++ b/code/botlib/be_ai_move.c @@ -1,3610 +1,3610 @@ -/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code is free software; you can redistribute it
-and/or modify it under the terms of the GNU General Public License as
-published by the Free Software Foundation; either version 2 of the License,
-or (at your option) any later version.
-
-Quake III Arena source code is distributed in the hope that it will be
-useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with Foobar; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-
-/*****************************************************************************
- * name: be_ai_move.c
- *
- * desc: bot movement AI
- *
- * $Archive: /MissionPack/code/botlib/be_ai_move.c $
- *
- *****************************************************************************/
-
-#include "../game/q_shared.h"
-#include "l_memory.h"
-#include "l_libvar.h"
-#include "l_utils.h"
-#include "l_script.h"
-#include "l_precomp.h"
-#include "l_struct.h"
-#include "aasfile.h"
-#include "../game/botlib.h"
-#include "../game/be_aas.h"
-#include "be_aas_funcs.h"
-#include "be_interface.h"
-
-#include "../game/be_ea.h"
-#include "../game/be_ai_goal.h"
-#include "../game/be_ai_move.h"
-
-
-//#define DEBUG_AI_MOVE
-//#define DEBUG_ELEVATOR
-//#define DEBUG_GRAPPLE
-
-// bk001204 - redundant bot_avoidspot_t, see ../game/be_ai_move.h
-
-//movement state
-//NOTE: the moveflags MFL_ONGROUND, MFL_TELEPORTED, MFL_WATERJUMP and
-// MFL_GRAPPLEPULL must be set outside the movement code
-typedef struct bot_movestate_s
-{
- //input vars (all set outside the movement code)
- vec3_t origin; //origin of the bot
- vec3_t velocity; //velocity of the bot
- vec3_t viewoffset; //view offset
- int entitynum; //entity number of the bot
- int client; //client number of the bot
- float thinktime; //time the bot thinks
- int presencetype; //presencetype of the bot
- vec3_t viewangles; //view angles of the bot
- //state vars
- int areanum; //area the bot is in
- int lastareanum; //last area the bot was in
- int lastgoalareanum; //last goal area number
- int lastreachnum; //last reachability number
- vec3_t lastorigin; //origin previous cycle
- int reachareanum; //area number of the reachabilty
- int moveflags; //movement flags
- int jumpreach; //set when jumped
- float grapplevisible_time; //last time the grapple was visible
- float lastgrappledist; //last distance to the grapple end
- float reachability_time; //time to use current reachability
- int avoidreach[MAX_AVOIDREACH]; //reachabilities to avoid
- float avoidreachtimes[MAX_AVOIDREACH]; //times to avoid the reachabilities
- int avoidreachtries[MAX_AVOIDREACH]; //number of tries before avoiding
- //
- bot_avoidspot_t avoidspots[MAX_AVOIDSPOTS]; //spots to avoid
- int numavoidspots;
-} bot_movestate_t;
-
-//used to avoid reachability links for some time after being used
-#define AVOIDREACH
-#define AVOIDREACH_TIME 6 //avoid links for 6 seconds after use
-#define AVOIDREACH_TRIES 4
-//prediction times
-#define PREDICTIONTIME_JUMP 3 //in seconds
-#define PREDICTIONTIME_MOVE 2 //in seconds
-//weapon indexes for weapon jumping
-#define WEAPONINDEX_ROCKET_LAUNCHER 5
-#define WEAPONINDEX_BFG 9
-
-#define MODELTYPE_FUNC_PLAT 1
-#define MODELTYPE_FUNC_BOB 2
-#define MODELTYPE_FUNC_DOOR 3
-#define MODELTYPE_FUNC_STATIC 4
-
-libvar_t *sv_maxstep;
-libvar_t *sv_maxbarrier;
-libvar_t *sv_gravity;
-libvar_t *weapindex_rocketlauncher;
-libvar_t *weapindex_bfg10k;
-libvar_t *weapindex_grapple;
-libvar_t *entitytypemissile;
-libvar_t *offhandgrapple;
-libvar_t *cmd_grappleoff;
-libvar_t *cmd_grappleon;
-//type of model, func_plat or func_bobbing
-int modeltypes[MAX_MODELS];
-
-bot_movestate_t *botmovestates[MAX_CLIENTS+1];
-
-//========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//========================================================================
-int BotAllocMoveState(void)
-{
- int i;
-
- for (i = 1; i <= MAX_CLIENTS; i++)
- {
- if (!botmovestates[i])
- {
- botmovestates[i] = GetClearedMemory(sizeof(bot_movestate_t));
- return i;
- } //end if
- } //end for
- return 0;
-} //end of the function BotAllocMoveState
-//========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//========================================================================
-void BotFreeMoveState(int handle)
-{
- if (handle <= 0 || handle > MAX_CLIENTS)
- {
- botimport.Print(PRT_FATAL, "move state handle %d out of range\n", handle);
- return;
- } //end if
- if (!botmovestates[handle])
- {
- botimport.Print(PRT_FATAL, "invalid move state %d\n", handle);
- return;
- } //end if
- FreeMemory(botmovestates[handle]);
- botmovestates[handle] = NULL;
-} //end of the function BotFreeMoveState
-//========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//========================================================================
-bot_movestate_t *BotMoveStateFromHandle(int handle)
-{
- if (handle <= 0 || handle > MAX_CLIENTS)
- {
- botimport.Print(PRT_FATAL, "move state handle %d out of range\n", handle);
- return NULL;
- } //end if
- if (!botmovestates[handle])
- {
- botimport.Print(PRT_FATAL, "invalid move state %d\n", handle);
- return NULL;
- } //end if
- return botmovestates[handle];
-} //end of the function BotMoveStateFromHandle
-//========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//========================================================================
-void BotInitMoveState(int handle, bot_initmove_t *initmove)
-{
- bot_movestate_t *ms;
-
- ms = BotMoveStateFromHandle(handle);
- if (!ms) return;
- VectorCopy(initmove->origin, ms->origin);
- VectorCopy(initmove->velocity, ms->velocity);
- VectorCopy(initmove->viewoffset, ms->viewoffset);
- ms->entitynum = initmove->entitynum;
- ms->client = initmove->client;
- ms->thinktime = initmove->thinktime;
- ms->presencetype = initmove->presencetype;
- VectorCopy(initmove->viewangles, ms->viewangles);
- //
- ms->moveflags &= ~MFL_ONGROUND;
- if (initmove->or_moveflags & MFL_ONGROUND) ms->moveflags |= MFL_ONGROUND;
- ms->moveflags &= ~MFL_TELEPORTED;
- if (initmove->or_moveflags & MFL_TELEPORTED) ms->moveflags |= MFL_TELEPORTED;
- ms->moveflags &= ~MFL_WATERJUMP;
- if (initmove->or_moveflags & MFL_WATERJUMP) ms->moveflags |= MFL_WATERJUMP;
- ms->moveflags &= ~MFL_WALK;
- if (initmove->or_moveflags & MFL_WALK) ms->moveflags |= MFL_WALK;
- ms->moveflags &= ~MFL_GRAPPLEPULL;
- if (initmove->or_moveflags & MFL_GRAPPLEPULL) ms->moveflags |= MFL_GRAPPLEPULL;
-} //end of the function BotInitMoveState
-//========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//========================================================================
-float AngleDiff(float ang1, float ang2)
-{
- float diff;
-
- diff = ang1 - ang2;
- if (ang1 > ang2)
- {
- if (diff > 180.0) diff -= 360.0;
- } //end if
- else
- {
- if (diff < -180.0) diff += 360.0;
- } //end else
- return diff;
-} //end of the function AngleDiff
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int BotFuzzyPointReachabilityArea(vec3_t origin)
-{
- int firstareanum, j, x, y, z;
- int areas[10], numareas, areanum, bestareanum;
- float dist, bestdist;
- vec3_t points[10], v, end;
-
- firstareanum = 0;
- areanum = AAS_PointAreaNum(origin);
- if (areanum)
- {
- firstareanum = areanum;
- if (AAS_AreaReachability(areanum)) return areanum;
- } //end if
- VectorCopy(origin, end);
- end[2] += 4;
- numareas = AAS_TraceAreas(origin, end, areas, points, 10);
- for (j = 0; j < numareas; j++)
- {
- if (AAS_AreaReachability(areas[j])) return areas[j];
- } //end for
- bestdist = 999999;
- bestareanum = 0;
- for (z = 1; z >= -1; z -= 1)
- {
- for (x = 1; x >= -1; x -= 1)
- {
- for (y = 1; y >= -1; y -= 1)
- {
- VectorCopy(origin, end);
- end[0] += x * 8;
- end[1] += y * 8;
- end[2] += z * 12;
- numareas = AAS_TraceAreas(origin, end, areas, points, 10);
- for (j = 0; j < numareas; j++)
- {
- if (AAS_AreaReachability(areas[j]))
- {
- VectorSubtract(points[j], origin, v);
- dist = VectorLength(v);
- if (dist < bestdist)
- {
- bestareanum = areas[j];
- bestdist = dist;
- } //end if
- } //end if
- if (!firstareanum) firstareanum = areas[j];
- } //end for
- } //end for
- } //end for
- if (bestareanum) return bestareanum;
- } //end for
- return firstareanum;
-} //end of the function BotFuzzyPointReachabilityArea
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int BotReachabilityArea(vec3_t origin, int client)
-{
- int modelnum, modeltype, reachnum, areanum;
- aas_reachability_t reach;
- vec3_t org, end, mins, maxs, up = {0, 0, 1};
- bsp_trace_t bsptrace;
- aas_trace_t trace;
-
- //check if the bot is standing on something
- AAS_PresenceTypeBoundingBox(PRESENCE_CROUCH, mins, maxs);
- VectorMA(origin, -3, up, end);
- bsptrace = AAS_Trace(origin, mins, maxs, end, client, CONTENTS_SOLID|CONTENTS_PLAYERCLIP);
- if (!bsptrace.startsolid && bsptrace.fraction < 1 && bsptrace.ent != ENTITYNUM_NONE)
- {
- //if standing on the world the bot should be in a valid area
- if (bsptrace.ent == ENTITYNUM_WORLD)
- {
- return BotFuzzyPointReachabilityArea(origin);
- } //end if
-
- modelnum = AAS_EntityModelindex(bsptrace.ent);
- modeltype = modeltypes[modelnum];
-
- //if standing on a func_plat or func_bobbing then the bot is assumed to be
- //in the area the reachability points to
- if (modeltype == MODELTYPE_FUNC_PLAT || modeltype == MODELTYPE_FUNC_BOB)
- {
- reachnum = AAS_NextModelReachability(0, modelnum);
- if (reachnum)
- {
- AAS_ReachabilityFromNum(reachnum, &reach);
- return reach.areanum;
- } //end if
- } //end else if
-
- //if the bot is swimming the bot should be in a valid area
- if (AAS_Swimming(origin))
- {
- return BotFuzzyPointReachabilityArea(origin);
- } //end if
- //
- areanum = BotFuzzyPointReachabilityArea(origin);
- //if the bot is in an area with reachabilities
- if (areanum && AAS_AreaReachability(areanum)) return areanum;
- //trace down till the ground is hit because the bot is standing on some other entity
- VectorCopy(origin, org);
- VectorCopy(org, end);
- end[2] -= 800;
- trace = AAS_TraceClientBBox(org, end, PRESENCE_CROUCH, -1);
- if (!trace.startsolid)
- {
- VectorCopy(trace.endpos, org);
- } //end if
- //
- return BotFuzzyPointReachabilityArea(org);
- } //end if
- //
- return BotFuzzyPointReachabilityArea(origin);
-} //end of the function BotReachabilityArea
-//===========================================================================
-// returns the reachability area the bot is in
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-/*
-int BotReachabilityArea(vec3_t origin, int testground)
-{
- int firstareanum, i, j, x, y, z;
- int areas[10], numareas, areanum, bestareanum;
- float dist, bestdist;
- vec3_t org, end, points[10], v;
- aas_trace_t trace;
-
- firstareanum = 0;
- for (i = 0; i < 2; i++)
- {
- VectorCopy(origin, org);
- //if test at the ground (used when bot is standing on an entity)
- if (i > 0)
- {
- VectorCopy(origin, end);
- end[2] -= 800;
- trace = AAS_TraceClientBBox(origin, end, PRESENCE_CROUCH, -1);
- if (!trace.startsolid)
- {
- VectorCopy(trace.endpos, org);
- } //end if
- } //end if
-
- firstareanum = 0;
- areanum = AAS_PointAreaNum(org);
- if (areanum)
- {
- firstareanum = areanum;
- if (AAS_AreaReachability(areanum)) return areanum;
- } //end if
- bestdist = 999999;
- bestareanum = 0;
- for (z = 1; z >= -1; z -= 1)
- {
- for (x = 1; x >= -1; x -= 1)
- {
- for (y = 1; y >= -1; y -= 1)
- {
- VectorCopy(org, end);
- end[0] += x * 8;
- end[1] += y * 8;
- end[2] += z * 12;
- numareas = AAS_TraceAreas(org, end, areas, points, 10);
- for (j = 0; j < numareas; j++)
- {
- if (AAS_AreaReachability(areas[j]))
- {
- VectorSubtract(points[j], org, v);
- dist = VectorLength(v);
- if (dist < bestdist)
- {
- bestareanum = areas[j];
- bestdist = dist;
- } //end if
- } //end if
- } //end for
- } //end for
- } //end for
- if (bestareanum) return bestareanum;
- } //end for
- if (!testground) break;
- } //end for
-//#ifdef DEBUG
- //botimport.Print(PRT_MESSAGE, "no reachability area\n");
-//#endif //DEBUG
- return firstareanum;
-} //end of the function BotReachabilityArea*/
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int BotOnMover(vec3_t origin, int entnum, aas_reachability_t *reach)
-{
- int i, modelnum;
- vec3_t mins, maxs, modelorigin, org, end;
- vec3_t angles = {0, 0, 0};
- vec3_t boxmins = {-16, -16, -8}, boxmaxs = {16, 16, 8};
- bsp_trace_t trace;
-
- modelnum = reach->facenum & 0x0000FFFF;
- //get some bsp model info
- AAS_BSPModelMinsMaxsOrigin(modelnum, angles, mins, maxs, NULL);
- //
- if (!AAS_OriginOfMoverWithModelNum(modelnum, modelorigin))
- {
- botimport.Print(PRT_MESSAGE, "no entity with model %d\n", modelnum);
- return qfalse;
- } //end if
- //
- for (i = 0; i < 2; i++)
- {
- if (origin[i] > modelorigin[i] + maxs[i] + 16) return qfalse;
- if (origin[i] < modelorigin[i] + mins[i] - 16) return qfalse;
- } //end for
- //
- VectorCopy(origin, org);
- org[2] += 24;
- VectorCopy(origin, end);
- end[2] -= 48;
- //
- trace = AAS_Trace(org, boxmins, boxmaxs, end, entnum, CONTENTS_SOLID|CONTENTS_PLAYERCLIP);
- if (!trace.startsolid && !trace.allsolid)
- {
- //NOTE: the reachability face number is the model number of the elevator
- if (trace.ent != ENTITYNUM_NONE && AAS_EntityModelNum(trace.ent) == modelnum)
- {
- return qtrue;
- } //end if
- } //end if
- return qfalse;
-} //end of the function BotOnMover
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int MoverDown(aas_reachability_t *reach)
-{
- int modelnum;
- vec3_t mins, maxs, origin;
- vec3_t angles = {0, 0, 0};
-
- modelnum = reach->facenum & 0x0000FFFF;
- //get some bsp model info
- AAS_BSPModelMinsMaxsOrigin(modelnum, angles, mins, maxs, origin);
- //
- if (!AAS_OriginOfMoverWithModelNum(modelnum, origin))
- {
- botimport.Print(PRT_MESSAGE, "no entity with model %d\n", modelnum);
- return qfalse;
- } //end if
- //if the top of the plat is below the reachability start point
- if (origin[2] + maxs[2] < reach->start[2]) return qtrue;
- return qfalse;
-} //end of the function MoverDown
-//========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//========================================================================
-void BotSetBrushModelTypes(void)
-{
- int ent, modelnum;
- char classname[MAX_EPAIRKEY], model[MAX_EPAIRKEY];
-
- Com_Memset(modeltypes, 0, MAX_MODELS * sizeof(int));
- //
- for (ent = AAS_NextBSPEntity(0); ent; ent = AAS_NextBSPEntity(ent))
- {
- if (!AAS_ValueForBSPEpairKey(ent, "classname", classname, MAX_EPAIRKEY)) continue;
- if (!AAS_ValueForBSPEpairKey(ent, "model", model, MAX_EPAIRKEY)) continue;
- if (model[0]) modelnum = atoi(model+1);
- else modelnum = 0;
-
- if (modelnum < 0 || modelnum > MAX_MODELS)
- {
- botimport.Print(PRT_MESSAGE, "entity %s model number out of range\n", classname);
- continue;
- } //end if
-
- if (!Q_stricmp(classname, "func_bobbing"))
- modeltypes[modelnum] = MODELTYPE_FUNC_BOB;
- else if (!Q_stricmp(classname, "func_plat"))
- modeltypes[modelnum] = MODELTYPE_FUNC_PLAT;
- else if (!Q_stricmp(classname, "func_door"))
- modeltypes[modelnum] = MODELTYPE_FUNC_DOOR;
- else if (!Q_stricmp(classname, "func_static"))
- modeltypes[modelnum] = MODELTYPE_FUNC_STATIC;
- } //end for
-} //end of the function BotSetBrushModelTypes
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int BotOnTopOfEntity(bot_movestate_t *ms)
-{
- vec3_t mins, maxs, end, up = {0, 0, 1};
- bsp_trace_t trace;
-
- AAS_PresenceTypeBoundingBox(ms->presencetype, mins, maxs);
- VectorMA(ms->origin, -3, up, end);
- trace = AAS_Trace(ms->origin, mins, maxs, end, ms->entitynum, CONTENTS_SOLID|CONTENTS_PLAYERCLIP);
- if (!trace.startsolid && (trace.ent != ENTITYNUM_WORLD && trace.ent != ENTITYNUM_NONE) )
- {
- return trace.ent;
- } //end if
- return -1;
-} //end of the function BotOnTopOfEntity
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int BotValidTravel(vec3_t origin, aas_reachability_t *reach, int travelflags)
-{
- //if the reachability uses an unwanted travel type
- if (AAS_TravelFlagForType(reach->traveltype) & ~travelflags) return qfalse;
- //don't go into areas with bad travel types
- if (AAS_AreaContentsTravelFlags(reach->areanum) & ~travelflags) return qfalse;
- return qtrue;
-} //end of the function BotValidTravel
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void BotAddToAvoidReach(bot_movestate_t *ms, int number, float avoidtime)
-{
- int i;
-
- for (i = 0; i < MAX_AVOIDREACH; i++)
- {
- if (ms->avoidreach[i] == number)
- {
- if (ms->avoidreachtimes[i] > AAS_Time()) ms->avoidreachtries[i]++;
- else ms->avoidreachtries[i] = 1;
- ms->avoidreachtimes[i] = AAS_Time() + avoidtime;
- return;
- } //end if
- } //end for
- //add the reachability to the reachabilities to avoid for a while
- for (i = 0; i < MAX_AVOIDREACH; i++)
- {
- if (ms->avoidreachtimes[i] < AAS_Time())
- {
- ms->avoidreach[i] = number;
- ms->avoidreachtimes[i] = AAS_Time() + avoidtime;
- ms->avoidreachtries[i] = 1;
- return;
- } //end if
- } //end for
-} //end of the function BotAddToAvoidReach
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-float DistanceFromLineSquared(vec3_t p, vec3_t lp1, vec3_t lp2)
-{
- vec3_t proj, dir;
- int j;
-
- AAS_ProjectPointOntoVector(p, lp1, lp2, proj);
- for (j = 0; j < 3; j++)
- if ((proj[j] > lp1[j] && proj[j] > lp2[j]) ||
- (proj[j] < lp1[j] && proj[j] < lp2[j]))
- break;
- if (j < 3) {
- if (fabs(proj[j] - lp1[j]) < fabs(proj[j] - lp2[j]))
- VectorSubtract(p, lp1, dir);
- else
- VectorSubtract(p, lp2, dir);
- return VectorLengthSquared(dir);
- }
- VectorSubtract(p, proj, dir);
- return VectorLengthSquared(dir);
-} //end of the function DistanceFromLineSquared
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-float VectorDistanceSquared(vec3_t p1, vec3_t p2)
-{
- vec3_t dir;
- VectorSubtract(p2, p1, dir);
- return VectorLengthSquared(dir);
-} //end of the function VectorDistanceSquared
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int BotAvoidSpots(vec3_t origin, aas_reachability_t *reach, bot_avoidspot_t *avoidspots, int numavoidspots)
-{
- int checkbetween, i, type;
- float squareddist, squaredradius;
-
- switch(reach->traveltype & TRAVELTYPE_MASK)
- {
- case TRAVEL_WALK: checkbetween = qtrue; break;
- case TRAVEL_CROUCH: checkbetween = qtrue; break;
- case TRAVEL_BARRIERJUMP: checkbetween = qtrue; break;
- case TRAVEL_LADDER: checkbetween = qtrue; break;
- case TRAVEL_WALKOFFLEDGE: checkbetween = qfalse; break;
- case TRAVEL_JUMP: checkbetween = qfalse; break;
- case TRAVEL_SWIM: checkbetween = qtrue; break;
- case TRAVEL_WATERJUMP: checkbetween = qtrue; break;
- case TRAVEL_TELEPORT: checkbetween = qfalse; break;
- case TRAVEL_ELEVATOR: checkbetween = qfalse; break;
- case TRAVEL_GRAPPLEHOOK: checkbetween = qfalse; break;
- case TRAVEL_ROCKETJUMP: checkbetween = qfalse; break;
- case TRAVEL_BFGJUMP: checkbetween = qfalse; break;
- case TRAVEL_JUMPPAD: checkbetween = qfalse; break;
- case TRAVEL_FUNCBOB: checkbetween = qfalse; break;
- default: checkbetween = qtrue; break;
- } //end switch
-
- type = AVOID_CLEAR;
- for (i = 0; i < numavoidspots; i++)
- {
- squaredradius = Square(avoidspots[i].radius);
- squareddist = DistanceFromLineSquared(avoidspots[i].origin, origin, reach->start);
- // if moving towards the avoid spot
- if (squareddist < squaredradius &&
- VectorDistanceSquared(avoidspots[i].origin, origin) > squareddist)
- {
- type = avoidspots[i].type;
- } //end if
- else if (checkbetween) {
- squareddist = DistanceFromLineSquared(avoidspots[i].origin, reach->start, reach->end);
- // if moving towards the avoid spot
- if (squareddist < squaredradius &&
- VectorDistanceSquared(avoidspots[i].origin, reach->start) > squareddist)
- {
- type = avoidspots[i].type;
- } //end if
- } //end if
- else
- {
- VectorDistanceSquared(avoidspots[i].origin, reach->end);
- // if the reachability leads closer to the avoid spot
- if (squareddist < squaredradius &&
- VectorDistanceSquared(avoidspots[i].origin, reach->start) > squareddist)
- {
- type = avoidspots[i].type;
- } //end if
- } //end else
- if (type == AVOID_ALWAYS)
- return type;
- } //end for
- return type;
-} //end of the function BotAvoidSpots
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void BotAddAvoidSpot(int movestate, vec3_t origin, float radius, int type)
-{
- bot_movestate_t *ms;
-
- ms = BotMoveStateFromHandle(movestate);
- if (!ms) return;
- if (type == AVOID_CLEAR)
- {
- ms->numavoidspots = 0;
- return;
- } //end if
-
- if (ms->numavoidspots >= MAX_AVOIDSPOTS)
- return;
- VectorCopy(origin, ms->avoidspots[ms->numavoidspots].origin);
- ms->avoidspots[ms->numavoidspots].radius = radius;
- ms->avoidspots[ms->numavoidspots].type = type;
- ms->numavoidspots++;
-} //end of the function BotAddAvoidSpot
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int BotGetReachabilityToGoal(vec3_t origin, int areanum,
- int lastgoalareanum, int lastareanum,
- int *avoidreach, float *avoidreachtimes, int *avoidreachtries,
- bot_goal_t *goal, int travelflags, int movetravelflags,
- struct bot_avoidspot_s *avoidspots, int numavoidspots, int *flags)
-{
- int i, t, besttime, bestreachnum, reachnum;
- aas_reachability_t reach;
-
- //if not in a valid area
- if (!areanum) return 0;
- //
- if (AAS_AreaDoNotEnter(areanum) || AAS_AreaDoNotEnter(goal->areanum))
- {
- travelflags |= TFL_DONOTENTER;
- movetravelflags |= TFL_DONOTENTER;
- } //end if
- //use the routing to find the next area to go to
- besttime = 0;
- bestreachnum = 0;
- //
- for (reachnum = AAS_NextAreaReachability(areanum, 0); reachnum;
- reachnum = AAS_NextAreaReachability(areanum, reachnum))
- {
-#ifdef AVOIDREACH
- //check if it isn't an reachability to avoid
- for (i = 0; i < MAX_AVOIDREACH; i++)
- {
- if (avoidreach[i] == reachnum && avoidreachtimes[i] >= AAS_Time()) break;
- } //end for
- if (i != MAX_AVOIDREACH && avoidreachtries[i] > AVOIDREACH_TRIES)
- {
-#ifdef DEBUG
- if (bot_developer)
- {
- botimport.Print(PRT_MESSAGE, "avoiding reachability %d\n", avoidreach[i]);
- } //end if
-#endif //DEBUG
- continue;
- } //end if
-#endif //AVOIDREACH
- //get the reachability from the number
- AAS_ReachabilityFromNum(reachnum, &reach);
- //NOTE: do not go back to the previous area if the goal didn't change
- //NOTE: is this actually avoidance of local routing minima between two areas???
- if (lastgoalareanum == goal->areanum && reach.areanum == lastareanum) continue;
- //if (AAS_AreaContentsTravelFlags(reach.areanum) & ~travelflags) continue;
- //if the travel isn't valid
- if (!BotValidTravel(origin, &reach, movetravelflags)) continue;
- //get the travel time
- t = AAS_AreaTravelTimeToGoalArea(reach.areanum, reach.end, goal->areanum, travelflags);
- //if the goal area isn't reachable from the reachable area
- if (!t) continue;
- //if the bot should not use this reachability to avoid bad spots
- if (BotAvoidSpots(origin, &reach, avoidspots, numavoidspots)) {
- if (flags) {
- *flags |= MOVERESULT_BLOCKEDBYAVOIDSPOT;
- }
- continue;
- }
- //add the travel time towards the area
- t += reach.traveltime;// + AAS_AreaTravelTime(areanum, origin, reach.start);
- //if the travel time is better than the ones already found
- if (!besttime || t < besttime)
- {
- besttime = t;
- bestreachnum = reachnum;
- } //end if
- } //end for
- //
- return bestreachnum;
-} //end of the function BotGetReachabilityToGoal
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int BotAddToTarget(vec3_t start, vec3_t end, float maxdist, float *dist, vec3_t target)
-{
- vec3_t dir;
- float curdist;
-
- VectorSubtract(end, start, dir);
- curdist = VectorNormalize(dir);
- if (*dist + curdist < maxdist)
- {
- VectorCopy(end, target);
- *dist += curdist;
- return qfalse;
- } //end if
- else
- {
- VectorMA(start, maxdist - *dist, dir, target);
- *dist = maxdist;
- return qtrue;
- } //end else
-} //end of the function BotAddToTarget
-
-int BotMovementViewTarget(int movestate, bot_goal_t *goal, int travelflags, float lookahead, vec3_t target)
-{
- aas_reachability_t reach;
- int reachnum, lastareanum;
- bot_movestate_t *ms;
- vec3_t end;
- float dist;
-
- ms = BotMoveStateFromHandle(movestate);
- if (!ms) return qfalse;
- reachnum = 0;
- //if the bot has no goal or no last reachability
- if (!ms->lastreachnum || !goal) return qfalse;
-
- reachnum = ms->lastreachnum;
- VectorCopy(ms->origin, end);
- lastareanum = ms->lastareanum;
- dist = 0;
- while(reachnum && dist < lookahead)
- {
- AAS_ReachabilityFromNum(reachnum, &reach);
- if (BotAddToTarget(end, reach.start, lookahead, &dist, target)) return qtrue;
- //never look beyond teleporters
- if ((reach.traveltype & TRAVELTYPE_MASK) == TRAVEL_TELEPORT) return qtrue;
- //never look beyond the weapon jump point
- if ((reach.traveltype & TRAVELTYPE_MASK) == TRAVEL_ROCKETJUMP) return qtrue;
- if ((reach.traveltype & TRAVELTYPE_MASK) == TRAVEL_BFGJUMP) return qtrue;
- //don't add jump pad distances
- if ((reach.traveltype & TRAVELTYPE_MASK) != TRAVEL_JUMPPAD &&
- (reach.traveltype & TRAVELTYPE_MASK) != TRAVEL_ELEVATOR &&
- (reach.traveltype & TRAVELTYPE_MASK) != TRAVEL_FUNCBOB)
- {
- if (BotAddToTarget(reach.start, reach.end, lookahead, &dist, target)) return qtrue;
- } //end if
- reachnum = BotGetReachabilityToGoal(reach.end, reach.areanum,
- ms->lastgoalareanum, lastareanum,
- ms->avoidreach, ms->avoidreachtimes, ms->avoidreachtries,
- goal, travelflags, travelflags, NULL, 0, NULL);
- VectorCopy(reach.end, end);
- lastareanum = reach.areanum;
- if (lastareanum == goal->areanum)
- {
- BotAddToTarget(reach.end, goal->origin, lookahead, &dist, target);
- return qtrue;
- } //end if
- } //end while
- //
- return qfalse;
-} //end of the function BotMovementViewTarget
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int BotVisible(int ent, vec3_t eye, vec3_t target)
-{
- bsp_trace_t trace;
-
- trace = AAS_Trace(eye, NULL, NULL, target, ent, CONTENTS_SOLID|CONTENTS_PLAYERCLIP);
- if (trace.fraction >= 1) return qtrue;
- return qfalse;
-} //end of the function BotVisible
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int BotPredictVisiblePosition(vec3_t origin, int areanum, bot_goal_t *goal, int travelflags, vec3_t target)
-{
- aas_reachability_t reach;
- int reachnum, lastgoalareanum, lastareanum, i;
- int avoidreach[MAX_AVOIDREACH];
- float avoidreachtimes[MAX_AVOIDREACH];
- int avoidreachtries[MAX_AVOIDREACH];
- vec3_t end;
-
- //if the bot has no goal or no last reachability
- if (!goal) return qfalse;
- //if the areanum is not valid
- if (!areanum) return qfalse;
- //if the goal areanum is not valid
- if (!goal->areanum) return qfalse;
-
- Com_Memset(avoidreach, 0, MAX_AVOIDREACH * sizeof(int));
- lastgoalareanum = goal->areanum;
- lastareanum = areanum;
- VectorCopy(origin, end);
- //only do 20 hops
- for (i = 0; i < 20 && (areanum != goal->areanum); i++)
- {
- //
- reachnum = BotGetReachabilityToGoal(end, areanum,
- lastgoalareanum, lastareanum,
- avoidreach, avoidreachtimes, avoidreachtries,
- goal, travelflags, travelflags, NULL, 0, NULL);
- if (!reachnum) return qfalse;
- AAS_ReachabilityFromNum(reachnum, &reach);
- //
- if (BotVisible(goal->entitynum, goal->origin, reach.start))
- {
- VectorCopy(reach.start, target);
- return qtrue;
- } //end if
- //
- if (BotVisible(goal->entitynum, goal->origin, reach.end))
- {
- VectorCopy(reach.end, target);
- return qtrue;
- } //end if
- //
- if (reach.areanum == goal->areanum)
- {
- VectorCopy(reach.end, target);
- return qtrue;
- } //end if
- //
- lastareanum = areanum;
- areanum = reach.areanum;
- VectorCopy(reach.end, end);
- //
- } //end while
- //
- return qfalse;
-} //end of the function BotPredictVisiblePosition
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void MoverBottomCenter(aas_reachability_t *reach, vec3_t bottomcenter)
-{
- int modelnum;
- vec3_t mins, maxs, origin, mids;
- vec3_t angles = {0, 0, 0};
-
- modelnum = reach->facenum & 0x0000FFFF;
- //get some bsp model info
- AAS_BSPModelMinsMaxsOrigin(modelnum, angles, mins, maxs, origin);
- //
- if (!AAS_OriginOfMoverWithModelNum(modelnum, origin))
- {
- botimport.Print(PRT_MESSAGE, "no entity with model %d\n", modelnum);
- } //end if
- //get a point just above the plat in the bottom position
- VectorAdd(mins, maxs, mids);
- VectorMA(origin, 0.5, mids, bottomcenter);
- bottomcenter[2] = reach->start[2];
-} //end of the function MoverBottomCenter
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-float BotGapDistance(vec3_t origin, vec3_t hordir, int entnum)
-{
- float dist, startz;
- vec3_t start, end;
- aas_trace_t trace;
-
- //do gap checking
- startz = origin[2];
- //this enables walking down stairs more fluidly
- {
- VectorCopy(origin, start);
- VectorCopy(origin, end);
- end[2] -= 60;
- trace = AAS_TraceClientBBox(start, end, PRESENCE_CROUCH, entnum);
- if (trace.fraction >= 1) return 1;
- startz = trace.endpos[2] + 1;
- }
- //
- for (dist = 8; dist <= 100; dist += 8)
- {
- VectorMA(origin, dist, hordir, start);
- start[2] = startz + 24;
- VectorCopy(start, end);
- end[2] -= 48 + sv_maxbarrier->value;
- trace = AAS_TraceClientBBox(start, end, PRESENCE_CROUCH, entnum);
- //if solid is found the bot can't walk any further and fall into a gap
- if (!trace.startsolid)
- {
- //if it is a gap
- if (trace.endpos[2] < startz - sv_maxstep->value - 8)
- {
- VectorCopy(trace.endpos, end);
- end[2] -= 20;
- if (AAS_PointContents(end) & CONTENTS_WATER) break;
- //if a gap is found slow down
- //botimport.Print(PRT_MESSAGE, "gap at %f\n", dist);
- return dist;
- } //end if
- startz = trace.endpos[2];
- } //end if
- } //end for
- return 0;
-} //end of the function BotGapDistance
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int BotCheckBarrierJump(bot_movestate_t *ms, vec3_t dir, float speed)
-{
- vec3_t start, hordir, end;
- aas_trace_t trace;
-
- VectorCopy(ms->origin, end);
- end[2] += sv_maxbarrier->value;
- //trace right up
- trace = AAS_TraceClientBBox(ms->origin, end, PRESENCE_NORMAL, ms->entitynum);
- //this shouldn't happen... but we check anyway
- if (trace.startsolid) return qfalse;
- //if very low ceiling it isn't possible to jump up to a barrier
- if (trace.endpos[2] - ms->origin[2] < sv_maxstep->value) return qfalse;
- //
- hordir[0] = dir[0];
- hordir[1] = dir[1];
- hordir[2] = 0;
- VectorNormalize(hordir);
- VectorMA(ms->origin, ms->thinktime * speed * 0.5, hordir, end);
- VectorCopy(trace.endpos, start);
- end[2] = trace.endpos[2];
- //trace from previous trace end pos horizontally in the move direction
- trace = AAS_TraceClientBBox(start, end, PRESENCE_NORMAL, ms->entitynum);
- //again this shouldn't happen
- if (trace.startsolid) return qfalse;
- //
- VectorCopy(trace.endpos, start);
- VectorCopy(trace.endpos, end);
- end[2] = ms->origin[2];
- //trace down from the previous trace end pos
- trace = AAS_TraceClientBBox(start, end, PRESENCE_NORMAL, ms->entitynum);
- //if solid
- if (trace.startsolid) return qfalse;
- //if no obstacle at all
- if (trace.fraction >= 1.0) return qfalse;
- //if less than the maximum step height
- if (trace.endpos[2] - ms->origin[2] < sv_maxstep->value) return qfalse;
- //
- EA_Jump(ms->client);
- EA_Move(ms->client, hordir, speed);
- ms->moveflags |= MFL_BARRIERJUMP;
- //there is a barrier
- return qtrue;
-} //end of the function BotCheckBarrierJump
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int BotSwimInDirection(bot_movestate_t *ms, vec3_t dir, float speed, int type)
-{
- vec3_t normdir;
-
- VectorCopy(dir, normdir);
- VectorNormalize(normdir);
- EA_Move(ms->client, normdir, speed);
- return qtrue;
-} //end of the function BotSwimInDirection
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int BotWalkInDirection(bot_movestate_t *ms, vec3_t dir, float speed, int type)
-{
- vec3_t hordir, cmdmove, velocity, tmpdir, origin;
- int presencetype, maxframes, cmdframes, stopevent;
- aas_clientmove_t move;
- float dist;
-
- if (AAS_OnGround(ms->origin, ms->presencetype, ms->entitynum)) ms->moveflags |= MFL_ONGROUND;
- //if the bot is on the ground
- if (ms->moveflags & MFL_ONGROUND)
- {
- //if there is a barrier the bot can jump on
- if (BotCheckBarrierJump(ms, dir, speed)) return qtrue;
- //remove barrier jump flag
- ms->moveflags &= ~MFL_BARRIERJUMP;
- //get the presence type for the movement
- if ((type & MOVE_CROUCH) && !(type & MOVE_JUMP)) presencetype = PRESENCE_CROUCH;
- else presencetype = PRESENCE_NORMAL;
- //horizontal direction
- hordir[0] = dir[0];
- hordir[1] = dir[1];
- hordir[2] = 0;
- VectorNormalize(hordir);
- //if the bot is not supposed to jump
- if (!(type & MOVE_JUMP))
- {
- //if there is a gap, try to jump over it
- if (BotGapDistance(ms->origin, hordir, ms->entitynum) > 0) type |= MOVE_JUMP;
- } //end if
- //get command movement
- VectorScale(hordir, speed, cmdmove);
- VectorCopy(ms->velocity, velocity);
- //
- if (type & MOVE_JUMP)
- {
- //botimport.Print(PRT_MESSAGE, "trying jump\n");
- cmdmove[2] = 400;
- maxframes = PREDICTIONTIME_JUMP / 0.1;
- cmdframes = 1;
- stopevent = SE_HITGROUND|SE_HITGROUNDDAMAGE|
- SE_ENTERWATER|SE_ENTERSLIME|SE_ENTERLAVA;
- } //end if
- else
- {
- maxframes = 2;
- cmdframes = 2;
- stopevent = SE_HITGROUNDDAMAGE|
- SE_ENTERWATER|SE_ENTERSLIME|SE_ENTERLAVA;
- } //end else
- //AAS_ClearShownDebugLines();
- //
- VectorCopy(ms->origin, origin);
- origin[2] += 0.5;
- AAS_PredictClientMovement(&move, ms->entitynum, origin, presencetype, qtrue,
- velocity, cmdmove, cmdframes, maxframes, 0.1f,
- stopevent, 0, qfalse);//qtrue);
- //if prediction time wasn't enough to fully predict the movement
- if (move.frames >= maxframes && (type & MOVE_JUMP))
- {
- //botimport.Print(PRT_MESSAGE, "client %d: max prediction frames\n", ms->client);
- return qfalse;
- } //end if
- //don't enter slime or lava and don't fall from too high
- if (move.stopevent & (SE_ENTERSLIME|SE_ENTERLAVA|SE_HITGROUNDDAMAGE))
- {
- //botimport.Print(PRT_MESSAGE, "client %d: would be hurt ", ms->client);
- //if (move.stopevent & SE_ENTERSLIME) botimport.Print(PRT_MESSAGE, "slime\n");
- //if (move.stopevent & SE_ENTERLAVA) botimport.Print(PRT_MESSAGE, "lava\n");
- //if (move.stopevent & SE_HITGROUNDDAMAGE) botimport.Print(PRT_MESSAGE, "hitground\n");
- return qfalse;
- } //end if
- //if ground was hit
- if (move.stopevent & SE_HITGROUND)
- {
- //check for nearby gap
- VectorNormalize2(move.velocity, tmpdir);
- dist = BotGapDistance(move.endpos, tmpdir, ms->entitynum);
- if (dist > 0) return qfalse;
- //
- dist = BotGapDistance(move.endpos, hordir, ms->entitynum);
- if (dist > 0) return qfalse;
- } //end if
- //get horizontal movement
- tmpdir[0] = move.endpos[0] - ms->origin[0];
- tmpdir[1] = move.endpos[1] - ms->origin[1];
- tmpdir[2] = 0;
- //
- //AAS_DrawCross(move.endpos, 4, LINECOLOR_BLUE);
- //the bot is blocked by something
- if (VectorLength(tmpdir) < speed * ms->thinktime * 0.5) return qfalse;
- //perform the movement
- if (type & MOVE_JUMP) EA_Jump(ms->client);
- if (type & MOVE_CROUCH) EA_Crouch(ms->client);
- EA_Move(ms->client, hordir, speed);
- //movement was succesfull
- return qtrue;
- } //end if
- else
- {
- if (ms->moveflags & MFL_BARRIERJUMP)
- {
- //if near the top or going down
- if (ms->velocity[2] < 50)
- {
- EA_Move(ms->client, dir, speed);
- } //end if
- } //end if
- //FIXME: do air control to avoid hazards
- return qtrue;
- } //end else
-} //end of the function BotWalkInDirection
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int BotMoveInDirection(int movestate, vec3_t dir, float speed, int type)
-{
- bot_movestate_t *ms;
-
- ms = BotMoveStateFromHandle(movestate);
- if (!ms) return qfalse;
- //if swimming
- if (AAS_Swimming(ms->origin))
- {
- return BotSwimInDirection(ms, dir, speed, type);
- } //end if
- else
- {
- return BotWalkInDirection(ms, dir, speed, type);
- } //end else
-} //end of the function BotMoveInDirection
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int Intersection(vec2_t p1, vec2_t p2, vec2_t p3, vec2_t p4, vec2_t out)
-{
- float x1, dx1, dy1, x2, dx2, dy2, d;
-
- dx1 = p2[0] - p1[0];
- dy1 = p2[1] - p1[1];
- dx2 = p4[0] - p3[0];
- dy2 = p4[1] - p3[1];
-
- d = dy1 * dx2 - dx1 * dy2;
- if (d != 0)
- {
- x1 = p1[1] * dx1 - p1[0] * dy1;
- x2 = p3[1] * dx2 - p3[0] * dy2;
- out[0] = (int) ((dx1 * x2 - dx2 * x1) / d);
- out[1] = (int) ((dy1 * x2 - dy2 * x1) / d);
- return qtrue;
- } //end if
- else
- {
- return qfalse;
- } //end else
-} //end of the function Intersection
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void BotCheckBlocked(bot_movestate_t *ms, vec3_t dir, int checkbottom, bot_moveresult_t *result)
-{
- vec3_t mins, maxs, end, up = {0, 0, 1};
- bsp_trace_t trace;
-
- //test for entities obstructing the bot's path
- AAS_PresenceTypeBoundingBox(ms->presencetype, mins, maxs);
- //
- if (fabs(DotProduct(dir, up)) < 0.7)
- {
- mins[2] += sv_maxstep->value; //if the bot can step on
- maxs[2] -= 10; //a little lower to avoid low ceiling
- } //end if
- VectorMA(ms->origin, 3, dir, end);
- trace = AAS_Trace(ms->origin, mins, maxs, end, ms->entitynum, CONTENTS_SOLID|CONTENTS_PLAYERCLIP|CONTENTS_BODY);
- //if not started in solid and not hitting the world entity
- if (!trace.startsolid && (trace.ent != ENTITYNUM_WORLD && trace.ent != ENTITYNUM_NONE) )
- {
- result->blocked = qtrue;
- result->blockentity = trace.ent;
-#ifdef DEBUG
- //botimport.Print(PRT_MESSAGE, "%d: BotCheckBlocked: I'm blocked\n", ms->client);
-#endif //DEBUG
- } //end if
- //if not in an area with reachability
- else if (checkbottom && !AAS_AreaReachability(ms->areanum))
- {
- //check if the bot is standing on something
- AAS_PresenceTypeBoundingBox(ms->presencetype, mins, maxs);
- VectorMA(ms->origin, -3, up, end);
- trace = AAS_Trace(ms->origin, mins, maxs, end, ms->entitynum, CONTENTS_SOLID|CONTENTS_PLAYERCLIP);
- if (!trace.startsolid && (trace.ent != ENTITYNUM_WORLD && trace.ent != ENTITYNUM_NONE) )
- {
- result->blocked = qtrue;
- result->blockentity = trace.ent;
- result->flags |= MOVERESULT_ONTOPOFOBSTACLE;
-#ifdef DEBUG
- //botimport.Print(PRT_MESSAGE, "%d: BotCheckBlocked: I'm blocked\n", ms->client);
-#endif //DEBUG
- } //end if
- } //end else
-} //end of the function BotCheckBlocked
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void BotClearMoveResult(bot_moveresult_t *moveresult)
-{
- moveresult->failure = qfalse;
- moveresult->type = 0;
- moveresult->blocked = qfalse;
- moveresult->blockentity = 0;
- moveresult->traveltype = 0;
- moveresult->flags = 0;
-} //end of the function BotClearMoveResult
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-bot_moveresult_t BotTravel_Walk(bot_movestate_t *ms, aas_reachability_t *reach)
-{
- float dist, speed;
- vec3_t hordir;
- bot_moveresult_t result;
-
- BotClearMoveResult(&result);
- //first walk straight to the reachability start
- hordir[0] = reach->start[0] - ms->origin[0];
- hordir[1] = reach->start[1] - ms->origin[1];
- hordir[2] = 0;
- dist = VectorNormalize(hordir);
- //
- BotCheckBlocked(ms, hordir, qtrue, &result);
- //
- if (dist < 10)
- {
- //walk straight to the reachability end
- hordir[0] = reach->end[0] - ms->origin[0];
- hordir[1] = reach->end[1] - ms->origin[1];
- hordir[2] = 0;
- dist = VectorNormalize(hordir);
- } //end if
- //if going towards a crouch area
- if (!(AAS_AreaPresenceType(reach->areanum) & PRESENCE_NORMAL))
- {
- //if pretty close to the reachable area
- if (dist < 20) EA_Crouch(ms->client);
- } //end if
- //
- dist = BotGapDistance(ms->origin, hordir, ms->entitynum);
- //
- if (ms->moveflags & MFL_WALK)
- {
- if (dist > 0) speed = 200 - (180 - 1 * dist);
- else speed = 200;
- EA_Walk(ms->client);
- } //end if
- else
- {
- if (dist > 0) speed = 400 - (360 - 2 * dist);
- else speed = 400;
- } //end else
- //elemantary action move in direction
- EA_Move(ms->client, hordir, speed);
- VectorCopy(hordir, result.movedir);
- //
- return result;
-} //end of the function BotTravel_Walk
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-bot_moveresult_t BotFinishTravel_Walk(bot_movestate_t *ms, aas_reachability_t *reach)
-{
- vec3_t hordir;
- float dist, speed;
- bot_moveresult_t result;
-
- BotClearMoveResult(&result);
- //if not on the ground and changed areas... don't walk back!!
- //(doesn't seem to help)
- /*
- ms->areanum = BotFuzzyPointReachabilityArea(ms->origin);
- if (ms->areanum == reach->areanum)
- {
-#ifdef DEBUG
- botimport.Print(PRT_MESSAGE, "BotFinishTravel_Walk: already in reach area\n");
-#endif //DEBUG
- return result;
- } //end if*/
- //go straight to the reachability end
- hordir[0] = reach->end[0] - ms->origin[0];
- hordir[1] = reach->end[1] - ms->origin[1];
- hordir[2] = 0;
- dist = VectorNormalize(hordir);
- //
- if (dist > 100) dist = 100;
- speed = 400 - (400 - 3 * dist);
- //
- EA_Move(ms->client, hordir, speed);
- VectorCopy(hordir, result.movedir);
- //
- return result;
-} //end of the function BotFinishTravel_Walk
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-bot_moveresult_t BotTravel_Crouch(bot_movestate_t *ms, aas_reachability_t *reach)
-{
- float speed;
- vec3_t hordir;
- bot_moveresult_t result;
-
- BotClearMoveResult(&result);
- //
- speed = 400;
- //walk straight to reachability end
- hordir[0] = reach->end[0] - ms->origin[0];
- hordir[1] = reach->end[1] - ms->origin[1];
- hordir[2] = 0;
- VectorNormalize(hordir);
- //
- BotCheckBlocked(ms, hordir, qtrue, &result);
- //elemantary actions
- EA_Crouch(ms->client);
- EA_Move(ms->client, hordir, speed);
- //
- VectorCopy(hordir, result.movedir);
- //
- return result;
-} //end of the function BotTravel_Crouch
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-bot_moveresult_t BotTravel_BarrierJump(bot_movestate_t *ms, aas_reachability_t *reach)
-{
- float dist, speed;
- vec3_t hordir;
- bot_moveresult_t result;
-
- BotClearMoveResult(&result);
- //walk straight to reachability start
- hordir[0] = reach->start[0] - ms->origin[0];
- hordir[1] = reach->start[1] - ms->origin[1];
- hordir[2] = 0;
- dist = VectorNormalize(hordir);
- //
- BotCheckBlocked(ms, hordir, qtrue, &result);
- //if pretty close to the barrier
- if (dist < 9)
- {
- EA_Jump(ms->client);
- } //end if
- else
- {
- if (dist > 60) dist = 60;
- speed = 360 - (360 - 6 * dist);
- EA_Move(ms->client, hordir, speed);
- } //end else
- VectorCopy(hordir, result.movedir);
- //
- return result;
-} //end of the function BotTravel_BarrierJump
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-bot_moveresult_t BotFinishTravel_BarrierJump(bot_movestate_t *ms, aas_reachability_t *reach)
-{
- float dist;
- vec3_t hordir;
- bot_moveresult_t result;
-
- BotClearMoveResult(&result);
- //if near the top or going down
- if (ms->velocity[2] < 250)
- {
- hordir[0] = reach->end[0] - ms->origin[0];
- hordir[1] = reach->end[1] - ms->origin[1];
- hordir[2] = 0;
- dist = VectorNormalize(hordir);
- //
- BotCheckBlocked(ms, hordir, qtrue, &result);
- //
- EA_Move(ms->client, hordir, 400);
- VectorCopy(hordir, result.movedir);
- } //end if
- //
- return result;
-} //end of the function BotFinishTravel_BarrierJump
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-bot_moveresult_t BotTravel_Swim(bot_movestate_t *ms, aas_reachability_t *reach)
-{
- vec3_t dir;
- bot_moveresult_t result;
-
- BotClearMoveResult(&result);
- //swim straight to reachability end
- VectorSubtract(reach->start, ms->origin, dir);
- VectorNormalize(dir);
- //
- BotCheckBlocked(ms, dir, qtrue, &result);
- //elemantary actions
- EA_Move(ms->client, dir, 400);
- //
- VectorCopy(dir, result.movedir);
- Vector2Angles(dir, result.ideal_viewangles);
- result.flags |= MOVERESULT_SWIMVIEW;
- //
- return result;
-} //end of the function BotTravel_Swim
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-bot_moveresult_t BotTravel_WaterJump(bot_movestate_t *ms, aas_reachability_t *reach)
-{
- vec3_t dir, hordir;
- float dist;
- bot_moveresult_t result;
-
- BotClearMoveResult(&result);
- //swim straight to reachability end
- VectorSubtract(reach->end, ms->origin, dir);
- VectorCopy(dir, hordir);
- hordir[2] = 0;
- dir[2] += 15 + crandom() * 40;
- //botimport.Print(PRT_MESSAGE, "BotTravel_WaterJump: dir[2] = %f\n", dir[2]);
- VectorNormalize(dir);
- dist = VectorNormalize(hordir);
- //elemantary actions
- //EA_Move(ms->client, dir, 400);
- EA_MoveForward(ms->client);
- //move up if close to the actual out of water jump spot
- if (dist < 40) EA_MoveUp(ms->client);
- //set the ideal view angles
- Vector2Angles(dir, result.ideal_viewangles);
- result.flags |= MOVERESULT_MOVEMENTVIEW;
- //
- VectorCopy(dir, result.movedir);
- //
- return result;
-} //end of the function BotTravel_WaterJump
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-bot_moveresult_t BotFinishTravel_WaterJump(bot_movestate_t *ms, aas_reachability_t *reach)
-{
- vec3_t dir, pnt;
- float dist;
- bot_moveresult_t result;
-
- //botimport.Print(PRT_MESSAGE, "BotFinishTravel_WaterJump\n");
- BotClearMoveResult(&result);
- //if waterjumping there's nothing to do
- if (ms->moveflags & MFL_WATERJUMP) return result;
- //if not touching any water anymore don't do anything
- //otherwise the bot sometimes keeps jumping?
- VectorCopy(ms->origin, pnt);
- pnt[2] -= 32; //extra for q2dm4 near red armor/mega health
- if (!(AAS_PointContents(pnt) & (CONTENTS_LAVA|CONTENTS_SLIME|CONTENTS_WATER))) return result;
- //swim straight to reachability end
- VectorSubtract(reach->end, ms->origin, dir);
- dir[0] += crandom() * 10;
- dir[1] += crandom() * 10;
- dir[2] += 70 + crandom() * 10;
- dist = VectorNormalize(dir);
- //elemantary actions
- EA_Move(ms->client, dir, 400);
- //set the ideal view angles
- Vector2Angles(dir, result.ideal_viewangles);
- result.flags |= MOVERESULT_MOVEMENTVIEW;
- //
- VectorCopy(dir, result.movedir);
- //
- return result;
-} //end of the function BotFinishTravel_WaterJump
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-bot_moveresult_t BotTravel_WalkOffLedge(bot_movestate_t *ms, aas_reachability_t *reach)
-{
- vec3_t hordir, dir;
- float dist, speed, reachhordist;
- bot_moveresult_t result;
-
- BotClearMoveResult(&result);
- //check if the bot is blocked by anything
- VectorSubtract(reach->start, ms->origin, dir);
- VectorNormalize(dir);
- BotCheckBlocked(ms, dir, qtrue, &result);
- //if the reachability start and end are practially above each other
- VectorSubtract(reach->end, reach->start, dir);
- dir[2] = 0;
- reachhordist = VectorLength(dir);
- //walk straight to the reachability start
- hordir[0] = reach->start[0] - ms->origin[0];
- hordir[1] = reach->start[1] - ms->origin[1];
- hordir[2] = 0;
- dist = VectorNormalize(hordir);
- //if pretty close to the start focus on the reachability end
- if (dist < 48)
- {
- hordir[0] = reach->end[0] - ms->origin[0];
- hordir[1] = reach->end[1] - ms->origin[1];
- hordir[2] = 0;
- VectorNormalize(hordir);
- //
- if (reachhordist < 20)
- {
- speed = 100;
- } //end if
- else if (!AAS_HorizontalVelocityForJump(0, reach->start, reach->end, &speed))
- {
- speed = 400;
- } //end if
- } //end if
- else
- {
- if (reachhordist < 20)
- {
- if (dist > 64) dist = 64;
- speed = 400 - (256 - 4 * dist);
- } //end if
- else
- {
- speed = 400;
- } //end else
- } //end else
- //
- BotCheckBlocked(ms, hordir, qtrue, &result);
- //elemantary action
- EA_Move(ms->client, hordir, speed);
- VectorCopy(hordir, result.movedir);
- //
- return result;
-} //end of the function BotTravel_WalkOffLedge
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int BotAirControl(vec3_t origin, vec3_t velocity, vec3_t goal, vec3_t dir, float *speed)
-{
- vec3_t org, vel;
- float dist;
- int i;
-
- VectorCopy(origin, org);
- VectorScale(velocity, 0.1, vel);
- for (i = 0; i < 50; i++)
- {
- vel[2] -= sv_gravity->value * 0.01;
- //if going down and next position would be below the goal
- if (vel[2] < 0 && org[2] + vel[2] < goal[2])
- {
- VectorScale(vel, (goal[2] - org[2]) / vel[2], vel);
- VectorAdd(org, vel, org);
- VectorSubtract(goal, org, dir);
- dist = VectorNormalize(dir);
- if (dist > 32) dist = 32;
- *speed = 400 - (400 - 13 * dist);
- return qtrue;
- } //end if
- else
- {
- VectorAdd(org, vel, org);
- } //end else
- } //end for
- VectorSet(dir, 0, 0, 0);
- *speed = 400;
- return qfalse;
-} //end of the function BotAirControl
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-bot_moveresult_t BotFinishTravel_WalkOffLedge(bot_movestate_t *ms, aas_reachability_t *reach)
-{
- vec3_t dir, hordir, end, v;
- float dist, speed;
- bot_moveresult_t result;
-
- BotClearMoveResult(&result);
- //
- VectorSubtract(reach->end, ms->origin, dir);
- BotCheckBlocked(ms, dir, qtrue, &result);
- //
- VectorSubtract(reach->end, ms->origin, v);
- v[2] = 0;
- dist = VectorNormalize(v);
- if (dist > 16) VectorMA(reach->end, 16, v, end);
- else VectorCopy(reach->end, end);
- //
- if (!BotAirControl(ms->origin, ms->velocity, end, hordir, &speed))
- {
- //go straight to the reachability end
- VectorCopy(dir, hordir);
- hordir[2] = 0;
- //
- dist = VectorNormalize(hordir);
- speed = 400;
- } //end if
- //
- EA_Move(ms->client, hordir, speed);
- VectorCopy(hordir, result.movedir);
- //
- return result;
-} //end of the function BotFinishTravel_WalkOffLedge
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-/*
-bot_moveresult_t BotTravel_Jump(bot_movestate_t *ms, aas_reachability_t *reach)
-{
- vec3_t hordir;
- float dist, gapdist, speed, horspeed, sv_jumpvel;
- bot_moveresult_t result;
-
- BotClearMoveResult(&result);
- //
- sv_jumpvel = botlibglobals.sv_jumpvel->value;
- //walk straight to the reachability start
- hordir[0] = reach->start[0] - ms->origin[0];
- hordir[1] = reach->start[1] - ms->origin[1];
- hordir[2] = 0;
- dist = VectorNormalize(hordir);
- //
- speed = 350;
- //
- gapdist = BotGapDistance(ms, hordir, ms->entitynum);
- //if pretty close to the start focus on the reachability end
- if (dist < 50 || (gapdist && gapdist < 50))
- {
- //NOTE: using max speed (400) works best
- //if (AAS_HorizontalVelocityForJump(sv_jumpvel, ms->origin, reach->end, &horspeed))
- //{
- // speed = horspeed * 400 / botlibglobals.sv_maxwalkvelocity->value;
- //} //end if
- hordir[0] = reach->end[0] - ms->origin[0];
- hordir[1] = reach->end[1] - ms->origin[1];
- VectorNormalize(hordir);
- //elemantary action jump
- EA_Jump(ms->client);
- //
- ms->jumpreach = ms->lastreachnum;
- speed = 600;
- } //end if
- else
- {
- if (AAS_HorizontalVelocityForJump(sv_jumpvel, reach->start, reach->end, &horspeed))
- {
- speed = horspeed * 400 / botlibglobals.sv_maxwalkvelocity->value;
- } //end if
- } //end else
- //elemantary action
- EA_Move(ms->client, hordir, speed);
- VectorCopy(hordir, result.movedir);
- //
- return result;
-} //end of the function BotTravel_Jump*/
-/*
-bot_moveresult_t BotTravel_Jump(bot_movestate_t *ms, aas_reachability_t *reach)
-{
- vec3_t hordir, dir1, dir2, mins, maxs, start, end;
- float dist1, dist2, speed;
- bot_moveresult_t result;
- bsp_trace_t trace;
-
- BotClearMoveResult(&result);
- //
- hordir[0] = reach->start[0] - reach->end[0];
- hordir[1] = reach->start[1] - reach->end[1];
- hordir[2] = 0;
- VectorNormalize(hordir);
- //
- VectorCopy(reach->start, start);
- start[2] += 1;
- //minus back the bouding box size plus 16
- VectorMA(reach->start, 80, hordir, end);
- //
- AAS_PresenceTypeBoundingBox(PRESENCE_NORMAL, mins, maxs);
- //check for solids
- trace = AAS_Trace(start, mins, maxs, end, ms->entitynum, MASK_PLAYERSOLID);
- if (trace.startsolid) VectorCopy(start, trace.endpos);
- //check for a gap
- for (dist1 = 0; dist1 < 80; dist1 += 10)
- {
- VectorMA(start, dist1+10, hordir, end);
- end[2] += 1;
- if (AAS_PointAreaNum(end) != ms->reachareanum) break;
- } //end for
- if (dist1 < 80) VectorMA(reach->start, dist1, hordir, trace.endpos);
-// dist1 = BotGapDistance(start, hordir, ms->entitynum);
-// if (dist1 && dist1 <= trace.fraction * 80) VectorMA(reach->start, dist1-20, hordir, trace.endpos);
- //
- VectorSubtract(ms->origin, reach->start, dir1);
- dir1[2] = 0;
- dist1 = VectorNormalize(dir1);
- VectorSubtract(ms->origin, trace.endpos, dir2);
- dir2[2] = 0;
- dist2 = VectorNormalize(dir2);
- //if just before the reachability start
- if (DotProduct(dir1, dir2) < -0.8 || dist2 < 5)
- {
- //botimport.Print(PRT_MESSAGE, "between jump start and run to point\n");
- hordir[0] = reach->end[0] - ms->origin[0];
- hordir[1] = reach->end[1] - ms->origin[1];
- hordir[2] = 0;
- VectorNormalize(hordir);
- //elemantary action jump
- if (dist1 < 24) EA_Jump(ms->client);
- else if (dist1 < 32) EA_DelayedJump(ms->client);
- EA_Move(ms->client, hordir, 600);
- //
- ms->jumpreach = ms->lastreachnum;
- } //end if
- else
- {
- //botimport.Print(PRT_MESSAGE, "going towards run to point\n");
- hordir[0] = trace.endpos[0] - ms->origin[0];
- hordir[1] = trace.endpos[1] - ms->origin[1];
- hordir[2] = 0;
- VectorNormalize(hordir);
- //
- if (dist2 > 80) dist2 = 80;
- speed = 400 - (400 - 5 * dist2);
- EA_Move(ms->client, hordir, speed);
- } //end else
- VectorCopy(hordir, result.movedir);
- //
- return result;
-} //end of the function BotTravel_Jump*/
-//*
-bot_moveresult_t BotTravel_Jump(bot_movestate_t *ms, aas_reachability_t *reach)
-{
- vec3_t hordir, dir1, dir2, start, end, runstart;
-// vec3_t runstart, dir1, dir2, hordir;
- float dist1, dist2, speed;
- bot_moveresult_t result;
-
- BotClearMoveResult(&result);
- //
- AAS_JumpReachRunStart(reach, runstart);
- //*
- hordir[0] = runstart[0] - reach->start[0];
- hordir[1] = runstart[1] - reach->start[1];
- hordir[2] = 0;
- VectorNormalize(hordir);
- //
- VectorCopy(reach->start, start);
- start[2] += 1;
- VectorMA(reach->start, 80, hordir, runstart);
- //check for a gap
- for (dist1 = 0; dist1 < 80; dist1 += 10)
- {
- VectorMA(start, dist1+10, hordir, end);
- end[2] += 1;
- if (AAS_PointAreaNum(end) != ms->reachareanum) break;
- } //end for
- if (dist1 < 80) VectorMA(reach->start, dist1, hordir, runstart);
- //
- VectorSubtract(ms->origin, reach->start, dir1);
- dir1[2] = 0;
- dist1 = VectorNormalize(dir1);
- VectorSubtract(ms->origin, runstart, dir2);
- dir2[2] = 0;
- dist2 = VectorNormalize(dir2);
- //if just before the reachability start
- if (DotProduct(dir1, dir2) < -0.8 || dist2 < 5)
- {
-// botimport.Print(PRT_MESSAGE, "between jump start and run start point\n");
- hordir[0] = reach->end[0] - ms->origin[0];
- hordir[1] = reach->end[1] - ms->origin[1];
- hordir[2] = 0;
- VectorNormalize(hordir);
- //elemantary action jump
- if (dist1 < 24) EA_Jump(ms->client);
- else if (dist1 < 32) EA_DelayedJump(ms->client);
- EA_Move(ms->client, hordir, 600);
- //
- ms->jumpreach = ms->lastreachnum;
- } //end if
- else
- {
-// botimport.Print(PRT_MESSAGE, "going towards run start point\n");
- hordir[0] = runstart[0] - ms->origin[0];
- hordir[1] = runstart[1] - ms->origin[1];
- hordir[2] = 0;
- VectorNormalize(hordir);
- //
- if (dist2 > 80) dist2 = 80;
- speed = 400 - (400 - 5 * dist2);
- EA_Move(ms->client, hordir, speed);
- } //end else
- VectorCopy(hordir, result.movedir);
- //
- return result;
-} //end of the function BotTravel_Jump*/
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-bot_moveresult_t BotFinishTravel_Jump(bot_movestate_t *ms, aas_reachability_t *reach)
-{
- vec3_t hordir, hordir2;
- float speed, dist;
- bot_moveresult_t result;
-
- BotClearMoveResult(&result);
- //if not jumped yet
- if (!ms->jumpreach) return result;
- //go straight to the reachability end
- hordir[0] = reach->end[0] - ms->origin[0];
- hordir[1] = reach->end[1] - ms->origin[1];
- hordir[2] = 0;
- dist = VectorNormalize(hordir);
- //
- hordir2[0] = reach->end[0] - reach->start[0];
- hordir2[1] = reach->end[1] - reach->start[1];
- hordir2[2] = 0;
- VectorNormalize(hordir2);
- //
- if (DotProduct(hordir, hordir2) < -0.5 && dist < 24) return result;
- //always use max speed when traveling through the air
- speed = 800;
- //
- EA_Move(ms->client, hordir, speed);
- VectorCopy(hordir, result.movedir);
- //
- return result;
-} //end of the function BotFinishTravel_Jump
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-bot_moveresult_t BotTravel_Ladder(bot_movestate_t *ms, aas_reachability_t *reach)
-{
- //float dist, speed;
- vec3_t dir, viewdir;//, hordir;
- vec3_t origin = {0, 0, 0};
-// vec3_t up = {0, 0, 1};
- bot_moveresult_t result;
-
- BotClearMoveResult(&result);
- //
-// if ((ms->moveflags & MFL_AGAINSTLADDER))
- //NOTE: not a good idea for ladders starting in water
- // || !(ms->moveflags & MFL_ONGROUND))
- {
- //botimport.Print(PRT_MESSAGE, "against ladder or not on ground\n");
- VectorSubtract(reach->end, ms->origin, dir);
- VectorNormalize(dir);
- //set the ideal view angles, facing the ladder up or down
- viewdir[0] = dir[0];
- viewdir[1] = dir[1];
- viewdir[2] = 3 * dir[2];
- Vector2Angles(viewdir, result.ideal_viewangles);
- //elemantary action
- EA_Move(ms->client, origin, 0);
- EA_MoveForward(ms->client);
- //set movement view flag so the AI can see the view is focussed
- result.flags |= MOVERESULT_MOVEMENTVIEW;
- } //end if
-/* else
- {
- //botimport.Print(PRT_MESSAGE, "moving towards ladder\n");
- VectorSubtract(reach->end, ms->origin, dir);
- //make sure the horizontal movement is large anough
- VectorCopy(dir, hordir);
- hordir[2] = 0;
- dist = VectorNormalize(hordir);
- //
- dir[0] = hordir[0];
- dir[1] = hordir[1];
- if (dir[2] > 0) dir[2] = 1;
- else dir[2] = -1;
- if (dist > 50) dist = 50;
- speed = 400 - (200 - 4 * dist);
- EA_Move(ms->client, dir, speed);
- } //end else*/
- //save the movement direction
- VectorCopy(dir, result.movedir);
- //
- return result;
-} //end of the function BotTravel_Ladder
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-bot_moveresult_t BotTravel_Teleport(bot_movestate_t *ms, aas_reachability_t *reach)
-{
- vec3_t hordir;
- float dist;
- bot_moveresult_t result;
-
- BotClearMoveResult(&result);
- //if the bot is being teleported
- if (ms->moveflags & MFL_TELEPORTED) return result;
-
- //walk straight to center of the teleporter
- VectorSubtract(reach->start, ms->origin, hordir);
- if (!(ms->moveflags & MFL_SWIMMING)) hordir[2] = 0;
- dist = VectorNormalize(hordir);
- //
- BotCheckBlocked(ms, hordir, qtrue, &result);
-
- if (dist < 30) EA_Move(ms->client, hordir, 200);
- else EA_Move(ms->client, hordir, 400);
-
- if (ms->moveflags & MFL_SWIMMING) result.flags |= MOVERESULT_SWIMVIEW;
-
- VectorCopy(hordir, result.movedir);
- return result;
-} //end of the function BotTravel_Teleport
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-bot_moveresult_t BotTravel_Elevator(bot_movestate_t *ms, aas_reachability_t *reach)
-{
- vec3_t dir, dir1, dir2, hordir, bottomcenter;
- float dist, dist1, dist2, speed;
- bot_moveresult_t result;
-
- BotClearMoveResult(&result);
- //if standing on the plat
- if (BotOnMover(ms->origin, ms->entitynum, reach))
- {
-#ifdef DEBUG_ELEVATOR
- botimport.Print(PRT_MESSAGE, "bot on elevator\n");
-#endif //DEBUG_ELEVATOR
- //if vertically not too far from the end point
- if (abs(ms->origin[2] - reach->end[2]) < sv_maxbarrier->value)
- {
-#ifdef DEBUG_ELEVATOR
- botimport.Print(PRT_MESSAGE, "bot moving to end\n");
-#endif //DEBUG_ELEVATOR
- //move to the end point
- VectorSubtract(reach->end, ms->origin, hordir);
- hordir[2] = 0;
- VectorNormalize(hordir);
- if (!BotCheckBarrierJump(ms, hordir, 100))
- {
- EA_Move(ms->client, hordir, 400);
- } //end if
- VectorCopy(hordir, result.movedir);
- } //end else
- //if not really close to the center of the elevator
- else
- {
- MoverBottomCenter(reach, bottomcenter);
- VectorSubtract(bottomcenter, ms->origin, hordir);
- hordir[2] = 0;
- dist = VectorNormalize(hordir);
- //
- if (dist > 10)
- {
-#ifdef DEBUG_ELEVATOR
- botimport.Print(PRT_MESSAGE, "bot moving to center\n");
-#endif //DEBUG_ELEVATOR
- //move to the center of the plat
- if (dist > 100) dist = 100;
- speed = 400 - (400 - 4 * dist);
- //
- EA_Move(ms->client, hordir, speed);
- VectorCopy(hordir, result.movedir);
- } //end if
- } //end else
- } //end if
- else
- {
-#ifdef DEBUG_ELEVATOR
- botimport.Print(PRT_MESSAGE, "bot not on elevator\n");
-#endif //DEBUG_ELEVATOR
- //if very near the reachability end
- VectorSubtract(reach->end, ms->origin, dir);
- dist = VectorLength(dir);
- if (dist < 64)
- {
- if (dist > 60) dist = 60;
- speed = 360 - (360 - 6 * dist);
- //
- if ((ms->moveflags & MFL_SWIMMING) || !BotCheckBarrierJump(ms, dir, 50))
- {
- if (speed > 5) EA_Move(ms->client, dir, speed);
- } //end if
- VectorCopy(dir, result.movedir);
- //
- if (ms->moveflags & MFL_SWIMMING) result.flags |= MOVERESULT_SWIMVIEW;
- //stop using this reachability
- ms->reachability_time = 0;
- return result;
- } //end if
- //get direction and distance to reachability start
- VectorSubtract(reach->start, ms->origin, dir1);
- if (!(ms->moveflags & MFL_SWIMMING)) dir1[2] = 0;
- dist1 = VectorNormalize(dir1);
- //if the elevator isn't down
- if (!MoverDown(reach))
- {
-#ifdef DEBUG_ELEVATOR
- botimport.Print(PRT_MESSAGE, "elevator not down\n");
-#endif //DEBUG_ELEVATOR
- dist = dist1;
- VectorCopy(dir1, dir);
- //
- BotCheckBlocked(ms, dir, qfalse, &result);
- //
- if (dist > 60) dist = 60;
- speed = 360 - (360 - 6 * dist);
- //
- if (!(ms->moveflags & MFL_SWIMMING) && !BotCheckBarrierJump(ms, dir, 50))
- {
- if (speed > 5) EA_Move(ms->client, dir, speed);
- } //end if
- VectorCopy(dir, result.movedir);
- //
- if (ms->moveflags & MFL_SWIMMING) result.flags |= MOVERESULT_SWIMVIEW;
- //this isn't a failure... just wait till the elevator comes down
- result.type = RESULTTYPE_ELEVATORUP;
- result.flags |= MOVERESULT_WAITING;
- return result;
- } //end if
- //get direction and distance to elevator bottom center
- MoverBottomCenter(reach, bottomcenter);
- VectorSubtract(bottomcenter, ms->origin, dir2);
- if (!(ms->moveflags & MFL_SWIMMING)) dir2[2] = 0;
- dist2 = VectorNormalize(dir2);
- //if very close to the reachability start or
- //closer to the elevator center or
- //between reachability start and elevator center
- if (dist1 < 20 || dist2 < dist1 || DotProduct(dir1, dir2) < 0)
- {
-#ifdef DEBUG_ELEVATOR
- botimport.Print(PRT_MESSAGE, "bot moving to center\n");
-#endif //DEBUG_ELEVATOR
- dist = dist2;
- VectorCopy(dir2, dir);
- } //end if
- else //closer to the reachability start
- {
-#ifdef DEBUG_ELEVATOR
- botimport.Print(PRT_MESSAGE, "bot moving to start\n");
-#endif //DEBUG_ELEVATOR
- dist = dist1;
- VectorCopy(dir1, dir);
- } //end else
- //
- BotCheckBlocked(ms, dir, qfalse, &result);
- //
- if (dist > 60) dist = 60;
- speed = 400 - (400 - 6 * dist);
- //
- if (!(ms->moveflags & MFL_SWIMMING) && !BotCheckBarrierJump(ms, dir, 50))
- {
- EA_Move(ms->client, dir, speed);
- } //end if
- VectorCopy(dir, result.movedir);
- //
- if (ms->moveflags & MFL_SWIMMING) result.flags |= MOVERESULT_SWIMVIEW;
- } //end else
- return result;
-} //end of the function BotTravel_Elevator
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-bot_moveresult_t BotFinishTravel_Elevator(bot_movestate_t *ms, aas_reachability_t *reach)
-{
- vec3_t bottomcenter, bottomdir, topdir;
- bot_moveresult_t result;
-
- BotClearMoveResult(&result);
- //
- MoverBottomCenter(reach, bottomcenter);
- VectorSubtract(bottomcenter, ms->origin, bottomdir);
- //
- VectorSubtract(reach->end, ms->origin, topdir);
- //
- if (fabs(bottomdir[2]) < fabs(topdir[2]))
- {
- VectorNormalize(bottomdir);
- EA_Move(ms->client, bottomdir, 300);
- } //end if
- else
- {
- VectorNormalize(topdir);
- EA_Move(ms->client, topdir, 300);
- } //end else
- return result;
-} //end of the function BotFinishTravel_Elevator
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void BotFuncBobStartEnd(aas_reachability_t *reach, vec3_t start, vec3_t end, vec3_t origin)
-{
- int spawnflags, modelnum;
- vec3_t mins, maxs, mid, angles = {0, 0, 0};
- int num0, num1;
-
- modelnum = reach->facenum & 0x0000FFFF;
- if (!AAS_OriginOfMoverWithModelNum(modelnum, origin))
- {
- botimport.Print(PRT_MESSAGE, "BotFuncBobStartEnd: no entity with model %d\n", modelnum);
- VectorSet(start, 0, 0, 0);
- VectorSet(end, 0, 0, 0);
- return;
- } //end if
- AAS_BSPModelMinsMaxsOrigin(modelnum, angles, mins, maxs, NULL);
- VectorAdd(mins, maxs, mid);
- VectorScale(mid, 0.5, mid);
- VectorCopy(mid, start);
- VectorCopy(mid, end);
- spawnflags = reach->facenum >> 16;
- num0 = reach->edgenum >> 16;
- if (num0 > 0x00007FFF) num0 |= 0xFFFF0000;
- num1 = reach->edgenum & 0x0000FFFF;
- if (num1 > 0x00007FFF) num1 |= 0xFFFF0000;
- if (spawnflags & 1)
- {
- start[0] = num0;
- end[0] = num1;
- //
- origin[0] += mid[0];
- origin[1] = mid[1];
- origin[2] = mid[2];
- } //end if
- else if (spawnflags & 2)
- {
- start[1] = num0;
- end[1] = num1;
- //
- origin[0] = mid[0];
- origin[1] += mid[1];
- origin[2] = mid[2];
- } //end else if
- else
- {
- start[2] = num0;
- end[2] = num1;
- //
- origin[0] = mid[0];
- origin[1] = mid[1];
- origin[2] += mid[2];
- } //end else
-} //end of the function BotFuncBobStartEnd
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-bot_moveresult_t BotTravel_FuncBobbing(bot_movestate_t *ms, aas_reachability_t *reach)
-{
- vec3_t dir, dir1, dir2, hordir, bottomcenter, bob_start, bob_end, bob_origin;
- float dist, dist1, dist2, speed;
- bot_moveresult_t result;
-
- BotClearMoveResult(&result);
- //
- BotFuncBobStartEnd(reach, bob_start, bob_end, bob_origin);
- //if standing ontop of the func_bobbing
- if (BotOnMover(ms->origin, ms->entitynum, reach))
- {
-#ifdef DEBUG_FUNCBOB
- botimport.Print(PRT_MESSAGE, "bot on func_bobbing\n");
-#endif
- //if near end point of reachability
- VectorSubtract(bob_origin, bob_end, dir);
- if (VectorLength(dir) < 24)
- {
-#ifdef DEBUG_FUNCBOB
- botimport.Print(PRT_MESSAGE, "bot moving to reachability end\n");
-#endif
- //move to the end point
- VectorSubtract(reach->end, ms->origin, hordir);
- hordir[2] = 0;
- VectorNormalize(hordir);
- if (!BotCheckBarrierJump(ms, hordir, 100))
- {
- EA_Move(ms->client, hordir, 400);
- } //end if
- VectorCopy(hordir, result.movedir);
- } //end else
- //if not really close to the center of the elevator
- else
- {
- MoverBottomCenter(reach, bottomcenter);
- VectorSubtract(bottomcenter, ms->origin, hordir);
- hordir[2] = 0;
- dist = VectorNormalize(hordir);
- //
- if (dist > 10)
- {
-#ifdef DEBUG_FUNCBOB
- botimport.Print(PRT_MESSAGE, "bot moving to func_bobbing center\n");
-#endif
- //move to the center of the plat
- if (dist > 100) dist = 100;
- speed = 400 - (400 - 4 * dist);
- //
- EA_Move(ms->client, hordir, speed);
- VectorCopy(hordir, result.movedir);
- } //end if
- } //end else
- } //end if
- else
- {
-#ifdef DEBUG_FUNCBOB
- botimport.Print(PRT_MESSAGE, "bot not ontop of func_bobbing\n");
-#endif
- //if very near the reachability end
- VectorSubtract(reach->end, ms->origin, dir);
- dist = VectorLength(dir);
- if (dist < 64)
- {
-#ifdef DEBUG_FUNCBOB
- botimport.Print(PRT_MESSAGE, "bot moving to end\n");
-#endif
- if (dist > 60) dist = 60;
- speed = 360 - (360 - 6 * dist);
- //if swimming or no barrier jump
- if ((ms->moveflags & MFL_SWIMMING) || !BotCheckBarrierJump(ms, dir, 50))
- {
- if (speed > 5) EA_Move(ms->client, dir, speed);
- } //end if
- VectorCopy(dir, result.movedir);
- //
- if (ms->moveflags & MFL_SWIMMING) result.flags |= MOVERESULT_SWIMVIEW;
- //stop using this reachability
- ms->reachability_time = 0;
- return result;
- } //end if
- //get direction and distance to reachability start
- VectorSubtract(reach->start, ms->origin, dir1);
- if (!(ms->moveflags & MFL_SWIMMING)) dir1[2] = 0;
- dist1 = VectorNormalize(dir1);
- //if func_bobbing is Not it's start position
- VectorSubtract(bob_origin, bob_start, dir);
- if (VectorLength(dir) > 16)
- {
-#ifdef DEBUG_FUNCBOB
- botimport.Print(PRT_MESSAGE, "func_bobbing not at start\n");
-#endif
- dist = dist1;
- VectorCopy(dir1, dir);
- //
- BotCheckBlocked(ms, dir, qfalse, &result);
- //
- if (dist > 60) dist = 60;
- speed = 360 - (360 - 6 * dist);
- //
- if (!(ms->moveflags & MFL_SWIMMING) && !BotCheckBarrierJump(ms, dir, 50))
- {
- if (speed > 5) EA_Move(ms->client, dir, speed);
- } //end if
- VectorCopy(dir, result.movedir);
- //
- if (ms->moveflags & MFL_SWIMMING) result.flags |= MOVERESULT_SWIMVIEW;
- //this isn't a failure... just wait till the func_bobbing arrives
- result.type = RESULTTYPE_WAITFORFUNCBOBBING;
- result.flags |= MOVERESULT_WAITING;
- return result;
- } //end if
- //get direction and distance to func_bob bottom center
- MoverBottomCenter(reach, bottomcenter);
- VectorSubtract(bottomcenter, ms->origin, dir2);
- if (!(ms->moveflags & MFL_SWIMMING)) dir2[2] = 0;
- dist2 = VectorNormalize(dir2);
- //if very close to the reachability start or
- //closer to the elevator center or
- //between reachability start and func_bobbing center
- if (dist1 < 20 || dist2 < dist1 || DotProduct(dir1, dir2) < 0)
- {
-#ifdef DEBUG_FUNCBOB
- botimport.Print(PRT_MESSAGE, "bot moving to func_bobbing center\n");
-#endif
- dist = dist2;
- VectorCopy(dir2, dir);
- } //end if
- else //closer to the reachability start
- {
-#ifdef DEBUG_FUNCBOB
- botimport.Print(PRT_MESSAGE, "bot moving to reachability start\n");
-#endif
- dist = dist1;
- VectorCopy(dir1, dir);
- } //end else
- //
- BotCheckBlocked(ms, dir, qfalse, &result);
- //
- if (dist > 60) dist = 60;
- speed = 400 - (400 - 6 * dist);
- //
- if (!(ms->moveflags & MFL_SWIMMING) && !BotCheckBarrierJump(ms, dir, 50))
- {
- EA_Move(ms->client, dir, speed);
- } //end if
- VectorCopy(dir, result.movedir);
- //
- if (ms->moveflags & MFL_SWIMMING) result.flags |= MOVERESULT_SWIMVIEW;
- } //end else
- return result;
-} //end of the function BotTravel_FuncBobbing
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-bot_moveresult_t BotFinishTravel_FuncBobbing(bot_movestate_t *ms, aas_reachability_t *reach)
-{
- vec3_t bob_origin, bob_start, bob_end, dir, hordir, bottomcenter;
- bot_moveresult_t result;
- float dist, speed;
-
- BotClearMoveResult(&result);
- //
- BotFuncBobStartEnd(reach, bob_start, bob_end, bob_origin);
- //
- VectorSubtract(bob_origin, bob_end, dir);
- dist = VectorLength(dir);
- //if the func_bobbing is near the end
- if (dist < 16)
- {
- VectorSubtract(reach->end, ms->origin, hordir);
- if (!(ms->moveflags & MFL_SWIMMING)) hordir[2] = 0;
- dist = VectorNormalize(hordir);
- //
- if (dist > 60) dist = 60;
- speed = 360 - (360 - 6 * dist);
- //
- if (speed > 5) EA_Move(ms->client, dir, speed);
- VectorCopy(dir, result.movedir);
- //
- if (ms->moveflags & MFL_SWIMMING) result.flags |= MOVERESULT_SWIMVIEW;
- } //end if
- else
- {
- MoverBottomCenter(reach, bottomcenter);
- VectorSubtract(bottomcenter, ms->origin, hordir);
- if (!(ms->moveflags & MFL_SWIMMING)) hordir[2] = 0;
- dist = VectorNormalize(hordir);
- //
- if (dist > 5)
- {
- //move to the center of the plat
- if (dist > 100) dist = 100;
- speed = 400 - (400 - 4 * dist);
- //
- EA_Move(ms->client, hordir, speed);
- VectorCopy(hordir, result.movedir);
- } //end if
- } //end else
- return result;
-} //end of the function BotFinishTravel_FuncBobbing
-//===========================================================================
-// 0 no valid grapple hook visible
-// 1 the grapple hook is still flying
-// 2 the grapple hooked into a wall
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int GrappleState(bot_movestate_t *ms, aas_reachability_t *reach)
-{
- int i;
- aas_entityinfo_t entinfo;
-
- //if the grapple hook is pulling
- if (ms->moveflags & MFL_GRAPPLEPULL)
- return 2;
- //check for a visible grapple missile entity
- //or visible grapple entity
- for (i = AAS_NextEntity(0); i; i = AAS_NextEntity(i))
- {
- if (AAS_EntityType(i) == (int) entitytypemissile->value)
- {
- AAS_EntityInfo(i, &entinfo);
- if (entinfo.weapon == (int) weapindex_grapple->value)
- {
- return 1;
- } //end if
- } //end if
- } //end for
- //no valid grapple at all
- return 0;
-} //end of the function GrappleState
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void BotResetGrapple(bot_movestate_t *ms)
-{
- aas_reachability_t reach;
-
- AAS_ReachabilityFromNum(ms->lastreachnum, &reach);
- //if not using the grapple hook reachability anymore
- if ((reach.traveltype & TRAVELTYPE_MASK) != TRAVEL_GRAPPLEHOOK)
- {
- if ((ms->moveflags & MFL_ACTIVEGRAPPLE) || ms->grapplevisible_time)
- {
- if (offhandgrapple->value)
- EA_Command(ms->client, cmd_grappleoff->string);
- ms->moveflags &= ~MFL_ACTIVEGRAPPLE;
- ms->grapplevisible_time = 0;
-#ifdef DEBUG_GRAPPLE
- botimport.Print(PRT_MESSAGE, "reset grapple\n");
-#endif //DEBUG_GRAPPLE
- } //end if
- } //end if
-} //end of the function BotResetGrapple
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-bot_moveresult_t BotTravel_Grapple(bot_movestate_t *ms, aas_reachability_t *reach)
-{
- bot_moveresult_t result;
- float dist, speed;
- vec3_t dir, viewdir, org;
- int state, areanum;
- bsp_trace_t trace;
-
-#ifdef DEBUG_GRAPPLE
- static int debugline;
- if (!debugline) debugline = botimport.DebugLineCreate();
- botimport.DebugLineShow(debugline, reach->start, reach->end, LINECOLOR_BLUE);
-#endif //DEBUG_GRAPPLE
-
- BotClearMoveResult(&result);
- //
- if (ms->moveflags & MFL_GRAPPLERESET)
- {
- if (offhandgrapple->value)
- EA_Command(ms->client, cmd_grappleoff->string);
- ms->moveflags &= ~MFL_ACTIVEGRAPPLE;
- return result;
- } //end if
- //
- if (!(int) offhandgrapple->value)
- {
- result.weapon = weapindex_grapple->value;
- result.flags |= MOVERESULT_MOVEMENTWEAPON;
- } //end if
- //
- if (ms->moveflags & MFL_ACTIVEGRAPPLE)
- {
-#ifdef DEBUG_GRAPPLE
- botimport.Print(PRT_MESSAGE, "BotTravel_Grapple: active grapple\n");
-#endif //DEBUG_GRAPPLE
- //
- state = GrappleState(ms, reach);
- //
- VectorSubtract(reach->end, ms->origin, dir);
- dir[2] = 0;
- dist = VectorLength(dir);
- //if very close to the grapple end or the grappled is hooked and
- //the bot doesn't get any closer
- if (state && dist < 48)
- {
- if (ms->lastgrappledist - dist < 1)
- {
-#ifdef DEBUG_GRAPPLE
- botimport.Print(PRT_ERROR, "grapple normal end\n");
-#endif //DEBUG_GRAPPLE
- if (offhandgrapple->value)
- EA_Command(ms->client, cmd_grappleoff->string);
- ms->moveflags &= ~MFL_ACTIVEGRAPPLE;
- ms->moveflags |= MFL_GRAPPLERESET;
- ms->reachability_time = 0; //end the reachability
- return result;
- } //end if
- } //end if
- //if no valid grapple at all, or the grapple hooked and the bot
- //isn't moving anymore
- else if (!state || (state == 2 && dist > ms->lastgrappledist - 2))
- {
- if (ms->grapplevisible_time < AAS_Time() - 0.4)
- {
-#ifdef DEBUG_GRAPPLE
- botimport.Print(PRT_ERROR, "grapple not visible\n");
-#endif //DEBUG_GRAPPLE
- if (offhandgrapple->value)
- EA_Command(ms->client, cmd_grappleoff->string);
- ms->moveflags &= ~MFL_ACTIVEGRAPPLE;
- ms->moveflags |= MFL_GRAPPLERESET;
- ms->reachability_time = 0; //end the reachability
- return result;
- } //end if
- } //end if
- else
- {
- ms->grapplevisible_time = AAS_Time();
- } //end else
- //
- if (!(int) offhandgrapple->value)
- {
- EA_Attack(ms->client);
- } //end if
- //remember the current grapple distance
- ms->lastgrappledist = dist;
- } //end if
- else
- {
-#ifdef DEBUG_GRAPPLE
- botimport.Print(PRT_MESSAGE, "BotTravel_Grapple: inactive grapple\n");
-#endif //DEBUG_GRAPPLE
- //
- ms->grapplevisible_time = AAS_Time();
- //
- VectorSubtract(reach->start, ms->origin, dir);
- if (!(ms->moveflags & MFL_SWIMMING)) dir[2] = 0;
- VectorAdd(ms->origin, ms->viewoffset, org);
- VectorSubtract(reach->end, org, viewdir);
- //
- dist = VectorNormalize(dir);
- Vector2Angles(viewdir, result.ideal_viewangles);
- result.flags |= MOVERESULT_MOVEMENTVIEW;
- //
- if (dist < 5 &&
- fabs(AngleDiff(result.ideal_viewangles[0], ms->viewangles[0])) < 2 &&
- fabs(AngleDiff(result.ideal_viewangles[1], ms->viewangles[1])) < 2)
- {
-#ifdef DEBUG_GRAPPLE
- botimport.Print(PRT_MESSAGE, "BotTravel_Grapple: activating grapple\n");
-#endif //DEBUG_GRAPPLE
- //check if the grapple missile path is clear
- VectorAdd(ms->origin, ms->viewoffset, org);
- trace = AAS_Trace(org, NULL, NULL, reach->end, ms->entitynum, CONTENTS_SOLID);
- VectorSubtract(reach->end, trace.endpos, dir);
- if (VectorLength(dir) > 16)
- {
- result.failure = qtrue;
- return result;
- } //end if
- //activate the grapple
- if (offhandgrapple->value)
- {
- EA_Command(ms->client, cmd_grappleon->string);
- } //end if
- else
- {
- EA_Attack(ms->client);
- } //end else
- ms->moveflags |= MFL_ACTIVEGRAPPLE;
- ms->lastgrappledist = 999999;
- } //end if
- else
- {
- if (dist < 70) speed = 300 - (300 - 4 * dist);
- else speed = 400;
- //
- BotCheckBlocked(ms, dir, qtrue, &result);
- //elemantary action move in direction
- EA_Move(ms->client, dir, speed);
- VectorCopy(dir, result.movedir);
- } //end else
- //if in another area before actually grappling
- areanum = AAS_PointAreaNum(ms->origin);
- if (areanum && areanum != ms->reachareanum) ms->reachability_time = 0;
- } //end else
- return result;
-} //end of the function BotTravel_Grapple
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-bot_moveresult_t BotTravel_RocketJump(bot_movestate_t *ms, aas_reachability_t *reach)
-{
- vec3_t hordir;
- float dist, speed;
- bot_moveresult_t result;
-
- //botimport.Print(PRT_MESSAGE, "BotTravel_RocketJump: bah\n");
- BotClearMoveResult(&result);
- //
- hordir[0] = reach->start[0] - ms->origin[0];
- hordir[1] = reach->start[1] - ms->origin[1];
- hordir[2] = 0;
- //
- dist = VectorNormalize(hordir);
- //look in the movement direction
- Vector2Angles(hordir, result.ideal_viewangles);
- //look straight down
- result.ideal_viewangles[PITCH] = 90;
- //
- if (dist < 5 &&
- fabs(AngleDiff(result.ideal_viewangles[0], ms->viewangles[0])) < 5 &&
- fabs(AngleDiff(result.ideal_viewangles[1], ms->viewangles[1])) < 5)
- {
- //botimport.Print(PRT_MESSAGE, "between jump start and run start point\n");
- hordir[0] = reach->end[0] - ms->origin[0];
- hordir[1] = reach->end[1] - ms->origin[1];
- hordir[2] = 0;
- VectorNormalize(hordir);
- //elemantary action jump
- EA_Jump(ms->client);
- EA_Attack(ms->client);
- EA_Move(ms->client, hordir, 800);
- //
- ms->jumpreach = ms->lastreachnum;
- } //end if
- else
- {
- if (dist > 80) dist = 80;
- speed = 400 - (400 - 5 * dist);
- EA_Move(ms->client, hordir, speed);
- } //end else
- //look in the movement direction
- Vector2Angles(hordir, result.ideal_viewangles);
- //look straight down
- result.ideal_viewangles[PITCH] = 90;
- //set the view angles directly
- EA_View(ms->client, result.ideal_viewangles);
- //view is important for the movment
- result.flags |= MOVERESULT_MOVEMENTVIEWSET;
- //select the rocket launcher
- EA_SelectWeapon(ms->client, (int) weapindex_rocketlauncher->value);
- //weapon is used for movement
- result.weapon = (int) weapindex_rocketlauncher->value;
- result.flags |= MOVERESULT_MOVEMENTWEAPON;
- //
- VectorCopy(hordir, result.movedir);
- //
- return result;
-} //end of the function BotTravel_RocketJump
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-bot_moveresult_t BotTravel_BFGJump(bot_movestate_t *ms, aas_reachability_t *reach)
-{
- vec3_t hordir;
- float dist, speed;
- bot_moveresult_t result;
-
- //botimport.Print(PRT_MESSAGE, "BotTravel_BFGJump: bah\n");
- BotClearMoveResult(&result);
- //
- hordir[0] = reach->start[0] - ms->origin[0];
- hordir[1] = reach->start[1] - ms->origin[1];
- hordir[2] = 0;
- //
- dist = VectorNormalize(hordir);
- //
- if (dist < 5 &&
- fabs(AngleDiff(result.ideal_viewangles[0], ms->viewangles[0])) < 5 &&
- fabs(AngleDiff(result.ideal_viewangles[1], ms->viewangles[1])) < 5)
- {
- //botimport.Print(PRT_MESSAGE, "between jump start and run start point\n");
- hordir[0] = reach->end[0] - ms->origin[0];
- hordir[1] = reach->end[1] - ms->origin[1];
- hordir[2] = 0;
- VectorNormalize(hordir);
- //elemantary action jump
- EA_Jump(ms->client);
- EA_Attack(ms->client);
- EA_Move(ms->client, hordir, 800);
- //
- ms->jumpreach = ms->lastreachnum;
- } //end if
- else
- {
- if (dist > 80) dist = 80;
- speed = 400 - (400 - 5 * dist);
- EA_Move(ms->client, hordir, speed);
- } //end else
- //look in the movement direction
- Vector2Angles(hordir, result.ideal_viewangles);
- //look straight down
- result.ideal_viewangles[PITCH] = 90;
- //set the view angles directly
- EA_View(ms->client, result.ideal_viewangles);
- //view is important for the movment
- result.flags |= MOVERESULT_MOVEMENTVIEWSET;
- //select the rocket launcher
- EA_SelectWeapon(ms->client, (int) weapindex_bfg10k->value);
- //weapon is used for movement
- result.weapon = (int) weapindex_bfg10k->value;
- result.flags |= MOVERESULT_MOVEMENTWEAPON;
- //
- VectorCopy(hordir, result.movedir);
- //
- return result;
-} //end of the function BotTravel_BFGJump
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-bot_moveresult_t BotFinishTravel_WeaponJump(bot_movestate_t *ms, aas_reachability_t *reach)
-{
- vec3_t hordir;
- float speed;
- bot_moveresult_t result;
-
- BotClearMoveResult(&result);
- //if not jumped yet
- if (!ms->jumpreach) return result;
- /*
- //go straight to the reachability end
- hordir[0] = reach->end[0] - ms->origin[0];
- hordir[1] = reach->end[1] - ms->origin[1];
- hordir[2] = 0;
- VectorNormalize(hordir);
- //always use max speed when traveling through the air
- EA_Move(ms->client, hordir, 800);
- VectorCopy(hordir, result.movedir);
- */
- //
- if (!BotAirControl(ms->origin, ms->velocity, reach->end, hordir, &speed))
- {
- //go straight to the reachability end
- VectorSubtract(reach->end, ms->origin, hordir);
- hordir[2] = 0;
- VectorNormalize(hordir);
- speed = 400;
- } //end if
- //
- EA_Move(ms->client, hordir, speed);
- VectorCopy(hordir, result.movedir);
- //
- return result;
-} //end of the function BotFinishTravel_WeaponJump
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-bot_moveresult_t BotTravel_JumpPad(bot_movestate_t *ms, aas_reachability_t *reach)
-{
- float dist, speed;
- vec3_t hordir;
- bot_moveresult_t result;
-
- BotClearMoveResult(&result);
- //first walk straight to the reachability start
- hordir[0] = reach->start[0] - ms->origin[0];
- hordir[1] = reach->start[1] - ms->origin[1];
- hordir[2] = 0;
- dist = VectorNormalize(hordir);
- //
- BotCheckBlocked(ms, hordir, qtrue, &result);
- speed = 400;
- //elemantary action move in direction
- EA_Move(ms->client, hordir, speed);
- VectorCopy(hordir, result.movedir);
- //
- return result;
-} //end of the function BotTravel_JumpPad
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-bot_moveresult_t BotFinishTravel_JumpPad(bot_movestate_t *ms, aas_reachability_t *reach)
-{
- float speed;
- vec3_t hordir;
- bot_moveresult_t result;
-
- BotClearMoveResult(&result);
- if (!BotAirControl(ms->origin, ms->velocity, reach->end, hordir, &speed))
- {
- hordir[0] = reach->end[0] - ms->origin[0];
- hordir[1] = reach->end[1] - ms->origin[1];
- hordir[2] = 0;
- VectorNormalize(hordir);
- speed = 400;
- } //end if
- BotCheckBlocked(ms, hordir, qtrue, &result);
- //elemantary action move in direction
- EA_Move(ms->client, hordir, speed);
- VectorCopy(hordir, result.movedir);
- //
- return result;
-} //end of the function BotFinishTravel_JumpPad
-//===========================================================================
-// time before the reachability times out
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int BotReachabilityTime(aas_reachability_t *reach)
-{
- switch(reach->traveltype & TRAVELTYPE_MASK)
- {
- case TRAVEL_WALK: return 5;
- case TRAVEL_CROUCH: return 5;
- case TRAVEL_BARRIERJUMP: return 5;
- case TRAVEL_LADDER: return 6;
- case TRAVEL_WALKOFFLEDGE: return 5;
- case TRAVEL_JUMP: return 5;
- case TRAVEL_SWIM: return 5;
- case TRAVEL_WATERJUMP: return 5;
- case TRAVEL_TELEPORT: return 5;
- case TRAVEL_ELEVATOR: return 10;
- case TRAVEL_GRAPPLEHOOK: return 8;
- case TRAVEL_ROCKETJUMP: return 6;
- case TRAVEL_BFGJUMP: return 6;
- case TRAVEL_JUMPPAD: return 10;
- case TRAVEL_FUNCBOB: return 10;
- default:
- {
- botimport.Print(PRT_ERROR, "travel type %d not implemented yet\n", reach->traveltype);
- return 8;
- } //end case
- } //end switch
-} //end of the function BotReachabilityTime
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-bot_moveresult_t BotMoveInGoalArea(bot_movestate_t *ms, bot_goal_t *goal)
-{
- bot_moveresult_t result;
- vec3_t dir;
- float dist, speed;
-
-#ifdef DEBUG
- //botimport.Print(PRT_MESSAGE, "%s: moving straight to goal\n", ClientName(ms->entitynum-1));
- //AAS_ClearShownDebugLines();
- //AAS_DebugLine(ms->origin, goal->origin, LINECOLOR_RED);
-#endif //DEBUG
- BotClearMoveResult(&result);
- //walk straight to the goal origin
- dir[0] = goal->origin[0] - ms->origin[0];
- dir[1] = goal->origin[1] - ms->origin[1];
- if (ms->moveflags & MFL_SWIMMING)
- {
- dir[2] = goal->origin[2] - ms->origin[2];
- result.traveltype = TRAVEL_SWIM;
- } //end if
- else
- {
- dir[2] = 0;
- result.traveltype = TRAVEL_WALK;
- } //endif
- //
- dist = VectorNormalize(dir);
- if (dist > 100) dist = 100;
- speed = 400 - (400 - 4 * dist);
- if (speed < 10) speed = 0;
- //
- BotCheckBlocked(ms, dir, qtrue, &result);
- //elemantary action move in direction
- EA_Move(ms->client, dir, speed);
- VectorCopy(dir, result.movedir);
- //
- if (ms->moveflags & MFL_SWIMMING)
- {
- Vector2Angles(dir, result.ideal_viewangles);
- result.flags |= MOVERESULT_SWIMVIEW;
- } //end if
- //if (!debugline) debugline = botimport.DebugLineCreate();
- //botimport.DebugLineShow(debugline, ms->origin, goal->origin, LINECOLOR_BLUE);
- //
- ms->lastreachnum = 0;
- ms->lastareanum = 0;
- ms->lastgoalareanum = goal->areanum;
- VectorCopy(ms->origin, ms->lastorigin);
- //
- return result;
-} //end of the function BotMoveInGoalArea
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void BotMoveToGoal(bot_moveresult_t *result, int movestate, bot_goal_t *goal, int travelflags)
-{
- int reachnum, lastreachnum, foundjumppad, ent, resultflags;
- aas_reachability_t reach, lastreach;
- bot_movestate_t *ms;
- //vec3_t mins, maxs, up = {0, 0, 1};
- //bsp_trace_t trace;
- //static int debugline;
-
-
- BotClearMoveResult(result);
- //
- ms = BotMoveStateFromHandle(movestate);
- if (!ms) return;
- //reset the grapple before testing if the bot has a valid goal
- //because the bot could loose all it's goals when stuck to a wall
- BotResetGrapple(ms);
- //
- if (!goal)
- {
-#ifdef DEBUG
- botimport.Print(PRT_MESSAGE, "client %d: movetogoal -> no goal\n", ms->client);
-#endif //DEBUG
- result->failure = qtrue;
- return;
- } //end if
- //botimport.Print(PRT_MESSAGE, "numavoidreach = %d\n", ms->numavoidreach);
- //remove some of the move flags
- ms->moveflags &= ~(MFL_SWIMMING|MFL_AGAINSTLADDER);
- //set some of the move flags
- //NOTE: the MFL_ONGROUND flag is also set in the higher AI
- if (AAS_OnGround(ms->origin, ms->presencetype, ms->entitynum)) ms->moveflags |= MFL_ONGROUND;
- //
- if (ms->moveflags & MFL_ONGROUND)
- {
- int modeltype, modelnum;
-
- ent = BotOnTopOfEntity(ms);
-
- if (ent != -1)
- {
- modelnum = AAS_EntityModelindex(ent);
- if (modelnum >= 0 && modelnum < MAX_MODELS)
- {
- modeltype = modeltypes[modelnum];
-
- if (modeltype == MODELTYPE_FUNC_PLAT)
- {
- AAS_ReachabilityFromNum(ms->lastreachnum, &reach);
- //if the bot is Not using the elevator
- if ((reach.traveltype & TRAVELTYPE_MASK) != TRAVEL_ELEVATOR ||
- //NOTE: the face number is the plat model number
- (reach.facenum & 0x0000FFFF) != modelnum)
- {
- reachnum = AAS_NextModelReachability(0, modelnum);
- if (reachnum)
- {
- //botimport.Print(PRT_MESSAGE, "client %d: accidentally ended up on func_plat\n", ms->client);
- AAS_ReachabilityFromNum(reachnum, &reach);
- ms->lastreachnum = reachnum;
- ms->reachability_time = AAS_Time() + BotReachabilityTime(&reach);
- } //end if
- else
- {
- if (bot_developer)
- {
- botimport.Print(PRT_MESSAGE, "client %d: on func_plat without reachability\n", ms->client);
- } //end if
- result->blocked = qtrue;
- result->blockentity = ent;
- result->flags |= MOVERESULT_ONTOPOFOBSTACLE;
- return;
- } //end else
- } //end if
- result->flags |= MOVERESULT_ONTOPOF_ELEVATOR;
- } //end if
- else if (modeltype == MODELTYPE_FUNC_BOB)
- {
- AAS_ReachabilityFromNum(ms->lastreachnum, &reach);
- //if the bot is Not using the func bobbing
- if ((reach.traveltype & TRAVELTYPE_MASK) != TRAVEL_FUNCBOB ||
- //NOTE: the face number is the func_bobbing model number
- (reach.facenum & 0x0000FFFF) != modelnum)
- {
- reachnum = AAS_NextModelReachability(0, modelnum);
- if (reachnum)
- {
- //botimport.Print(PRT_MESSAGE, "client %d: accidentally ended up on func_bobbing\n", ms->client);
- AAS_ReachabilityFromNum(reachnum, &reach);
- ms->lastreachnum = reachnum;
- ms->reachability_time = AAS_Time() + BotReachabilityTime(&reach);
- } //end if
- else
- {
- if (bot_developer)
- {
- botimport.Print(PRT_MESSAGE, "client %d: on func_bobbing without reachability\n", ms->client);
- } //end if
- result->blocked = qtrue;
- result->blockentity = ent;
- result->flags |= MOVERESULT_ONTOPOFOBSTACLE;
- return;
- } //end else
- } //end if
- result->flags |= MOVERESULT_ONTOPOF_FUNCBOB;
- } //end if
- else if (modeltype == MODELTYPE_FUNC_STATIC || modeltype == MODELTYPE_FUNC_DOOR)
- {
- // check if ontop of a door bridge ?
- ms->areanum = BotFuzzyPointReachabilityArea(ms->origin);
- // if not in a reachability area
- if (!AAS_AreaReachability(ms->areanum))
- {
- result->blocked = qtrue;
- result->blockentity = ent;
- result->flags |= MOVERESULT_ONTOPOFOBSTACLE;
- return;
- } //end if
- } //end else if
- else
- {
- result->blocked = qtrue;
- result->blockentity = ent;
- result->flags |= MOVERESULT_ONTOPOFOBSTACLE;
- return;
- } //end else
- } //end if
- } //end if
- } //end if
- //if swimming
- if (AAS_Swimming(ms->origin)) ms->moveflags |= MFL_SWIMMING;
- //if against a ladder
- if (AAS_AgainstLadder(ms->origin)) ms->moveflags |= MFL_AGAINSTLADDER;
- //if the bot is on the ground, swimming or against a ladder
- if (ms->moveflags & (MFL_ONGROUND|MFL_SWIMMING|MFL_AGAINSTLADDER))
- {
- //botimport.Print(PRT_MESSAGE, "%s: onground, swimming or against ladder\n", ClientName(ms->entitynum-1));
- //
- AAS_ReachabilityFromNum(ms->lastreachnum, &lastreach);
- //reachability area the bot is in
- //ms->areanum = BotReachabilityArea(ms->origin, ((lastreach.traveltype & TRAVELTYPE_MASK) != TRAVEL_ELEVATOR));
- ms->areanum = BotFuzzyPointReachabilityArea(ms->origin);
- //
- if ( !ms->areanum )
- {
- result->failure = qtrue;
- result->blocked = qtrue;
- result->blockentity = 0;
- result->type = RESULTTYPE_INSOLIDAREA;
- return;
- } //end if
- //if the bot is in the goal area
- if (ms->areanum == goal->areanum)
- {
- *result = BotMoveInGoalArea(ms, goal);
- return;
- } //end if
- //assume we can use the reachability from the last frame
- reachnum = ms->lastreachnum;
- //if there is a last reachability
- if (reachnum)
- {
- AAS_ReachabilityFromNum(reachnum, &reach);
- //check if the reachability is still valid
- if (!(AAS_TravelFlagForType(reach.traveltype) & travelflags))
- {
- reachnum = 0;
- } //end if
- //special grapple hook case
- else if ((reach.traveltype & TRAVELTYPE_MASK) == TRAVEL_GRAPPLEHOOK)
- {
- if (ms->reachability_time < AAS_Time() ||
- (ms->moveflags & MFL_GRAPPLERESET))
- {
- reachnum = 0;
- } //end if
- } //end if
- //special elevator case
- else if ((reach.traveltype & TRAVELTYPE_MASK) == TRAVEL_ELEVATOR ||
- (reach.traveltype & TRAVELTYPE_MASK) == TRAVEL_FUNCBOB)
- {
- if ((result->flags & MOVERESULT_ONTOPOF_FUNCBOB) ||
- (result->flags & MOVERESULT_ONTOPOF_FUNCBOB))
- {
- ms->reachability_time = AAS_Time() + 5;
- } //end if
- //if the bot was going for an elevator and reached the reachability area
- if (ms->areanum == reach.areanum ||
- ms->reachability_time < AAS_Time())
- {
- reachnum = 0;
- } //end if
- } //end if
- else
- {
-#ifdef DEBUG
- if (bot_developer)
- {
- if (ms->reachability_time < AAS_Time())
- {
- botimport.Print(PRT_MESSAGE, "client %d: reachability timeout in ", ms->client);
- AAS_PrintTravelType(reach.traveltype & TRAVELTYPE_MASK);
- botimport.Print(PRT_MESSAGE, "\n");
- } //end if
- /*
- if (ms->lastareanum != ms->areanum)
- {
- botimport.Print(PRT_MESSAGE, "changed from area %d to %d\n", ms->lastareanum, ms->areanum);
- } //end if*/
- } //end if
-#endif //DEBUG
- //if the goal area changed or the reachability timed out
- //or the area changed
- if (ms->lastgoalareanum != goal->areanum ||
- ms->reachability_time < AAS_Time() ||
- ms->lastareanum != ms->areanum)
- {
- reachnum = 0;
- //botimport.Print(PRT_MESSAGE, "area change or timeout\n");
- } //end else if
- } //end else
- } //end if
- resultflags = 0;
- //if the bot needs a new reachability
- if (!reachnum)
- {
- //if the area has no reachability links
- if (!AAS_AreaReachability(ms->areanum))
- {
-#ifdef DEBUG
- if (bot_developer)
- {
- botimport.Print(PRT_MESSAGE, "area %d no reachability\n", ms->areanum);
- } //end if
-#endif //DEBUG
- } //end if
- //get a new reachability leading towards the goal
- reachnum = BotGetReachabilityToGoal(ms->origin, ms->areanum,
- ms->lastgoalareanum, ms->lastareanum,
- ms->avoidreach, ms->avoidreachtimes, ms->avoidreachtries,
- goal, travelflags, travelflags,
- ms->avoidspots, ms->numavoidspots, &resultflags);
- //the area number the reachability starts in
- ms->reachareanum = ms->areanum;
- //reset some state variables
- ms->jumpreach = 0; //for TRAVEL_JUMP
- ms->moveflags &= ~MFL_GRAPPLERESET; //for TRAVEL_GRAPPLEHOOK
- //if there is a reachability to the goal
- if (reachnum)
- {
- AAS_ReachabilityFromNum(reachnum, &reach);
- //set a timeout for this reachability
- ms->reachability_time = AAS_Time() + BotReachabilityTime(&reach);
- //
-#ifdef AVOIDREACH
- //add the reachability to the reachabilities to avoid for a while
- BotAddToAvoidReach(ms, reachnum, AVOIDREACH_TIME);
-#endif //AVOIDREACH
- } //end if
-#ifdef DEBUG
-
- else if (bot_developer)
- {
- botimport.Print(PRT_MESSAGE, "goal not reachable\n");
- Com_Memset(&reach, 0, sizeof(aas_reachability_t)); //make compiler happy
- } //end else
- if (bot_developer)
- {
- //if still going for the same goal
- if (ms->lastgoalareanum == goal->areanum)
- {
- if (ms->lastareanum == reach.areanum)
- {
- botimport.Print(PRT_MESSAGE, "same goal, going back to previous area\n");
- } //end if
- } //end if
- } //end if
-#endif //DEBUG
- } //end else
- //
- ms->lastreachnum = reachnum;
- ms->lastgoalareanum = goal->areanum;
- ms->lastareanum = ms->areanum;
- //if the bot has a reachability
- if (reachnum)
- {
- //get the reachability from the number
- AAS_ReachabilityFromNum(reachnum, &reach);
- result->traveltype = reach.traveltype;
- //
-#ifdef DEBUG_AI_MOVE
- AAS_ClearShownDebugLines();
- AAS_PrintTravelType(reach.traveltype & TRAVELTYPE_MASK);
- AAS_ShowReachability(&reach);
-#endif //DEBUG_AI_MOVE
- //
-#ifdef DEBUG
- //botimport.Print(PRT_MESSAGE, "client %d: ", ms->client);
- //AAS_PrintTravelType(reach.traveltype);
- //botimport.Print(PRT_MESSAGE, "\n");
-#endif //DEBUG
- switch(reach.traveltype & TRAVELTYPE_MASK)
- {
- case TRAVEL_WALK: *result = BotTravel_Walk(ms, &reach); break;
- case TRAVEL_CROUCH: *result = BotTravel_Crouch(ms, &reach); break;
- case TRAVEL_BARRIERJUMP: *result = BotTravel_BarrierJump(ms, &reach); break;
- case TRAVEL_LADDER: *result = BotTravel_Ladder(ms, &reach); break;
- case TRAVEL_WALKOFFLEDGE: *result = BotTravel_WalkOffLedge(ms, &reach); break;
- case TRAVEL_JUMP: *result = BotTravel_Jump(ms, &reach); break;
- case TRAVEL_SWIM: *result = BotTravel_Swim(ms, &reach); break;
- case TRAVEL_WATERJUMP: *result = BotTravel_WaterJump(ms, &reach); break;
- case TRAVEL_TELEPORT: *result = BotTravel_Teleport(ms, &reach); break;
- case TRAVEL_ELEVATOR: *result = BotTravel_Elevator(ms, &reach); break;
- case TRAVEL_GRAPPLEHOOK: *result = BotTravel_Grapple(ms, &reach); break;
- case TRAVEL_ROCKETJUMP: *result = BotTravel_RocketJump(ms, &reach); break;
- case TRAVEL_BFGJUMP: *result = BotTravel_BFGJump(ms, &reach); break;
- case TRAVEL_JUMPPAD: *result = BotTravel_JumpPad(ms, &reach); break;
- case TRAVEL_FUNCBOB: *result = BotTravel_FuncBobbing(ms, &reach); break;
- default:
- {
- botimport.Print(PRT_FATAL, "travel type %d not implemented yet\n", (reach.traveltype & TRAVELTYPE_MASK));
- break;
- } //end case
- } //end switch
- result->traveltype = reach.traveltype;
- result->flags |= resultflags;
- } //end if
- else
- {
- result->failure = qtrue;
- result->flags |= resultflags;
- Com_Memset(&reach, 0, sizeof(aas_reachability_t));
- } //end else
-#ifdef DEBUG
- if (bot_developer)
- {
- if (result->failure)
- {
- botimport.Print(PRT_MESSAGE, "client %d: movement failure in ", ms->client);
- AAS_PrintTravelType(reach.traveltype & TRAVELTYPE_MASK);
- botimport.Print(PRT_MESSAGE, "\n");
- } //end if
- } //end if
-#endif //DEBUG
- } //end if
- else
- {
- int i, numareas, areas[16];
- vec3_t end;
-
- //special handling of jump pads when the bot uses a jump pad without knowing it
- foundjumppad = qfalse;
- VectorMA(ms->origin, -2 * ms->thinktime, ms->velocity, end);
- numareas = AAS_TraceAreas(ms->origin, end, areas, NULL, 16);
- for (i = numareas-1; i >= 0; i--)
- {
- if (AAS_AreaJumpPad(areas[i]))
- {
- //botimport.Print(PRT_MESSAGE, "client %d used a jumppad without knowing, area %d\n", ms->client, areas[i]);
- foundjumppad = qtrue;
- lastreachnum = BotGetReachabilityToGoal(end, areas[i],
- ms->lastgoalareanum, ms->lastareanum,
- ms->avoidreach, ms->avoidreachtimes, ms->avoidreachtries,
- goal, travelflags, TFL_JUMPPAD, ms->avoidspots, ms->numavoidspots, NULL);
- if (lastreachnum)
- {
- ms->lastreachnum = lastreachnum;
- ms->lastareanum = areas[i];
- //botimport.Print(PRT_MESSAGE, "found jumppad reachability\n");
- break;
- } //end if
- else
- {
- for (lastreachnum = AAS_NextAreaReachability(areas[i], 0); lastreachnum;
- lastreachnum = AAS_NextAreaReachability(areas[i], lastreachnum))
- {
- //get the reachability from the number
- AAS_ReachabilityFromNum(lastreachnum, &reach);
- if ((reach.traveltype & TRAVELTYPE_MASK) == TRAVEL_JUMPPAD)
- {
- ms->lastreachnum = lastreachnum;
- ms->lastareanum = areas[i];
- //botimport.Print(PRT_MESSAGE, "found jumppad reachability hard!!\n");
- break;
- } //end if
- } //end for
- if (lastreachnum) break;
- } //end else
- } //end if
- } //end for
- if (bot_developer)
- {
- //if a jumppad is found with the trace but no reachability is found
- if (foundjumppad && !ms->lastreachnum)
- {
- botimport.Print(PRT_MESSAGE, "client %d didn't find jumppad reachability\n", ms->client);
- } //end if
- } //end if
- //
- if (ms->lastreachnum)
- {
- //botimport.Print(PRT_MESSAGE, "%s: NOT onground, swimming or against ladder\n", ClientName(ms->entitynum-1));
- AAS_ReachabilityFromNum(ms->lastreachnum, &reach);
- result->traveltype = reach.traveltype;
-#ifdef DEBUG
- //botimport.Print(PRT_MESSAGE, "client %d finish: ", ms->client);
- //AAS_PrintTravelType(reach.traveltype & TRAVELTYPE_MASK);
- //botimport.Print(PRT_MESSAGE, "\n");
-#endif //DEBUG
- //
- switch(reach.traveltype & TRAVELTYPE_MASK)
- {
- case TRAVEL_WALK: *result = BotTravel_Walk(ms, &reach); break;//BotFinishTravel_Walk(ms, &reach); break;
- case TRAVEL_CROUCH: /*do nothing*/ break;
- case TRAVEL_BARRIERJUMP: *result = BotFinishTravel_BarrierJump(ms, &reach); break;
- case TRAVEL_LADDER: *result = BotTravel_Ladder(ms, &reach); break;
- case TRAVEL_WALKOFFLEDGE: *result = BotFinishTravel_WalkOffLedge(ms, &reach); break;
- case TRAVEL_JUMP: *result = BotFinishTravel_Jump(ms, &reach); break;
- case TRAVEL_SWIM: *result = BotTravel_Swim(ms, &reach); break;
- case TRAVEL_WATERJUMP: *result = BotFinishTravel_WaterJump(ms, &reach); break;
- case TRAVEL_TELEPORT: /*do nothing*/ break;
- case TRAVEL_ELEVATOR: *result = BotFinishTravel_Elevator(ms, &reach); break;
- case TRAVEL_GRAPPLEHOOK: *result = BotTravel_Grapple(ms, &reach); break;
- case TRAVEL_ROCKETJUMP:
- case TRAVEL_BFGJUMP: *result = BotFinishTravel_WeaponJump(ms, &reach); break;
- case TRAVEL_JUMPPAD: *result = BotFinishTravel_JumpPad(ms, &reach); break;
- case TRAVEL_FUNCBOB: *result = BotFinishTravel_FuncBobbing(ms, &reach); break;
- default:
- {
- botimport.Print(PRT_FATAL, "(last) travel type %d not implemented yet\n", (reach.traveltype & TRAVELTYPE_MASK));
- break;
- } //end case
- } //end switch
- result->traveltype = reach.traveltype;
-#ifdef DEBUG
- if (bot_developer)
- {
- if (result->failure)
- {
- botimport.Print(PRT_MESSAGE, "client %d: movement failure in finish ", ms->client);
- AAS_PrintTravelType(reach.traveltype & TRAVELTYPE_MASK);
- botimport.Print(PRT_MESSAGE, "\n");
- } //end if
- } //end if
-#endif //DEBUG
- } //end if
- } //end else
- //FIXME: is it right to do this here?
- if (result->blocked) ms->reachability_time -= 10 * ms->thinktime;
- //copy the last origin
- VectorCopy(ms->origin, ms->lastorigin);
- //return the movement result
- return;
-} //end of the function BotMoveToGoal
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void BotResetAvoidReach(int movestate)
-{
- bot_movestate_t *ms;
-
- ms = BotMoveStateFromHandle(movestate);
- if (!ms) return;
- Com_Memset(ms->avoidreach, 0, MAX_AVOIDREACH * sizeof(int));
- Com_Memset(ms->avoidreachtimes, 0, MAX_AVOIDREACH * sizeof(float));
- Com_Memset(ms->avoidreachtries, 0, MAX_AVOIDREACH * sizeof(int));
-} //end of the function BotResetAvoidReach
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void BotResetLastAvoidReach(int movestate)
-{
- int i, latest;
- float latesttime;
- bot_movestate_t *ms;
-
- ms = BotMoveStateFromHandle(movestate);
- if (!ms) return;
- latesttime = 0;
- latest = 0;
- for (i = 0; i < MAX_AVOIDREACH; i++)
- {
- if (ms->avoidreachtimes[i] > latesttime)
- {
- latesttime = ms->avoidreachtimes[i];
- latest = i;
- } //end if
- } //end for
- if (latesttime)
- {
- ms->avoidreachtimes[latest] = 0;
- if (ms->avoidreachtries[i] > 0) ms->avoidreachtries[latest]--;
- } //end if
-} //end of the function BotResetLastAvoidReach
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void BotResetMoveState(int movestate)
-{
- bot_movestate_t *ms;
-
- ms = BotMoveStateFromHandle(movestate);
- if (!ms) return;
- Com_Memset(ms, 0, sizeof(bot_movestate_t));
-} //end of the function BotResetMoveState
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int BotSetupMoveAI(void)
-{
- BotSetBrushModelTypes();
- sv_maxstep = LibVar("sv_step", "18");
- sv_maxbarrier = LibVar("sv_maxbarrier", "32");
- sv_gravity = LibVar("sv_gravity", "800");
- weapindex_rocketlauncher = LibVar("weapindex_rocketlauncher", "5");
- weapindex_bfg10k = LibVar("weapindex_bfg10k", "9");
- weapindex_grapple = LibVar("weapindex_grapple", "10");
- entitytypemissile = LibVar("entitytypemissile", "3");
- offhandgrapple = LibVar("offhandgrapple", "0");
- cmd_grappleon = LibVar("cmd_grappleon", "grappleon");
- cmd_grappleoff = LibVar("cmd_grappleoff", "grappleoff");
- return BLERR_NOERROR;
-} //end of the function BotSetupMoveAI
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void BotShutdownMoveAI(void)
-{
- int i;
-
- for (i = 1; i <= MAX_CLIENTS; i++)
- {
- if (botmovestates[i])
- {
- FreeMemory(botmovestates[i]);
- botmovestates[i] = NULL;
- } //end if
- } //end for
-} //end of the function BotShutdownMoveAI
-
-
+/* +=========================================================================== +Copyright (C) 1999-2005 Id Software, Inc. + +This file is part of Quake III Arena source code. + +Quake III Arena source code is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +Quake III Arena source code is distributed in the hope that it will be +useful, but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Foobar; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ + +/***************************************************************************** + * name: be_ai_move.c + * + * desc: bot movement AI + * + * $Archive: /MissionPack/code/botlib/be_ai_move.c $ + * + *****************************************************************************/ + +#include "../game/q_shared.h" +#include "l_memory.h" +#include "l_libvar.h" +#include "l_utils.h" +#include "l_script.h" +#include "l_precomp.h" +#include "l_struct.h" +#include "aasfile.h" +#include "../game/botlib.h" +#include "../game/be_aas.h" +#include "be_aas_funcs.h" +#include "be_interface.h" + +#include "../game/be_ea.h" +#include "../game/be_ai_goal.h" +#include "../game/be_ai_move.h" + + +//#define DEBUG_AI_MOVE +//#define DEBUG_ELEVATOR +//#define DEBUG_GRAPPLE + +// bk001204 - redundant bot_avoidspot_t, see ../game/be_ai_move.h + +//movement state +//NOTE: the moveflags MFL_ONGROUND, MFL_TELEPORTED, MFL_WATERJUMP and +// MFL_GRAPPLEPULL must be set outside the movement code +typedef struct bot_movestate_s +{ + //input vars (all set outside the movement code) + vec3_t origin; //origin of the bot + vec3_t velocity; //velocity of the bot + vec3_t viewoffset; //view offset + int entitynum; //entity number of the bot + int client; //client number of the bot + float thinktime; //time the bot thinks + int presencetype; //presencetype of the bot + vec3_t viewangles; //view angles of the bot + //state vars + int areanum; //area the bot is in + int lastareanum; //last area the bot was in + int lastgoalareanum; //last goal area number + int lastreachnum; //last reachability number + vec3_t lastorigin; //origin previous cycle + int reachareanum; //area number of the reachabilty + int moveflags; //movement flags + int jumpreach; //set when jumped + float grapplevisible_time; //last time the grapple was visible + float lastgrappledist; //last distance to the grapple end + float reachability_time; //time to use current reachability + int avoidreach[MAX_AVOIDREACH]; //reachabilities to avoid + float avoidreachtimes[MAX_AVOIDREACH]; //times to avoid the reachabilities + int avoidreachtries[MAX_AVOIDREACH]; //number of tries before avoiding + // + bot_avoidspot_t avoidspots[MAX_AVOIDSPOTS]; //spots to avoid + int numavoidspots; +} bot_movestate_t; + +//used to avoid reachability links for some time after being used +#define AVOIDREACH +#define AVOIDREACH_TIME 6 //avoid links for 6 seconds after use +#define AVOIDREACH_TRIES 4 +//prediction times +#define PREDICTIONTIME_JUMP 3 //in seconds +#define PREDICTIONTIME_MOVE 2 //in seconds +//weapon indexes for weapon jumping +#define WEAPONINDEX_ROCKET_LAUNCHER 5 +#define WEAPONINDEX_BFG 9 + +#define MODELTYPE_FUNC_PLAT 1 +#define MODELTYPE_FUNC_BOB 2 +#define MODELTYPE_FUNC_DOOR 3 +#define MODELTYPE_FUNC_STATIC 4 + +libvar_t *sv_maxstep; +libvar_t *sv_maxbarrier; +libvar_t *sv_gravity; +libvar_t *weapindex_rocketlauncher; +libvar_t *weapindex_bfg10k; +libvar_t *weapindex_grapple; +libvar_t *entitytypemissile; +libvar_t *offhandgrapple; +libvar_t *cmd_grappleoff; +libvar_t *cmd_grappleon; +//type of model, func_plat or func_bobbing +int modeltypes[MAX_MODELS]; + +bot_movestate_t *botmovestates[MAX_CLIENTS+1]; + +//======================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//======================================================================== +int BotAllocMoveState(void) +{ + int i; + + for (i = 1; i <= MAX_CLIENTS; i++) + { + if (!botmovestates[i]) + { + botmovestates[i] = GetClearedMemory(sizeof(bot_movestate_t)); + return i; + } //end if + } //end for + return 0; +} //end of the function BotAllocMoveState +//======================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//======================================================================== +void BotFreeMoveState(int handle) +{ + if (handle <= 0 || handle > MAX_CLIENTS) + { + botimport.Print(PRT_FATAL, "move state handle %d out of range\n", handle); + return; + } //end if + if (!botmovestates[handle]) + { + botimport.Print(PRT_FATAL, "invalid move state %d\n", handle); + return; + } //end if + FreeMemory(botmovestates[handle]); + botmovestates[handle] = NULL; +} //end of the function BotFreeMoveState +//======================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//======================================================================== +bot_movestate_t *BotMoveStateFromHandle(int handle) +{ + if (handle <= 0 || handle > MAX_CLIENTS) + { + botimport.Print(PRT_FATAL, "move state handle %d out of range\n", handle); + return NULL; + } //end if + if (!botmovestates[handle]) + { + botimport.Print(PRT_FATAL, "invalid move state %d\n", handle); + return NULL; + } //end if + return botmovestates[handle]; +} //end of the function BotMoveStateFromHandle +//======================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//======================================================================== +void BotInitMoveState(int handle, bot_initmove_t *initmove) +{ + bot_movestate_t *ms; + + ms = BotMoveStateFromHandle(handle); + if (!ms) return; + VectorCopy(initmove->origin, ms->origin); + VectorCopy(initmove->velocity, ms->velocity); + VectorCopy(initmove->viewoffset, ms->viewoffset); + ms->entitynum = initmove->entitynum; + ms->client = initmove->client; + ms->thinktime = initmove->thinktime; + ms->presencetype = initmove->presencetype; + VectorCopy(initmove->viewangles, ms->viewangles); + // + ms->moveflags &= ~MFL_ONGROUND; + if (initmove->or_moveflags & MFL_ONGROUND) ms->moveflags |= MFL_ONGROUND; + ms->moveflags &= ~MFL_TELEPORTED; + if (initmove->or_moveflags & MFL_TELEPORTED) ms->moveflags |= MFL_TELEPORTED; + ms->moveflags &= ~MFL_WATERJUMP; + if (initmove->or_moveflags & MFL_WATERJUMP) ms->moveflags |= MFL_WATERJUMP; + ms->moveflags &= ~MFL_WALK; + if (initmove->or_moveflags & MFL_WALK) ms->moveflags |= MFL_WALK; + ms->moveflags &= ~MFL_GRAPPLEPULL; + if (initmove->or_moveflags & MFL_GRAPPLEPULL) ms->moveflags |= MFL_GRAPPLEPULL; +} //end of the function BotInitMoveState +//======================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//======================================================================== +float AngleDiff(float ang1, float ang2) +{ + float diff; + + diff = ang1 - ang2; + if (ang1 > ang2) + { + if (diff > 180.0) diff -= 360.0; + } //end if + else + { + if (diff < -180.0) diff += 360.0; + } //end else + return diff; +} //end of the function AngleDiff +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int BotFuzzyPointReachabilityArea(vec3_t origin) +{ + int firstareanum, j, x, y, z; + int areas[10], numareas, areanum, bestareanum; + float dist, bestdist; + vec3_t points[10], v, end; + + firstareanum = 0; + areanum = AAS_PointAreaNum(origin); + if (areanum) + { + firstareanum = areanum; + if (AAS_AreaReachability(areanum)) return areanum; + } //end if + VectorCopy(origin, end); + end[2] += 4; + numareas = AAS_TraceAreas(origin, end, areas, points, 10); + for (j = 0; j < numareas; j++) + { + if (AAS_AreaReachability(areas[j])) return areas[j]; + } //end for + bestdist = 999999; + bestareanum = 0; + for (z = 1; z >= -1; z -= 1) + { + for (x = 1; x >= -1; x -= 1) + { + for (y = 1; y >= -1; y -= 1) + { + VectorCopy(origin, end); + end[0] += x * 8; + end[1] += y * 8; + end[2] += z * 12; + numareas = AAS_TraceAreas(origin, end, areas, points, 10); + for (j = 0; j < numareas; j++) + { + if (AAS_AreaReachability(areas[j])) + { + VectorSubtract(points[j], origin, v); + dist = VectorLength(v); + if (dist < bestdist) + { + bestareanum = areas[j]; + bestdist = dist; + } //end if + } //end if + if (!firstareanum) firstareanum = areas[j]; + } //end for + } //end for + } //end for + if (bestareanum) return bestareanum; + } //end for + return firstareanum; +} //end of the function BotFuzzyPointReachabilityArea +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int BotReachabilityArea(vec3_t origin, int client) +{ + int modelnum, modeltype, reachnum, areanum; + aas_reachability_t reach; + vec3_t org, end, mins, maxs, up = {0, 0, 1}; + bsp_trace_t bsptrace; + aas_trace_t trace; + + //check if the bot is standing on something + AAS_PresenceTypeBoundingBox(PRESENCE_CROUCH, mins, maxs); + VectorMA(origin, -3, up, end); + bsptrace = AAS_Trace(origin, mins, maxs, end, client, CONTENTS_SOLID|CONTENTS_PLAYERCLIP); + if (!bsptrace.startsolid && bsptrace.fraction < 1 && bsptrace.ent != ENTITYNUM_NONE) + { + //if standing on the world the bot should be in a valid area + if (bsptrace.ent == ENTITYNUM_WORLD) + { + return BotFuzzyPointReachabilityArea(origin); + } //end if + + modelnum = AAS_EntityModelindex(bsptrace.ent); + modeltype = modeltypes[modelnum]; + + //if standing on a func_plat or func_bobbing then the bot is assumed to be + //in the area the reachability points to + if (modeltype == MODELTYPE_FUNC_PLAT || modeltype == MODELTYPE_FUNC_BOB) + { + reachnum = AAS_NextModelReachability(0, modelnum); + if (reachnum) + { + AAS_ReachabilityFromNum(reachnum, &reach); + return reach.areanum; + } //end if + } //end else if + + //if the bot is swimming the bot should be in a valid area + if (AAS_Swimming(origin)) + { + return BotFuzzyPointReachabilityArea(origin); + } //end if + // + areanum = BotFuzzyPointReachabilityArea(origin); + //if the bot is in an area with reachabilities + if (areanum && AAS_AreaReachability(areanum)) return areanum; + //trace down till the ground is hit because the bot is standing on some other entity + VectorCopy(origin, org); + VectorCopy(org, end); + end[2] -= 800; + trace = AAS_TraceClientBBox(org, end, PRESENCE_CROUCH, -1); + if (!trace.startsolid) + { + VectorCopy(trace.endpos, org); + } //end if + // + return BotFuzzyPointReachabilityArea(org); + } //end if + // + return BotFuzzyPointReachabilityArea(origin); +} //end of the function BotReachabilityArea +//=========================================================================== +// returns the reachability area the bot is in +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +/* +int BotReachabilityArea(vec3_t origin, int testground) +{ + int firstareanum, i, j, x, y, z; + int areas[10], numareas, areanum, bestareanum; + float dist, bestdist; + vec3_t org, end, points[10], v; + aas_trace_t trace; + + firstareanum = 0; + for (i = 0; i < 2; i++) + { + VectorCopy(origin, org); + //if test at the ground (used when bot is standing on an entity) + if (i > 0) + { + VectorCopy(origin, end); + end[2] -= 800; + trace = AAS_TraceClientBBox(origin, end, PRESENCE_CROUCH, -1); + if (!trace.startsolid) + { + VectorCopy(trace.endpos, org); + } //end if + } //end if + + firstareanum = 0; + areanum = AAS_PointAreaNum(org); + if (areanum) + { + firstareanum = areanum; + if (AAS_AreaReachability(areanum)) return areanum; + } //end if + bestdist = 999999; + bestareanum = 0; + for (z = 1; z >= -1; z -= 1) + { + for (x = 1; x >= -1; x -= 1) + { + for (y = 1; y >= -1; y -= 1) + { + VectorCopy(org, end); + end[0] += x * 8; + end[1] += y * 8; + end[2] += z * 12; + numareas = AAS_TraceAreas(org, end, areas, points, 10); + for (j = 0; j < numareas; j++) + { + if (AAS_AreaReachability(areas[j])) + { + VectorSubtract(points[j], org, v); + dist = VectorLength(v); + if (dist < bestdist) + { + bestareanum = areas[j]; + bestdist = dist; + } //end if + } //end if + } //end for + } //end for + } //end for + if (bestareanum) return bestareanum; + } //end for + if (!testground) break; + } //end for +//#ifdef DEBUG + //botimport.Print(PRT_MESSAGE, "no reachability area\n"); +//#endif //DEBUG + return firstareanum; +} //end of the function BotReachabilityArea*/ +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int BotOnMover(vec3_t origin, int entnum, aas_reachability_t *reach) +{ + int i, modelnum; + vec3_t mins, maxs, modelorigin, org, end; + vec3_t angles = {0, 0, 0}; + vec3_t boxmins = {-16, -16, -8}, boxmaxs = {16, 16, 8}; + bsp_trace_t trace; + + modelnum = reach->facenum & 0x0000FFFF; + //get some bsp model info + AAS_BSPModelMinsMaxsOrigin(modelnum, angles, mins, maxs, NULL); + // + if (!AAS_OriginOfMoverWithModelNum(modelnum, modelorigin)) + { + botimport.Print(PRT_MESSAGE, "no entity with model %d\n", modelnum); + return qfalse; + } //end if + // + for (i = 0; i < 2; i++) + { + if (origin[i] > modelorigin[i] + maxs[i] + 16) return qfalse; + if (origin[i] < modelorigin[i] + mins[i] - 16) return qfalse; + } //end for + // + VectorCopy(origin, org); + org[2] += 24; + VectorCopy(origin, end); + end[2] -= 48; + // + trace = AAS_Trace(org, boxmins, boxmaxs, end, entnum, CONTENTS_SOLID|CONTENTS_PLAYERCLIP); + if (!trace.startsolid && !trace.allsolid) + { + //NOTE: the reachability face number is the model number of the elevator + if (trace.ent != ENTITYNUM_NONE && AAS_EntityModelNum(trace.ent) == modelnum) + { + return qtrue; + } //end if + } //end if + return qfalse; +} //end of the function BotOnMover +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int MoverDown(aas_reachability_t *reach) +{ + int modelnum; + vec3_t mins, maxs, origin; + vec3_t angles = {0, 0, 0}; + + modelnum = reach->facenum & 0x0000FFFF; + //get some bsp model info + AAS_BSPModelMinsMaxsOrigin(modelnum, angles, mins, maxs, origin); + // + if (!AAS_OriginOfMoverWithModelNum(modelnum, origin)) + { + botimport.Print(PRT_MESSAGE, "no entity with model %d\n", modelnum); + return qfalse; + } //end if + //if the top of the plat is below the reachability start point + if (origin[2] + maxs[2] < reach->start[2]) return qtrue; + return qfalse; +} //end of the function MoverDown +//======================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//======================================================================== +void BotSetBrushModelTypes(void) +{ + int ent, modelnum; + char classname[MAX_EPAIRKEY], model[MAX_EPAIRKEY]; + + Com_Memset(modeltypes, 0, MAX_MODELS * sizeof(int)); + // + for (ent = AAS_NextBSPEntity(0); ent; ent = AAS_NextBSPEntity(ent)) + { + if (!AAS_ValueForBSPEpairKey(ent, "classname", classname, MAX_EPAIRKEY)) continue; + if (!AAS_ValueForBSPEpairKey(ent, "model", model, MAX_EPAIRKEY)) continue; + if (model[0]) modelnum = atoi(model+1); + else modelnum = 0; + + if (modelnum < 0 || modelnum > MAX_MODELS) + { + botimport.Print(PRT_MESSAGE, "entity %s model number out of range\n", classname); + continue; + } //end if + + if (!Q_stricmp(classname, "func_bobbing")) + modeltypes[modelnum] = MODELTYPE_FUNC_BOB; + else if (!Q_stricmp(classname, "func_plat")) + modeltypes[modelnum] = MODELTYPE_FUNC_PLAT; + else if (!Q_stricmp(classname, "func_door")) + modeltypes[modelnum] = MODELTYPE_FUNC_DOOR; + else if (!Q_stricmp(classname, "func_static")) + modeltypes[modelnum] = MODELTYPE_FUNC_STATIC; + } //end for +} //end of the function BotSetBrushModelTypes +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int BotOnTopOfEntity(bot_movestate_t *ms) +{ + vec3_t mins, maxs, end, up = {0, 0, 1}; + bsp_trace_t trace; + + AAS_PresenceTypeBoundingBox(ms->presencetype, mins, maxs); + VectorMA(ms->origin, -3, up, end); + trace = AAS_Trace(ms->origin, mins, maxs, end, ms->entitynum, CONTENTS_SOLID|CONTENTS_PLAYERCLIP); + if (!trace.startsolid && (trace.ent != ENTITYNUM_WORLD && trace.ent != ENTITYNUM_NONE) ) + { + return trace.ent; + } //end if + return -1; +} //end of the function BotOnTopOfEntity +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int BotValidTravel(vec3_t origin, aas_reachability_t *reach, int travelflags) +{ + //if the reachability uses an unwanted travel type + if (AAS_TravelFlagForType(reach->traveltype) & ~travelflags) return qfalse; + //don't go into areas with bad travel types + if (AAS_AreaContentsTravelFlags(reach->areanum) & ~travelflags) return qfalse; + return qtrue; +} //end of the function BotValidTravel +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void BotAddToAvoidReach(bot_movestate_t *ms, int number, float avoidtime) +{ + int i; + + for (i = 0; i < MAX_AVOIDREACH; i++) + { + if (ms->avoidreach[i] == number) + { + if (ms->avoidreachtimes[i] > AAS_Time()) ms->avoidreachtries[i]++; + else ms->avoidreachtries[i] = 1; + ms->avoidreachtimes[i] = AAS_Time() + avoidtime; + return; + } //end if + } //end for + //add the reachability to the reachabilities to avoid for a while + for (i = 0; i < MAX_AVOIDREACH; i++) + { + if (ms->avoidreachtimes[i] < AAS_Time()) + { + ms->avoidreach[i] = number; + ms->avoidreachtimes[i] = AAS_Time() + avoidtime; + ms->avoidreachtries[i] = 1; + return; + } //end if + } //end for +} //end of the function BotAddToAvoidReach +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +float DistanceFromLineSquared(vec3_t p, vec3_t lp1, vec3_t lp2) +{ + vec3_t proj, dir; + int j; + + AAS_ProjectPointOntoVector(p, lp1, lp2, proj); + for (j = 0; j < 3; j++) + if ((proj[j] > lp1[j] && proj[j] > lp2[j]) || + (proj[j] < lp1[j] && proj[j] < lp2[j])) + break; + if (j < 3) { + if (fabs(proj[j] - lp1[j]) < fabs(proj[j] - lp2[j])) + VectorSubtract(p, lp1, dir); + else + VectorSubtract(p, lp2, dir); + return VectorLengthSquared(dir); + } + VectorSubtract(p, proj, dir); + return VectorLengthSquared(dir); +} //end of the function DistanceFromLineSquared +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +float VectorDistanceSquared(vec3_t p1, vec3_t p2) +{ + vec3_t dir; + VectorSubtract(p2, p1, dir); + return VectorLengthSquared(dir); +} //end of the function VectorDistanceSquared +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int BotAvoidSpots(vec3_t origin, aas_reachability_t *reach, bot_avoidspot_t *avoidspots, int numavoidspots) +{ + int checkbetween, i, type; + float squareddist, squaredradius; + + switch(reach->traveltype & TRAVELTYPE_MASK) + { + case TRAVEL_WALK: checkbetween = qtrue; break; + case TRAVEL_CROUCH: checkbetween = qtrue; break; + case TRAVEL_BARRIERJUMP: checkbetween = qtrue; break; + case TRAVEL_LADDER: checkbetween = qtrue; break; + case TRAVEL_WALKOFFLEDGE: checkbetween = qfalse; break; + case TRAVEL_JUMP: checkbetween = qfalse; break; + case TRAVEL_SWIM: checkbetween = qtrue; break; + case TRAVEL_WATERJUMP: checkbetween = qtrue; break; + case TRAVEL_TELEPORT: checkbetween = qfalse; break; + case TRAVEL_ELEVATOR: checkbetween = qfalse; break; + case TRAVEL_GRAPPLEHOOK: checkbetween = qfalse; break; + case TRAVEL_ROCKETJUMP: checkbetween = qfalse; break; + case TRAVEL_BFGJUMP: checkbetween = qfalse; break; + case TRAVEL_JUMPPAD: checkbetween = qfalse; break; + case TRAVEL_FUNCBOB: checkbetween = qfalse; break; + default: checkbetween = qtrue; break; + } //end switch + + type = AVOID_CLEAR; + for (i = 0; i < numavoidspots; i++) + { + squaredradius = Square(avoidspots[i].radius); + squareddist = DistanceFromLineSquared(avoidspots[i].origin, origin, reach->start); + // if moving towards the avoid spot + if (squareddist < squaredradius && + VectorDistanceSquared(avoidspots[i].origin, origin) > squareddist) + { + type = avoidspots[i].type; + } //end if + else if (checkbetween) { + squareddist = DistanceFromLineSquared(avoidspots[i].origin, reach->start, reach->end); + // if moving towards the avoid spot + if (squareddist < squaredradius && + VectorDistanceSquared(avoidspots[i].origin, reach->start) > squareddist) + { + type = avoidspots[i].type; + } //end if + } //end if + else + { + VectorDistanceSquared(avoidspots[i].origin, reach->end); + // if the reachability leads closer to the avoid spot + if (squareddist < squaredradius && + VectorDistanceSquared(avoidspots[i].origin, reach->start) > squareddist) + { + type = avoidspots[i].type; + } //end if + } //end else + if (type == AVOID_ALWAYS) + return type; + } //end for + return type; +} //end of the function BotAvoidSpots +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void BotAddAvoidSpot(int movestate, vec3_t origin, float radius, int type) +{ + bot_movestate_t *ms; + + ms = BotMoveStateFromHandle(movestate); + if (!ms) return; + if (type == AVOID_CLEAR) + { + ms->numavoidspots = 0; + return; + } //end if + + if (ms->numavoidspots >= MAX_AVOIDSPOTS) + return; + VectorCopy(origin, ms->avoidspots[ms->numavoidspots].origin); + ms->avoidspots[ms->numavoidspots].radius = radius; + ms->avoidspots[ms->numavoidspots].type = type; + ms->numavoidspots++; +} //end of the function BotAddAvoidSpot +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int BotGetReachabilityToGoal(vec3_t origin, int areanum, + int lastgoalareanum, int lastareanum, + int *avoidreach, float *avoidreachtimes, int *avoidreachtries, + bot_goal_t *goal, int travelflags, int movetravelflags, + struct bot_avoidspot_s *avoidspots, int numavoidspots, int *flags) +{ + int i, t, besttime, bestreachnum, reachnum; + aas_reachability_t reach; + + //if not in a valid area + if (!areanum) return 0; + // + if (AAS_AreaDoNotEnter(areanum) || AAS_AreaDoNotEnter(goal->areanum)) + { + travelflags |= TFL_DONOTENTER; + movetravelflags |= TFL_DONOTENTER; + } //end if + //use the routing to find the next area to go to + besttime = 0; + bestreachnum = 0; + // + for (reachnum = AAS_NextAreaReachability(areanum, 0); reachnum; + reachnum = AAS_NextAreaReachability(areanum, reachnum)) + { +#ifdef AVOIDREACH + //check if it isn't an reachability to avoid + for (i = 0; i < MAX_AVOIDREACH; i++) + { + if (avoidreach[i] == reachnum && avoidreachtimes[i] >= AAS_Time()) break; + } //end for + if (i != MAX_AVOIDREACH && avoidreachtries[i] > AVOIDREACH_TRIES) + { +#ifdef DEBUG + if (bot_developer) + { + botimport.Print(PRT_MESSAGE, "avoiding reachability %d\n", avoidreach[i]); + } //end if +#endif //DEBUG + continue; + } //end if +#endif //AVOIDREACH + //get the reachability from the number + AAS_ReachabilityFromNum(reachnum, &reach); + //NOTE: do not go back to the previous area if the goal didn't change + //NOTE: is this actually avoidance of local routing minima between two areas??? + if (lastgoalareanum == goal->areanum && reach.areanum == lastareanum) continue; + //if (AAS_AreaContentsTravelFlags(reach.areanum) & ~travelflags) continue; + //if the travel isn't valid + if (!BotValidTravel(origin, &reach, movetravelflags)) continue; + //get the travel time + t = AAS_AreaTravelTimeToGoalArea(reach.areanum, reach.end, goal->areanum, travelflags); + //if the goal area isn't reachable from the reachable area + if (!t) continue; + //if the bot should not use this reachability to avoid bad spots + if (BotAvoidSpots(origin, &reach, avoidspots, numavoidspots)) { + if (flags) { + *flags |= MOVERESULT_BLOCKEDBYAVOIDSPOT; + } + continue; + } + //add the travel time towards the area + t += reach.traveltime;// + AAS_AreaTravelTime(areanum, origin, reach.start); + //if the travel time is better than the ones already found + if (!besttime || t < besttime) + { + besttime = t; + bestreachnum = reachnum; + } //end if + } //end for + // + return bestreachnum; +} //end of the function BotGetReachabilityToGoal +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int BotAddToTarget(vec3_t start, vec3_t end, float maxdist, float *dist, vec3_t target) +{ + vec3_t dir; + float curdist; + + VectorSubtract(end, start, dir); + curdist = VectorNormalize(dir); + if (*dist + curdist < maxdist) + { + VectorCopy(end, target); + *dist += curdist; + return qfalse; + } //end if + else + { + VectorMA(start, maxdist - *dist, dir, target); + *dist = maxdist; + return qtrue; + } //end else +} //end of the function BotAddToTarget + +int BotMovementViewTarget(int movestate, bot_goal_t *goal, int travelflags, float lookahead, vec3_t target) +{ + aas_reachability_t reach; + int reachnum, lastareanum; + bot_movestate_t *ms; + vec3_t end; + float dist; + + ms = BotMoveStateFromHandle(movestate); + if (!ms) return qfalse; + reachnum = 0; + //if the bot has no goal or no last reachability + if (!ms->lastreachnum || !goal) return qfalse; + + reachnum = ms->lastreachnum; + VectorCopy(ms->origin, end); + lastareanum = ms->lastareanum; + dist = 0; + while(reachnum && dist < lookahead) + { + AAS_ReachabilityFromNum(reachnum, &reach); + if (BotAddToTarget(end, reach.start, lookahead, &dist, target)) return qtrue; + //never look beyond teleporters + if ((reach.traveltype & TRAVELTYPE_MASK) == TRAVEL_TELEPORT) return qtrue; + //never look beyond the weapon jump point + if ((reach.traveltype & TRAVELTYPE_MASK) == TRAVEL_ROCKETJUMP) return qtrue; + if ((reach.traveltype & TRAVELTYPE_MASK) == TRAVEL_BFGJUMP) return qtrue; + //don't add jump pad distances + if ((reach.traveltype & TRAVELTYPE_MASK) != TRAVEL_JUMPPAD && + (reach.traveltype & TRAVELTYPE_MASK) != TRAVEL_ELEVATOR && + (reach.traveltype & TRAVELTYPE_MASK) != TRAVEL_FUNCBOB) + { + if (BotAddToTarget(reach.start, reach.end, lookahead, &dist, target)) return qtrue; + } //end if + reachnum = BotGetReachabilityToGoal(reach.end, reach.areanum, + ms->lastgoalareanum, lastareanum, + ms->avoidreach, ms->avoidreachtimes, ms->avoidreachtries, + goal, travelflags, travelflags, NULL, 0, NULL); + VectorCopy(reach.end, end); + lastareanum = reach.areanum; + if (lastareanum == goal->areanum) + { + BotAddToTarget(reach.end, goal->origin, lookahead, &dist, target); + return qtrue; + } //end if + } //end while + // + return qfalse; +} //end of the function BotMovementViewTarget +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int BotVisible(int ent, vec3_t eye, vec3_t target) +{ + bsp_trace_t trace; + + trace = AAS_Trace(eye, NULL, NULL, target, ent, CONTENTS_SOLID|CONTENTS_PLAYERCLIP); + if (trace.fraction >= 1) return qtrue; + return qfalse; +} //end of the function BotVisible +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int BotPredictVisiblePosition(vec3_t origin, int areanum, bot_goal_t *goal, int travelflags, vec3_t target) +{ + aas_reachability_t reach; + int reachnum, lastgoalareanum, lastareanum, i; + int avoidreach[MAX_AVOIDREACH]; + float avoidreachtimes[MAX_AVOIDREACH]; + int avoidreachtries[MAX_AVOIDREACH]; + vec3_t end; + + //if the bot has no goal or no last reachability + if (!goal) return qfalse; + //if the areanum is not valid + if (!areanum) return qfalse; + //if the goal areanum is not valid + if (!goal->areanum) return qfalse; + + Com_Memset(avoidreach, 0, MAX_AVOIDREACH * sizeof(int)); + lastgoalareanum = goal->areanum; + lastareanum = areanum; + VectorCopy(origin, end); + //only do 20 hops + for (i = 0; i < 20 && (areanum != goal->areanum); i++) + { + // + reachnum = BotGetReachabilityToGoal(end, areanum, + lastgoalareanum, lastareanum, + avoidreach, avoidreachtimes, avoidreachtries, + goal, travelflags, travelflags, NULL, 0, NULL); + if (!reachnum) return qfalse; + AAS_ReachabilityFromNum(reachnum, &reach); + // + if (BotVisible(goal->entitynum, goal->origin, reach.start)) + { + VectorCopy(reach.start, target); + return qtrue; + } //end if + // + if (BotVisible(goal->entitynum, goal->origin, reach.end)) + { + VectorCopy(reach.end, target); + return qtrue; + } //end if + // + if (reach.areanum == goal->areanum) + { + VectorCopy(reach.end, target); + return qtrue; + } //end if + // + lastareanum = areanum; + areanum = reach.areanum; + VectorCopy(reach.end, end); + // + } //end while + // + return qfalse; +} //end of the function BotPredictVisiblePosition +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void MoverBottomCenter(aas_reachability_t *reach, vec3_t bottomcenter) +{ + int modelnum; + vec3_t mins, maxs, origin, mids; + vec3_t angles = {0, 0, 0}; + + modelnum = reach->facenum & 0x0000FFFF; + //get some bsp model info + AAS_BSPModelMinsMaxsOrigin(modelnum, angles, mins, maxs, origin); + // + if (!AAS_OriginOfMoverWithModelNum(modelnum, origin)) + { + botimport.Print(PRT_MESSAGE, "no entity with model %d\n", modelnum); + } //end if + //get a point just above the plat in the bottom position + VectorAdd(mins, maxs, mids); + VectorMA(origin, 0.5, mids, bottomcenter); + bottomcenter[2] = reach->start[2]; +} //end of the function MoverBottomCenter +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +float BotGapDistance(vec3_t origin, vec3_t hordir, int entnum) +{ + float dist, startz; + vec3_t start, end; + aas_trace_t trace; + + //do gap checking + startz = origin[2]; + //this enables walking down stairs more fluidly + { + VectorCopy(origin, start); + VectorCopy(origin, end); + end[2] -= 60; + trace = AAS_TraceClientBBox(start, end, PRESENCE_CROUCH, entnum); + if (trace.fraction >= 1) return 1; + startz = trace.endpos[2] + 1; + } + // + for (dist = 8; dist <= 100; dist += 8) + { + VectorMA(origin, dist, hordir, start); + start[2] = startz + 24; + VectorCopy(start, end); + end[2] -= 48 + sv_maxbarrier->value; + trace = AAS_TraceClientBBox(start, end, PRESENCE_CROUCH, entnum); + //if solid is found the bot can't walk any further and fall into a gap + if (!trace.startsolid) + { + //if it is a gap + if (trace.endpos[2] < startz - sv_maxstep->value - 8) + { + VectorCopy(trace.endpos, end); + end[2] -= 20; + if (AAS_PointContents(end) & CONTENTS_WATER) break; + //if a gap is found slow down + //botimport.Print(PRT_MESSAGE, "gap at %f\n", dist); + return dist; + } //end if + startz = trace.endpos[2]; + } //end if + } //end for + return 0; +} //end of the function BotGapDistance +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int BotCheckBarrierJump(bot_movestate_t *ms, vec3_t dir, float speed) +{ + vec3_t start, hordir, end; + aas_trace_t trace; + + VectorCopy(ms->origin, end); + end[2] += sv_maxbarrier->value; + //trace right up + trace = AAS_TraceClientBBox(ms->origin, end, PRESENCE_NORMAL, ms->entitynum); + //this shouldn't happen... but we check anyway + if (trace.startsolid) return qfalse; + //if very low ceiling it isn't possible to jump up to a barrier + if (trace.endpos[2] - ms->origin[2] < sv_maxstep->value) return qfalse; + // + hordir[0] = dir[0]; + hordir[1] = dir[1]; + hordir[2] = 0; + VectorNormalize(hordir); + VectorMA(ms->origin, ms->thinktime * speed * 0.5, hordir, end); + VectorCopy(trace.endpos, start); + end[2] = trace.endpos[2]; + //trace from previous trace end pos horizontally in the move direction + trace = AAS_TraceClientBBox(start, end, PRESENCE_NORMAL, ms->entitynum); + //again this shouldn't happen + if (trace.startsolid) return qfalse; + // + VectorCopy(trace.endpos, start); + VectorCopy(trace.endpos, end); + end[2] = ms->origin[2]; + //trace down from the previous trace end pos + trace = AAS_TraceClientBBox(start, end, PRESENCE_NORMAL, ms->entitynum); + //if solid + if (trace.startsolid) return qfalse; + //if no obstacle at all + if (trace.fraction >= 1.0) return qfalse; + //if less than the maximum step height + if (trace.endpos[2] - ms->origin[2] < sv_maxstep->value) return qfalse; + // + EA_Jump(ms->client); + EA_Move(ms->client, hordir, speed); + ms->moveflags |= MFL_BARRIERJUMP; + //there is a barrier + return qtrue; +} //end of the function BotCheckBarrierJump +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int BotSwimInDirection(bot_movestate_t *ms, vec3_t dir, float speed, int type) +{ + vec3_t normdir; + + VectorCopy(dir, normdir); + VectorNormalize(normdir); + EA_Move(ms->client, normdir, speed); + return qtrue; +} //end of the function BotSwimInDirection +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int BotWalkInDirection(bot_movestate_t *ms, vec3_t dir, float speed, int type) +{ + vec3_t hordir, cmdmove, velocity, tmpdir, origin; + int presencetype, maxframes, cmdframes, stopevent; + aas_clientmove_t move; + float dist; + + if (AAS_OnGround(ms->origin, ms->presencetype, ms->entitynum)) ms->moveflags |= MFL_ONGROUND; + //if the bot is on the ground + if (ms->moveflags & MFL_ONGROUND) + { + //if there is a barrier the bot can jump on + if (BotCheckBarrierJump(ms, dir, speed)) return qtrue; + //remove barrier jump flag + ms->moveflags &= ~MFL_BARRIERJUMP; + //get the presence type for the movement + if ((type & MOVE_CROUCH) && !(type & MOVE_JUMP)) presencetype = PRESENCE_CROUCH; + else presencetype = PRESENCE_NORMAL; + //horizontal direction + hordir[0] = dir[0]; + hordir[1] = dir[1]; + hordir[2] = 0; + VectorNormalize(hordir); + //if the bot is not supposed to jump + if (!(type & MOVE_JUMP)) + { + //if there is a gap, try to jump over it + if (BotGapDistance(ms->origin, hordir, ms->entitynum) > 0) type |= MOVE_JUMP; + } //end if + //get command movement + VectorScale(hordir, speed, cmdmove); + VectorCopy(ms->velocity, velocity); + // + if (type & MOVE_JUMP) + { + //botimport.Print(PRT_MESSAGE, "trying jump\n"); + cmdmove[2] = 400; + maxframes = PREDICTIONTIME_JUMP / 0.1; + cmdframes = 1; + stopevent = SE_HITGROUND|SE_HITGROUNDDAMAGE| + SE_ENTERWATER|SE_ENTERSLIME|SE_ENTERLAVA; + } //end if + else + { + maxframes = 2; + cmdframes = 2; + stopevent = SE_HITGROUNDDAMAGE| + SE_ENTERWATER|SE_ENTERSLIME|SE_ENTERLAVA; + } //end else + //AAS_ClearShownDebugLines(); + // + VectorCopy(ms->origin, origin); + origin[2] += 0.5; + AAS_PredictClientMovement(&move, ms->entitynum, origin, presencetype, qtrue, + velocity, cmdmove, cmdframes, maxframes, 0.1f, + stopevent, 0, qfalse);//qtrue); + //if prediction time wasn't enough to fully predict the movement + if (move.frames >= maxframes && (type & MOVE_JUMP)) + { + //botimport.Print(PRT_MESSAGE, "client %d: max prediction frames\n", ms->client); + return qfalse; + } //end if + //don't enter slime or lava and don't fall from too high + if (move.stopevent & (SE_ENTERSLIME|SE_ENTERLAVA|SE_HITGROUNDDAMAGE)) + { + //botimport.Print(PRT_MESSAGE, "client %d: would be hurt ", ms->client); + //if (move.stopevent & SE_ENTERSLIME) botimport.Print(PRT_MESSAGE, "slime\n"); + //if (move.stopevent & SE_ENTERLAVA) botimport.Print(PRT_MESSAGE, "lava\n"); + //if (move.stopevent & SE_HITGROUNDDAMAGE) botimport.Print(PRT_MESSAGE, "hitground\n"); + return qfalse; + } //end if + //if ground was hit + if (move.stopevent & SE_HITGROUND) + { + //check for nearby gap + VectorNormalize2(move.velocity, tmpdir); + dist = BotGapDistance(move.endpos, tmpdir, ms->entitynum); + if (dist > 0) return qfalse; + // + dist = BotGapDistance(move.endpos, hordir, ms->entitynum); + if (dist > 0) return qfalse; + } //end if + //get horizontal movement + tmpdir[0] = move.endpos[0] - ms->origin[0]; + tmpdir[1] = move.endpos[1] - ms->origin[1]; + tmpdir[2] = 0; + // + //AAS_DrawCross(move.endpos, 4, LINECOLOR_BLUE); + //the bot is blocked by something + if (VectorLength(tmpdir) < speed * ms->thinktime * 0.5) return qfalse; + //perform the movement + if (type & MOVE_JUMP) EA_Jump(ms->client); + if (type & MOVE_CROUCH) EA_Crouch(ms->client); + EA_Move(ms->client, hordir, speed); + //movement was succesfull + return qtrue; + } //end if + else + { + if (ms->moveflags & MFL_BARRIERJUMP) + { + //if near the top or going down + if (ms->velocity[2] < 50) + { + EA_Move(ms->client, dir, speed); + } //end if + } //end if + //FIXME: do air control to avoid hazards + return qtrue; + } //end else +} //end of the function BotWalkInDirection +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int BotMoveInDirection(int movestate, vec3_t dir, float speed, int type) +{ + bot_movestate_t *ms; + + ms = BotMoveStateFromHandle(movestate); + if (!ms) return qfalse; + //if swimming + if (AAS_Swimming(ms->origin)) + { + return BotSwimInDirection(ms, dir, speed, type); + } //end if + else + { + return BotWalkInDirection(ms, dir, speed, type); + } //end else +} //end of the function BotMoveInDirection +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int Intersection(vec2_t p1, vec2_t p2, vec2_t p3, vec2_t p4, vec2_t out) +{ + float x1, dx1, dy1, x2, dx2, dy2, d; + + dx1 = p2[0] - p1[0]; + dy1 = p2[1] - p1[1]; + dx2 = p4[0] - p3[0]; + dy2 = p4[1] - p3[1]; + + d = dy1 * dx2 - dx1 * dy2; + if (d != 0) + { + x1 = p1[1] * dx1 - p1[0] * dy1; + x2 = p3[1] * dx2 - p3[0] * dy2; + out[0] = (int) ((dx1 * x2 - dx2 * x1) / d); + out[1] = (int) ((dy1 * x2 - dy2 * x1) / d); + return qtrue; + } //end if + else + { + return qfalse; + } //end else +} //end of the function Intersection +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void BotCheckBlocked(bot_movestate_t *ms, vec3_t dir, int checkbottom, bot_moveresult_t *result) +{ + vec3_t mins, maxs, end, up = {0, 0, 1}; + bsp_trace_t trace; + + //test for entities obstructing the bot's path + AAS_PresenceTypeBoundingBox(ms->presencetype, mins, maxs); + // + if (fabs(DotProduct(dir, up)) < 0.7) + { + mins[2] += sv_maxstep->value; //if the bot can step on + maxs[2] -= 10; //a little lower to avoid low ceiling + } //end if + VectorMA(ms->origin, 3, dir, end); + trace = AAS_Trace(ms->origin, mins, maxs, end, ms->entitynum, CONTENTS_SOLID|CONTENTS_PLAYERCLIP|CONTENTS_BODY); + //if not started in solid and not hitting the world entity + if (!trace.startsolid && (trace.ent != ENTITYNUM_WORLD && trace.ent != ENTITYNUM_NONE) ) + { + result->blocked = qtrue; + result->blockentity = trace.ent; +#ifdef DEBUG + //botimport.Print(PRT_MESSAGE, "%d: BotCheckBlocked: I'm blocked\n", ms->client); +#endif //DEBUG + } //end if + //if not in an area with reachability + else if (checkbottom && !AAS_AreaReachability(ms->areanum)) + { + //check if the bot is standing on something + AAS_PresenceTypeBoundingBox(ms->presencetype, mins, maxs); + VectorMA(ms->origin, -3, up, end); + trace = AAS_Trace(ms->origin, mins, maxs, end, ms->entitynum, CONTENTS_SOLID|CONTENTS_PLAYERCLIP); + if (!trace.startsolid && (trace.ent != ENTITYNUM_WORLD && trace.ent != ENTITYNUM_NONE) ) + { + result->blocked = qtrue; + result->blockentity = trace.ent; + result->flags |= MOVERESULT_ONTOPOFOBSTACLE; +#ifdef DEBUG + //botimport.Print(PRT_MESSAGE, "%d: BotCheckBlocked: I'm blocked\n", ms->client); +#endif //DEBUG + } //end if + } //end else +} //end of the function BotCheckBlocked +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void BotClearMoveResult(bot_moveresult_t *moveresult) +{ + moveresult->failure = qfalse; + moveresult->type = 0; + moveresult->blocked = qfalse; + moveresult->blockentity = 0; + moveresult->traveltype = 0; + moveresult->flags = 0; +} //end of the function BotClearMoveResult +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +bot_moveresult_t BotTravel_Walk(bot_movestate_t *ms, aas_reachability_t *reach) +{ + float dist, speed; + vec3_t hordir; + bot_moveresult_t result; + + BotClearMoveResult(&result); + //first walk straight to the reachability start + hordir[0] = reach->start[0] - ms->origin[0]; + hordir[1] = reach->start[1] - ms->origin[1]; + hordir[2] = 0; + dist = VectorNormalize(hordir); + // + BotCheckBlocked(ms, hordir, qtrue, &result); + // + if (dist < 10) + { + //walk straight to the reachability end + hordir[0] = reach->end[0] - ms->origin[0]; + hordir[1] = reach->end[1] - ms->origin[1]; + hordir[2] = 0; + dist = VectorNormalize(hordir); + } //end if + //if going towards a crouch area + if (!(AAS_AreaPresenceType(reach->areanum) & PRESENCE_NORMAL)) + { + //if pretty close to the reachable area + if (dist < 20) EA_Crouch(ms->client); + } //end if + // + dist = BotGapDistance(ms->origin, hordir, ms->entitynum); + // + if (ms->moveflags & MFL_WALK) + { + if (dist > 0) speed = 200 - (180 - 1 * dist); + else speed = 200; + EA_Walk(ms->client); + } //end if + else + { + if (dist > 0) speed = 400 - (360 - 2 * dist); + else speed = 400; + } //end else + //elemantary action move in direction + EA_Move(ms->client, hordir, speed); + VectorCopy(hordir, result.movedir); + // + return result; +} //end of the function BotTravel_Walk +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +bot_moveresult_t BotFinishTravel_Walk(bot_movestate_t *ms, aas_reachability_t *reach) +{ + vec3_t hordir; + float dist, speed; + bot_moveresult_t result; + + BotClearMoveResult(&result); + //if not on the ground and changed areas... don't walk back!! + //(doesn't seem to help) + /* + ms->areanum = BotFuzzyPointReachabilityArea(ms->origin); + if (ms->areanum == reach->areanum) + { +#ifdef DEBUG + botimport.Print(PRT_MESSAGE, "BotFinishTravel_Walk: already in reach area\n"); +#endif //DEBUG + return result; + } //end if*/ + //go straight to the reachability end + hordir[0] = reach->end[0] - ms->origin[0]; + hordir[1] = reach->end[1] - ms->origin[1]; + hordir[2] = 0; + dist = VectorNormalize(hordir); + // + if (dist > 100) dist = 100; + speed = 400 - (400 - 3 * dist); + // + EA_Move(ms->client, hordir, speed); + VectorCopy(hordir, result.movedir); + // + return result; +} //end of the function BotFinishTravel_Walk +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +bot_moveresult_t BotTravel_Crouch(bot_movestate_t *ms, aas_reachability_t *reach) +{ + float speed; + vec3_t hordir; + bot_moveresult_t result; + + BotClearMoveResult(&result); + // + speed = 400; + //walk straight to reachability end + hordir[0] = reach->end[0] - ms->origin[0]; + hordir[1] = reach->end[1] - ms->origin[1]; + hordir[2] = 0; + VectorNormalize(hordir); + // + BotCheckBlocked(ms, hordir, qtrue, &result); + //elemantary actions + EA_Crouch(ms->client); + EA_Move(ms->client, hordir, speed); + // + VectorCopy(hordir, result.movedir); + // + return result; +} //end of the function BotTravel_Crouch +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +bot_moveresult_t BotTravel_BarrierJump(bot_movestate_t *ms, aas_reachability_t *reach) +{ + float dist, speed; + vec3_t hordir; + bot_moveresult_t result; + + BotClearMoveResult(&result); + //walk straight to reachability start + hordir[0] = reach->start[0] - ms->origin[0]; + hordir[1] = reach->start[1] - ms->origin[1]; + hordir[2] = 0; + dist = VectorNormalize(hordir); + // + BotCheckBlocked(ms, hordir, qtrue, &result); + //if pretty close to the barrier + if (dist < 9) + { + EA_Jump(ms->client); + } //end if + else + { + if (dist > 60) dist = 60; + speed = 360 - (360 - 6 * dist); + EA_Move(ms->client, hordir, speed); + } //end else + VectorCopy(hordir, result.movedir); + // + return result; +} //end of the function BotTravel_BarrierJump +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +bot_moveresult_t BotFinishTravel_BarrierJump(bot_movestate_t *ms, aas_reachability_t *reach) +{ + float dist; + vec3_t hordir; + bot_moveresult_t result; + + BotClearMoveResult(&result); + //if near the top or going down + if (ms->velocity[2] < 250) + { + hordir[0] = reach->end[0] - ms->origin[0]; + hordir[1] = reach->end[1] - ms->origin[1]; + hordir[2] = 0; + dist = VectorNormalize(hordir); + // + BotCheckBlocked(ms, hordir, qtrue, &result); + // + EA_Move(ms->client, hordir, 400); + VectorCopy(hordir, result.movedir); + } //end if + // + return result; +} //end of the function BotFinishTravel_BarrierJump +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +bot_moveresult_t BotTravel_Swim(bot_movestate_t *ms, aas_reachability_t *reach) +{ + vec3_t dir; + bot_moveresult_t result; + + BotClearMoveResult(&result); + //swim straight to reachability end + VectorSubtract(reach->start, ms->origin, dir); + VectorNormalize(dir); + // + BotCheckBlocked(ms, dir, qtrue, &result); + //elemantary actions + EA_Move(ms->client, dir, 400); + // + VectorCopy(dir, result.movedir); + Vector2Angles(dir, result.ideal_viewangles); + result.flags |= MOVERESULT_SWIMVIEW; + // + return result; +} //end of the function BotTravel_Swim +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +bot_moveresult_t BotTravel_WaterJump(bot_movestate_t *ms, aas_reachability_t *reach) +{ + vec3_t dir, hordir; + float dist; + bot_moveresult_t result; + + BotClearMoveResult(&result); + //swim straight to reachability end + VectorSubtract(reach->end, ms->origin, dir); + VectorCopy(dir, hordir); + hordir[2] = 0; + dir[2] += 15 + crandom() * 40; + //botimport.Print(PRT_MESSAGE, "BotTravel_WaterJump: dir[2] = %f\n", dir[2]); + VectorNormalize(dir); + dist = VectorNormalize(hordir); + //elemantary actions + //EA_Move(ms->client, dir, 400); + EA_MoveForward(ms->client); + //move up if close to the actual out of water jump spot + if (dist < 40) EA_MoveUp(ms->client); + //set the ideal view angles + Vector2Angles(dir, result.ideal_viewangles); + result.flags |= MOVERESULT_MOVEMENTVIEW; + // + VectorCopy(dir, result.movedir); + // + return result; +} //end of the function BotTravel_WaterJump +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +bot_moveresult_t BotFinishTravel_WaterJump(bot_movestate_t *ms, aas_reachability_t *reach) +{ + vec3_t dir, pnt; + float dist; + bot_moveresult_t result; + + //botimport.Print(PRT_MESSAGE, "BotFinishTravel_WaterJump\n"); + BotClearMoveResult(&result); + //if waterjumping there's nothing to do + if (ms->moveflags & MFL_WATERJUMP) return result; + //if not touching any water anymore don't do anything + //otherwise the bot sometimes keeps jumping? + VectorCopy(ms->origin, pnt); + pnt[2] -= 32; //extra for q2dm4 near red armor/mega health + if (!(AAS_PointContents(pnt) & (CONTENTS_LAVA|CONTENTS_SLIME|CONTENTS_WATER))) return result; + //swim straight to reachability end + VectorSubtract(reach->end, ms->origin, dir); + dir[0] += crandom() * 10; + dir[1] += crandom() * 10; + dir[2] += 70 + crandom() * 10; + dist = VectorNormalize(dir); + //elemantary actions + EA_Move(ms->client, dir, 400); + //set the ideal view angles + Vector2Angles(dir, result.ideal_viewangles); + result.flags |= MOVERESULT_MOVEMENTVIEW; + // + VectorCopy(dir, result.movedir); + // + return result; +} //end of the function BotFinishTravel_WaterJump +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +bot_moveresult_t BotTravel_WalkOffLedge(bot_movestate_t *ms, aas_reachability_t *reach) +{ + vec3_t hordir, dir; + float dist, speed, reachhordist; + bot_moveresult_t result; + + BotClearMoveResult(&result); + //check if the bot is blocked by anything + VectorSubtract(reach->start, ms->origin, dir); + VectorNormalize(dir); + BotCheckBlocked(ms, dir, qtrue, &result); + //if the reachability start and end are practially above each other + VectorSubtract(reach->end, reach->start, dir); + dir[2] = 0; + reachhordist = VectorLength(dir); + //walk straight to the reachability start + hordir[0] = reach->start[0] - ms->origin[0]; + hordir[1] = reach->start[1] - ms->origin[1]; + hordir[2] = 0; + dist = VectorNormalize(hordir); + //if pretty close to the start focus on the reachability end + if (dist < 48) + { + hordir[0] = reach->end[0] - ms->origin[0]; + hordir[1] = reach->end[1] - ms->origin[1]; + hordir[2] = 0; + VectorNormalize(hordir); + // + if (reachhordist < 20) + { + speed = 100; + } //end if + else if (!AAS_HorizontalVelocityForJump(0, reach->start, reach->end, &speed)) + { + speed = 400; + } //end if + } //end if + else + { + if (reachhordist < 20) + { + if (dist > 64) dist = 64; + speed = 400 - (256 - 4 * dist); + } //end if + else + { + speed = 400; + } //end else + } //end else + // + BotCheckBlocked(ms, hordir, qtrue, &result); + //elemantary action + EA_Move(ms->client, hordir, speed); + VectorCopy(hordir, result.movedir); + // + return result; +} //end of the function BotTravel_WalkOffLedge +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int BotAirControl(vec3_t origin, vec3_t velocity, vec3_t goal, vec3_t dir, float *speed) +{ + vec3_t org, vel; + float dist; + int i; + + VectorCopy(origin, org); + VectorScale(velocity, 0.1, vel); + for (i = 0; i < 50; i++) + { + vel[2] -= sv_gravity->value * 0.01; + //if going down and next position would be below the goal + if (vel[2] < 0 && org[2] + vel[2] < goal[2]) + { + VectorScale(vel, (goal[2] - org[2]) / vel[2], vel); + VectorAdd(org, vel, org); + VectorSubtract(goal, org, dir); + dist = VectorNormalize(dir); + if (dist > 32) dist = 32; + *speed = 400 - (400 - 13 * dist); + return qtrue; + } //end if + else + { + VectorAdd(org, vel, org); + } //end else + } //end for + VectorSet(dir, 0, 0, 0); + *speed = 400; + return qfalse; +} //end of the function BotAirControl +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +bot_moveresult_t BotFinishTravel_WalkOffLedge(bot_movestate_t *ms, aas_reachability_t *reach) +{ + vec3_t dir, hordir, end, v; + float dist, speed; + bot_moveresult_t result; + + BotClearMoveResult(&result); + // + VectorSubtract(reach->end, ms->origin, dir); + BotCheckBlocked(ms, dir, qtrue, &result); + // + VectorSubtract(reach->end, ms->origin, v); + v[2] = 0; + dist = VectorNormalize(v); + if (dist > 16) VectorMA(reach->end, 16, v, end); + else VectorCopy(reach->end, end); + // + if (!BotAirControl(ms->origin, ms->velocity, end, hordir, &speed)) + { + //go straight to the reachability end + VectorCopy(dir, hordir); + hordir[2] = 0; + // + dist = VectorNormalize(hordir); + speed = 400; + } //end if + // + EA_Move(ms->client, hordir, speed); + VectorCopy(hordir, result.movedir); + // + return result; +} //end of the function BotFinishTravel_WalkOffLedge +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +/* +bot_moveresult_t BotTravel_Jump(bot_movestate_t *ms, aas_reachability_t *reach) +{ + vec3_t hordir; + float dist, gapdist, speed, horspeed, sv_jumpvel; + bot_moveresult_t result; + + BotClearMoveResult(&result); + // + sv_jumpvel = botlibglobals.sv_jumpvel->value; + //walk straight to the reachability start + hordir[0] = reach->start[0] - ms->origin[0]; + hordir[1] = reach->start[1] - ms->origin[1]; + hordir[2] = 0; + dist = VectorNormalize(hordir); + // + speed = 350; + // + gapdist = BotGapDistance(ms, hordir, ms->entitynum); + //if pretty close to the start focus on the reachability end + if (dist < 50 || (gapdist && gapdist < 50)) + { + //NOTE: using max speed (400) works best + //if (AAS_HorizontalVelocityForJump(sv_jumpvel, ms->origin, reach->end, &horspeed)) + //{ + // speed = horspeed * 400 / botlibglobals.sv_maxwalkvelocity->value; + //} //end if + hordir[0] = reach->end[0] - ms->origin[0]; + hordir[1] = reach->end[1] - ms->origin[1]; + VectorNormalize(hordir); + //elemantary action jump + EA_Jump(ms->client); + // + ms->jumpreach = ms->lastreachnum; + speed = 600; + } //end if + else + { + if (AAS_HorizontalVelocityForJump(sv_jumpvel, reach->start, reach->end, &horspeed)) + { + speed = horspeed * 400 / botlibglobals.sv_maxwalkvelocity->value; + } //end if + } //end else + //elemantary action + EA_Move(ms->client, hordir, speed); + VectorCopy(hordir, result.movedir); + // + return result; +} //end of the function BotTravel_Jump*/ +/* +bot_moveresult_t BotTravel_Jump(bot_movestate_t *ms, aas_reachability_t *reach) +{ + vec3_t hordir, dir1, dir2, mins, maxs, start, end; + float dist1, dist2, speed; + bot_moveresult_t result; + bsp_trace_t trace; + + BotClearMoveResult(&result); + // + hordir[0] = reach->start[0] - reach->end[0]; + hordir[1] = reach->start[1] - reach->end[1]; + hordir[2] = 0; + VectorNormalize(hordir); + // + VectorCopy(reach->start, start); + start[2] += 1; + //minus back the bouding box size plus 16 + VectorMA(reach->start, 80, hordir, end); + // + AAS_PresenceTypeBoundingBox(PRESENCE_NORMAL, mins, maxs); + //check for solids + trace = AAS_Trace(start, mins, maxs, end, ms->entitynum, MASK_PLAYERSOLID); + if (trace.startsolid) VectorCopy(start, trace.endpos); + //check for a gap + for (dist1 = 0; dist1 < 80; dist1 += 10) + { + VectorMA(start, dist1+10, hordir, end); + end[2] += 1; + if (AAS_PointAreaNum(end) != ms->reachareanum) break; + } //end for + if (dist1 < 80) VectorMA(reach->start, dist1, hordir, trace.endpos); +// dist1 = BotGapDistance(start, hordir, ms->entitynum); +// if (dist1 && dist1 <= trace.fraction * 80) VectorMA(reach->start, dist1-20, hordir, trace.endpos); + // + VectorSubtract(ms->origin, reach->start, dir1); + dir1[2] = 0; + dist1 = VectorNormalize(dir1); + VectorSubtract(ms->origin, trace.endpos, dir2); + dir2[2] = 0; + dist2 = VectorNormalize(dir2); + //if just before the reachability start + if (DotProduct(dir1, dir2) < -0.8 || dist2 < 5) + { + //botimport.Print(PRT_MESSAGE, "between jump start and run to point\n"); + hordir[0] = reach->end[0] - ms->origin[0]; + hordir[1] = reach->end[1] - ms->origin[1]; + hordir[2] = 0; + VectorNormalize(hordir); + //elemantary action jump + if (dist1 < 24) EA_Jump(ms->client); + else if (dist1 < 32) EA_DelayedJump(ms->client); + EA_Move(ms->client, hordir, 600); + // + ms->jumpreach = ms->lastreachnum; + } //end if + else + { + //botimport.Print(PRT_MESSAGE, "going towards run to point\n"); + hordir[0] = trace.endpos[0] - ms->origin[0]; + hordir[1] = trace.endpos[1] - ms->origin[1]; + hordir[2] = 0; + VectorNormalize(hordir); + // + if (dist2 > 80) dist2 = 80; + speed = 400 - (400 - 5 * dist2); + EA_Move(ms->client, hordir, speed); + } //end else + VectorCopy(hordir, result.movedir); + // + return result; +} //end of the function BotTravel_Jump*/ +//* +bot_moveresult_t BotTravel_Jump(bot_movestate_t *ms, aas_reachability_t *reach) +{ + vec3_t hordir, dir1, dir2, start, end, runstart; +// vec3_t runstart, dir1, dir2, hordir; + float dist1, dist2, speed; + bot_moveresult_t result; + + BotClearMoveResult(&result); + // + AAS_JumpReachRunStart(reach, runstart); + //* + hordir[0] = runstart[0] - reach->start[0]; + hordir[1] = runstart[1] - reach->start[1]; + hordir[2] = 0; + VectorNormalize(hordir); + // + VectorCopy(reach->start, start); + start[2] += 1; + VectorMA(reach->start, 80, hordir, runstart); + //check for a gap + for (dist1 = 0; dist1 < 80; dist1 += 10) + { + VectorMA(start, dist1+10, hordir, end); + end[2] += 1; + if (AAS_PointAreaNum(end) != ms->reachareanum) break; + } //end for + if (dist1 < 80) VectorMA(reach->start, dist1, hordir, runstart); + // + VectorSubtract(ms->origin, reach->start, dir1); + dir1[2] = 0; + dist1 = VectorNormalize(dir1); + VectorSubtract(ms->origin, runstart, dir2); + dir2[2] = 0; + dist2 = VectorNormalize(dir2); + //if just before the reachability start + if (DotProduct(dir1, dir2) < -0.8 || dist2 < 5) + { +// botimport.Print(PRT_MESSAGE, "between jump start and run start point\n"); + hordir[0] = reach->end[0] - ms->origin[0]; + hordir[1] = reach->end[1] - ms->origin[1]; + hordir[2] = 0; + VectorNormalize(hordir); + //elemantary action jump + if (dist1 < 24) EA_Jump(ms->client); + else if (dist1 < 32) EA_DelayedJump(ms->client); + EA_Move(ms->client, hordir, 600); + // + ms->jumpreach = ms->lastreachnum; + } //end if + else + { +// botimport.Print(PRT_MESSAGE, "going towards run start point\n"); + hordir[0] = runstart[0] - ms->origin[0]; + hordir[1] = runstart[1] - ms->origin[1]; + hordir[2] = 0; + VectorNormalize(hordir); + // + if (dist2 > 80) dist2 = 80; + speed = 400 - (400 - 5 * dist2); + EA_Move(ms->client, hordir, speed); + } //end else + VectorCopy(hordir, result.movedir); + // + return result; +} //end of the function BotTravel_Jump*/ +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +bot_moveresult_t BotFinishTravel_Jump(bot_movestate_t *ms, aas_reachability_t *reach) +{ + vec3_t hordir, hordir2; + float speed, dist; + bot_moveresult_t result; + + BotClearMoveResult(&result); + //if not jumped yet + if (!ms->jumpreach) return result; + //go straight to the reachability end + hordir[0] = reach->end[0] - ms->origin[0]; + hordir[1] = reach->end[1] - ms->origin[1]; + hordir[2] = 0; + dist = VectorNormalize(hordir); + // + hordir2[0] = reach->end[0] - reach->start[0]; + hordir2[1] = reach->end[1] - reach->start[1]; + hordir2[2] = 0; + VectorNormalize(hordir2); + // + if (DotProduct(hordir, hordir2) < -0.5 && dist < 24) return result; + //always use max speed when traveling through the air + speed = 800; + // + EA_Move(ms->client, hordir, speed); + VectorCopy(hordir, result.movedir); + // + return result; +} //end of the function BotFinishTravel_Jump +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +bot_moveresult_t BotTravel_Ladder(bot_movestate_t *ms, aas_reachability_t *reach) +{ + //float dist, speed; + vec3_t dir, viewdir;//, hordir; + vec3_t origin = {0, 0, 0}; +// vec3_t up = {0, 0, 1}; + bot_moveresult_t result; + + BotClearMoveResult(&result); + // +// if ((ms->moveflags & MFL_AGAINSTLADDER)) + //NOTE: not a good idea for ladders starting in water + // || !(ms->moveflags & MFL_ONGROUND)) + { + //botimport.Print(PRT_MESSAGE, "against ladder or not on ground\n"); + VectorSubtract(reach->end, ms->origin, dir); + VectorNormalize(dir); + //set the ideal view angles, facing the ladder up or down + viewdir[0] = dir[0]; + viewdir[1] = dir[1]; + viewdir[2] = 3 * dir[2]; + Vector2Angles(viewdir, result.ideal_viewangles); + //elemantary action + EA_Move(ms->client, origin, 0); + EA_MoveForward(ms->client); + //set movement view flag so the AI can see the view is focussed + result.flags |= MOVERESULT_MOVEMENTVIEW; + } //end if +/* else + { + //botimport.Print(PRT_MESSAGE, "moving towards ladder\n"); + VectorSubtract(reach->end, ms->origin, dir); + //make sure the horizontal movement is large anough + VectorCopy(dir, hordir); + hordir[2] = 0; + dist = VectorNormalize(hordir); + // + dir[0] = hordir[0]; + dir[1] = hordir[1]; + if (dir[2] > 0) dir[2] = 1; + else dir[2] = -1; + if (dist > 50) dist = 50; + speed = 400 - (200 - 4 * dist); + EA_Move(ms->client, dir, speed); + } //end else*/ + //save the movement direction + VectorCopy(dir, result.movedir); + // + return result; +} //end of the function BotTravel_Ladder +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +bot_moveresult_t BotTravel_Teleport(bot_movestate_t *ms, aas_reachability_t *reach) +{ + vec3_t hordir; + float dist; + bot_moveresult_t result; + + BotClearMoveResult(&result); + //if the bot is being teleported + if (ms->moveflags & MFL_TELEPORTED) return result; + + //walk straight to center of the teleporter + VectorSubtract(reach->start, ms->origin, hordir); + if (!(ms->moveflags & MFL_SWIMMING)) hordir[2] = 0; + dist = VectorNormalize(hordir); + // + BotCheckBlocked(ms, hordir, qtrue, &result); + + if (dist < 30) EA_Move(ms->client, hordir, 200); + else EA_Move(ms->client, hordir, 400); + + if (ms->moveflags & MFL_SWIMMING) result.flags |= MOVERESULT_SWIMVIEW; + + VectorCopy(hordir, result.movedir); + return result; +} //end of the function BotTravel_Teleport +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +bot_moveresult_t BotTravel_Elevator(bot_movestate_t *ms, aas_reachability_t *reach) +{ + vec3_t dir, dir1, dir2, hordir, bottomcenter; + float dist, dist1, dist2, speed; + bot_moveresult_t result; + + BotClearMoveResult(&result); + //if standing on the plat + if (BotOnMover(ms->origin, ms->entitynum, reach)) + { +#ifdef DEBUG_ELEVATOR + botimport.Print(PRT_MESSAGE, "bot on elevator\n"); +#endif //DEBUG_ELEVATOR + //if vertically not too far from the end point + if (abs(ms->origin[2] - reach->end[2]) < sv_maxbarrier->value) + { +#ifdef DEBUG_ELEVATOR + botimport.Print(PRT_MESSAGE, "bot moving to end\n"); +#endif //DEBUG_ELEVATOR + //move to the end point + VectorSubtract(reach->end, ms->origin, hordir); + hordir[2] = 0; + VectorNormalize(hordir); + if (!BotCheckBarrierJump(ms, hordir, 100)) + { + EA_Move(ms->client, hordir, 400); + } //end if + VectorCopy(hordir, result.movedir); + } //end else + //if not really close to the center of the elevator + else + { + MoverBottomCenter(reach, bottomcenter); + VectorSubtract(bottomcenter, ms->origin, hordir); + hordir[2] = 0; + dist = VectorNormalize(hordir); + // + if (dist > 10) + { +#ifdef DEBUG_ELEVATOR + botimport.Print(PRT_MESSAGE, "bot moving to center\n"); +#endif //DEBUG_ELEVATOR + //move to the center of the plat + if (dist > 100) dist = 100; + speed = 400 - (400 - 4 * dist); + // + EA_Move(ms->client, hordir, speed); + VectorCopy(hordir, result.movedir); + } //end if + } //end else + } //end if + else + { +#ifdef DEBUG_ELEVATOR + botimport.Print(PRT_MESSAGE, "bot not on elevator\n"); +#endif //DEBUG_ELEVATOR + //if very near the reachability end + VectorSubtract(reach->end, ms->origin, dir); + dist = VectorLength(dir); + if (dist < 64) + { + if (dist > 60) dist = 60; + speed = 360 - (360 - 6 * dist); + // + if ((ms->moveflags & MFL_SWIMMING) || !BotCheckBarrierJump(ms, dir, 50)) + { + if (speed > 5) EA_Move(ms->client, dir, speed); + } //end if + VectorCopy(dir, result.movedir); + // + if (ms->moveflags & MFL_SWIMMING) result.flags |= MOVERESULT_SWIMVIEW; + //stop using this reachability + ms->reachability_time = 0; + return result; + } //end if + //get direction and distance to reachability start + VectorSubtract(reach->start, ms->origin, dir1); + if (!(ms->moveflags & MFL_SWIMMING)) dir1[2] = 0; + dist1 = VectorNormalize(dir1); + //if the elevator isn't down + if (!MoverDown(reach)) + { +#ifdef DEBUG_ELEVATOR + botimport.Print(PRT_MESSAGE, "elevator not down\n"); +#endif //DEBUG_ELEVATOR + dist = dist1; + VectorCopy(dir1, dir); + // + BotCheckBlocked(ms, dir, qfalse, &result); + // + if (dist > 60) dist = 60; + speed = 360 - (360 - 6 * dist); + // + if (!(ms->moveflags & MFL_SWIMMING) && !BotCheckBarrierJump(ms, dir, 50)) + { + if (speed > 5) EA_Move(ms->client, dir, speed); + } //end if + VectorCopy(dir, result.movedir); + // + if (ms->moveflags & MFL_SWIMMING) result.flags |= MOVERESULT_SWIMVIEW; + //this isn't a failure... just wait till the elevator comes down + result.type = RESULTTYPE_ELEVATORUP; + result.flags |= MOVERESULT_WAITING; + return result; + } //end if + //get direction and distance to elevator bottom center + MoverBottomCenter(reach, bottomcenter); + VectorSubtract(bottomcenter, ms->origin, dir2); + if (!(ms->moveflags & MFL_SWIMMING)) dir2[2] = 0; + dist2 = VectorNormalize(dir2); + //if very close to the reachability start or + //closer to the elevator center or + //between reachability start and elevator center + if (dist1 < 20 || dist2 < dist1 || DotProduct(dir1, dir2) < 0) + { +#ifdef DEBUG_ELEVATOR + botimport.Print(PRT_MESSAGE, "bot moving to center\n"); +#endif //DEBUG_ELEVATOR + dist = dist2; + VectorCopy(dir2, dir); + } //end if + else //closer to the reachability start + { +#ifdef DEBUG_ELEVATOR + botimport.Print(PRT_MESSAGE, "bot moving to start\n"); +#endif //DEBUG_ELEVATOR + dist = dist1; + VectorCopy(dir1, dir); + } //end else + // + BotCheckBlocked(ms, dir, qfalse, &result); + // + if (dist > 60) dist = 60; + speed = 400 - (400 - 6 * dist); + // + if (!(ms->moveflags & MFL_SWIMMING) && !BotCheckBarrierJump(ms, dir, 50)) + { + EA_Move(ms->client, dir, speed); + } //end if + VectorCopy(dir, result.movedir); + // + if (ms->moveflags & MFL_SWIMMING) result.flags |= MOVERESULT_SWIMVIEW; + } //end else + return result; +} //end of the function BotTravel_Elevator +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +bot_moveresult_t BotFinishTravel_Elevator(bot_movestate_t *ms, aas_reachability_t *reach) +{ + vec3_t bottomcenter, bottomdir, topdir; + bot_moveresult_t result; + + BotClearMoveResult(&result); + // + MoverBottomCenter(reach, bottomcenter); + VectorSubtract(bottomcenter, ms->origin, bottomdir); + // + VectorSubtract(reach->end, ms->origin, topdir); + // + if (fabs(bottomdir[2]) < fabs(topdir[2])) + { + VectorNormalize(bottomdir); + EA_Move(ms->client, bottomdir, 300); + } //end if + else + { + VectorNormalize(topdir); + EA_Move(ms->client, topdir, 300); + } //end else + return result; +} //end of the function BotFinishTravel_Elevator +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void BotFuncBobStartEnd(aas_reachability_t *reach, vec3_t start, vec3_t end, vec3_t origin) +{ + int spawnflags, modelnum; + vec3_t mins, maxs, mid, angles = {0, 0, 0}; + int num0, num1; + + modelnum = reach->facenum & 0x0000FFFF; + if (!AAS_OriginOfMoverWithModelNum(modelnum, origin)) + { + botimport.Print(PRT_MESSAGE, "BotFuncBobStartEnd: no entity with model %d\n", modelnum); + VectorSet(start, 0, 0, 0); + VectorSet(end, 0, 0, 0); + return; + } //end if + AAS_BSPModelMinsMaxsOrigin(modelnum, angles, mins, maxs, NULL); + VectorAdd(mins, maxs, mid); + VectorScale(mid, 0.5, mid); + VectorCopy(mid, start); + VectorCopy(mid, end); + spawnflags = reach->facenum >> 16; + num0 = reach->edgenum >> 16; + if (num0 > 0x00007FFF) num0 |= 0xFFFF0000; + num1 = reach->edgenum & 0x0000FFFF; + if (num1 > 0x00007FFF) num1 |= 0xFFFF0000; + if (spawnflags & 1) + { + start[0] = num0; + end[0] = num1; + // + origin[0] += mid[0]; + origin[1] = mid[1]; + origin[2] = mid[2]; + } //end if + else if (spawnflags & 2) + { + start[1] = num0; + end[1] = num1; + // + origin[0] = mid[0]; + origin[1] += mid[1]; + origin[2] = mid[2]; + } //end else if + else + { + start[2] = num0; + end[2] = num1; + // + origin[0] = mid[0]; + origin[1] = mid[1]; + origin[2] += mid[2]; + } //end else +} //end of the function BotFuncBobStartEnd +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +bot_moveresult_t BotTravel_FuncBobbing(bot_movestate_t *ms, aas_reachability_t *reach) +{ + vec3_t dir, dir1, dir2, hordir, bottomcenter, bob_start, bob_end, bob_origin; + float dist, dist1, dist2, speed; + bot_moveresult_t result; + + BotClearMoveResult(&result); + // + BotFuncBobStartEnd(reach, bob_start, bob_end, bob_origin); + //if standing ontop of the func_bobbing + if (BotOnMover(ms->origin, ms->entitynum, reach)) + { +#ifdef DEBUG_FUNCBOB + botimport.Print(PRT_MESSAGE, "bot on func_bobbing\n"); +#endif + //if near end point of reachability + VectorSubtract(bob_origin, bob_end, dir); + if (VectorLength(dir) < 24) + { +#ifdef DEBUG_FUNCBOB + botimport.Print(PRT_MESSAGE, "bot moving to reachability end\n"); +#endif + //move to the end point + VectorSubtract(reach->end, ms->origin, hordir); + hordir[2] = 0; + VectorNormalize(hordir); + if (!BotCheckBarrierJump(ms, hordir, 100)) + { + EA_Move(ms->client, hordir, 400); + } //end if + VectorCopy(hordir, result.movedir); + } //end else + //if not really close to the center of the elevator + else + { + MoverBottomCenter(reach, bottomcenter); + VectorSubtract(bottomcenter, ms->origin, hordir); + hordir[2] = 0; + dist = VectorNormalize(hordir); + // + if (dist > 10) + { +#ifdef DEBUG_FUNCBOB + botimport.Print(PRT_MESSAGE, "bot moving to func_bobbing center\n"); +#endif + //move to the center of the plat + if (dist > 100) dist = 100; + speed = 400 - (400 - 4 * dist); + // + EA_Move(ms->client, hordir, speed); + VectorCopy(hordir, result.movedir); + } //end if + } //end else + } //end if + else + { +#ifdef DEBUG_FUNCBOB + botimport.Print(PRT_MESSAGE, "bot not ontop of func_bobbing\n"); +#endif + //if very near the reachability end + VectorSubtract(reach->end, ms->origin, dir); + dist = VectorLength(dir); + if (dist < 64) + { +#ifdef DEBUG_FUNCBOB + botimport.Print(PRT_MESSAGE, "bot moving to end\n"); +#endif + if (dist > 60) dist = 60; + speed = 360 - (360 - 6 * dist); + //if swimming or no barrier jump + if ((ms->moveflags & MFL_SWIMMING) || !BotCheckBarrierJump(ms, dir, 50)) + { + if (speed > 5) EA_Move(ms->client, dir, speed); + } //end if + VectorCopy(dir, result.movedir); + // + if (ms->moveflags & MFL_SWIMMING) result.flags |= MOVERESULT_SWIMVIEW; + //stop using this reachability + ms->reachability_time = 0; + return result; + } //end if + //get direction and distance to reachability start + VectorSubtract(reach->start, ms->origin, dir1); + if (!(ms->moveflags & MFL_SWIMMING)) dir1[2] = 0; + dist1 = VectorNormalize(dir1); + //if func_bobbing is Not it's start position + VectorSubtract(bob_origin, bob_start, dir); + if (VectorLength(dir) > 16) + { +#ifdef DEBUG_FUNCBOB + botimport.Print(PRT_MESSAGE, "func_bobbing not at start\n"); +#endif + dist = dist1; + VectorCopy(dir1, dir); + // + BotCheckBlocked(ms, dir, qfalse, &result); + // + if (dist > 60) dist = 60; + speed = 360 - (360 - 6 * dist); + // + if (!(ms->moveflags & MFL_SWIMMING) && !BotCheckBarrierJump(ms, dir, 50)) + { + if (speed > 5) EA_Move(ms->client, dir, speed); + } //end if + VectorCopy(dir, result.movedir); + // + if (ms->moveflags & MFL_SWIMMING) result.flags |= MOVERESULT_SWIMVIEW; + //this isn't a failure... just wait till the func_bobbing arrives + result.type = RESULTTYPE_WAITFORFUNCBOBBING; + result.flags |= MOVERESULT_WAITING; + return result; + } //end if + //get direction and distance to func_bob bottom center + MoverBottomCenter(reach, bottomcenter); + VectorSubtract(bottomcenter, ms->origin, dir2); + if (!(ms->moveflags & MFL_SWIMMING)) dir2[2] = 0; + dist2 = VectorNormalize(dir2); + //if very close to the reachability start or + //closer to the elevator center or + //between reachability start and func_bobbing center + if (dist1 < 20 || dist2 < dist1 || DotProduct(dir1, dir2) < 0) + { +#ifdef DEBUG_FUNCBOB + botimport.Print(PRT_MESSAGE, "bot moving to func_bobbing center\n"); +#endif + dist = dist2; + VectorCopy(dir2, dir); + } //end if + else //closer to the reachability start + { +#ifdef DEBUG_FUNCBOB + botimport.Print(PRT_MESSAGE, "bot moving to reachability start\n"); +#endif + dist = dist1; + VectorCopy(dir1, dir); + } //end else + // + BotCheckBlocked(ms, dir, qfalse, &result); + // + if (dist > 60) dist = 60; + speed = 400 - (400 - 6 * dist); + // + if (!(ms->moveflags & MFL_SWIMMING) && !BotCheckBarrierJump(ms, dir, 50)) + { + EA_Move(ms->client, dir, speed); + } //end if + VectorCopy(dir, result.movedir); + // + if (ms->moveflags & MFL_SWIMMING) result.flags |= MOVERESULT_SWIMVIEW; + } //end else + return result; +} //end of the function BotTravel_FuncBobbing +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +bot_moveresult_t BotFinishTravel_FuncBobbing(bot_movestate_t *ms, aas_reachability_t *reach) +{ + vec3_t bob_origin, bob_start, bob_end, dir, hordir, bottomcenter; + bot_moveresult_t result; + float dist, speed; + + BotClearMoveResult(&result); + // + BotFuncBobStartEnd(reach, bob_start, bob_end, bob_origin); + // + VectorSubtract(bob_origin, bob_end, dir); + dist = VectorLength(dir); + //if the func_bobbing is near the end + if (dist < 16) + { + VectorSubtract(reach->end, ms->origin, hordir); + if (!(ms->moveflags & MFL_SWIMMING)) hordir[2] = 0; + dist = VectorNormalize(hordir); + // + if (dist > 60) dist = 60; + speed = 360 - (360 - 6 * dist); + // + if (speed > 5) EA_Move(ms->client, dir, speed); + VectorCopy(dir, result.movedir); + // + if (ms->moveflags & MFL_SWIMMING) result.flags |= MOVERESULT_SWIMVIEW; + } //end if + else + { + MoverBottomCenter(reach, bottomcenter); + VectorSubtract(bottomcenter, ms->origin, hordir); + if (!(ms->moveflags & MFL_SWIMMING)) hordir[2] = 0; + dist = VectorNormalize(hordir); + // + if (dist > 5) + { + //move to the center of the plat + if (dist > 100) dist = 100; + speed = 400 - (400 - 4 * dist); + // + EA_Move(ms->client, hordir, speed); + VectorCopy(hordir, result.movedir); + } //end if + } //end else + return result; +} //end of the function BotFinishTravel_FuncBobbing +//=========================================================================== +// 0 no valid grapple hook visible +// 1 the grapple hook is still flying +// 2 the grapple hooked into a wall +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int GrappleState(bot_movestate_t *ms, aas_reachability_t *reach) +{ + int i; + aas_entityinfo_t entinfo; + + //if the grapple hook is pulling + if (ms->moveflags & MFL_GRAPPLEPULL) + return 2; + //check for a visible grapple missile entity + //or visible grapple entity + for (i = AAS_NextEntity(0); i; i = AAS_NextEntity(i)) + { + if (AAS_EntityType(i) == (int) entitytypemissile->value) + { + AAS_EntityInfo(i, &entinfo); + if (entinfo.weapon == (int) weapindex_grapple->value) + { + return 1; + } //end if + } //end if + } //end for + //no valid grapple at all + return 0; +} //end of the function GrappleState +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void BotResetGrapple(bot_movestate_t *ms) +{ + aas_reachability_t reach; + + AAS_ReachabilityFromNum(ms->lastreachnum, &reach); + //if not using the grapple hook reachability anymore + if ((reach.traveltype & TRAVELTYPE_MASK) != TRAVEL_GRAPPLEHOOK) + { + if ((ms->moveflags & MFL_ACTIVEGRAPPLE) || ms->grapplevisible_time) + { + if (offhandgrapple->value) + EA_Command(ms->client, cmd_grappleoff->string); + ms->moveflags &= ~MFL_ACTIVEGRAPPLE; + ms->grapplevisible_time = 0; +#ifdef DEBUG_GRAPPLE + botimport.Print(PRT_MESSAGE, "reset grapple\n"); +#endif //DEBUG_GRAPPLE + } //end if + } //end if +} //end of the function BotResetGrapple +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +bot_moveresult_t BotTravel_Grapple(bot_movestate_t *ms, aas_reachability_t *reach) +{ + bot_moveresult_t result; + float dist, speed; + vec3_t dir, viewdir, org; + int state, areanum; + bsp_trace_t trace; + +#ifdef DEBUG_GRAPPLE + static int debugline; + if (!debugline) debugline = botimport.DebugLineCreate(); + botimport.DebugLineShow(debugline, reach->start, reach->end, LINECOLOR_BLUE); +#endif //DEBUG_GRAPPLE + + BotClearMoveResult(&result); + // + if (ms->moveflags & MFL_GRAPPLERESET) + { + if (offhandgrapple->value) + EA_Command(ms->client, cmd_grappleoff->string); + ms->moveflags &= ~MFL_ACTIVEGRAPPLE; + return result; + } //end if + // + if (!(int) offhandgrapple->value) + { + result.weapon = weapindex_grapple->value; + result.flags |= MOVERESULT_MOVEMENTWEAPON; + } //end if + // + if (ms->moveflags & MFL_ACTIVEGRAPPLE) + { +#ifdef DEBUG_GRAPPLE + botimport.Print(PRT_MESSAGE, "BotTravel_Grapple: active grapple\n"); +#endif //DEBUG_GRAPPLE + // + state = GrappleState(ms, reach); + // + VectorSubtract(reach->end, ms->origin, dir); + dir[2] = 0; + dist = VectorLength(dir); + //if very close to the grapple end or the grappled is hooked and + //the bot doesn't get any closer + if (state && dist < 48) + { + if (ms->lastgrappledist - dist < 1) + { +#ifdef DEBUG_GRAPPLE + botimport.Print(PRT_ERROR, "grapple normal end\n"); +#endif //DEBUG_GRAPPLE + if (offhandgrapple->value) + EA_Command(ms->client, cmd_grappleoff->string); + ms->moveflags &= ~MFL_ACTIVEGRAPPLE; + ms->moveflags |= MFL_GRAPPLERESET; + ms->reachability_time = 0; //end the reachability + return result; + } //end if + } //end if + //if no valid grapple at all, or the grapple hooked and the bot + //isn't moving anymore + else if (!state || (state == 2 && dist > ms->lastgrappledist - 2)) + { + if (ms->grapplevisible_time < AAS_Time() - 0.4) + { +#ifdef DEBUG_GRAPPLE + botimport.Print(PRT_ERROR, "grapple not visible\n"); +#endif //DEBUG_GRAPPLE + if (offhandgrapple->value) + EA_Command(ms->client, cmd_grappleoff->string); + ms->moveflags &= ~MFL_ACTIVEGRAPPLE; + ms->moveflags |= MFL_GRAPPLERESET; + ms->reachability_time = 0; //end the reachability + return result; + } //end if + } //end if + else + { + ms->grapplevisible_time = AAS_Time(); + } //end else + // + if (!(int) offhandgrapple->value) + { + EA_Attack(ms->client); + } //end if + //remember the current grapple distance + ms->lastgrappledist = dist; + } //end if + else + { +#ifdef DEBUG_GRAPPLE + botimport.Print(PRT_MESSAGE, "BotTravel_Grapple: inactive grapple\n"); +#endif //DEBUG_GRAPPLE + // + ms->grapplevisible_time = AAS_Time(); + // + VectorSubtract(reach->start, ms->origin, dir); + if (!(ms->moveflags & MFL_SWIMMING)) dir[2] = 0; + VectorAdd(ms->origin, ms->viewoffset, org); + VectorSubtract(reach->end, org, viewdir); + // + dist = VectorNormalize(dir); + Vector2Angles(viewdir, result.ideal_viewangles); + result.flags |= MOVERESULT_MOVEMENTVIEW; + // + if (dist < 5 && + fabs(AngleDiff(result.ideal_viewangles[0], ms->viewangles[0])) < 2 && + fabs(AngleDiff(result.ideal_viewangles[1], ms->viewangles[1])) < 2) + { +#ifdef DEBUG_GRAPPLE + botimport.Print(PRT_MESSAGE, "BotTravel_Grapple: activating grapple\n"); +#endif //DEBUG_GRAPPLE + //check if the grapple missile path is clear + VectorAdd(ms->origin, ms->viewoffset, org); + trace = AAS_Trace(org, NULL, NULL, reach->end, ms->entitynum, CONTENTS_SOLID); + VectorSubtract(reach->end, trace.endpos, dir); + if (VectorLength(dir) > 16) + { + result.failure = qtrue; + return result; + } //end if + //activate the grapple + if (offhandgrapple->value) + { + EA_Command(ms->client, cmd_grappleon->string); + } //end if + else + { + EA_Attack(ms->client); + } //end else + ms->moveflags |= MFL_ACTIVEGRAPPLE; + ms->lastgrappledist = 999999; + } //end if + else + { + if (dist < 70) speed = 300 - (300 - 4 * dist); + else speed = 400; + // + BotCheckBlocked(ms, dir, qtrue, &result); + //elemantary action move in direction + EA_Move(ms->client, dir, speed); + VectorCopy(dir, result.movedir); + } //end else + //if in another area before actually grappling + areanum = AAS_PointAreaNum(ms->origin); + if (areanum && areanum != ms->reachareanum) ms->reachability_time = 0; + } //end else + return result; +} //end of the function BotTravel_Grapple +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +bot_moveresult_t BotTravel_RocketJump(bot_movestate_t *ms, aas_reachability_t *reach) +{ + vec3_t hordir; + float dist, speed; + bot_moveresult_t result; + + //botimport.Print(PRT_MESSAGE, "BotTravel_RocketJump: bah\n"); + BotClearMoveResult(&result); + // + hordir[0] = reach->start[0] - ms->origin[0]; + hordir[1] = reach->start[1] - ms->origin[1]; + hordir[2] = 0; + // + dist = VectorNormalize(hordir); + //look in the movement direction + Vector2Angles(hordir, result.ideal_viewangles); + //look straight down + result.ideal_viewangles[PITCH] = 90; + // + if (dist < 5 && + fabs(AngleDiff(result.ideal_viewangles[0], ms->viewangles[0])) < 5 && + fabs(AngleDiff(result.ideal_viewangles[1], ms->viewangles[1])) < 5) + { + //botimport.Print(PRT_MESSAGE, "between jump start and run start point\n"); + hordir[0] = reach->end[0] - ms->origin[0]; + hordir[1] = reach->end[1] - ms->origin[1]; + hordir[2] = 0; + VectorNormalize(hordir); + //elemantary action jump + EA_Jump(ms->client); + EA_Attack(ms->client); + EA_Move(ms->client, hordir, 800); + // + ms->jumpreach = ms->lastreachnum; + } //end if + else + { + if (dist > 80) dist = 80; + speed = 400 - (400 - 5 * dist); + EA_Move(ms->client, hordir, speed); + } //end else + //look in the movement direction + Vector2Angles(hordir, result.ideal_viewangles); + //look straight down + result.ideal_viewangles[PITCH] = 90; + //set the view angles directly + EA_View(ms->client, result.ideal_viewangles); + //view is important for the movment + result.flags |= MOVERESULT_MOVEMENTVIEWSET; + //select the rocket launcher + EA_SelectWeapon(ms->client, (int) weapindex_rocketlauncher->value); + //weapon is used for movement + result.weapon = (int) weapindex_rocketlauncher->value; + result.flags |= MOVERESULT_MOVEMENTWEAPON; + // + VectorCopy(hordir, result.movedir); + // + return result; +} //end of the function BotTravel_RocketJump +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +bot_moveresult_t BotTravel_BFGJump(bot_movestate_t *ms, aas_reachability_t *reach) +{ + vec3_t hordir; + float dist, speed; + bot_moveresult_t result; + + //botimport.Print(PRT_MESSAGE, "BotTravel_BFGJump: bah\n"); + BotClearMoveResult(&result); + // + hordir[0] = reach->start[0] - ms->origin[0]; + hordir[1] = reach->start[1] - ms->origin[1]; + hordir[2] = 0; + // + dist = VectorNormalize(hordir); + // + if (dist < 5 && + fabs(AngleDiff(result.ideal_viewangles[0], ms->viewangles[0])) < 5 && + fabs(AngleDiff(result.ideal_viewangles[1], ms->viewangles[1])) < 5) + { + //botimport.Print(PRT_MESSAGE, "between jump start and run start point\n"); + hordir[0] = reach->end[0] - ms->origin[0]; + hordir[1] = reach->end[1] - ms->origin[1]; + hordir[2] = 0; + VectorNormalize(hordir); + //elemantary action jump + EA_Jump(ms->client); + EA_Attack(ms->client); + EA_Move(ms->client, hordir, 800); + // + ms->jumpreach = ms->lastreachnum; + } //end if + else + { + if (dist > 80) dist = 80; + speed = 400 - (400 - 5 * dist); + EA_Move(ms->client, hordir, speed); + } //end else + //look in the movement direction + Vector2Angles(hordir, result.ideal_viewangles); + //look straight down + result.ideal_viewangles[PITCH] = 90; + //set the view angles directly + EA_View(ms->client, result.ideal_viewangles); + //view is important for the movment + result.flags |= MOVERESULT_MOVEMENTVIEWSET; + //select the rocket launcher + EA_SelectWeapon(ms->client, (int) weapindex_bfg10k->value); + //weapon is used for movement + result.weapon = (int) weapindex_bfg10k->value; + result.flags |= MOVERESULT_MOVEMENTWEAPON; + // + VectorCopy(hordir, result.movedir); + // + return result; +} //end of the function BotTravel_BFGJump +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +bot_moveresult_t BotFinishTravel_WeaponJump(bot_movestate_t *ms, aas_reachability_t *reach) +{ + vec3_t hordir; + float speed; + bot_moveresult_t result; + + BotClearMoveResult(&result); + //if not jumped yet + if (!ms->jumpreach) return result; + /* + //go straight to the reachability end + hordir[0] = reach->end[0] - ms->origin[0]; + hordir[1] = reach->end[1] - ms->origin[1]; + hordir[2] = 0; + VectorNormalize(hordir); + //always use max speed when traveling through the air + EA_Move(ms->client, hordir, 800); + VectorCopy(hordir, result.movedir); + */ + // + if (!BotAirControl(ms->origin, ms->velocity, reach->end, hordir, &speed)) + { + //go straight to the reachability end + VectorSubtract(reach->end, ms->origin, hordir); + hordir[2] = 0; + VectorNormalize(hordir); + speed = 400; + } //end if + // + EA_Move(ms->client, hordir, speed); + VectorCopy(hordir, result.movedir); + // + return result; +} //end of the function BotFinishTravel_WeaponJump +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +bot_moveresult_t BotTravel_JumpPad(bot_movestate_t *ms, aas_reachability_t *reach) +{ + float dist, speed; + vec3_t hordir; + bot_moveresult_t result; + + BotClearMoveResult(&result); + //first walk straight to the reachability start + hordir[0] = reach->start[0] - ms->origin[0]; + hordir[1] = reach->start[1] - ms->origin[1]; + hordir[2] = 0; + dist = VectorNormalize(hordir); + // + BotCheckBlocked(ms, hordir, qtrue, &result); + speed = 400; + //elemantary action move in direction + EA_Move(ms->client, hordir, speed); + VectorCopy(hordir, result.movedir); + // + return result; +} //end of the function BotTravel_JumpPad +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +bot_moveresult_t BotFinishTravel_JumpPad(bot_movestate_t *ms, aas_reachability_t *reach) +{ + float speed; + vec3_t hordir; + bot_moveresult_t result; + + BotClearMoveResult(&result); + if (!BotAirControl(ms->origin, ms->velocity, reach->end, hordir, &speed)) + { + hordir[0] = reach->end[0] - ms->origin[0]; + hordir[1] = reach->end[1] - ms->origin[1]; + hordir[2] = 0; + VectorNormalize(hordir); + speed = 400; + } //end if + BotCheckBlocked(ms, hordir, qtrue, &result); + //elemantary action move in direction + EA_Move(ms->client, hordir, speed); + VectorCopy(hordir, result.movedir); + // + return result; +} //end of the function BotFinishTravel_JumpPad +//=========================================================================== +// time before the reachability times out +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int BotReachabilityTime(aas_reachability_t *reach) +{ + switch(reach->traveltype & TRAVELTYPE_MASK) + { + case TRAVEL_WALK: return 5; + case TRAVEL_CROUCH: return 5; + case TRAVEL_BARRIERJUMP: return 5; + case TRAVEL_LADDER: return 6; + case TRAVEL_WALKOFFLEDGE: return 5; + case TRAVEL_JUMP: return 5; + case TRAVEL_SWIM: return 5; + case TRAVEL_WATERJUMP: return 5; + case TRAVEL_TELEPORT: return 5; + case TRAVEL_ELEVATOR: return 10; + case TRAVEL_GRAPPLEHOOK: return 8; + case TRAVEL_ROCKETJUMP: return 6; + case TRAVEL_BFGJUMP: return 6; + case TRAVEL_JUMPPAD: return 10; + case TRAVEL_FUNCBOB: return 10; + default: + { + botimport.Print(PRT_ERROR, "travel type %d not implemented yet\n", reach->traveltype); + return 8; + } //end case + } //end switch +} //end of the function BotReachabilityTime +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +bot_moveresult_t BotMoveInGoalArea(bot_movestate_t *ms, bot_goal_t *goal) +{ + bot_moveresult_t result; + vec3_t dir; + float dist, speed; + +#ifdef DEBUG + //botimport.Print(PRT_MESSAGE, "%s: moving straight to goal\n", ClientName(ms->entitynum-1)); + //AAS_ClearShownDebugLines(); + //AAS_DebugLine(ms->origin, goal->origin, LINECOLOR_RED); +#endif //DEBUG + BotClearMoveResult(&result); + //walk straight to the goal origin + dir[0] = goal->origin[0] - ms->origin[0]; + dir[1] = goal->origin[1] - ms->origin[1]; + if (ms->moveflags & MFL_SWIMMING) + { + dir[2] = goal->origin[2] - ms->origin[2]; + result.traveltype = TRAVEL_SWIM; + } //end if + else + { + dir[2] = 0; + result.traveltype = TRAVEL_WALK; + } //endif + // + dist = VectorNormalize(dir); + if (dist > 100) dist = 100; + speed = 400 - (400 - 4 * dist); + if (speed < 10) speed = 0; + // + BotCheckBlocked(ms, dir, qtrue, &result); + //elemantary action move in direction + EA_Move(ms->client, dir, speed); + VectorCopy(dir, result.movedir); + // + if (ms->moveflags & MFL_SWIMMING) + { + Vector2Angles(dir, result.ideal_viewangles); + result.flags |= MOVERESULT_SWIMVIEW; + } //end if + //if (!debugline) debugline = botimport.DebugLineCreate(); + //botimport.DebugLineShow(debugline, ms->origin, goal->origin, LINECOLOR_BLUE); + // + ms->lastreachnum = 0; + ms->lastareanum = 0; + ms->lastgoalareanum = goal->areanum; + VectorCopy(ms->origin, ms->lastorigin); + // + return result; +} //end of the function BotMoveInGoalArea +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void BotMoveToGoal(bot_moveresult_t *result, int movestate, bot_goal_t *goal, int travelflags) +{ + int reachnum, lastreachnum, foundjumppad, ent, resultflags; + aas_reachability_t reach, lastreach; + bot_movestate_t *ms; + //vec3_t mins, maxs, up = {0, 0, 1}; + //bsp_trace_t trace; + //static int debugline; + + + BotClearMoveResult(result); + // + ms = BotMoveStateFromHandle(movestate); + if (!ms) return; + //reset the grapple before testing if the bot has a valid goal + //because the bot could loose all it's goals when stuck to a wall + BotResetGrapple(ms); + // + if (!goal) + { +#ifdef DEBUG + botimport.Print(PRT_MESSAGE, "client %d: movetogoal -> no goal\n", ms->client); +#endif //DEBUG + result->failure = qtrue; + return; + } //end if + //botimport.Print(PRT_MESSAGE, "numavoidreach = %d\n", ms->numavoidreach); + //remove some of the move flags + ms->moveflags &= ~(MFL_SWIMMING|MFL_AGAINSTLADDER); + //set some of the move flags + //NOTE: the MFL_ONGROUND flag is also set in the higher AI + if (AAS_OnGround(ms->origin, ms->presencetype, ms->entitynum)) ms->moveflags |= MFL_ONGROUND; + // + if (ms->moveflags & MFL_ONGROUND) + { + int modeltype, modelnum; + + ent = BotOnTopOfEntity(ms); + + if (ent != -1) + { + modelnum = AAS_EntityModelindex(ent); + if (modelnum >= 0 && modelnum < MAX_MODELS) + { + modeltype = modeltypes[modelnum]; + + if (modeltype == MODELTYPE_FUNC_PLAT) + { + AAS_ReachabilityFromNum(ms->lastreachnum, &reach); + //if the bot is Not using the elevator + if ((reach.traveltype & TRAVELTYPE_MASK) != TRAVEL_ELEVATOR || + //NOTE: the face number is the plat model number + (reach.facenum & 0x0000FFFF) != modelnum) + { + reachnum = AAS_NextModelReachability(0, modelnum); + if (reachnum) + { + //botimport.Print(PRT_MESSAGE, "client %d: accidentally ended up on func_plat\n", ms->client); + AAS_ReachabilityFromNum(reachnum, &reach); + ms->lastreachnum = reachnum; + ms->reachability_time = AAS_Time() + BotReachabilityTime(&reach); + } //end if + else + { + if (bot_developer) + { + botimport.Print(PRT_MESSAGE, "client %d: on func_plat without reachability\n", ms->client); + } //end if + result->blocked = qtrue; + result->blockentity = ent; + result->flags |= MOVERESULT_ONTOPOFOBSTACLE; + return; + } //end else + } //end if + result->flags |= MOVERESULT_ONTOPOF_ELEVATOR; + } //end if + else if (modeltype == MODELTYPE_FUNC_BOB) + { + AAS_ReachabilityFromNum(ms->lastreachnum, &reach); + //if the bot is Not using the func bobbing + if ((reach.traveltype & TRAVELTYPE_MASK) != TRAVEL_FUNCBOB || + //NOTE: the face number is the func_bobbing model number + (reach.facenum & 0x0000FFFF) != modelnum) + { + reachnum = AAS_NextModelReachability(0, modelnum); + if (reachnum) + { + //botimport.Print(PRT_MESSAGE, "client %d: accidentally ended up on func_bobbing\n", ms->client); + AAS_ReachabilityFromNum(reachnum, &reach); + ms->lastreachnum = reachnum; + ms->reachability_time = AAS_Time() + BotReachabilityTime(&reach); + } //end if + else + { + if (bot_developer) + { + botimport.Print(PRT_MESSAGE, "client %d: on func_bobbing without reachability\n", ms->client); + } //end if + result->blocked = qtrue; + result->blockentity = ent; + result->flags |= MOVERESULT_ONTOPOFOBSTACLE; + return; + } //end else + } //end if + result->flags |= MOVERESULT_ONTOPOF_FUNCBOB; + } //end if + else if (modeltype == MODELTYPE_FUNC_STATIC || modeltype == MODELTYPE_FUNC_DOOR) + { + // check if ontop of a door bridge ? + ms->areanum = BotFuzzyPointReachabilityArea(ms->origin); + // if not in a reachability area + if (!AAS_AreaReachability(ms->areanum)) + { + result->blocked = qtrue; + result->blockentity = ent; + result->flags |= MOVERESULT_ONTOPOFOBSTACLE; + return; + } //end if + } //end else if + else + { + result->blocked = qtrue; + result->blockentity = ent; + result->flags |= MOVERESULT_ONTOPOFOBSTACLE; + return; + } //end else + } //end if + } //end if + } //end if + //if swimming + if (AAS_Swimming(ms->origin)) ms->moveflags |= MFL_SWIMMING; + //if against a ladder + if (AAS_AgainstLadder(ms->origin)) ms->moveflags |= MFL_AGAINSTLADDER; + //if the bot is on the ground, swimming or against a ladder + if (ms->moveflags & (MFL_ONGROUND|MFL_SWIMMING|MFL_AGAINSTLADDER)) + { + //botimport.Print(PRT_MESSAGE, "%s: onground, swimming or against ladder\n", ClientName(ms->entitynum-1)); + // + AAS_ReachabilityFromNum(ms->lastreachnum, &lastreach); + //reachability area the bot is in + //ms->areanum = BotReachabilityArea(ms->origin, ((lastreach.traveltype & TRAVELTYPE_MASK) != TRAVEL_ELEVATOR)); + ms->areanum = BotFuzzyPointReachabilityArea(ms->origin); + // + if ( !ms->areanum ) + { + result->failure = qtrue; + result->blocked = qtrue; + result->blockentity = 0; + result->type = RESULTTYPE_INSOLIDAREA; + return; + } //end if + //if the bot is in the goal area + if (ms->areanum == goal->areanum) + { + *result = BotMoveInGoalArea(ms, goal); + return; + } //end if + //assume we can use the reachability from the last frame + reachnum = ms->lastreachnum; + //if there is a last reachability + if (reachnum) + { + AAS_ReachabilityFromNum(reachnum, &reach); + //check if the reachability is still valid + if (!(AAS_TravelFlagForType(reach.traveltype) & travelflags)) + { + reachnum = 0; + } //end if + //special grapple hook case + else if ((reach.traveltype & TRAVELTYPE_MASK) == TRAVEL_GRAPPLEHOOK) + { + if (ms->reachability_time < AAS_Time() || + (ms->moveflags & MFL_GRAPPLERESET)) + { + reachnum = 0; + } //end if + } //end if + //special elevator case + else if ((reach.traveltype & TRAVELTYPE_MASK) == TRAVEL_ELEVATOR || + (reach.traveltype & TRAVELTYPE_MASK) == TRAVEL_FUNCBOB) + { + if ((result->flags & MOVERESULT_ONTOPOF_FUNCBOB) || + (result->flags & MOVERESULT_ONTOPOF_FUNCBOB)) + { + ms->reachability_time = AAS_Time() + 5; + } //end if + //if the bot was going for an elevator and reached the reachability area + if (ms->areanum == reach.areanum || + ms->reachability_time < AAS_Time()) + { + reachnum = 0; + } //end if + } //end if + else + { +#ifdef DEBUG + if (bot_developer) + { + if (ms->reachability_time < AAS_Time()) + { + botimport.Print(PRT_MESSAGE, "client %d: reachability timeout in ", ms->client); + AAS_PrintTravelType(reach.traveltype & TRAVELTYPE_MASK); + botimport.Print(PRT_MESSAGE, "\n"); + } //end if + /* + if (ms->lastareanum != ms->areanum) + { + botimport.Print(PRT_MESSAGE, "changed from area %d to %d\n", ms->lastareanum, ms->areanum); + } //end if*/ + } //end if +#endif //DEBUG + //if the goal area changed or the reachability timed out + //or the area changed + if (ms->lastgoalareanum != goal->areanum || + ms->reachability_time < AAS_Time() || + ms->lastareanum != ms->areanum) + { + reachnum = 0; + //botimport.Print(PRT_MESSAGE, "area change or timeout\n"); + } //end else if + } //end else + } //end if + resultflags = 0; + //if the bot needs a new reachability + if (!reachnum) + { + //if the area has no reachability links + if (!AAS_AreaReachability(ms->areanum)) + { +#ifdef DEBUG + if (bot_developer) + { + botimport.Print(PRT_MESSAGE, "area %d no reachability\n", ms->areanum); + } //end if +#endif //DEBUG + } //end if + //get a new reachability leading towards the goal + reachnum = BotGetReachabilityToGoal(ms->origin, ms->areanum, + ms->lastgoalareanum, ms->lastareanum, + ms->avoidreach, ms->avoidreachtimes, ms->avoidreachtries, + goal, travelflags, travelflags, + ms->avoidspots, ms->numavoidspots, &resultflags); + //the area number the reachability starts in + ms->reachareanum = ms->areanum; + //reset some state variables + ms->jumpreach = 0; //for TRAVEL_JUMP + ms->moveflags &= ~MFL_GRAPPLERESET; //for TRAVEL_GRAPPLEHOOK + //if there is a reachability to the goal + if (reachnum) + { + AAS_ReachabilityFromNum(reachnum, &reach); + //set a timeout for this reachability + ms->reachability_time = AAS_Time() + BotReachabilityTime(&reach); + // +#ifdef AVOIDREACH + //add the reachability to the reachabilities to avoid for a while + BotAddToAvoidReach(ms, reachnum, AVOIDREACH_TIME); +#endif //AVOIDREACH + } //end if +#ifdef DEBUG + + else if (bot_developer) + { + botimport.Print(PRT_MESSAGE, "goal not reachable\n"); + Com_Memset(&reach, 0, sizeof(aas_reachability_t)); //make compiler happy + } //end else + if (bot_developer) + { + //if still going for the same goal + if (ms->lastgoalareanum == goal->areanum) + { + if (ms->lastareanum == reach.areanum) + { + botimport.Print(PRT_MESSAGE, "same goal, going back to previous area\n"); + } //end if + } //end if + } //end if +#endif //DEBUG + } //end else + // + ms->lastreachnum = reachnum; + ms->lastgoalareanum = goal->areanum; + ms->lastareanum = ms->areanum; + //if the bot has a reachability + if (reachnum) + { + //get the reachability from the number + AAS_ReachabilityFromNum(reachnum, &reach); + result->traveltype = reach.traveltype; + // +#ifdef DEBUG_AI_MOVE + AAS_ClearShownDebugLines(); + AAS_PrintTravelType(reach.traveltype & TRAVELTYPE_MASK); + AAS_ShowReachability(&reach); +#endif //DEBUG_AI_MOVE + // +#ifdef DEBUG + //botimport.Print(PRT_MESSAGE, "client %d: ", ms->client); + //AAS_PrintTravelType(reach.traveltype); + //botimport.Print(PRT_MESSAGE, "\n"); +#endif //DEBUG + switch(reach.traveltype & TRAVELTYPE_MASK) + { + case TRAVEL_WALK: *result = BotTravel_Walk(ms, &reach); break; + case TRAVEL_CROUCH: *result = BotTravel_Crouch(ms, &reach); break; + case TRAVEL_BARRIERJUMP: *result = BotTravel_BarrierJump(ms, &reach); break; + case TRAVEL_LADDER: *result = BotTravel_Ladder(ms, &reach); break; + case TRAVEL_WALKOFFLEDGE: *result = BotTravel_WalkOffLedge(ms, &reach); break; + case TRAVEL_JUMP: *result = BotTravel_Jump(ms, &reach); break; + case TRAVEL_SWIM: *result = BotTravel_Swim(ms, &reach); break; + case TRAVEL_WATERJUMP: *result = BotTravel_WaterJump(ms, &reach); break; + case TRAVEL_TELEPORT: *result = BotTravel_Teleport(ms, &reach); break; + case TRAVEL_ELEVATOR: *result = BotTravel_Elevator(ms, &reach); break; + case TRAVEL_GRAPPLEHOOK: *result = BotTravel_Grapple(ms, &reach); break; + case TRAVEL_ROCKETJUMP: *result = BotTravel_RocketJump(ms, &reach); break; + case TRAVEL_BFGJUMP: *result = BotTravel_BFGJump(ms, &reach); break; + case TRAVEL_JUMPPAD: *result = BotTravel_JumpPad(ms, &reach); break; + case TRAVEL_FUNCBOB: *result = BotTravel_FuncBobbing(ms, &reach); break; + default: + { + botimport.Print(PRT_FATAL, "travel type %d not implemented yet\n", (reach.traveltype & TRAVELTYPE_MASK)); + break; + } //end case + } //end switch + result->traveltype = reach.traveltype; + result->flags |= resultflags; + } //end if + else + { + result->failure = qtrue; + result->flags |= resultflags; + Com_Memset(&reach, 0, sizeof(aas_reachability_t)); + } //end else +#ifdef DEBUG + if (bot_developer) + { + if (result->failure) + { + botimport.Print(PRT_MESSAGE, "client %d: movement failure in ", ms->client); + AAS_PrintTravelType(reach.traveltype & TRAVELTYPE_MASK); + botimport.Print(PRT_MESSAGE, "\n"); + } //end if + } //end if +#endif //DEBUG + } //end if + else + { + int i, numareas, areas[16]; + vec3_t end; + + //special handling of jump pads when the bot uses a jump pad without knowing it + foundjumppad = qfalse; + VectorMA(ms->origin, -2 * ms->thinktime, ms->velocity, end); + numareas = AAS_TraceAreas(ms->origin, end, areas, NULL, 16); + for (i = numareas-1; i >= 0; i--) + { + if (AAS_AreaJumpPad(areas[i])) + { + //botimport.Print(PRT_MESSAGE, "client %d used a jumppad without knowing, area %d\n", ms->client, areas[i]); + foundjumppad = qtrue; + lastreachnum = BotGetReachabilityToGoal(end, areas[i], + ms->lastgoalareanum, ms->lastareanum, + ms->avoidreach, ms->avoidreachtimes, ms->avoidreachtries, + goal, travelflags, TFL_JUMPPAD, ms->avoidspots, ms->numavoidspots, NULL); + if (lastreachnum) + { + ms->lastreachnum = lastreachnum; + ms->lastareanum = areas[i]; + //botimport.Print(PRT_MESSAGE, "found jumppad reachability\n"); + break; + } //end if + else + { + for (lastreachnum = AAS_NextAreaReachability(areas[i], 0); lastreachnum; + lastreachnum = AAS_NextAreaReachability(areas[i], lastreachnum)) + { + //get the reachability from the number + AAS_ReachabilityFromNum(lastreachnum, &reach); + if ((reach.traveltype & TRAVELTYPE_MASK) == TRAVEL_JUMPPAD) + { + ms->lastreachnum = lastreachnum; + ms->lastareanum = areas[i]; + //botimport.Print(PRT_MESSAGE, "found jumppad reachability hard!!\n"); + break; + } //end if + } //end for + if (lastreachnum) break; + } //end else + } //end if + } //end for + if (bot_developer) + { + //if a jumppad is found with the trace but no reachability is found + if (foundjumppad && !ms->lastreachnum) + { + botimport.Print(PRT_MESSAGE, "client %d didn't find jumppad reachability\n", ms->client); + } //end if + } //end if + // + if (ms->lastreachnum) + { + //botimport.Print(PRT_MESSAGE, "%s: NOT onground, swimming or against ladder\n", ClientName(ms->entitynum-1)); + AAS_ReachabilityFromNum(ms->lastreachnum, &reach); + result->traveltype = reach.traveltype; +#ifdef DEBUG + //botimport.Print(PRT_MESSAGE, "client %d finish: ", ms->client); + //AAS_PrintTravelType(reach.traveltype & TRAVELTYPE_MASK); + //botimport.Print(PRT_MESSAGE, "\n"); +#endif //DEBUG + // + switch(reach.traveltype & TRAVELTYPE_MASK) + { + case TRAVEL_WALK: *result = BotTravel_Walk(ms, &reach); break;//BotFinishTravel_Walk(ms, &reach); break; + case TRAVEL_CROUCH: /*do nothing*/ break; + case TRAVEL_BARRIERJUMP: *result = BotFinishTravel_BarrierJump(ms, &reach); break; + case TRAVEL_LADDER: *result = BotTravel_Ladder(ms, &reach); break; + case TRAVEL_WALKOFFLEDGE: *result = BotFinishTravel_WalkOffLedge(ms, &reach); break; + case TRAVEL_JUMP: *result = BotFinishTravel_Jump(ms, &reach); break; + case TRAVEL_SWIM: *result = BotTravel_Swim(ms, &reach); break; + case TRAVEL_WATERJUMP: *result = BotFinishTravel_WaterJump(ms, &reach); break; + case TRAVEL_TELEPORT: /*do nothing*/ break; + case TRAVEL_ELEVATOR: *result = BotFinishTravel_Elevator(ms, &reach); break; + case TRAVEL_GRAPPLEHOOK: *result = BotTravel_Grapple(ms, &reach); break; + case TRAVEL_ROCKETJUMP: + case TRAVEL_BFGJUMP: *result = BotFinishTravel_WeaponJump(ms, &reach); break; + case TRAVEL_JUMPPAD: *result = BotFinishTravel_JumpPad(ms, &reach); break; + case TRAVEL_FUNCBOB: *result = BotFinishTravel_FuncBobbing(ms, &reach); break; + default: + { + botimport.Print(PRT_FATAL, "(last) travel type %d not implemented yet\n", (reach.traveltype & TRAVELTYPE_MASK)); + break; + } //end case + } //end switch + result->traveltype = reach.traveltype; +#ifdef DEBUG + if (bot_developer) + { + if (result->failure) + { + botimport.Print(PRT_MESSAGE, "client %d: movement failure in finish ", ms->client); + AAS_PrintTravelType(reach.traveltype & TRAVELTYPE_MASK); + botimport.Print(PRT_MESSAGE, "\n"); + } //end if + } //end if +#endif //DEBUG + } //end if + } //end else + //FIXME: is it right to do this here? + if (result->blocked) ms->reachability_time -= 10 * ms->thinktime; + //copy the last origin + VectorCopy(ms->origin, ms->lastorigin); + //return the movement result + return; +} //end of the function BotMoveToGoal +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void BotResetAvoidReach(int movestate) +{ + bot_movestate_t *ms; + + ms = BotMoveStateFromHandle(movestate); + if (!ms) return; + Com_Memset(ms->avoidreach, 0, MAX_AVOIDREACH * sizeof(int)); + Com_Memset(ms->avoidreachtimes, 0, MAX_AVOIDREACH * sizeof(float)); + Com_Memset(ms->avoidreachtries, 0, MAX_AVOIDREACH * sizeof(int)); +} //end of the function BotResetAvoidReach +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void BotResetLastAvoidReach(int movestate) +{ + int i, latest; + float latesttime; + bot_movestate_t *ms; + + ms = BotMoveStateFromHandle(movestate); + if (!ms) return; + latesttime = 0; + latest = 0; + for (i = 0; i < MAX_AVOIDREACH; i++) + { + if (ms->avoidreachtimes[i] > latesttime) + { + latesttime = ms->avoidreachtimes[i]; + latest = i; + } //end if + } //end for + if (latesttime) + { + ms->avoidreachtimes[latest] = 0; + if (ms->avoidreachtries[i] > 0) ms->avoidreachtries[latest]--; + } //end if +} //end of the function BotResetLastAvoidReach +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void BotResetMoveState(int movestate) +{ + bot_movestate_t *ms; + + ms = BotMoveStateFromHandle(movestate); + if (!ms) return; + Com_Memset(ms, 0, sizeof(bot_movestate_t)); +} //end of the function BotResetMoveState +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int BotSetupMoveAI(void) +{ + BotSetBrushModelTypes(); + sv_maxstep = LibVar("sv_step", "18"); + sv_maxbarrier = LibVar("sv_maxbarrier", "32"); + sv_gravity = LibVar("sv_gravity", "800"); + weapindex_rocketlauncher = LibVar("weapindex_rocketlauncher", "5"); + weapindex_bfg10k = LibVar("weapindex_bfg10k", "9"); + weapindex_grapple = LibVar("weapindex_grapple", "10"); + entitytypemissile = LibVar("entitytypemissile", "3"); + offhandgrapple = LibVar("offhandgrapple", "0"); + cmd_grappleon = LibVar("cmd_grappleon", "grappleon"); + cmd_grappleoff = LibVar("cmd_grappleoff", "grappleoff"); + return BLERR_NOERROR; +} //end of the function BotSetupMoveAI +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void BotShutdownMoveAI(void) +{ + int i; + + for (i = 1; i <= MAX_CLIENTS; i++) + { + if (botmovestates[i]) + { + FreeMemory(botmovestates[i]); + botmovestates[i] = NULL; + } //end if + } //end for +} //end of the function BotShutdownMoveAI + + |