2
===========================================================================
3
Copyright (C) 1999-2005 Id Software, Inc.
5
This file is part of Quake III Arena source code.
7
Quake III Arena source code is free software; you can redistribute it
8
and/or modify it under the terms of the GNU General Public License as
9
published by the Free Software Foundation; either version 2 of the License,
10
or (at your option) any later version.
12
Quake III Arena source code is distributed in the hope that it will be
13
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
14
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
GNU General Public License for more details.
17
You should have received a copy of the GNU General Public License
18
along with Quake III Arena source code; if not, write to the Free Software
19
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20
===========================================================================
23
/*****************************************************************************
26
* desc: bot movement AI
28
* $Archive: /MissionPack/code/botlib/be_ai_move.c $
30
*****************************************************************************/
32
#include "../qcommon/q_shared.h"
37
#include "l_precomp.h"
42
#include "be_aas_funcs.h"
43
#include "be_interface.h"
46
#include "be_ai_goal.h"
47
#include "be_ai_move.h"
50
//#define DEBUG_AI_MOVE
51
//#define DEBUG_ELEVATOR
52
//#define DEBUG_GRAPPLE
54
// bk001204 - redundant bot_avoidspot_t, see be_ai_move.h
57
//NOTE: the moveflags MFL_ONGROUND, MFL_TELEPORTED, MFL_WATERJUMP and
58
// MFL_GRAPPLEPULL must be set outside the movement code
59
typedef struct bot_movestate_s
61
//input vars (all set outside the movement code)
62
vec3_t origin; //origin of the bot
63
vec3_t velocity; //velocity of the bot
64
vec3_t viewoffset; //view offset
65
int entitynum; //entity number of the bot
66
int client; //client number of the bot
67
float thinktime; //time the bot thinks
68
int presencetype; //presencetype of the bot
69
vec3_t viewangles; //view angles of the bot
71
int areanum; //area the bot is in
72
int lastareanum; //last area the bot was in
73
int lastgoalareanum; //last goal area number
74
int lastreachnum; //last reachability number
75
vec3_t lastorigin; //origin previous cycle
76
int reachareanum; //area number of the reachabilty
77
int moveflags; //movement flags
78
int jumpreach; //set when jumped
79
float grapplevisible_time; //last time the grapple was visible
80
float lastgrappledist; //last distance to the grapple end
81
float reachability_time; //time to use current reachability
82
int avoidreach[MAX_AVOIDREACH]; //reachabilities to avoid
83
float avoidreachtimes[MAX_AVOIDREACH]; //times to avoid the reachabilities
84
int avoidreachtries[MAX_AVOIDREACH]; //number of tries before avoiding
86
bot_avoidspot_t avoidspots[MAX_AVOIDSPOTS]; //spots to avoid
90
//used to avoid reachability links for some time after being used
92
#define AVOIDREACH_TIME 6 //avoid links for 6 seconds after use
93
#define AVOIDREACH_TRIES 4
95
#define PREDICTIONTIME_JUMP 3 //in seconds
96
#define PREDICTIONTIME_MOVE 2 //in seconds
97
//weapon indexes for weapon jumping
98
#define WEAPONINDEX_ROCKET_LAUNCHER 5
99
#define WEAPONINDEX_BFG 9
101
#define MODELTYPE_FUNC_PLAT 1
102
#define MODELTYPE_FUNC_BOB 2
103
#define MODELTYPE_FUNC_DOOR 3
104
#define MODELTYPE_FUNC_STATIC 4
106
libvar_t *sv_maxstep;
107
libvar_t *sv_maxbarrier;
108
libvar_t *sv_gravity;
109
libvar_t *weapindex_rocketlauncher;
110
libvar_t *weapindex_bfg10k;
111
libvar_t *weapindex_grapple;
112
libvar_t *entitytypemissile;
113
libvar_t *offhandgrapple;
114
libvar_t *cmd_grappleoff;
115
libvar_t *cmd_grappleon;
116
//type of model, func_plat or func_bobbing
117
int modeltypes[MAX_MODELS];
119
bot_movestate_t *botmovestates[MAX_CLIENTS+1];
121
//========================================================================
125
// Changes Globals: -
126
//========================================================================
127
int BotAllocMoveState(void)
131
for (i = 1; i <= MAX_CLIENTS; i++)
133
if (!botmovestates[i])
135
botmovestates[i] = GetClearedMemory(sizeof(bot_movestate_t));
140
} //end of the function BotAllocMoveState
141
//========================================================================
145
// Changes Globals: -
146
//========================================================================
147
void BotFreeMoveState(int handle)
149
if (handle <= 0 || handle > MAX_CLIENTS)
151
botimport.Print(PRT_FATAL, "move state handle %d out of range\n", handle);
154
if (!botmovestates[handle])
156
botimport.Print(PRT_FATAL, "invalid move state %d\n", handle);
159
FreeMemory(botmovestates[handle]);
160
botmovestates[handle] = NULL;
161
} //end of the function BotFreeMoveState
162
//========================================================================
166
// Changes Globals: -
167
//========================================================================
168
bot_movestate_t *BotMoveStateFromHandle(int handle)
170
if (handle <= 0 || handle > MAX_CLIENTS)
172
botimport.Print(PRT_FATAL, "move state handle %d out of range\n", handle);
175
if (!botmovestates[handle])
177
botimport.Print(PRT_FATAL, "invalid move state %d\n", handle);
180
return botmovestates[handle];
181
} //end of the function BotMoveStateFromHandle
182
//========================================================================
186
// Changes Globals: -
187
//========================================================================
188
void BotInitMoveState(int handle, bot_initmove_t *initmove)
192
ms = BotMoveStateFromHandle(handle);
194
VectorCopy(initmove->origin, ms->origin);
195
VectorCopy(initmove->velocity, ms->velocity);
196
VectorCopy(initmove->viewoffset, ms->viewoffset);
197
ms->entitynum = initmove->entitynum;
198
ms->client = initmove->client;
199
ms->thinktime = initmove->thinktime;
200
ms->presencetype = initmove->presencetype;
201
VectorCopy(initmove->viewangles, ms->viewangles);
203
ms->moveflags &= ~MFL_ONGROUND;
204
if (initmove->or_moveflags & MFL_ONGROUND) ms->moveflags |= MFL_ONGROUND;
205
ms->moveflags &= ~MFL_TELEPORTED;
206
if (initmove->or_moveflags & MFL_TELEPORTED) ms->moveflags |= MFL_TELEPORTED;
207
ms->moveflags &= ~MFL_WATERJUMP;
208
if (initmove->or_moveflags & MFL_WATERJUMP) ms->moveflags |= MFL_WATERJUMP;
209
ms->moveflags &= ~MFL_WALK;
210
if (initmove->or_moveflags & MFL_WALK) ms->moveflags |= MFL_WALK;
211
ms->moveflags &= ~MFL_GRAPPLEPULL;
212
if (initmove->or_moveflags & MFL_GRAPPLEPULL) ms->moveflags |= MFL_GRAPPLEPULL;
213
} //end of the function BotInitMoveState
214
//========================================================================
218
// Changes Globals: -
219
//========================================================================
220
float AngleDiff(float ang1, float ang2)
227
if (diff > 180.0) diff -= 360.0;
231
if (diff < -180.0) diff += 360.0;
234
} //end of the function AngleDiff
235
//===========================================================================
239
// Changes Globals: -
240
//===========================================================================
241
int BotFuzzyPointReachabilityArea(vec3_t origin)
243
int firstareanum, j, x, y, z;
244
int areas[10], numareas, areanum, bestareanum;
245
float dist, bestdist;
246
vec3_t points[10], v, end;
249
areanum = AAS_PointAreaNum(origin);
252
firstareanum = areanum;
253
if (AAS_AreaReachability(areanum)) return areanum;
255
VectorCopy(origin, end);
257
numareas = AAS_TraceAreas(origin, end, areas, points, 10);
258
for (j = 0; j < numareas; j++)
260
if (AAS_AreaReachability(areas[j])) return areas[j];
264
for (z = 1; z >= -1; z -= 1)
266
for (x = 1; x >= -1; x -= 1)
268
for (y = 1; y >= -1; y -= 1)
270
VectorCopy(origin, end);
274
numareas = AAS_TraceAreas(origin, end, areas, points, 10);
275
for (j = 0; j < numareas; j++)
277
if (AAS_AreaReachability(areas[j]))
279
VectorSubtract(points[j], origin, v);
280
dist = VectorLength(v);
283
bestareanum = areas[j];
287
if (!firstareanum) firstareanum = areas[j];
291
if (bestareanum) return bestareanum;
294
} //end of the function BotFuzzyPointReachabilityArea
295
//===========================================================================
299
// Changes Globals: -
300
//===========================================================================
301
int BotReachabilityArea(vec3_t origin, int client)
303
int modelnum, modeltype, reachnum, areanum;
304
aas_reachability_t reach;
305
vec3_t org, end, mins, maxs, up = {0, 0, 1};
306
bsp_trace_t bsptrace;
309
//check if the bot is standing on something
310
AAS_PresenceTypeBoundingBox(PRESENCE_CROUCH, mins, maxs);
311
VectorMA(origin, -3, up, end);
312
bsptrace = AAS_Trace(origin, mins, maxs, end, client, CONTENTS_SOLID|CONTENTS_PLAYERCLIP);
313
if (!bsptrace.startsolid && bsptrace.fraction < 1 && bsptrace.ent != ENTITYNUM_NONE)
315
//if standing on the world the bot should be in a valid area
316
if (bsptrace.ent == ENTITYNUM_WORLD)
318
return BotFuzzyPointReachabilityArea(origin);
321
modelnum = AAS_EntityModelindex(bsptrace.ent);
322
modeltype = modeltypes[modelnum];
324
//if standing on a func_plat or func_bobbing then the bot is assumed to be
325
//in the area the reachability points to
326
if (modeltype == MODELTYPE_FUNC_PLAT || modeltype == MODELTYPE_FUNC_BOB)
328
reachnum = AAS_NextModelReachability(0, modelnum);
331
AAS_ReachabilityFromNum(reachnum, &reach);
332
return reach.areanum;
336
//if the bot is swimming the bot should be in a valid area
337
if (AAS_Swimming(origin))
339
return BotFuzzyPointReachabilityArea(origin);
342
areanum = BotFuzzyPointReachabilityArea(origin);
343
//if the bot is in an area with reachabilities
344
if (areanum && AAS_AreaReachability(areanum)) return areanum;
345
//trace down till the ground is hit because the bot is standing on some other entity
346
VectorCopy(origin, org);
347
VectorCopy(org, end);
349
trace = AAS_TraceClientBBox(org, end, PRESENCE_CROUCH, -1);
350
if (!trace.startsolid)
352
VectorCopy(trace.endpos, org);
355
return BotFuzzyPointReachabilityArea(org);
358
return BotFuzzyPointReachabilityArea(origin);
359
} //end of the function BotReachabilityArea
360
//===========================================================================
361
// returns the reachability area the bot is in
365
// Changes Globals: -
366
//===========================================================================
368
int BotReachabilityArea(vec3_t origin, int testground)
370
int firstareanum, i, j, x, y, z;
371
int areas[10], numareas, areanum, bestareanum;
372
float dist, bestdist;
373
vec3_t org, end, points[10], v;
377
for (i = 0; i < 2; i++)
379
VectorCopy(origin, org);
380
//if test at the ground (used when bot is standing on an entity)
383
VectorCopy(origin, end);
385
trace = AAS_TraceClientBBox(origin, end, PRESENCE_CROUCH, -1);
386
if (!trace.startsolid)
388
VectorCopy(trace.endpos, org);
393
areanum = AAS_PointAreaNum(org);
396
firstareanum = areanum;
397
if (AAS_AreaReachability(areanum)) return areanum;
401
for (z = 1; z >= -1; z -= 1)
403
for (x = 1; x >= -1; x -= 1)
405
for (y = 1; y >= -1; y -= 1)
407
VectorCopy(org, end);
411
numareas = AAS_TraceAreas(org, end, areas, points, 10);
412
for (j = 0; j < numareas; j++)
414
if (AAS_AreaReachability(areas[j]))
416
VectorSubtract(points[j], org, v);
417
dist = VectorLength(v);
420
bestareanum = areas[j];
427
if (bestareanum) return bestareanum;
429
if (!testground) break;
432
//botimport.Print(PRT_MESSAGE, "no reachability area\n");
435
} //end of the function BotReachabilityArea*/
436
//===========================================================================
440
// Changes Globals: -
441
//===========================================================================
442
int BotOnMover(vec3_t origin, int entnum, aas_reachability_t *reach)
445
vec3_t mins, maxs, modelorigin, org, end;
446
vec3_t angles = {0, 0, 0};
447
vec3_t boxmins = {-16, -16, -8}, boxmaxs = {16, 16, 8};
450
modelnum = reach->facenum & 0x0000FFFF;
451
//get some bsp model info
452
AAS_BSPModelMinsMaxsOrigin(modelnum, angles, mins, maxs, NULL);
454
if (!AAS_OriginOfMoverWithModelNum(modelnum, modelorigin))
456
botimport.Print(PRT_MESSAGE, "no entity with model %d\n", modelnum);
460
for (i = 0; i < 2; i++)
462
if (origin[i] > modelorigin[i] + maxs[i] + 16) return qfalse;
463
if (origin[i] < modelorigin[i] + mins[i] - 16) return qfalse;
466
VectorCopy(origin, org);
468
VectorCopy(origin, end);
471
trace = AAS_Trace(org, boxmins, boxmaxs, end, entnum, CONTENTS_SOLID|CONTENTS_PLAYERCLIP);
472
if (!trace.startsolid && !trace.allsolid)
474
//NOTE: the reachability face number is the model number of the elevator
475
if (trace.ent != ENTITYNUM_NONE && AAS_EntityModelNum(trace.ent) == modelnum)
481
} //end of the function BotOnMover
482
//===========================================================================
486
// Changes Globals: -
487
//===========================================================================
488
int MoverDown(aas_reachability_t *reach)
491
vec3_t mins, maxs, origin;
492
vec3_t angles = {0, 0, 0};
494
modelnum = reach->facenum & 0x0000FFFF;
495
//get some bsp model info
496
AAS_BSPModelMinsMaxsOrigin(modelnum, angles, mins, maxs, origin);
498
if (!AAS_OriginOfMoverWithModelNum(modelnum, origin))
500
botimport.Print(PRT_MESSAGE, "no entity with model %d\n", modelnum);
503
//if the top of the plat is below the reachability start point
504
if (origin[2] + maxs[2] < reach->start[2]) return qtrue;
506
} //end of the function MoverDown
507
//========================================================================
511
// Changes Globals: -
512
//========================================================================
513
void BotSetBrushModelTypes(void)
516
char classname[MAX_EPAIRKEY], model[MAX_EPAIRKEY];
518
Com_Memset(modeltypes, 0, MAX_MODELS * sizeof(int));
520
for (ent = AAS_NextBSPEntity(0); ent; ent = AAS_NextBSPEntity(ent))
522
if (!AAS_ValueForBSPEpairKey(ent, "classname", classname, MAX_EPAIRKEY)) continue;
523
if (!AAS_ValueForBSPEpairKey(ent, "model", model, MAX_EPAIRKEY)) continue;
524
if (model[0]) modelnum = atoi(model+1);
527
if (modelnum < 0 || modelnum > MAX_MODELS)
529
botimport.Print(PRT_MESSAGE, "entity %s model number out of range\n", classname);
533
if (!Q_stricmp(classname, "func_bobbing"))
534
modeltypes[modelnum] = MODELTYPE_FUNC_BOB;
535
else if (!Q_stricmp(classname, "func_plat"))
536
modeltypes[modelnum] = MODELTYPE_FUNC_PLAT;
537
else if (!Q_stricmp(classname, "func_door"))
538
modeltypes[modelnum] = MODELTYPE_FUNC_DOOR;
539
else if (!Q_stricmp(classname, "func_static"))
540
modeltypes[modelnum] = MODELTYPE_FUNC_STATIC;
542
} //end of the function BotSetBrushModelTypes
543
//===========================================================================
547
// Changes Globals: -
548
//===========================================================================
549
int BotOnTopOfEntity(bot_movestate_t *ms)
551
vec3_t mins, maxs, end, up = {0, 0, 1};
554
AAS_PresenceTypeBoundingBox(ms->presencetype, mins, maxs);
555
VectorMA(ms->origin, -3, up, end);
556
trace = AAS_Trace(ms->origin, mins, maxs, end, ms->entitynum, CONTENTS_SOLID|CONTENTS_PLAYERCLIP);
557
if (!trace.startsolid && (trace.ent != ENTITYNUM_WORLD && trace.ent != ENTITYNUM_NONE) )
562
} //end of the function BotOnTopOfEntity
563
//===========================================================================
567
// Changes Globals: -
568
//===========================================================================
569
int BotValidTravel(vec3_t origin, aas_reachability_t *reach, int travelflags)
571
//if the reachability uses an unwanted travel type
572
if (AAS_TravelFlagForType(reach->traveltype) & ~travelflags) return qfalse;
573
//don't go into areas with bad travel types
574
if (AAS_AreaContentsTravelFlags(reach->areanum) & ~travelflags) return qfalse;
576
} //end of the function BotValidTravel
577
//===========================================================================
581
// Changes Globals: -
582
//===========================================================================
583
void BotAddToAvoidReach(bot_movestate_t *ms, int number, float avoidtime)
587
for (i = 0; i < MAX_AVOIDREACH; i++)
589
if (ms->avoidreach[i] == number)
591
if (ms->avoidreachtimes[i] > AAS_Time()) ms->avoidreachtries[i]++;
592
else ms->avoidreachtries[i] = 1;
593
ms->avoidreachtimes[i] = AAS_Time() + avoidtime;
597
//add the reachability to the reachabilities to avoid for a while
598
for (i = 0; i < MAX_AVOIDREACH; i++)
600
if (ms->avoidreachtimes[i] < AAS_Time())
602
ms->avoidreach[i] = number;
603
ms->avoidreachtimes[i] = AAS_Time() + avoidtime;
604
ms->avoidreachtries[i] = 1;
608
} //end of the function BotAddToAvoidReach
609
//===========================================================================
613
// Changes Globals: -
614
//===========================================================================
615
float DistanceFromLineSquared(vec3_t p, vec3_t lp1, vec3_t lp2)
620
AAS_ProjectPointOntoVector(p, lp1, lp2, proj);
621
for (j = 0; j < 3; j++)
622
if ((proj[j] > lp1[j] && proj[j] > lp2[j]) ||
623
(proj[j] < lp1[j] && proj[j] < lp2[j]))
626
if (fabs(proj[j] - lp1[j]) < fabs(proj[j] - lp2[j]))
627
VectorSubtract(p, lp1, dir);
629
VectorSubtract(p, lp2, dir);
630
return VectorLengthSquared(dir);
632
VectorSubtract(p, proj, dir);
633
return VectorLengthSquared(dir);
634
} //end of the function DistanceFromLineSquared
635
//===========================================================================
639
// Changes Globals: -
640
//===========================================================================
641
float VectorDistanceSquared(vec3_t p1, vec3_t p2)
644
VectorSubtract(p2, p1, dir);
645
return VectorLengthSquared(dir);
646
} //end of the function VectorDistanceSquared
647
//===========================================================================
651
// Changes Globals: -
652
//===========================================================================
653
int BotAvoidSpots(vec3_t origin, aas_reachability_t *reach, bot_avoidspot_t *avoidspots, int numavoidspots)
655
int checkbetween, i, type;
656
float squareddist, squaredradius;
658
switch(reach->traveltype & TRAVELTYPE_MASK)
660
case TRAVEL_WALK: checkbetween = qtrue; break;
661
case TRAVEL_CROUCH: checkbetween = qtrue; break;
662
case TRAVEL_BARRIERJUMP: checkbetween = qtrue; break;
663
case TRAVEL_LADDER: checkbetween = qtrue; break;
664
case TRAVEL_WALKOFFLEDGE: checkbetween = qfalse; break;
665
case TRAVEL_JUMP: checkbetween = qfalse; break;
666
case TRAVEL_SWIM: checkbetween = qtrue; break;
667
case TRAVEL_WATERJUMP: checkbetween = qtrue; break;
668
case TRAVEL_TELEPORT: checkbetween = qfalse; break;
669
case TRAVEL_ELEVATOR: checkbetween = qfalse; break;
670
case TRAVEL_GRAPPLEHOOK: checkbetween = qfalse; break;
671
case TRAVEL_ROCKETJUMP: checkbetween = qfalse; break;
672
case TRAVEL_BFGJUMP: checkbetween = qfalse; break;
673
case TRAVEL_JUMPPAD: checkbetween = qfalse; break;
674
case TRAVEL_FUNCBOB: checkbetween = qfalse; break;
675
default: checkbetween = qtrue; break;
679
for (i = 0; i < numavoidspots; i++)
681
squaredradius = Square(avoidspots[i].radius);
682
squareddist = DistanceFromLineSquared(avoidspots[i].origin, origin, reach->start);
683
// if moving towards the avoid spot
684
if (squareddist < squaredradius &&
685
VectorDistanceSquared(avoidspots[i].origin, origin) > squareddist)
687
type = avoidspots[i].type;
689
else if (checkbetween) {
690
squareddist = DistanceFromLineSquared(avoidspots[i].origin, reach->start, reach->end);
691
// if moving towards the avoid spot
692
if (squareddist < squaredradius &&
693
VectorDistanceSquared(avoidspots[i].origin, reach->start) > squareddist)
695
type = avoidspots[i].type;
700
VectorDistanceSquared(avoidspots[i].origin, reach->end);
701
// if the reachability leads closer to the avoid spot
702
if (squareddist < squaredradius &&
703
VectorDistanceSquared(avoidspots[i].origin, reach->start) > squareddist)
705
type = avoidspots[i].type;
708
if (type == AVOID_ALWAYS)
712
} //end of the function BotAvoidSpots
713
//===========================================================================
717
// Changes Globals: -
718
//===========================================================================
719
void BotAddAvoidSpot(int movestate, vec3_t origin, float radius, int type)
723
ms = BotMoveStateFromHandle(movestate);
725
if (type == AVOID_CLEAR)
727
ms->numavoidspots = 0;
731
if (ms->numavoidspots >= MAX_AVOIDSPOTS)
733
VectorCopy(origin, ms->avoidspots[ms->numavoidspots].origin);
734
ms->avoidspots[ms->numavoidspots].radius = radius;
735
ms->avoidspots[ms->numavoidspots].type = type;
737
} //end of the function BotAddAvoidSpot
738
//===========================================================================
742
// Changes Globals: -
743
//===========================================================================
744
int BotGetReachabilityToGoal(vec3_t origin, int areanum,
745
int lastgoalareanum, int lastareanum,
746
int *avoidreach, float *avoidreachtimes, int *avoidreachtries,
747
bot_goal_t *goal, int travelflags, int movetravelflags,
748
struct bot_avoidspot_s *avoidspots, int numavoidspots, int *flags)
750
int i, t, besttime, bestreachnum, reachnum;
751
aas_reachability_t reach;
753
//if not in a valid area
754
if (!areanum) return 0;
756
if (AAS_AreaDoNotEnter(areanum) || AAS_AreaDoNotEnter(goal->areanum))
758
travelflags |= TFL_DONOTENTER;
759
movetravelflags |= TFL_DONOTENTER;
761
//use the routing to find the next area to go to
765
for (reachnum = AAS_NextAreaReachability(areanum, 0); reachnum;
766
reachnum = AAS_NextAreaReachability(areanum, reachnum))
769
//check if it isn't an reachability to avoid
770
for (i = 0; i < MAX_AVOIDREACH; i++)
772
if (avoidreach[i] == reachnum && avoidreachtimes[i] >= AAS_Time()) break;
774
if (i != MAX_AVOIDREACH && avoidreachtries[i] > AVOIDREACH_TRIES)
779
botimport.Print(PRT_MESSAGE, "avoiding reachability %d\n", avoidreach[i]);
785
//get the reachability from the number
786
AAS_ReachabilityFromNum(reachnum, &reach);
787
//NOTE: do not go back to the previous area if the goal didn't change
788
//NOTE: is this actually avoidance of local routing minima between two areas???
789
if (lastgoalareanum == goal->areanum && reach.areanum == lastareanum) continue;
790
//if (AAS_AreaContentsTravelFlags(reach.areanum) & ~travelflags) continue;
791
//if the travel isn't valid
792
if (!BotValidTravel(origin, &reach, movetravelflags)) continue;
793
//get the travel time
794
t = AAS_AreaTravelTimeToGoalArea(reach.areanum, reach.end, goal->areanum, travelflags);
795
//if the goal area isn't reachable from the reachable area
797
//if the bot should not use this reachability to avoid bad spots
798
if (BotAvoidSpots(origin, &reach, avoidspots, numavoidspots)) {
800
*flags |= MOVERESULT_BLOCKEDBYAVOIDSPOT;
804
//add the travel time towards the area
805
t += reach.traveltime;// + AAS_AreaTravelTime(areanum, origin, reach.start);
806
//if the travel time is better than the ones already found
807
if (!besttime || t < besttime)
810
bestreachnum = reachnum;
815
} //end of the function BotGetReachabilityToGoal
816
//===========================================================================
820
// Changes Globals: -
821
//===========================================================================
822
int BotAddToTarget(vec3_t start, vec3_t end, float maxdist, float *dist, vec3_t target)
827
VectorSubtract(end, start, dir);
828
curdist = VectorNormalize(dir);
829
if (*dist + curdist < maxdist)
831
VectorCopy(end, target);
837
VectorMA(start, maxdist - *dist, dir, target);
841
} //end of the function BotAddToTarget
843
int BotMovementViewTarget(int movestate, bot_goal_t *goal, int travelflags, float lookahead, vec3_t target)
845
aas_reachability_t reach;
846
int reachnum, lastareanum;
851
ms = BotMoveStateFromHandle(movestate);
852
if (!ms) return qfalse;
854
//if the bot has no goal or no last reachability
855
if (!ms->lastreachnum || !goal) return qfalse;
857
reachnum = ms->lastreachnum;
858
VectorCopy(ms->origin, end);
859
lastareanum = ms->lastareanum;
861
while(reachnum && dist < lookahead)
863
AAS_ReachabilityFromNum(reachnum, &reach);
864
if (BotAddToTarget(end, reach.start, lookahead, &dist, target)) return qtrue;
865
//never look beyond teleporters
866
if ((reach.traveltype & TRAVELTYPE_MASK) == TRAVEL_TELEPORT) return qtrue;
867
//never look beyond the weapon jump point
868
if ((reach.traveltype & TRAVELTYPE_MASK) == TRAVEL_ROCKETJUMP) return qtrue;
869
if ((reach.traveltype & TRAVELTYPE_MASK) == TRAVEL_BFGJUMP) return qtrue;
870
//don't add jump pad distances
871
if ((reach.traveltype & TRAVELTYPE_MASK) != TRAVEL_JUMPPAD &&
872
(reach.traveltype & TRAVELTYPE_MASK) != TRAVEL_ELEVATOR &&
873
(reach.traveltype & TRAVELTYPE_MASK) != TRAVEL_FUNCBOB)
875
if (BotAddToTarget(reach.start, reach.end, lookahead, &dist, target)) return qtrue;
877
reachnum = BotGetReachabilityToGoal(reach.end, reach.areanum,
878
ms->lastgoalareanum, lastareanum,
879
ms->avoidreach, ms->avoidreachtimes, ms->avoidreachtries,
880
goal, travelflags, travelflags, NULL, 0, NULL);
881
VectorCopy(reach.end, end);
882
lastareanum = reach.areanum;
883
if (lastareanum == goal->areanum)
885
BotAddToTarget(reach.end, goal->origin, lookahead, &dist, target);
891
} //end of the function BotMovementViewTarget
892
//===========================================================================
896
// Changes Globals: -
897
//===========================================================================
898
int BotVisible(int ent, vec3_t eye, vec3_t target)
902
trace = AAS_Trace(eye, NULL, NULL, target, ent, CONTENTS_SOLID|CONTENTS_PLAYERCLIP);
903
if (trace.fraction >= 1) return qtrue;
905
} //end of the function BotVisible
906
//===========================================================================
910
// Changes Globals: -
911
//===========================================================================
912
int BotPredictVisiblePosition(vec3_t origin, int areanum, bot_goal_t *goal, int travelflags, vec3_t target)
914
aas_reachability_t reach;
915
int reachnum, lastgoalareanum, lastareanum, i;
916
int avoidreach[MAX_AVOIDREACH];
917
float avoidreachtimes[MAX_AVOIDREACH];
918
int avoidreachtries[MAX_AVOIDREACH];
921
//if the bot has no goal or no last reachability
922
if (!goal) return qfalse;
923
//if the areanum is not valid
924
if (!areanum) return qfalse;
925
//if the goal areanum is not valid
926
if (!goal->areanum) return qfalse;
928
Com_Memset(avoidreach, 0, MAX_AVOIDREACH * sizeof(int));
929
lastgoalareanum = goal->areanum;
930
lastareanum = areanum;
931
VectorCopy(origin, end);
933
for (i = 0; i < 20 && (areanum != goal->areanum); i++)
936
reachnum = BotGetReachabilityToGoal(end, areanum,
937
lastgoalareanum, lastareanum,
938
avoidreach, avoidreachtimes, avoidreachtries,
939
goal, travelflags, travelflags, NULL, 0, NULL);
940
if (!reachnum) return qfalse;
941
AAS_ReachabilityFromNum(reachnum, &reach);
943
if (BotVisible(goal->entitynum, goal->origin, reach.start))
945
VectorCopy(reach.start, target);
949
if (BotVisible(goal->entitynum, goal->origin, reach.end))
951
VectorCopy(reach.end, target);
955
if (reach.areanum == goal->areanum)
957
VectorCopy(reach.end, target);
961
lastareanum = areanum;
962
areanum = reach.areanum;
963
VectorCopy(reach.end, end);
968
} //end of the function BotPredictVisiblePosition
969
//===========================================================================
973
// Changes Globals: -
974
//===========================================================================
975
void MoverBottomCenter(aas_reachability_t *reach, vec3_t bottomcenter)
978
vec3_t mins, maxs, origin, mids;
979
vec3_t angles = {0, 0, 0};
981
modelnum = reach->facenum & 0x0000FFFF;
982
//get some bsp model info
983
AAS_BSPModelMinsMaxsOrigin(modelnum, angles, mins, maxs, origin);
985
if (!AAS_OriginOfMoverWithModelNum(modelnum, origin))
987
botimport.Print(PRT_MESSAGE, "no entity with model %d\n", modelnum);
989
//get a point just above the plat in the bottom position
990
VectorAdd(mins, maxs, mids);
991
VectorMA(origin, 0.5, mids, bottomcenter);
992
bottomcenter[2] = reach->start[2];
993
} //end of the function MoverBottomCenter
994
//===========================================================================
998
// Changes Globals: -
999
//===========================================================================
1000
float BotGapDistance(vec3_t origin, vec3_t hordir, int entnum)
1008
//this enables walking down stairs more fluidly
1010
VectorCopy(origin, start);
1011
VectorCopy(origin, end);
1013
trace = AAS_TraceClientBBox(start, end, PRESENCE_CROUCH, entnum);
1014
if (trace.fraction >= 1) return 1;
1015
startz = trace.endpos[2] + 1;
1018
for (dist = 8; dist <= 100; dist += 8)
1020
VectorMA(origin, dist, hordir, start);
1021
start[2] = startz + 24;
1022
VectorCopy(start, end);
1023
end[2] -= 48 + sv_maxbarrier->value;
1024
trace = AAS_TraceClientBBox(start, end, PRESENCE_CROUCH, entnum);
1025
//if solid is found the bot can't walk any further and fall into a gap
1026
if (!trace.startsolid)
1029
if (trace.endpos[2] < startz - sv_maxstep->value - 8)
1031
VectorCopy(trace.endpos, end);
1033
if (AAS_PointContents(end) & CONTENTS_WATER) break;
1034
//if a gap is found slow down
1035
//botimport.Print(PRT_MESSAGE, "gap at %f\n", dist);
1038
startz = trace.endpos[2];
1042
} //end of the function BotGapDistance
1043
//===========================================================================
1047
// Changes Globals: -
1048
//===========================================================================
1049
int BotCheckBarrierJump(bot_movestate_t *ms, vec3_t dir, float speed)
1051
vec3_t start, hordir, end;
1054
VectorCopy(ms->origin, end);
1055
end[2] += sv_maxbarrier->value;
1057
trace = AAS_TraceClientBBox(ms->origin, end, PRESENCE_NORMAL, ms->entitynum);
1058
//this shouldn't happen... but we check anyway
1059
if (trace.startsolid) return qfalse;
1060
//if very low ceiling it isn't possible to jump up to a barrier
1061
if (trace.endpos[2] - ms->origin[2] < sv_maxstep->value) return qfalse;
1066
VectorNormalize(hordir);
1067
VectorMA(ms->origin, ms->thinktime * speed * 0.5, hordir, end);
1068
VectorCopy(trace.endpos, start);
1069
end[2] = trace.endpos[2];
1070
//trace from previous trace end pos horizontally in the move direction
1071
trace = AAS_TraceClientBBox(start, end, PRESENCE_NORMAL, ms->entitynum);
1072
//again this shouldn't happen
1073
if (trace.startsolid) return qfalse;
1075
VectorCopy(trace.endpos, start);
1076
VectorCopy(trace.endpos, end);
1077
end[2] = ms->origin[2];
1078
//trace down from the previous trace end pos
1079
trace = AAS_TraceClientBBox(start, end, PRESENCE_NORMAL, ms->entitynum);
1081
if (trace.startsolid) return qfalse;
1082
//if no obstacle at all
1083
if (trace.fraction >= 1.0) return qfalse;
1084
//if less than the maximum step height
1085
if (trace.endpos[2] - ms->origin[2] < sv_maxstep->value) return qfalse;
1087
EA_Jump(ms->client);
1088
EA_Move(ms->client, hordir, speed);
1089
ms->moveflags |= MFL_BARRIERJUMP;
1090
//there is a barrier
1092
} //end of the function BotCheckBarrierJump
1093
//===========================================================================
1097
// Changes Globals: -
1098
//===========================================================================
1099
int BotSwimInDirection(bot_movestate_t *ms, vec3_t dir, float speed, int type)
1103
VectorCopy(dir, normdir);
1104
VectorNormalize(normdir);
1105
EA_Move(ms->client, normdir, speed);
1107
} //end of the function BotSwimInDirection
1108
//===========================================================================
1112
// Changes Globals: -
1113
//===========================================================================
1114
int BotWalkInDirection(bot_movestate_t *ms, vec3_t dir, float speed, int type)
1116
vec3_t hordir, cmdmove, velocity, tmpdir, origin;
1117
int presencetype, maxframes, cmdframes, stopevent;
1118
aas_clientmove_t move;
1121
if (AAS_OnGround(ms->origin, ms->presencetype, ms->entitynum)) ms->moveflags |= MFL_ONGROUND;
1122
//if the bot is on the ground
1123
if (ms->moveflags & MFL_ONGROUND)
1125
//if there is a barrier the bot can jump on
1126
if (BotCheckBarrierJump(ms, dir, speed)) return qtrue;
1127
//remove barrier jump flag
1128
ms->moveflags &= ~MFL_BARRIERJUMP;
1129
//get the presence type for the movement
1130
if ((type & MOVE_CROUCH) && !(type & MOVE_JUMP)) presencetype = PRESENCE_CROUCH;
1131
else presencetype = PRESENCE_NORMAL;
1132
//horizontal direction
1136
VectorNormalize(hordir);
1137
//if the bot is not supposed to jump
1138
if (!(type & MOVE_JUMP))
1140
//if there is a gap, try to jump over it
1141
if (BotGapDistance(ms->origin, hordir, ms->entitynum) > 0) type |= MOVE_JUMP;
1143
//get command movement
1144
VectorScale(hordir, speed, cmdmove);
1145
VectorCopy(ms->velocity, velocity);
1147
if (type & MOVE_JUMP)
1149
//botimport.Print(PRT_MESSAGE, "trying jump\n");
1151
maxframes = PREDICTIONTIME_JUMP / 0.1;
1153
stopevent = SE_HITGROUND|SE_HITGROUNDDAMAGE|
1154
SE_ENTERWATER|SE_ENTERSLIME|SE_ENTERLAVA;
1160
stopevent = SE_HITGROUNDDAMAGE|
1161
SE_ENTERWATER|SE_ENTERSLIME|SE_ENTERLAVA;
1163
//AAS_ClearShownDebugLines();
1165
VectorCopy(ms->origin, origin);
1167
AAS_PredictClientMovement(&move, ms->entitynum, origin, presencetype, qtrue,
1168
velocity, cmdmove, cmdframes, maxframes, 0.1f,
1169
stopevent, 0, qfalse);//qtrue);
1170
//if prediction time wasn't enough to fully predict the movement
1171
if (move.frames >= maxframes && (type & MOVE_JUMP))
1173
//botimport.Print(PRT_MESSAGE, "client %d: max prediction frames\n", ms->client);
1176
//don't enter slime or lava and don't fall from too high
1177
if (move.stopevent & (SE_ENTERSLIME|SE_ENTERLAVA|SE_HITGROUNDDAMAGE))
1179
//botimport.Print(PRT_MESSAGE, "client %d: would be hurt ", ms->client);
1180
//if (move.stopevent & SE_ENTERSLIME) botimport.Print(PRT_MESSAGE, "slime\n");
1181
//if (move.stopevent & SE_ENTERLAVA) botimport.Print(PRT_MESSAGE, "lava\n");
1182
//if (move.stopevent & SE_HITGROUNDDAMAGE) botimport.Print(PRT_MESSAGE, "hitground\n");
1186
if (move.stopevent & SE_HITGROUND)
1188
//check for nearby gap
1189
VectorNormalize2(move.velocity, tmpdir);
1190
dist = BotGapDistance(move.endpos, tmpdir, ms->entitynum);
1191
if (dist > 0) return qfalse;
1193
dist = BotGapDistance(move.endpos, hordir, ms->entitynum);
1194
if (dist > 0) return qfalse;
1196
//get horizontal movement
1197
tmpdir[0] = move.endpos[0] - ms->origin[0];
1198
tmpdir[1] = move.endpos[1] - ms->origin[1];
1201
//AAS_DrawCross(move.endpos, 4, LINECOLOR_BLUE);
1202
//the bot is blocked by something
1203
if (VectorLength(tmpdir) < speed * ms->thinktime * 0.5) return qfalse;
1204
//perform the movement
1205
if (type & MOVE_JUMP) EA_Jump(ms->client);
1206
if (type & MOVE_CROUCH) EA_Crouch(ms->client);
1207
EA_Move(ms->client, hordir, speed);
1208
//movement was succesfull
1213
if (ms->moveflags & MFL_BARRIERJUMP)
1215
//if near the top or going down
1216
if (ms->velocity[2] < 50)
1218
EA_Move(ms->client, dir, speed);
1221
//FIXME: do air control to avoid hazards
1224
} //end of the function BotWalkInDirection
1225
//===========================================================================
1229
// Changes Globals: -
1230
//===========================================================================
1231
int BotMoveInDirection(int movestate, vec3_t dir, float speed, int type)
1233
bot_movestate_t *ms;
1235
ms = BotMoveStateFromHandle(movestate);
1236
if (!ms) return qfalse;
1238
if (AAS_Swimming(ms->origin))
1240
return BotSwimInDirection(ms, dir, speed, type);
1244
return BotWalkInDirection(ms, dir, speed, type);
1246
} //end of the function BotMoveInDirection
1247
//===========================================================================
1251
// Changes Globals: -
1252
//===========================================================================
1253
int Intersection(vec2_t p1, vec2_t p2, vec2_t p3, vec2_t p4, vec2_t out)
1255
float x1, dx1, dy1, x2, dx2, dy2, d;
1257
dx1 = p2[0] - p1[0];
1258
dy1 = p2[1] - p1[1];
1259
dx2 = p4[0] - p3[0];
1260
dy2 = p4[1] - p3[1];
1262
d = dy1 * dx2 - dx1 * dy2;
1265
x1 = p1[1] * dx1 - p1[0] * dy1;
1266
x2 = p3[1] * dx2 - p3[0] * dy2;
1267
out[0] = (int) ((dx1 * x2 - dx2 * x1) / d);
1268
out[1] = (int) ((dy1 * x2 - dy2 * x1) / d);
1275
} //end of the function Intersection
1276
//===========================================================================
1280
// Changes Globals: -
1281
//===========================================================================
1282
void BotCheckBlocked(bot_movestate_t *ms, vec3_t dir, int checkbottom, bot_moveresult_t *result)
1284
vec3_t mins, maxs, end, up = {0, 0, 1};
1287
//test for entities obstructing the bot's path
1288
AAS_PresenceTypeBoundingBox(ms->presencetype, mins, maxs);
1290
if (fabs(DotProduct(dir, up)) < 0.7)
1292
mins[2] += sv_maxstep->value; //if the bot can step on
1293
maxs[2] -= 10; //a little lower to avoid low ceiling
1295
VectorMA(ms->origin, 3, dir, end);
1296
trace = AAS_Trace(ms->origin, mins, maxs, end, ms->entitynum, CONTENTS_SOLID|CONTENTS_PLAYERCLIP|CONTENTS_BODY);
1297
//if not started in solid and not hitting the world entity
1298
if (!trace.startsolid && (trace.ent != ENTITYNUM_WORLD && trace.ent != ENTITYNUM_NONE) )
1300
result->blocked = qtrue;
1301
result->blockentity = trace.ent;
1303
//botimport.Print(PRT_MESSAGE, "%d: BotCheckBlocked: I'm blocked\n", ms->client);
1306
//if not in an area with reachability
1307
else if (checkbottom && !AAS_AreaReachability(ms->areanum))
1309
//check if the bot is standing on something
1310
AAS_PresenceTypeBoundingBox(ms->presencetype, mins, maxs);
1311
VectorMA(ms->origin, -3, up, end);
1312
trace = AAS_Trace(ms->origin, mins, maxs, end, ms->entitynum, CONTENTS_SOLID|CONTENTS_PLAYERCLIP);
1313
if (!trace.startsolid && (trace.ent != ENTITYNUM_WORLD && trace.ent != ENTITYNUM_NONE) )
1315
result->blocked = qtrue;
1316
result->blockentity = trace.ent;
1317
result->flags |= MOVERESULT_ONTOPOFOBSTACLE;
1319
//botimport.Print(PRT_MESSAGE, "%d: BotCheckBlocked: I'm blocked\n", ms->client);
1323
} //end of the function BotCheckBlocked
1324
//===========================================================================
1328
// Changes Globals: -
1329
//===========================================================================
1330
bot_moveresult_t BotTravel_Walk(bot_movestate_t *ms, aas_reachability_t *reach)
1334
bot_moveresult_t_cleared( result );
1336
//first walk straight to the reachability start
1337
hordir[0] = reach->start[0] - ms->origin[0];
1338
hordir[1] = reach->start[1] - ms->origin[1];
1340
dist = VectorNormalize(hordir);
1342
BotCheckBlocked(ms, hordir, qtrue, &result);
1346
//walk straight to the reachability end
1347
hordir[0] = reach->end[0] - ms->origin[0];
1348
hordir[1] = reach->end[1] - ms->origin[1];
1350
dist = VectorNormalize(hordir);
1352
//if going towards a crouch area
1353
if (!(AAS_AreaPresenceType(reach->areanum) & PRESENCE_NORMAL))
1355
//if pretty close to the reachable area
1356
if (dist < 20) EA_Crouch(ms->client);
1359
dist = BotGapDistance(ms->origin, hordir, ms->entitynum);
1361
if (ms->moveflags & MFL_WALK)
1363
if (dist > 0) speed = 200 - (180 - 1 * dist);
1365
EA_Walk(ms->client);
1369
if (dist > 0) speed = 400 - (360 - 2 * dist);
1372
//elemantary action move in direction
1373
EA_Move(ms->client, hordir, speed);
1374
VectorCopy(hordir, result.movedir);
1377
} //end of the function BotTravel_Walk
1378
//===========================================================================
1382
// Changes Globals: -
1383
//===========================================================================
1384
bot_moveresult_t BotFinishTravel_Walk(bot_movestate_t *ms, aas_reachability_t *reach)
1388
bot_moveresult_t_cleared( result );
1389
//if not on the ground and changed areas... don't walk back!!
1390
//(doesn't seem to help)
1392
ms->areanum = BotFuzzyPointReachabilityArea(ms->origin);
1393
if (ms->areanum == reach->areanum)
1396
botimport.Print(PRT_MESSAGE, "BotFinishTravel_Walk: already in reach area\n");
1400
//go straight to the reachability end
1401
hordir[0] = reach->end[0] - ms->origin[0];
1402
hordir[1] = reach->end[1] - ms->origin[1];
1404
dist = VectorNormalize(hordir);
1406
if (dist > 100) dist = 100;
1407
speed = 400 - (400 - 3 * dist);
1409
EA_Move(ms->client, hordir, speed);
1410
VectorCopy(hordir, result.movedir);
1413
} //end of the function BotFinishTravel_Walk
1414
//===========================================================================
1418
// Changes Globals: -
1419
//===========================================================================
1420
bot_moveresult_t BotTravel_Crouch(bot_movestate_t *ms, aas_reachability_t *reach)
1424
bot_moveresult_t_cleared( result );
1428
//walk straight to reachability end
1429
hordir[0] = reach->end[0] - ms->origin[0];
1430
hordir[1] = reach->end[1] - ms->origin[1];
1432
VectorNormalize(hordir);
1434
BotCheckBlocked(ms, hordir, qtrue, &result);
1435
//elemantary actions
1436
EA_Crouch(ms->client);
1437
EA_Move(ms->client, hordir, speed);
1439
VectorCopy(hordir, result.movedir);
1442
} //end of the function BotTravel_Crouch
1443
//===========================================================================
1447
// Changes Globals: -
1448
//===========================================================================
1449
bot_moveresult_t BotTravel_BarrierJump(bot_movestate_t *ms, aas_reachability_t *reach)
1453
bot_moveresult_t_cleared( result );
1455
//walk straight to reachability start
1456
hordir[0] = reach->start[0] - ms->origin[0];
1457
hordir[1] = reach->start[1] - ms->origin[1];
1459
dist = VectorNormalize(hordir);
1461
BotCheckBlocked(ms, hordir, qtrue, &result);
1462
//if pretty close to the barrier
1465
EA_Jump(ms->client);
1469
if (dist > 60) dist = 60;
1470
speed = 360 - (360 - 6 * dist);
1471
EA_Move(ms->client, hordir, speed);
1473
VectorCopy(hordir, result.movedir);
1476
} //end of the function BotTravel_BarrierJump
1477
//===========================================================================
1481
// Changes Globals: -
1482
//===========================================================================
1483
bot_moveresult_t BotFinishTravel_BarrierJump(bot_movestate_t *ms, aas_reachability_t *reach)
1487
bot_moveresult_t_cleared( result );
1489
//if near the top or going down
1490
if (ms->velocity[2] < 250)
1492
hordir[0] = reach->end[0] - ms->origin[0];
1493
hordir[1] = reach->end[1] - ms->origin[1];
1495
dist = VectorNormalize(hordir);
1497
BotCheckBlocked(ms, hordir, qtrue, &result);
1499
EA_Move(ms->client, hordir, 400);
1500
VectorCopy(hordir, result.movedir);
1504
} //end of the function BotFinishTravel_BarrierJump
1505
//===========================================================================
1509
// Changes Globals: -
1510
//===========================================================================
1511
bot_moveresult_t BotTravel_Swim(bot_movestate_t *ms, aas_reachability_t *reach)
1514
bot_moveresult_t_cleared( result );
1516
//swim straight to reachability end
1517
VectorSubtract(reach->start, ms->origin, dir);
1518
VectorNormalize(dir);
1520
BotCheckBlocked(ms, dir, qtrue, &result);
1521
//elemantary actions
1522
EA_Move(ms->client, dir, 400);
1524
VectorCopy(dir, result.movedir);
1525
Vector2Angles(dir, result.ideal_viewangles);
1526
result.flags |= MOVERESULT_SWIMVIEW;
1529
} //end of the function BotTravel_Swim
1530
//===========================================================================
1534
// Changes Globals: -
1535
//===========================================================================
1536
bot_moveresult_t BotTravel_WaterJump(bot_movestate_t *ms, aas_reachability_t *reach)
1540
bot_moveresult_t_cleared( result );
1542
//swim straight to reachability end
1543
VectorSubtract(reach->end, ms->origin, dir);
1544
VectorCopy(dir, hordir);
1546
dir[2] += 15 + crandom() * 40;
1547
//botimport.Print(PRT_MESSAGE, "BotTravel_WaterJump: dir[2] = %f\n", dir[2]);
1548
VectorNormalize(dir);
1549
dist = VectorNormalize(hordir);
1550
//elemantary actions
1551
//EA_Move(ms->client, dir, 400);
1552
EA_MoveForward(ms->client);
1553
//move up if close to the actual out of water jump spot
1554
if (dist < 40) EA_MoveUp(ms->client);
1555
//set the ideal view angles
1556
Vector2Angles(dir, result.ideal_viewangles);
1557
result.flags |= MOVERESULT_MOVEMENTVIEW;
1559
VectorCopy(dir, result.movedir);
1562
} //end of the function BotTravel_WaterJump
1563
//===========================================================================
1567
// Changes Globals: -
1568
//===========================================================================
1569
bot_moveresult_t BotFinishTravel_WaterJump(bot_movestate_t *ms, aas_reachability_t *reach)
1573
bot_moveresult_t_cleared( result );
1575
//botimport.Print(PRT_MESSAGE, "BotFinishTravel_WaterJump\n");
1576
//if waterjumping there's nothing to do
1577
if (ms->moveflags & MFL_WATERJUMP) return result;
1578
//if not touching any water anymore don't do anything
1579
//otherwise the bot sometimes keeps jumping?
1580
VectorCopy(ms->origin, pnt);
1581
pnt[2] -= 32; //extra for q2dm4 near red armor/mega health
1582
if (!(AAS_PointContents(pnt) & (CONTENTS_LAVA|CONTENTS_SLIME|CONTENTS_WATER))) return result;
1583
//swim straight to reachability end
1584
VectorSubtract(reach->end, ms->origin, dir);
1585
dir[0] += crandom() * 10;
1586
dir[1] += crandom() * 10;
1587
dir[2] += 70 + crandom() * 10;
1588
dist = VectorNormalize(dir);
1589
//elemantary actions
1590
EA_Move(ms->client, dir, 400);
1591
//set the ideal view angles
1592
Vector2Angles(dir, result.ideal_viewangles);
1593
result.flags |= MOVERESULT_MOVEMENTVIEW;
1595
VectorCopy(dir, result.movedir);
1598
} //end of the function BotFinishTravel_WaterJump
1599
//===========================================================================
1603
// Changes Globals: -
1604
//===========================================================================
1605
bot_moveresult_t BotTravel_WalkOffLedge(bot_movestate_t *ms, aas_reachability_t *reach)
1608
float dist, speed, reachhordist;
1609
bot_moveresult_t_cleared( result );
1611
//check if the bot is blocked by anything
1612
VectorSubtract(reach->start, ms->origin, dir);
1613
VectorNormalize(dir);
1614
BotCheckBlocked(ms, dir, qtrue, &result);
1615
//if the reachability start and end are practially above each other
1616
VectorSubtract(reach->end, reach->start, dir);
1618
reachhordist = VectorLength(dir);
1619
//walk straight to the reachability start
1620
hordir[0] = reach->start[0] - ms->origin[0];
1621
hordir[1] = reach->start[1] - ms->origin[1];
1623
dist = VectorNormalize(hordir);
1624
//if pretty close to the start focus on the reachability end
1627
hordir[0] = reach->end[0] - ms->origin[0];
1628
hordir[1] = reach->end[1] - ms->origin[1];
1630
VectorNormalize(hordir);
1632
if (reachhordist < 20)
1636
else if (!AAS_HorizontalVelocityForJump(0, reach->start, reach->end, &speed))
1643
if (reachhordist < 20)
1645
if (dist > 64) dist = 64;
1646
speed = 400 - (256 - 4 * dist);
1654
BotCheckBlocked(ms, hordir, qtrue, &result);
1656
EA_Move(ms->client, hordir, speed);
1657
VectorCopy(hordir, result.movedir);
1660
} //end of the function BotTravel_WalkOffLedge
1661
//===========================================================================
1665
// Changes Globals: -
1666
//===========================================================================
1667
int BotAirControl(vec3_t origin, vec3_t velocity, vec3_t goal, vec3_t dir, float *speed)
1673
VectorCopy(origin, org);
1674
VectorScale(velocity, 0.1, vel);
1675
for (i = 0; i < 50; i++)
1677
vel[2] -= sv_gravity->value * 0.01;
1678
//if going down and next position would be below the goal
1679
if (vel[2] < 0 && org[2] + vel[2] < goal[2])
1681
VectorScale(vel, (goal[2] - org[2]) / vel[2], vel);
1682
VectorAdd(org, vel, org);
1683
VectorSubtract(goal, org, dir);
1684
dist = VectorNormalize(dir);
1685
if (dist > 32) dist = 32;
1686
*speed = 400 - (400 - 13 * dist);
1691
VectorAdd(org, vel, org);
1694
VectorSet(dir, 0, 0, 0);
1697
} //end of the function BotAirControl
1698
//===========================================================================
1702
// Changes Globals: -
1703
//===========================================================================
1704
bot_moveresult_t BotFinishTravel_WalkOffLedge(bot_movestate_t *ms, aas_reachability_t *reach)
1706
vec3_t dir, hordir, end, v;
1708
bot_moveresult_t_cleared( result );
1711
VectorSubtract(reach->end, ms->origin, dir);
1712
BotCheckBlocked(ms, dir, qtrue, &result);
1714
VectorSubtract(reach->end, ms->origin, v);
1716
dist = VectorNormalize(v);
1717
if (dist > 16) VectorMA(reach->end, 16, v, end);
1718
else VectorCopy(reach->end, end);
1720
if (!BotAirControl(ms->origin, ms->velocity, end, hordir, &speed))
1722
//go straight to the reachability end
1723
VectorCopy(dir, hordir);
1726
dist = VectorNormalize(hordir);
1730
EA_Move(ms->client, hordir, speed);
1731
VectorCopy(hordir, result.movedir);
1734
} //end of the function BotFinishTravel_WalkOffLedge
1735
//===========================================================================
1739
// Changes Globals: -
1740
//===========================================================================
1742
bot_moveresult_t BotTravel_Jump(bot_movestate_t *ms, aas_reachability_t *reach)
1745
float dist, gapdist, speed, horspeed, sv_jumpvel;
1746
bot_moveresult_t_cleared( result );
1749
sv_jumpvel = botlibglobals.sv_jumpvel->value;
1750
//walk straight to the reachability start
1751
hordir[0] = reach->start[0] - ms->origin[0];
1752
hordir[1] = reach->start[1] - ms->origin[1];
1754
dist = VectorNormalize(hordir);
1758
gapdist = BotGapDistance(ms, hordir, ms->entitynum);
1759
//if pretty close to the start focus on the reachability end
1760
if (dist < 50 || (gapdist && gapdist < 50))
1762
//NOTE: using max speed (400) works best
1763
//if (AAS_HorizontalVelocityForJump(sv_jumpvel, ms->origin, reach->end, &horspeed))
1765
// speed = horspeed * 400 / botlibglobals.sv_maxwalkvelocity->value;
1767
hordir[0] = reach->end[0] - ms->origin[0];
1768
hordir[1] = reach->end[1] - ms->origin[1];
1769
VectorNormalize(hordir);
1770
//elemantary action jump
1771
EA_Jump(ms->client);
1773
ms->jumpreach = ms->lastreachnum;
1778
if (AAS_HorizontalVelocityForJump(sv_jumpvel, reach->start, reach->end, &horspeed))
1780
speed = horspeed * 400 / botlibglobals.sv_maxwalkvelocity->value;
1784
EA_Move(ms->client, hordir, speed);
1785
VectorCopy(hordir, result.movedir);
1788
} //end of the function BotTravel_Jump*/
1790
bot_moveresult_t BotTravel_Jump(bot_movestate_t *ms, aas_reachability_t *reach)
1792
vec3_t hordir, dir1, dir2, mins, maxs, start, end;
1793
float dist1, dist2, speed;
1794
bot_moveresult_t_cleared( result );
1798
hordir[0] = reach->start[0] - reach->end[0];
1799
hordir[1] = reach->start[1] - reach->end[1];
1801
VectorNormalize(hordir);
1803
VectorCopy(reach->start, start);
1805
//minus back the bouding box size plus 16
1806
VectorMA(reach->start, 80, hordir, end);
1808
AAS_PresenceTypeBoundingBox(PRESENCE_NORMAL, mins, maxs);
1810
trace = AAS_Trace(start, mins, maxs, end, ms->entitynum, MASK_PLAYERSOLID);
1811
if (trace.startsolid) VectorCopy(start, trace.endpos);
1813
for (dist1 = 0; dist1 < 80; dist1 += 10)
1815
VectorMA(start, dist1+10, hordir, end);
1817
if (AAS_PointAreaNum(end) != ms->reachareanum) break;
1819
if (dist1 < 80) VectorMA(reach->start, dist1, hordir, trace.endpos);
1820
// dist1 = BotGapDistance(start, hordir, ms->entitynum);
1821
// if (dist1 && dist1 <= trace.fraction * 80) VectorMA(reach->start, dist1-20, hordir, trace.endpos);
1823
VectorSubtract(ms->origin, reach->start, dir1);
1825
dist1 = VectorNormalize(dir1);
1826
VectorSubtract(ms->origin, trace.endpos, dir2);
1828
dist2 = VectorNormalize(dir2);
1829
//if just before the reachability start
1830
if (DotProduct(dir1, dir2) < -0.8 || dist2 < 5)
1832
//botimport.Print(PRT_MESSAGE, "between jump start and run to point\n");
1833
hordir[0] = reach->end[0] - ms->origin[0];
1834
hordir[1] = reach->end[1] - ms->origin[1];
1836
VectorNormalize(hordir);
1837
//elemantary action jump
1838
if (dist1 < 24) EA_Jump(ms->client);
1839
else if (dist1 < 32) EA_DelayedJump(ms->client);
1840
EA_Move(ms->client, hordir, 600);
1842
ms->jumpreach = ms->lastreachnum;
1846
//botimport.Print(PRT_MESSAGE, "going towards run to point\n");
1847
hordir[0] = trace.endpos[0] - ms->origin[0];
1848
hordir[1] = trace.endpos[1] - ms->origin[1];
1850
VectorNormalize(hordir);
1852
if (dist2 > 80) dist2 = 80;
1853
speed = 400 - (400 - 5 * dist2);
1854
EA_Move(ms->client, hordir, speed);
1856
VectorCopy(hordir, result.movedir);
1859
} //end of the function BotTravel_Jump*/
1861
bot_moveresult_t BotTravel_Jump(bot_movestate_t *ms, aas_reachability_t *reach)
1863
vec3_t hordir, dir1, dir2, start, end, runstart;
1864
// vec3_t runstart, dir1, dir2, hordir;
1865
float dist1, dist2, speed;
1866
bot_moveresult_t_cleared( result );
1869
AAS_JumpReachRunStart(reach, runstart);
1871
hordir[0] = runstart[0] - reach->start[0];
1872
hordir[1] = runstart[1] - reach->start[1];
1874
VectorNormalize(hordir);
1876
VectorCopy(reach->start, start);
1878
VectorMA(reach->start, 80, hordir, runstart);
1880
for (dist1 = 0; dist1 < 80; dist1 += 10)
1882
VectorMA(start, dist1+10, hordir, end);
1884
if (AAS_PointAreaNum(end) != ms->reachareanum) break;
1886
if (dist1 < 80) VectorMA(reach->start, dist1, hordir, runstart);
1888
VectorSubtract(ms->origin, reach->start, dir1);
1890
dist1 = VectorNormalize(dir1);
1891
VectorSubtract(ms->origin, runstart, dir2);
1893
dist2 = VectorNormalize(dir2);
1894
//if just before the reachability start
1895
if (DotProduct(dir1, dir2) < -0.8 || dist2 < 5)
1897
// botimport.Print(PRT_MESSAGE, "between jump start and run start point\n");
1898
hordir[0] = reach->end[0] - ms->origin[0];
1899
hordir[1] = reach->end[1] - ms->origin[1];
1901
VectorNormalize(hordir);
1902
//elemantary action jump
1903
if (dist1 < 24) EA_Jump(ms->client);
1904
else if (dist1 < 32) EA_DelayedJump(ms->client);
1905
EA_Move(ms->client, hordir, 600);
1907
ms->jumpreach = ms->lastreachnum;
1911
// botimport.Print(PRT_MESSAGE, "going towards run start point\n");
1912
hordir[0] = runstart[0] - ms->origin[0];
1913
hordir[1] = runstart[1] - ms->origin[1];
1915
VectorNormalize(hordir);
1917
if (dist2 > 80) dist2 = 80;
1918
speed = 400 - (400 - 5 * dist2);
1919
EA_Move(ms->client, hordir, speed);
1921
VectorCopy(hordir, result.movedir);
1924
} //end of the function BotTravel_Jump*/
1925
//===========================================================================
1929
// Changes Globals: -
1930
//===========================================================================
1931
bot_moveresult_t BotFinishTravel_Jump(bot_movestate_t *ms, aas_reachability_t *reach)
1933
vec3_t hordir, hordir2;
1935
bot_moveresult_t_cleared( result );
1938
if (!ms->jumpreach) return result;
1939
//go straight to the reachability end
1940
hordir[0] = reach->end[0] - ms->origin[0];
1941
hordir[1] = reach->end[1] - ms->origin[1];
1943
dist = VectorNormalize(hordir);
1945
hordir2[0] = reach->end[0] - reach->start[0];
1946
hordir2[1] = reach->end[1] - reach->start[1];
1948
VectorNormalize(hordir2);
1950
if (DotProduct(hordir, hordir2) < -0.5 && dist < 24) return result;
1951
//always use max speed when traveling through the air
1954
EA_Move(ms->client, hordir, speed);
1955
VectorCopy(hordir, result.movedir);
1958
} //end of the function BotFinishTravel_Jump
1959
//===========================================================================
1963
// Changes Globals: -
1964
//===========================================================================
1965
bot_moveresult_t BotTravel_Ladder(bot_movestate_t *ms, aas_reachability_t *reach)
1967
//float dist, speed;
1968
vec3_t dir, viewdir;//, hordir;
1969
vec3_t origin = {0, 0, 0};
1970
// vec3_t up = {0, 0, 1};
1971
bot_moveresult_t_cleared( result );
1974
// if ((ms->moveflags & MFL_AGAINSTLADDER))
1975
//NOTE: not a good idea for ladders starting in water
1976
// || !(ms->moveflags & MFL_ONGROUND))
1978
//botimport.Print(PRT_MESSAGE, "against ladder or not on ground\n");
1979
VectorSubtract(reach->end, ms->origin, dir);
1980
VectorNormalize(dir);
1981
//set the ideal view angles, facing the ladder up or down
1982
viewdir[0] = dir[0];
1983
viewdir[1] = dir[1];
1984
viewdir[2] = 3 * dir[2];
1985
Vector2Angles(viewdir, result.ideal_viewangles);
1987
EA_Move(ms->client, origin, 0);
1988
EA_MoveForward(ms->client);
1989
//set movement view flag so the AI can see the view is focussed
1990
result.flags |= MOVERESULT_MOVEMENTVIEW;
1994
//botimport.Print(PRT_MESSAGE, "moving towards ladder\n");
1995
VectorSubtract(reach->end, ms->origin, dir);
1996
//make sure the horizontal movement is large anough
1997
VectorCopy(dir, hordir);
1999
dist = VectorNormalize(hordir);
2003
if (dir[2] > 0) dir[2] = 1;
2005
if (dist > 50) dist = 50;
2006
speed = 400 - (200 - 4 * dist);
2007
EA_Move(ms->client, dir, speed);
2009
//save the movement direction
2010
VectorCopy(dir, result.movedir);
2013
} //end of the function BotTravel_Ladder
2014
//===========================================================================
2018
// Changes Globals: -
2019
//===========================================================================
2020
bot_moveresult_t BotTravel_Teleport(bot_movestate_t *ms, aas_reachability_t *reach)
2024
bot_moveresult_t_cleared( result );
2026
//if the bot is being teleported
2027
if (ms->moveflags & MFL_TELEPORTED) return result;
2029
//walk straight to center of the teleporter
2030
VectorSubtract(reach->start, ms->origin, hordir);
2031
if (!(ms->moveflags & MFL_SWIMMING)) hordir[2] = 0;
2032
dist = VectorNormalize(hordir);
2034
BotCheckBlocked(ms, hordir, qtrue, &result);
2036
if (dist < 30) EA_Move(ms->client, hordir, 200);
2037
else EA_Move(ms->client, hordir, 400);
2039
if (ms->moveflags & MFL_SWIMMING) result.flags |= MOVERESULT_SWIMVIEW;
2041
VectorCopy(hordir, result.movedir);
2043
} //end of the function BotTravel_Teleport
2044
//===========================================================================
2048
// Changes Globals: -
2049
//===========================================================================
2050
bot_moveresult_t BotTravel_Elevator(bot_movestate_t *ms, aas_reachability_t *reach)
2052
vec3_t dir, dir1, dir2, hordir, bottomcenter;
2053
float dist, dist1, dist2, speed;
2054
bot_moveresult_t_cleared( result );
2056
//if standing on the plat
2057
if (BotOnMover(ms->origin, ms->entitynum, reach))
2059
#ifdef DEBUG_ELEVATOR
2060
botimport.Print(PRT_MESSAGE, "bot on elevator\n");
2061
#endif //DEBUG_ELEVATOR
2062
//if vertically not too far from the end point
2063
if (abs(ms->origin[2] - reach->end[2]) < sv_maxbarrier->value)
2065
#ifdef DEBUG_ELEVATOR
2066
botimport.Print(PRT_MESSAGE, "bot moving to end\n");
2067
#endif //DEBUG_ELEVATOR
2068
//move to the end point
2069
VectorSubtract(reach->end, ms->origin, hordir);
2071
VectorNormalize(hordir);
2072
if (!BotCheckBarrierJump(ms, hordir, 100))
2074
EA_Move(ms->client, hordir, 400);
2076
VectorCopy(hordir, result.movedir);
2078
//if not really close to the center of the elevator
2081
MoverBottomCenter(reach, bottomcenter);
2082
VectorSubtract(bottomcenter, ms->origin, hordir);
2084
dist = VectorNormalize(hordir);
2088
#ifdef DEBUG_ELEVATOR
2089
botimport.Print(PRT_MESSAGE, "bot moving to center\n");
2090
#endif //DEBUG_ELEVATOR
2091
//move to the center of the plat
2092
if (dist > 100) dist = 100;
2093
speed = 400 - (400 - 4 * dist);
2095
EA_Move(ms->client, hordir, speed);
2096
VectorCopy(hordir, result.movedir);
2102
#ifdef DEBUG_ELEVATOR
2103
botimport.Print(PRT_MESSAGE, "bot not on elevator\n");
2104
#endif //DEBUG_ELEVATOR
2105
//if very near the reachability end
2106
VectorSubtract(reach->end, ms->origin, dir);
2107
dist = VectorLength(dir);
2110
if (dist > 60) dist = 60;
2111
speed = 360 - (360 - 6 * dist);
2113
if ((ms->moveflags & MFL_SWIMMING) || !BotCheckBarrierJump(ms, dir, 50))
2115
if (speed > 5) EA_Move(ms->client, dir, speed);
2117
VectorCopy(dir, result.movedir);
2119
if (ms->moveflags & MFL_SWIMMING) result.flags |= MOVERESULT_SWIMVIEW;
2120
//stop using this reachability
2121
ms->reachability_time = 0;
2124
//get direction and distance to reachability start
2125
VectorSubtract(reach->start, ms->origin, dir1);
2126
if (!(ms->moveflags & MFL_SWIMMING)) dir1[2] = 0;
2127
dist1 = VectorNormalize(dir1);
2128
//if the elevator isn't down
2129
if (!MoverDown(reach))
2131
#ifdef DEBUG_ELEVATOR
2132
botimport.Print(PRT_MESSAGE, "elevator not down\n");
2133
#endif //DEBUG_ELEVATOR
2135
VectorCopy(dir1, dir);
2137
BotCheckBlocked(ms, dir, qfalse, &result);
2139
if (dist > 60) dist = 60;
2140
speed = 360 - (360 - 6 * dist);
2142
if (!(ms->moveflags & MFL_SWIMMING) && !BotCheckBarrierJump(ms, dir, 50))
2144
if (speed > 5) EA_Move(ms->client, dir, speed);
2146
VectorCopy(dir, result.movedir);
2148
if (ms->moveflags & MFL_SWIMMING) result.flags |= MOVERESULT_SWIMVIEW;
2149
//this isn't a failure... just wait till the elevator comes down
2150
result.type = RESULTTYPE_ELEVATORUP;
2151
result.flags |= MOVERESULT_WAITING;
2154
//get direction and distance to elevator bottom center
2155
MoverBottomCenter(reach, bottomcenter);
2156
VectorSubtract(bottomcenter, ms->origin, dir2);
2157
if (!(ms->moveflags & MFL_SWIMMING)) dir2[2] = 0;
2158
dist2 = VectorNormalize(dir2);
2159
//if very close to the reachability start or
2160
//closer to the elevator center or
2161
//between reachability start and elevator center
2162
if (dist1 < 20 || dist2 < dist1 || DotProduct(dir1, dir2) < 0)
2164
#ifdef DEBUG_ELEVATOR
2165
botimport.Print(PRT_MESSAGE, "bot moving to center\n");
2166
#endif //DEBUG_ELEVATOR
2168
VectorCopy(dir2, dir);
2170
else //closer to the reachability start
2172
#ifdef DEBUG_ELEVATOR
2173
botimport.Print(PRT_MESSAGE, "bot moving to start\n");
2174
#endif //DEBUG_ELEVATOR
2176
VectorCopy(dir1, dir);
2179
BotCheckBlocked(ms, dir, qfalse, &result);
2181
if (dist > 60) dist = 60;
2182
speed = 400 - (400 - 6 * dist);
2184
if (!(ms->moveflags & MFL_SWIMMING) && !BotCheckBarrierJump(ms, dir, 50))
2186
EA_Move(ms->client, dir, speed);
2188
VectorCopy(dir, result.movedir);
2190
if (ms->moveflags & MFL_SWIMMING) result.flags |= MOVERESULT_SWIMVIEW;
2193
} //end of the function BotTravel_Elevator
2194
//===========================================================================
2198
// Changes Globals: -
2199
//===========================================================================
2200
bot_moveresult_t BotFinishTravel_Elevator(bot_movestate_t *ms, aas_reachability_t *reach)
2202
vec3_t bottomcenter, bottomdir, topdir;
2203
bot_moveresult_t_cleared( result );
2206
MoverBottomCenter(reach, bottomcenter);
2207
VectorSubtract(bottomcenter, ms->origin, bottomdir);
2209
VectorSubtract(reach->end, ms->origin, topdir);
2211
if (fabs(bottomdir[2]) < fabs(topdir[2]))
2213
VectorNormalize(bottomdir);
2214
EA_Move(ms->client, bottomdir, 300);
2218
VectorNormalize(topdir);
2219
EA_Move(ms->client, topdir, 300);
2222
} //end of the function BotFinishTravel_Elevator
2223
//===========================================================================
2227
// Changes Globals: -
2228
//===========================================================================
2229
void BotFuncBobStartEnd(aas_reachability_t *reach, vec3_t start, vec3_t end, vec3_t origin)
2231
int spawnflags, modelnum;
2232
vec3_t mins, maxs, mid, angles = {0, 0, 0};
2235
modelnum = reach->facenum & 0x0000FFFF;
2236
if (!AAS_OriginOfMoverWithModelNum(modelnum, origin))
2238
botimport.Print(PRT_MESSAGE, "BotFuncBobStartEnd: no entity with model %d\n", modelnum);
2239
VectorSet(start, 0, 0, 0);
2240
VectorSet(end, 0, 0, 0);
2243
AAS_BSPModelMinsMaxsOrigin(modelnum, angles, mins, maxs, NULL);
2244
VectorAdd(mins, maxs, mid);
2245
VectorScale(mid, 0.5, mid);
2246
VectorCopy(mid, start);
2247
VectorCopy(mid, end);
2248
spawnflags = reach->facenum >> 16;
2249
num0 = reach->edgenum >> 16;
2250
if (num0 > 0x00007FFF) num0 |= 0xFFFF0000;
2251
num1 = reach->edgenum & 0x0000FFFF;
2252
if (num1 > 0x00007FFF) num1 |= 0xFFFF0000;
2258
origin[0] += mid[0];
2262
else if (spawnflags & 2)
2268
origin[1] += mid[1];
2278
origin[2] += mid[2];
2280
} //end of the function BotFuncBobStartEnd
2281
//===========================================================================
2285
// Changes Globals: -
2286
//===========================================================================
2287
bot_moveresult_t BotTravel_FuncBobbing(bot_movestate_t *ms, aas_reachability_t *reach)
2289
vec3_t dir, dir1, dir2, hordir, bottomcenter, bob_start, bob_end, bob_origin;
2290
float dist, dist1, dist2, speed;
2291
bot_moveresult_t_cleared( result );
2294
BotFuncBobStartEnd(reach, bob_start, bob_end, bob_origin);
2295
//if standing ontop of the func_bobbing
2296
if (BotOnMover(ms->origin, ms->entitynum, reach))
2298
#ifdef DEBUG_FUNCBOB
2299
botimport.Print(PRT_MESSAGE, "bot on func_bobbing\n");
2301
//if near end point of reachability
2302
VectorSubtract(bob_origin, bob_end, dir);
2303
if (VectorLength(dir) < 24)
2305
#ifdef DEBUG_FUNCBOB
2306
botimport.Print(PRT_MESSAGE, "bot moving to reachability end\n");
2308
//move to the end point
2309
VectorSubtract(reach->end, ms->origin, hordir);
2311
VectorNormalize(hordir);
2312
if (!BotCheckBarrierJump(ms, hordir, 100))
2314
EA_Move(ms->client, hordir, 400);
2316
VectorCopy(hordir, result.movedir);
2318
//if not really close to the center of the elevator
2321
MoverBottomCenter(reach, bottomcenter);
2322
VectorSubtract(bottomcenter, ms->origin, hordir);
2324
dist = VectorNormalize(hordir);
2328
#ifdef DEBUG_FUNCBOB
2329
botimport.Print(PRT_MESSAGE, "bot moving to func_bobbing center\n");
2331
//move to the center of the plat
2332
if (dist > 100) dist = 100;
2333
speed = 400 - (400 - 4 * dist);
2335
EA_Move(ms->client, hordir, speed);
2336
VectorCopy(hordir, result.movedir);
2342
#ifdef DEBUG_FUNCBOB
2343
botimport.Print(PRT_MESSAGE, "bot not ontop of func_bobbing\n");
2345
//if very near the reachability end
2346
VectorSubtract(reach->end, ms->origin, dir);
2347
dist = VectorLength(dir);
2350
#ifdef DEBUG_FUNCBOB
2351
botimport.Print(PRT_MESSAGE, "bot moving to end\n");
2353
if (dist > 60) dist = 60;
2354
speed = 360 - (360 - 6 * dist);
2355
//if swimming or no barrier jump
2356
if ((ms->moveflags & MFL_SWIMMING) || !BotCheckBarrierJump(ms, dir, 50))
2358
if (speed > 5) EA_Move(ms->client, dir, speed);
2360
VectorCopy(dir, result.movedir);
2362
if (ms->moveflags & MFL_SWIMMING) result.flags |= MOVERESULT_SWIMVIEW;
2363
//stop using this reachability
2364
ms->reachability_time = 0;
2367
//get direction and distance to reachability start
2368
VectorSubtract(reach->start, ms->origin, dir1);
2369
if (!(ms->moveflags & MFL_SWIMMING)) dir1[2] = 0;
2370
dist1 = VectorNormalize(dir1);
2371
//if func_bobbing is Not it's start position
2372
VectorSubtract(bob_origin, bob_start, dir);
2373
if (VectorLength(dir) > 16)
2375
#ifdef DEBUG_FUNCBOB
2376
botimport.Print(PRT_MESSAGE, "func_bobbing not at start\n");
2379
VectorCopy(dir1, dir);
2381
BotCheckBlocked(ms, dir, qfalse, &result);
2383
if (dist > 60) dist = 60;
2384
speed = 360 - (360 - 6 * dist);
2386
if (!(ms->moveflags & MFL_SWIMMING) && !BotCheckBarrierJump(ms, dir, 50))
2388
if (speed > 5) EA_Move(ms->client, dir, speed);
2390
VectorCopy(dir, result.movedir);
2392
if (ms->moveflags & MFL_SWIMMING) result.flags |= MOVERESULT_SWIMVIEW;
2393
//this isn't a failure... just wait till the func_bobbing arrives
2394
result.type = RESULTTYPE_WAITFORFUNCBOBBING;
2395
result.flags |= MOVERESULT_WAITING;
2398
//get direction and distance to func_bob bottom center
2399
MoverBottomCenter(reach, bottomcenter);
2400
VectorSubtract(bottomcenter, ms->origin, dir2);
2401
if (!(ms->moveflags & MFL_SWIMMING)) dir2[2] = 0;
2402
dist2 = VectorNormalize(dir2);
2403
//if very close to the reachability start or
2404
//closer to the elevator center or
2405
//between reachability start and func_bobbing center
2406
if (dist1 < 20 || dist2 < dist1 || DotProduct(dir1, dir2) < 0)
2408
#ifdef DEBUG_FUNCBOB
2409
botimport.Print(PRT_MESSAGE, "bot moving to func_bobbing center\n");
2412
VectorCopy(dir2, dir);
2414
else //closer to the reachability start
2416
#ifdef DEBUG_FUNCBOB
2417
botimport.Print(PRT_MESSAGE, "bot moving to reachability start\n");
2420
VectorCopy(dir1, dir);
2423
BotCheckBlocked(ms, dir, qfalse, &result);
2425
if (dist > 60) dist = 60;
2426
speed = 400 - (400 - 6 * dist);
2428
if (!(ms->moveflags & MFL_SWIMMING) && !BotCheckBarrierJump(ms, dir, 50))
2430
EA_Move(ms->client, dir, speed);
2432
VectorCopy(dir, result.movedir);
2434
if (ms->moveflags & MFL_SWIMMING) result.flags |= MOVERESULT_SWIMVIEW;
2437
} //end of the function BotTravel_FuncBobbing
2438
//===========================================================================
2442
// Changes Globals: -
2443
//===========================================================================
2444
bot_moveresult_t BotFinishTravel_FuncBobbing(bot_movestate_t *ms, aas_reachability_t *reach)
2446
vec3_t bob_origin, bob_start, bob_end, dir, hordir, bottomcenter;
2447
bot_moveresult_t_cleared( result );
2451
BotFuncBobStartEnd(reach, bob_start, bob_end, bob_origin);
2453
VectorSubtract(bob_origin, bob_end, dir);
2454
dist = VectorLength(dir);
2455
//if the func_bobbing is near the end
2458
VectorSubtract(reach->end, ms->origin, hordir);
2459
if (!(ms->moveflags & MFL_SWIMMING)) hordir[2] = 0;
2460
dist = VectorNormalize(hordir);
2462
if (dist > 60) dist = 60;
2463
speed = 360 - (360 - 6 * dist);
2465
if (speed > 5) EA_Move(ms->client, dir, speed);
2466
VectorCopy(dir, result.movedir);
2468
if (ms->moveflags & MFL_SWIMMING) result.flags |= MOVERESULT_SWIMVIEW;
2472
MoverBottomCenter(reach, bottomcenter);
2473
VectorSubtract(bottomcenter, ms->origin, hordir);
2474
if (!(ms->moveflags & MFL_SWIMMING)) hordir[2] = 0;
2475
dist = VectorNormalize(hordir);
2479
//move to the center of the plat
2480
if (dist > 100) dist = 100;
2481
speed = 400 - (400 - 4 * dist);
2483
EA_Move(ms->client, hordir, speed);
2484
VectorCopy(hordir, result.movedir);
2488
} //end of the function BotFinishTravel_FuncBobbing
2489
//===========================================================================
2490
// 0 no valid grapple hook visible
2491
// 1 the grapple hook is still flying
2492
// 2 the grapple hooked into a wall
2496
// Changes Globals: -
2497
//===========================================================================
2498
int GrappleState(bot_movestate_t *ms, aas_reachability_t *reach)
2501
aas_entityinfo_t entinfo;
2503
//if the grapple hook is pulling
2504
if (ms->moveflags & MFL_GRAPPLEPULL)
2506
//check for a visible grapple missile entity
2507
//or visible grapple entity
2508
for (i = AAS_NextEntity(0); i; i = AAS_NextEntity(i))
2510
if (AAS_EntityType(i) == (int) entitytypemissile->value)
2512
AAS_EntityInfo(i, &entinfo);
2513
if (entinfo.weapon == (int) weapindex_grapple->value)
2519
//no valid grapple at all
2521
} //end of the function GrappleState
2522
//===========================================================================
2526
// Changes Globals: -
2527
//===========================================================================
2528
void BotResetGrapple(bot_movestate_t *ms)
2530
aas_reachability_t reach;
2532
AAS_ReachabilityFromNum(ms->lastreachnum, &reach);
2533
//if not using the grapple hook reachability anymore
2534
if ((reach.traveltype & TRAVELTYPE_MASK) != TRAVEL_GRAPPLEHOOK)
2536
if ((ms->moveflags & MFL_ACTIVEGRAPPLE) || ms->grapplevisible_time)
2538
if (offhandgrapple->value)
2539
EA_Command(ms->client, cmd_grappleoff->string);
2540
ms->moveflags &= ~MFL_ACTIVEGRAPPLE;
2541
ms->grapplevisible_time = 0;
2542
#ifdef DEBUG_GRAPPLE
2543
botimport.Print(PRT_MESSAGE, "reset grapple\n");
2544
#endif //DEBUG_GRAPPLE
2547
} //end of the function BotResetGrapple
2548
//===========================================================================
2552
// Changes Globals: -
2553
//===========================================================================
2554
bot_moveresult_t BotTravel_Grapple(bot_movestate_t *ms, aas_reachability_t *reach)
2556
bot_moveresult_t_cleared( result );
2558
vec3_t dir, viewdir, org;
2562
#ifdef DEBUG_GRAPPLE
2563
static int debugline;
2564
if (!debugline) debugline = botimport.DebugLineCreate();
2565
botimport.DebugLineShow(debugline, reach->start, reach->end, LINECOLOR_BLUE);
2566
#endif //DEBUG_GRAPPLE
2569
if (ms->moveflags & MFL_GRAPPLERESET)
2571
if (offhandgrapple->value)
2572
EA_Command(ms->client, cmd_grappleoff->string);
2573
ms->moveflags &= ~MFL_ACTIVEGRAPPLE;
2577
if (!(int) offhandgrapple->value)
2579
result.weapon = weapindex_grapple->value;
2580
result.flags |= MOVERESULT_MOVEMENTWEAPON;
2583
if (ms->moveflags & MFL_ACTIVEGRAPPLE)
2585
#ifdef DEBUG_GRAPPLE
2586
botimport.Print(PRT_MESSAGE, "BotTravel_Grapple: active grapple\n");
2587
#endif //DEBUG_GRAPPLE
2589
state = GrappleState(ms, reach);
2591
VectorSubtract(reach->end, ms->origin, dir);
2593
dist = VectorLength(dir);
2594
//if very close to the grapple end or the grappled is hooked and
2595
//the bot doesn't get any closer
2596
if (state && dist < 48)
2598
if (ms->lastgrappledist - dist < 1)
2600
#ifdef DEBUG_GRAPPLE
2601
botimport.Print(PRT_ERROR, "grapple normal end\n");
2602
#endif //DEBUG_GRAPPLE
2603
if (offhandgrapple->value)
2604
EA_Command(ms->client, cmd_grappleoff->string);
2605
ms->moveflags &= ~MFL_ACTIVEGRAPPLE;
2606
ms->moveflags |= MFL_GRAPPLERESET;
2607
ms->reachability_time = 0; //end the reachability
2611
//if no valid grapple at all, or the grapple hooked and the bot
2612
//isn't moving anymore
2613
else if (!state || (state == 2 && dist > ms->lastgrappledist - 2))
2615
if (ms->grapplevisible_time < AAS_Time() - 0.4)
2617
#ifdef DEBUG_GRAPPLE
2618
botimport.Print(PRT_ERROR, "grapple not visible\n");
2619
#endif //DEBUG_GRAPPLE
2620
if (offhandgrapple->value)
2621
EA_Command(ms->client, cmd_grappleoff->string);
2622
ms->moveflags &= ~MFL_ACTIVEGRAPPLE;
2623
ms->moveflags |= MFL_GRAPPLERESET;
2624
ms->reachability_time = 0; //end the reachability
2630
ms->grapplevisible_time = AAS_Time();
2633
if (!(int) offhandgrapple->value)
2635
EA_Attack(ms->client);
2637
//remember the current grapple distance
2638
ms->lastgrappledist = dist;
2642
#ifdef DEBUG_GRAPPLE
2643
botimport.Print(PRT_MESSAGE, "BotTravel_Grapple: inactive grapple\n");
2644
#endif //DEBUG_GRAPPLE
2646
ms->grapplevisible_time = AAS_Time();
2648
VectorSubtract(reach->start, ms->origin, dir);
2649
if (!(ms->moveflags & MFL_SWIMMING)) dir[2] = 0;
2650
VectorAdd(ms->origin, ms->viewoffset, org);
2651
VectorSubtract(reach->end, org, viewdir);
2653
dist = VectorNormalize(dir);
2654
Vector2Angles(viewdir, result.ideal_viewangles);
2655
result.flags |= MOVERESULT_MOVEMENTVIEW;
2658
fabs(AngleDiff(result.ideal_viewangles[0], ms->viewangles[0])) < 2 &&
2659
fabs(AngleDiff(result.ideal_viewangles[1], ms->viewangles[1])) < 2)
2661
#ifdef DEBUG_GRAPPLE
2662
botimport.Print(PRT_MESSAGE, "BotTravel_Grapple: activating grapple\n");
2663
#endif //DEBUG_GRAPPLE
2664
//check if the grapple missile path is clear
2665
VectorAdd(ms->origin, ms->viewoffset, org);
2666
trace = AAS_Trace(org, NULL, NULL, reach->end, ms->entitynum, CONTENTS_SOLID);
2667
VectorSubtract(reach->end, trace.endpos, dir);
2668
if (VectorLength(dir) > 16)
2670
result.failure = qtrue;
2673
//activate the grapple
2674
if (offhandgrapple->value)
2676
EA_Command(ms->client, cmd_grappleon->string);
2680
EA_Attack(ms->client);
2682
ms->moveflags |= MFL_ACTIVEGRAPPLE;
2683
ms->lastgrappledist = 999999;
2687
if (dist < 70) speed = 300 - (300 - 4 * dist);
2690
BotCheckBlocked(ms, dir, qtrue, &result);
2691
//elemantary action move in direction
2692
EA_Move(ms->client, dir, speed);
2693
VectorCopy(dir, result.movedir);
2695
//if in another area before actually grappling
2696
areanum = AAS_PointAreaNum(ms->origin);
2697
if (areanum && areanum != ms->reachareanum) ms->reachability_time = 0;
2700
} //end of the function BotTravel_Grapple
2701
//===========================================================================
2705
// Changes Globals: -
2706
//===========================================================================
2707
bot_moveresult_t BotTravel_RocketJump(bot_movestate_t *ms, aas_reachability_t *reach)
2711
bot_moveresult_t_cleared( result );
2713
//botimport.Print(PRT_MESSAGE, "BotTravel_RocketJump: bah\n");
2715
hordir[0] = reach->start[0] - ms->origin[0];
2716
hordir[1] = reach->start[1] - ms->origin[1];
2719
dist = VectorNormalize(hordir);
2720
//look in the movement direction
2721
Vector2Angles(hordir, result.ideal_viewangles);
2722
//look straight down
2723
result.ideal_viewangles[PITCH] = 90;
2726
fabs(AngleDiff(result.ideal_viewangles[0], ms->viewangles[0])) < 5 &&
2727
fabs(AngleDiff(result.ideal_viewangles[1], ms->viewangles[1])) < 5)
2729
//botimport.Print(PRT_MESSAGE, "between jump start and run start point\n");
2730
hordir[0] = reach->end[0] - ms->origin[0];
2731
hordir[1] = reach->end[1] - ms->origin[1];
2733
VectorNormalize(hordir);
2734
//elemantary action jump
2735
EA_Jump(ms->client);
2736
EA_Attack(ms->client);
2737
EA_Move(ms->client, hordir, 800);
2739
ms->jumpreach = ms->lastreachnum;
2743
if (dist > 80) dist = 80;
2744
speed = 400 - (400 - 5 * dist);
2745
EA_Move(ms->client, hordir, speed);
2747
//look in the movement direction
2748
Vector2Angles(hordir, result.ideal_viewangles);
2749
//look straight down
2750
result.ideal_viewangles[PITCH] = 90;
2751
//set the view angles directly
2752
EA_View(ms->client, result.ideal_viewangles);
2753
//view is important for the movment
2754
result.flags |= MOVERESULT_MOVEMENTVIEWSET;
2755
//select the rocket launcher
2756
EA_SelectWeapon(ms->client, (int) weapindex_rocketlauncher->value);
2757
//weapon is used for movement
2758
result.weapon = (int) weapindex_rocketlauncher->value;
2759
result.flags |= MOVERESULT_MOVEMENTWEAPON;
2761
VectorCopy(hordir, result.movedir);
2764
} //end of the function BotTravel_RocketJump
2765
//===========================================================================
2769
// Changes Globals: -
2770
//===========================================================================
2771
bot_moveresult_t BotTravel_BFGJump(bot_movestate_t *ms, aas_reachability_t *reach)
2775
bot_moveresult_t_cleared( result );
2777
//botimport.Print(PRT_MESSAGE, "BotTravel_BFGJump: bah\n");
2779
hordir[0] = reach->start[0] - ms->origin[0];
2780
hordir[1] = reach->start[1] - ms->origin[1];
2783
dist = VectorNormalize(hordir);
2786
fabs(AngleDiff(result.ideal_viewangles[0], ms->viewangles[0])) < 5 &&
2787
fabs(AngleDiff(result.ideal_viewangles[1], ms->viewangles[1])) < 5)
2789
//botimport.Print(PRT_MESSAGE, "between jump start and run start point\n");
2790
hordir[0] = reach->end[0] - ms->origin[0];
2791
hordir[1] = reach->end[1] - ms->origin[1];
2793
VectorNormalize(hordir);
2794
//elemantary action jump
2795
EA_Jump(ms->client);
2796
EA_Attack(ms->client);
2797
EA_Move(ms->client, hordir, 800);
2799
ms->jumpreach = ms->lastreachnum;
2803
if (dist > 80) dist = 80;
2804
speed = 400 - (400 - 5 * dist);
2805
EA_Move(ms->client, hordir, speed);
2807
//look in the movement direction
2808
Vector2Angles(hordir, result.ideal_viewangles);
2809
//look straight down
2810
result.ideal_viewangles[PITCH] = 90;
2811
//set the view angles directly
2812
EA_View(ms->client, result.ideal_viewangles);
2813
//view is important for the movment
2814
result.flags |= MOVERESULT_MOVEMENTVIEWSET;
2815
//select the rocket launcher
2816
EA_SelectWeapon(ms->client, (int) weapindex_bfg10k->value);
2817
//weapon is used for movement
2818
result.weapon = (int) weapindex_bfg10k->value;
2819
result.flags |= MOVERESULT_MOVEMENTWEAPON;
2821
VectorCopy(hordir, result.movedir);
2824
} //end of the function BotTravel_BFGJump
2825
//===========================================================================
2829
// Changes Globals: -
2830
//===========================================================================
2831
bot_moveresult_t BotFinishTravel_WeaponJump(bot_movestate_t *ms, aas_reachability_t *reach)
2835
bot_moveresult_t_cleared( result );
2838
if (!ms->jumpreach) return result;
2840
//go straight to the reachability end
2841
hordir[0] = reach->end[0] - ms->origin[0];
2842
hordir[1] = reach->end[1] - ms->origin[1];
2844
VectorNormalize(hordir);
2845
//always use max speed when traveling through the air
2846
EA_Move(ms->client, hordir, 800);
2847
VectorCopy(hordir, result.movedir);
2850
if (!BotAirControl(ms->origin, ms->velocity, reach->end, hordir, &speed))
2852
//go straight to the reachability end
2853
VectorSubtract(reach->end, ms->origin, hordir);
2855
VectorNormalize(hordir);
2859
EA_Move(ms->client, hordir, speed);
2860
VectorCopy(hordir, result.movedir);
2863
} //end of the function BotFinishTravel_WeaponJump
2864
//===========================================================================
2868
// Changes Globals: -
2869
//===========================================================================
2870
bot_moveresult_t BotTravel_JumpPad(bot_movestate_t *ms, aas_reachability_t *reach)
2874
bot_moveresult_t_cleared( result );
2876
//first walk straight to the reachability start
2877
hordir[0] = reach->start[0] - ms->origin[0];
2878
hordir[1] = reach->start[1] - ms->origin[1];
2880
dist = VectorNormalize(hordir);
2882
BotCheckBlocked(ms, hordir, qtrue, &result);
2884
//elemantary action move in direction
2885
EA_Move(ms->client, hordir, speed);
2886
VectorCopy(hordir, result.movedir);
2889
} //end of the function BotTravel_JumpPad
2890
//===========================================================================
2894
// Changes Globals: -
2895
//===========================================================================
2896
bot_moveresult_t BotFinishTravel_JumpPad(bot_movestate_t *ms, aas_reachability_t *reach)
2900
bot_moveresult_t_cleared( result );
2902
if (!BotAirControl(ms->origin, ms->velocity, reach->end, hordir, &speed))
2904
hordir[0] = reach->end[0] - ms->origin[0];
2905
hordir[1] = reach->end[1] - ms->origin[1];
2907
VectorNormalize(hordir);
2910
BotCheckBlocked(ms, hordir, qtrue, &result);
2911
//elemantary action move in direction
2912
EA_Move(ms->client, hordir, speed);
2913
VectorCopy(hordir, result.movedir);
2916
} //end of the function BotFinishTravel_JumpPad
2917
//===========================================================================
2918
// time before the reachability times out
2922
// Changes Globals: -
2923
//===========================================================================
2924
int BotReachabilityTime(aas_reachability_t *reach)
2926
switch(reach->traveltype & TRAVELTYPE_MASK)
2928
case TRAVEL_WALK: return 5;
2929
case TRAVEL_CROUCH: return 5;
2930
case TRAVEL_BARRIERJUMP: return 5;
2931
case TRAVEL_LADDER: return 6;
2932
case TRAVEL_WALKOFFLEDGE: return 5;
2933
case TRAVEL_JUMP: return 5;
2934
case TRAVEL_SWIM: return 5;
2935
case TRAVEL_WATERJUMP: return 5;
2936
case TRAVEL_TELEPORT: return 5;
2937
case TRAVEL_ELEVATOR: return 10;
2938
case TRAVEL_GRAPPLEHOOK: return 8;
2939
case TRAVEL_ROCKETJUMP: return 6;
2940
case TRAVEL_BFGJUMP: return 6;
2941
case TRAVEL_JUMPPAD: return 10;
2942
case TRAVEL_FUNCBOB: return 10;
2945
botimport.Print(PRT_ERROR, "travel type %d not implemented yet\n", reach->traveltype);
2949
} //end of the function BotReachabilityTime
2950
//===========================================================================
2954
// Changes Globals: -
2955
//===========================================================================
2956
bot_moveresult_t BotMoveInGoalArea(bot_movestate_t *ms, bot_goal_t *goal)
2958
bot_moveresult_t_cleared( result );
2963
//botimport.Print(PRT_MESSAGE, "%s: moving straight to goal\n", ClientName(ms->entitynum-1));
2964
//AAS_ClearShownDebugLines();
2965
//AAS_DebugLine(ms->origin, goal->origin, LINECOLOR_RED);
2967
//walk straight to the goal origin
2968
dir[0] = goal->origin[0] - ms->origin[0];
2969
dir[1] = goal->origin[1] - ms->origin[1];
2970
if (ms->moveflags & MFL_SWIMMING)
2972
dir[2] = goal->origin[2] - ms->origin[2];
2973
result.traveltype = TRAVEL_SWIM;
2978
result.traveltype = TRAVEL_WALK;
2981
dist = VectorNormalize(dir);
2982
if (dist > 100) dist = 100;
2983
speed = 400 - (400 - 4 * dist);
2984
if (speed < 10) speed = 0;
2986
BotCheckBlocked(ms, dir, qtrue, &result);
2987
//elemantary action move in direction
2988
EA_Move(ms->client, dir, speed);
2989
VectorCopy(dir, result.movedir);
2991
if (ms->moveflags & MFL_SWIMMING)
2993
Vector2Angles(dir, result.ideal_viewangles);
2994
result.flags |= MOVERESULT_SWIMVIEW;
2996
//if (!debugline) debugline = botimport.DebugLineCreate();
2997
//botimport.DebugLineShow(debugline, ms->origin, goal->origin, LINECOLOR_BLUE);
2999
ms->lastreachnum = 0;
3000
ms->lastareanum = 0;
3001
ms->lastgoalareanum = goal->areanum;
3002
VectorCopy(ms->origin, ms->lastorigin);
3005
} //end of the function BotMoveInGoalArea
3006
//===========================================================================
3010
// Changes Globals: -
3011
//===========================================================================
3012
void BotMoveToGoal(bot_moveresult_t *result, int movestate, bot_goal_t *goal, int travelflags)
3014
int reachnum, lastreachnum, foundjumppad, ent, resultflags;
3015
aas_reachability_t reach, lastreach;
3016
bot_movestate_t *ms;
3017
//vec3_t mins, maxs, up = {0, 0, 1};
3018
//bsp_trace_t trace;
3019
//static int debugline;
3021
result->failure = qfalse;
3023
result->blocked = qfalse;
3024
result->blockentity = 0;
3025
result->traveltype = 0;
3029
ms = BotMoveStateFromHandle(movestate);
3031
//reset the grapple before testing if the bot has a valid goal
3032
//because the bot could loose all it's goals when stuck to a wall
3033
BotResetGrapple(ms);
3038
botimport.Print(PRT_MESSAGE, "client %d: movetogoal -> no goal\n", ms->client);
3040
result->failure = qtrue;
3043
//botimport.Print(PRT_MESSAGE, "numavoidreach = %d\n", ms->numavoidreach);
3044
//remove some of the move flags
3045
ms->moveflags &= ~(MFL_SWIMMING|MFL_AGAINSTLADDER);
3046
//set some of the move flags
3047
//NOTE: the MFL_ONGROUND flag is also set in the higher AI
3048
if (AAS_OnGround(ms->origin, ms->presencetype, ms->entitynum)) ms->moveflags |= MFL_ONGROUND;
3050
if (ms->moveflags & MFL_ONGROUND)
3052
int modeltype, modelnum;
3054
ent = BotOnTopOfEntity(ms);
3058
modelnum = AAS_EntityModelindex(ent);
3059
if (modelnum >= 0 && modelnum < MAX_MODELS)
3061
modeltype = modeltypes[modelnum];
3063
if (modeltype == MODELTYPE_FUNC_PLAT)
3065
AAS_ReachabilityFromNum(ms->lastreachnum, &reach);
3066
//if the bot is Not using the elevator
3067
if ((reach.traveltype & TRAVELTYPE_MASK) != TRAVEL_ELEVATOR ||
3068
//NOTE: the face number is the plat model number
3069
(reach.facenum & 0x0000FFFF) != modelnum)
3071
reachnum = AAS_NextModelReachability(0, modelnum);
3074
//botimport.Print(PRT_MESSAGE, "client %d: accidentally ended up on func_plat\n", ms->client);
3075
AAS_ReachabilityFromNum(reachnum, &reach);
3076
ms->lastreachnum = reachnum;
3077
ms->reachability_time = AAS_Time() + BotReachabilityTime(&reach);
3083
botimport.Print(PRT_MESSAGE, "client %d: on func_plat without reachability\n", ms->client);
3085
result->blocked = qtrue;
3086
result->blockentity = ent;
3087
result->flags |= MOVERESULT_ONTOPOFOBSTACLE;
3091
result->flags |= MOVERESULT_ONTOPOF_ELEVATOR;
3093
else if (modeltype == MODELTYPE_FUNC_BOB)
3095
AAS_ReachabilityFromNum(ms->lastreachnum, &reach);
3096
//if the bot is Not using the func bobbing
3097
if ((reach.traveltype & TRAVELTYPE_MASK) != TRAVEL_FUNCBOB ||
3098
//NOTE: the face number is the func_bobbing model number
3099
(reach.facenum & 0x0000FFFF) != modelnum)
3101
reachnum = AAS_NextModelReachability(0, modelnum);
3104
//botimport.Print(PRT_MESSAGE, "client %d: accidentally ended up on func_bobbing\n", ms->client);
3105
AAS_ReachabilityFromNum(reachnum, &reach);
3106
ms->lastreachnum = reachnum;
3107
ms->reachability_time = AAS_Time() + BotReachabilityTime(&reach);
3113
botimport.Print(PRT_MESSAGE, "client %d: on func_bobbing without reachability\n", ms->client);
3115
result->blocked = qtrue;
3116
result->blockentity = ent;
3117
result->flags |= MOVERESULT_ONTOPOFOBSTACLE;
3121
result->flags |= MOVERESULT_ONTOPOF_FUNCBOB;
3123
else if (modeltype == MODELTYPE_FUNC_STATIC || modeltype == MODELTYPE_FUNC_DOOR)
3125
// check if ontop of a door bridge ?
3126
ms->areanum = BotFuzzyPointReachabilityArea(ms->origin);
3127
// if not in a reachability area
3128
if (!AAS_AreaReachability(ms->areanum))
3130
result->blocked = qtrue;
3131
result->blockentity = ent;
3132
result->flags |= MOVERESULT_ONTOPOFOBSTACLE;
3138
result->blocked = qtrue;
3139
result->blockentity = ent;
3140
result->flags |= MOVERESULT_ONTOPOFOBSTACLE;
3147
if (AAS_Swimming(ms->origin)) ms->moveflags |= MFL_SWIMMING;
3148
//if against a ladder
3149
if (AAS_AgainstLadder(ms->origin)) ms->moveflags |= MFL_AGAINSTLADDER;
3150
//if the bot is on the ground, swimming or against a ladder
3151
if (ms->moveflags & (MFL_ONGROUND|MFL_SWIMMING|MFL_AGAINSTLADDER))
3153
//botimport.Print(PRT_MESSAGE, "%s: onground, swimming or against ladder\n", ClientName(ms->entitynum-1));
3155
AAS_ReachabilityFromNum(ms->lastreachnum, &lastreach);
3156
//reachability area the bot is in
3157
//ms->areanum = BotReachabilityArea(ms->origin, ((lastreach.traveltype & TRAVELTYPE_MASK) != TRAVEL_ELEVATOR));
3158
ms->areanum = BotFuzzyPointReachabilityArea(ms->origin);
3162
result->failure = qtrue;
3163
result->blocked = qtrue;
3164
result->blockentity = 0;
3165
result->type = RESULTTYPE_INSOLIDAREA;
3168
//if the bot is in the goal area
3169
if (ms->areanum == goal->areanum)
3171
*result = BotMoveInGoalArea(ms, goal);
3174
//assume we can use the reachability from the last frame
3175
reachnum = ms->lastreachnum;
3176
//if there is a last reachability
3179
AAS_ReachabilityFromNum(reachnum, &reach);
3180
//check if the reachability is still valid
3181
if (!(AAS_TravelFlagForType(reach.traveltype) & travelflags))
3185
//special grapple hook case
3186
else if ((reach.traveltype & TRAVELTYPE_MASK) == TRAVEL_GRAPPLEHOOK)
3188
if (ms->reachability_time < AAS_Time() ||
3189
(ms->moveflags & MFL_GRAPPLERESET))
3194
//special elevator case
3195
else if ((reach.traveltype & TRAVELTYPE_MASK) == TRAVEL_ELEVATOR ||
3196
(reach.traveltype & TRAVELTYPE_MASK) == TRAVEL_FUNCBOB)
3198
if ((result->flags & MOVERESULT_ONTOPOF_FUNCBOB) ||
3199
(result->flags & MOVERESULT_ONTOPOF_FUNCBOB))
3201
ms->reachability_time = AAS_Time() + 5;
3203
//if the bot was going for an elevator and reached the reachability area
3204
if (ms->areanum == reach.areanum ||
3205
ms->reachability_time < AAS_Time())
3215
if (ms->reachability_time < AAS_Time())
3217
botimport.Print(PRT_MESSAGE, "client %d: reachability timeout in ", ms->client);
3218
AAS_PrintTravelType(reach.traveltype & TRAVELTYPE_MASK);
3219
botimport.Print(PRT_MESSAGE, "\n");
3222
if (ms->lastareanum != ms->areanum)
3224
botimport.Print(PRT_MESSAGE, "changed from area %d to %d\n", ms->lastareanum, ms->areanum);
3228
//if the goal area changed or the reachability timed out
3229
//or the area changed
3230
if (ms->lastgoalareanum != goal->areanum ||
3231
ms->reachability_time < AAS_Time() ||
3232
ms->lastareanum != ms->areanum)
3235
//botimport.Print(PRT_MESSAGE, "area change or timeout\n");
3240
//if the bot needs a new reachability
3243
//if the area has no reachability links
3244
if (!AAS_AreaReachability(ms->areanum))
3249
botimport.Print(PRT_MESSAGE, "area %d no reachability\n", ms->areanum);
3253
//get a new reachability leading towards the goal
3254
reachnum = BotGetReachabilityToGoal(ms->origin, ms->areanum,
3255
ms->lastgoalareanum, ms->lastareanum,
3256
ms->avoidreach, ms->avoidreachtimes, ms->avoidreachtries,
3257
goal, travelflags, travelflags,
3258
ms->avoidspots, ms->numavoidspots, &resultflags);
3259
//the area number the reachability starts in
3260
ms->reachareanum = ms->areanum;
3261
//reset some state variables
3262
ms->jumpreach = 0; //for TRAVEL_JUMP
3263
ms->moveflags &= ~MFL_GRAPPLERESET; //for TRAVEL_GRAPPLEHOOK
3264
//if there is a reachability to the goal
3267
AAS_ReachabilityFromNum(reachnum, &reach);
3268
//set a timeout for this reachability
3269
ms->reachability_time = AAS_Time() + BotReachabilityTime(&reach);
3272
//add the reachability to the reachabilities to avoid for a while
3273
BotAddToAvoidReach(ms, reachnum, AVOIDREACH_TIME);
3278
else if (bot_developer)
3280
botimport.Print(PRT_MESSAGE, "goal not reachable\n");
3281
Com_Memset(&reach, 0, sizeof(aas_reachability_t)); //make compiler happy
3285
//if still going for the same goal
3286
if (ms->lastgoalareanum == goal->areanum)
3288
if (ms->lastareanum == reach.areanum)
3290
botimport.Print(PRT_MESSAGE, "same goal, going back to previous area\n");
3297
ms->lastreachnum = reachnum;
3298
ms->lastgoalareanum = goal->areanum;
3299
ms->lastareanum = ms->areanum;
3300
//if the bot has a reachability
3303
//get the reachability from the number
3304
AAS_ReachabilityFromNum(reachnum, &reach);
3305
result->traveltype = reach.traveltype;
3307
#ifdef DEBUG_AI_MOVE
3308
AAS_ClearShownDebugLines();
3309
AAS_PrintTravelType(reach.traveltype & TRAVELTYPE_MASK);
3310
AAS_ShowReachability(&reach);
3311
#endif //DEBUG_AI_MOVE
3314
//botimport.Print(PRT_MESSAGE, "client %d: ", ms->client);
3315
//AAS_PrintTravelType(reach.traveltype);
3316
//botimport.Print(PRT_MESSAGE, "\n");
3318
switch(reach.traveltype & TRAVELTYPE_MASK)
3320
case TRAVEL_WALK: *result = BotTravel_Walk(ms, &reach); break;
3321
case TRAVEL_CROUCH: *result = BotTravel_Crouch(ms, &reach); break;
3322
case TRAVEL_BARRIERJUMP: *result = BotTravel_BarrierJump(ms, &reach); break;
3323
case TRAVEL_LADDER: *result = BotTravel_Ladder(ms, &reach); break;
3324
case TRAVEL_WALKOFFLEDGE: *result = BotTravel_WalkOffLedge(ms, &reach); break;
3325
case TRAVEL_JUMP: *result = BotTravel_Jump(ms, &reach); break;
3326
case TRAVEL_SWIM: *result = BotTravel_Swim(ms, &reach); break;
3327
case TRAVEL_WATERJUMP: *result = BotTravel_WaterJump(ms, &reach); break;
3328
case TRAVEL_TELEPORT: *result = BotTravel_Teleport(ms, &reach); break;
3329
case TRAVEL_ELEVATOR: *result = BotTravel_Elevator(ms, &reach); break;
3330
case TRAVEL_GRAPPLEHOOK: *result = BotTravel_Grapple(ms, &reach); break;
3331
case TRAVEL_ROCKETJUMP: *result = BotTravel_RocketJump(ms, &reach); break;
3332
case TRAVEL_BFGJUMP: *result = BotTravel_BFGJump(ms, &reach); break;
3333
case TRAVEL_JUMPPAD: *result = BotTravel_JumpPad(ms, &reach); break;
3334
case TRAVEL_FUNCBOB: *result = BotTravel_FuncBobbing(ms, &reach); break;
3337
botimport.Print(PRT_FATAL, "travel type %d not implemented yet\n", (reach.traveltype & TRAVELTYPE_MASK));
3341
result->traveltype = reach.traveltype;
3342
result->flags |= resultflags;
3346
result->failure = qtrue;
3347
result->flags |= resultflags;
3348
Com_Memset(&reach, 0, sizeof(aas_reachability_t));
3353
if (result->failure)
3355
botimport.Print(PRT_MESSAGE, "client %d: movement failure in ", ms->client);
3356
AAS_PrintTravelType(reach.traveltype & TRAVELTYPE_MASK);
3357
botimport.Print(PRT_MESSAGE, "\n");
3364
int i, numareas, areas[16];
3367
//special handling of jump pads when the bot uses a jump pad without knowing it
3368
foundjumppad = qfalse;
3369
VectorMA(ms->origin, -2 * ms->thinktime, ms->velocity, end);
3370
numareas = AAS_TraceAreas(ms->origin, end, areas, NULL, 16);
3371
for (i = numareas-1; i >= 0; i--)
3373
if (AAS_AreaJumpPad(areas[i]))
3375
//botimport.Print(PRT_MESSAGE, "client %d used a jumppad without knowing, area %d\n", ms->client, areas[i]);
3376
foundjumppad = qtrue;
3377
lastreachnum = BotGetReachabilityToGoal(end, areas[i],
3378
ms->lastgoalareanum, ms->lastareanum,
3379
ms->avoidreach, ms->avoidreachtimes, ms->avoidreachtries,
3380
goal, travelflags, TFL_JUMPPAD, ms->avoidspots, ms->numavoidspots, NULL);
3383
ms->lastreachnum = lastreachnum;
3384
ms->lastareanum = areas[i];
3385
//botimport.Print(PRT_MESSAGE, "found jumppad reachability\n");
3390
for (lastreachnum = AAS_NextAreaReachability(areas[i], 0); lastreachnum;
3391
lastreachnum = AAS_NextAreaReachability(areas[i], lastreachnum))
3393
//get the reachability from the number
3394
AAS_ReachabilityFromNum(lastreachnum, &reach);
3395
if ((reach.traveltype & TRAVELTYPE_MASK) == TRAVEL_JUMPPAD)
3397
ms->lastreachnum = lastreachnum;
3398
ms->lastareanum = areas[i];
3399
//botimport.Print(PRT_MESSAGE, "found jumppad reachability hard!!\n");
3403
if (lastreachnum) break;
3409
//if a jumppad is found with the trace but no reachability is found
3410
if (foundjumppad && !ms->lastreachnum)
3412
botimport.Print(PRT_MESSAGE, "client %d didn't find jumppad reachability\n", ms->client);
3416
if (ms->lastreachnum)
3418
//botimport.Print(PRT_MESSAGE, "%s: NOT onground, swimming or against ladder\n", ClientName(ms->entitynum-1));
3419
AAS_ReachabilityFromNum(ms->lastreachnum, &reach);
3420
result->traveltype = reach.traveltype;
3422
//botimport.Print(PRT_MESSAGE, "client %d finish: ", ms->client);
3423
//AAS_PrintTravelType(reach.traveltype & TRAVELTYPE_MASK);
3424
//botimport.Print(PRT_MESSAGE, "\n");
3427
switch(reach.traveltype & TRAVELTYPE_MASK)
3429
case TRAVEL_WALK: *result = BotTravel_Walk(ms, &reach); break;//BotFinishTravel_Walk(ms, &reach); break;
3430
case TRAVEL_CROUCH: /*do nothing*/ break;
3431
case TRAVEL_BARRIERJUMP: *result = BotFinishTravel_BarrierJump(ms, &reach); break;
3432
case TRAVEL_LADDER: *result = BotTravel_Ladder(ms, &reach); break;
3433
case TRAVEL_WALKOFFLEDGE: *result = BotFinishTravel_WalkOffLedge(ms, &reach); break;
3434
case TRAVEL_JUMP: *result = BotFinishTravel_Jump(ms, &reach); break;
3435
case TRAVEL_SWIM: *result = BotTravel_Swim(ms, &reach); break;
3436
case TRAVEL_WATERJUMP: *result = BotFinishTravel_WaterJump(ms, &reach); break;
3437
case TRAVEL_TELEPORT: /*do nothing*/ break;
3438
case TRAVEL_ELEVATOR: *result = BotFinishTravel_Elevator(ms, &reach); break;
3439
case TRAVEL_GRAPPLEHOOK: *result = BotTravel_Grapple(ms, &reach); break;
3440
case TRAVEL_ROCKETJUMP:
3441
case TRAVEL_BFGJUMP: *result = BotFinishTravel_WeaponJump(ms, &reach); break;
3442
case TRAVEL_JUMPPAD: *result = BotFinishTravel_JumpPad(ms, &reach); break;
3443
case TRAVEL_FUNCBOB: *result = BotFinishTravel_FuncBobbing(ms, &reach); break;
3446
botimport.Print(PRT_FATAL, "(last) travel type %d not implemented yet\n", (reach.traveltype & TRAVELTYPE_MASK));
3450
result->traveltype = reach.traveltype;
3454
if (result->failure)
3456
botimport.Print(PRT_MESSAGE, "client %d: movement failure in finish ", ms->client);
3457
AAS_PrintTravelType(reach.traveltype & TRAVELTYPE_MASK);
3458
botimport.Print(PRT_MESSAGE, "\n");
3464
//FIXME: is it right to do this here?
3465
if (result->blocked) ms->reachability_time -= 10 * ms->thinktime;
3466
//copy the last origin
3467
VectorCopy(ms->origin, ms->lastorigin);
3468
//return the movement result
3470
} //end of the function BotMoveToGoal
3471
//===========================================================================
3475
// Changes Globals: -
3476
//===========================================================================
3477
void BotResetAvoidReach(int movestate)
3479
bot_movestate_t *ms;
3481
ms = BotMoveStateFromHandle(movestate);
3483
Com_Memset(ms->avoidreach, 0, MAX_AVOIDREACH * sizeof(int));
3484
Com_Memset(ms->avoidreachtimes, 0, MAX_AVOIDREACH * sizeof(float));
3485
Com_Memset(ms->avoidreachtries, 0, MAX_AVOIDREACH * sizeof(int));
3486
} //end of the function BotResetAvoidReach
3487
//===========================================================================
3491
// Changes Globals: -
3492
//===========================================================================
3493
void BotResetLastAvoidReach(int movestate)
3497
bot_movestate_t *ms;
3499
ms = BotMoveStateFromHandle(movestate);
3503
for (i = 0; i < MAX_AVOIDREACH; i++)
3505
if (ms->avoidreachtimes[i] > latesttime)
3507
latesttime = ms->avoidreachtimes[i];
3513
ms->avoidreachtimes[latest] = 0;
3514
if (ms->avoidreachtries[i] > 0) ms->avoidreachtries[latest]--;
3516
} //end of the function BotResetLastAvoidReach
3517
//===========================================================================
3521
// Changes Globals: -
3522
//===========================================================================
3523
void BotResetMoveState(int movestate)
3525
bot_movestate_t *ms;
3527
ms = BotMoveStateFromHandle(movestate);
3529
Com_Memset(ms, 0, sizeof(bot_movestate_t));
3530
} //end of the function BotResetMoveState
3531
//===========================================================================
3535
// Changes Globals: -
3536
//===========================================================================
3537
int BotSetupMoveAI(void)
3539
BotSetBrushModelTypes();
3540
sv_maxstep = LibVar("sv_step", "18");
3541
sv_maxbarrier = LibVar("sv_maxbarrier", "32");
3542
sv_gravity = LibVar("sv_gravity", "800");
3543
weapindex_rocketlauncher = LibVar("weapindex_rocketlauncher", "5");
3544
weapindex_bfg10k = LibVar("weapindex_bfg10k", "9");
3545
weapindex_grapple = LibVar("weapindex_grapple", "10");
3546
entitytypemissile = LibVar("entitytypemissile", "3");
3547
offhandgrapple = LibVar("offhandgrapple", "0");
3548
cmd_grappleon = LibVar("cmd_grappleon", "grappleon");
3549
cmd_grappleoff = LibVar("cmd_grappleoff", "grappleoff");
3550
return BLERR_NOERROR;
3551
} //end of the function BotSetupMoveAI
3552
//===========================================================================
3556
// Changes Globals: -
3557
//===========================================================================
3558
void BotShutdownMoveAI(void)
3562
for (i = 1; i <= MAX_CLIENTS; i++)
3564
if (botmovestates[i])
3566
FreeMemory(botmovestates[i]);
3567
botmovestates[i] = NULL;
3570
} //end of the function BotShutdownMoveAI