1 /*
2 ===========================================================================
3 Copyright (C) 1999-2005 Id Software, Inc.
4
5 This file is part of Quake III Arena source code.
6
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.
11
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.
16
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 ===========================================================================
21 */
22
23 /*****************************************************************************
24 * name: be_ai_move.c
25 *
26 * desc: bot movement AI
27 *
28 * $Archive: /MissionPack/code/botlib/be_ai_move.c $
29 *
30 *****************************************************************************/
31
32 #include "../qcommon/q_shared.h"
33 #include "l_memory.h"
34 #include "l_libvar.h"
35 #include "l_utils.h"
36 #include "l_script.h"
37 #include "l_precomp.h"
38 #include "l_struct.h"
39 #include "aasfile.h"
40 #include "botlib.h"
41 #include "be_aas.h"
42 #include "be_aas_funcs.h"
43 #include "be_interface.h"
44
45 #include "be_ea.h"
46 #include "be_ai_goal.h"
47 #include "be_ai_move.h"
48
49
50 //#define DEBUG_AI_MOVE
51 //#define DEBUG_ELEVATOR
52 //#define DEBUG_GRAPPLE
53
54 //movement state
55 //NOTE: the moveflags MFL_ONGROUND, MFL_TELEPORTED, MFL_WATERJUMP and
56 // MFL_GRAPPLEPULL must be set outside the movement code
57 typedef struct bot_movestate_s
58 {
59 //input vars (all set outside the movement code)
60 vec3_t origin; //origin of the bot
61 vec3_t velocity; //velocity of the bot
62 vec3_t viewoffset; //view offset
63 int entitynum; //entity number of the bot
64 int client; //client number of the bot
65 float thinktime; //time the bot thinks
66 int presencetype; //presencetype of the bot
67 vec3_t viewangles; //view angles of the bot
68 //state vars
69 int areanum; //area the bot is in
70 int lastareanum; //last area the bot was in
71 int lastgoalareanum; //last goal area number
72 int lastreachnum; //last reachability number
73 vec3_t lastorigin; //origin previous cycle
74 int reachareanum; //area number of the reachabilty
75 int moveflags; //movement flags
76 int jumpreach; //set when jumped
77 float grapplevisible_time; //last time the grapple was visible
78 float lastgrappledist; //last distance to the grapple end
79 float reachability_time; //time to use current reachability
80 int avoidreach[MAX_AVOIDREACH]; //reachabilities to avoid
81 float avoidreachtimes[MAX_AVOIDREACH]; //times to avoid the reachabilities
82 int avoidreachtries[MAX_AVOIDREACH]; //number of tries before avoiding
83 //
84 bot_avoidspot_t avoidspots[MAX_AVOIDSPOTS]; //spots to avoid
85 int numavoidspots;
86 } bot_movestate_t;
87
88 //used to avoid reachability links for some time after being used
89 #define AVOIDREACH
90 #define AVOIDREACH_TIME 6 //avoid links for 6 seconds after use
91 #define AVOIDREACH_TRIES 4
92 //prediction times
93 #define PREDICTIONTIME_JUMP 3 //in seconds
94 #define PREDICTIONTIME_MOVE 2 //in seconds
95 //weapon indexes for weapon jumping
96 #define WEAPONINDEX_ROCKET_LAUNCHER 5
97 #define WEAPONINDEX_BFG 9
98
99 #define MODELTYPE_FUNC_PLAT 1
100 #define MODELTYPE_FUNC_BOB 2
101 #define MODELTYPE_FUNC_DOOR 3
102 #define MODELTYPE_FUNC_STATIC 4
103
104 libvar_t *sv_maxstep;
105 libvar_t *sv_maxbarrier;
106 libvar_t *sv_gravity;
107 libvar_t *weapindex_rocketlauncher;
108 libvar_t *weapindex_bfg10k;
109 libvar_t *weapindex_grapple;
110 libvar_t *entitytypemissile;
111 libvar_t *offhandgrapple;
112 libvar_t *cmd_grappleoff;
113 libvar_t *cmd_grappleon;
114 //type of model, func_plat or func_bobbing
115 int modeltypes[MAX_MODELS];
116
117 bot_movestate_t *botmovestates[MAX_CLIENTS+1];
118
119 //========================================================================
120 //
121 // Parameter: -
122 // Returns: -
123 // Changes Globals: -
124 //========================================================================
BotAllocMoveState(void)125 int BotAllocMoveState(void)
126 {
127 int i;
128
129 for (i = 1; i <= MAX_CLIENTS; i++)
130 {
131 if (!botmovestates[i])
132 {
133 botmovestates[i] = GetClearedMemory(sizeof(bot_movestate_t));
134 return i;
135 } //end if
136 } //end for
137 return 0;
138 } //end of the function BotAllocMoveState
139 //========================================================================
140 //
141 // Parameter: -
142 // Returns: -
143 // Changes Globals: -
144 //========================================================================
BotFreeMoveState(int handle)145 void BotFreeMoveState(int handle)
146 {
147 if (handle <= 0 || handle > MAX_CLIENTS)
148 {
149 botimport.Print(PRT_FATAL, "move state handle %d out of range\n", handle);
150 return;
151 } //end if
152 if (!botmovestates[handle])
153 {
154 botimport.Print(PRT_FATAL, "invalid move state %d\n", handle);
155 return;
156 } //end if
157 FreeMemory(botmovestates[handle]);
158 botmovestates[handle] = NULL;
159 } //end of the function BotFreeMoveState
160 //========================================================================
161 //
162 // Parameter: -
163 // Returns: -
164 // Changes Globals: -
165 //========================================================================
BotMoveStateFromHandle(int handle)166 bot_movestate_t *BotMoveStateFromHandle(int handle)
167 {
168 if (handle <= 0 || handle > MAX_CLIENTS)
169 {
170 botimport.Print(PRT_FATAL, "move state handle %d out of range\n", handle);
171 return NULL;
172 } //end if
173 if (!botmovestates[handle])
174 {
175 botimport.Print(PRT_FATAL, "invalid move state %d\n", handle);
176 return NULL;
177 } //end if
178 return botmovestates[handle];
179 } //end of the function BotMoveStateFromHandle
180 //========================================================================
181 //
182 // Parameter: -
183 // Returns: -
184 // Changes Globals: -
185 //========================================================================
BotInitMoveState(int handle,bot_initmove_t * initmove)186 void BotInitMoveState(int handle, bot_initmove_t *initmove)
187 {
188 bot_movestate_t *ms;
189
190 ms = BotMoveStateFromHandle(handle);
191 if (!ms) return;
192 VectorCopy(initmove->origin, ms->origin);
193 VectorCopy(initmove->velocity, ms->velocity);
194 VectorCopy(initmove->viewoffset, ms->viewoffset);
195 ms->entitynum = initmove->entitynum;
196 ms->client = initmove->client;
197 ms->thinktime = initmove->thinktime;
198 ms->presencetype = initmove->presencetype;
199 VectorCopy(initmove->viewangles, ms->viewangles);
200 //
201 ms->moveflags &= ~MFL_ONGROUND;
202 if (initmove->or_moveflags & MFL_ONGROUND) ms->moveflags |= MFL_ONGROUND;
203 ms->moveflags &= ~MFL_TELEPORTED;
204 if (initmove->or_moveflags & MFL_TELEPORTED) ms->moveflags |= MFL_TELEPORTED;
205 ms->moveflags &= ~MFL_WATERJUMP;
206 if (initmove->or_moveflags & MFL_WATERJUMP) ms->moveflags |= MFL_WATERJUMP;
207 ms->moveflags &= ~MFL_WALK;
208 if (initmove->or_moveflags & MFL_WALK) ms->moveflags |= MFL_WALK;
209 ms->moveflags &= ~MFL_GRAPPLEPULL;
210 if (initmove->or_moveflags & MFL_GRAPPLEPULL) ms->moveflags |= MFL_GRAPPLEPULL;
211 } //end of the function BotInitMoveState
212 //========================================================================
213 //
214 // Parameter: -
215 // Returns: -
216 // Changes Globals: -
217 //========================================================================
AngleDiff(float ang1,float ang2)218 float AngleDiff(float ang1, float ang2)
219 {
220 float diff;
221
222 diff = ang1 - ang2;
223 if (ang1 > ang2)
224 {
225 if (diff > 180.0) diff -= 360.0;
226 } //end if
227 else
228 {
229 if (diff < -180.0) diff += 360.0;
230 } //end else
231 return diff;
232 } //end of the function AngleDiff
233 //===========================================================================
234 //
235 // Parameter: -
236 // Returns: -
237 // Changes Globals: -
238 //===========================================================================
BotFuzzyPointReachabilityArea(vec3_t origin)239 int BotFuzzyPointReachabilityArea(vec3_t origin)
240 {
241 int firstareanum, j, x, y, z;
242 int areas[10], numareas, areanum, bestareanum;
243 float dist, bestdist;
244 vec3_t points[10], v, end;
245
246 firstareanum = 0;
247 areanum = AAS_PointAreaNum(origin);
248 if (areanum)
249 {
250 firstareanum = areanum;
251 if (AAS_AreaReachability(areanum)) return areanum;
252 } //end if
253 VectorCopy(origin, end);
254 end[2] += 4;
255 numareas = AAS_TraceAreas(origin, end, areas, points, 10);
256 for (j = 0; j < numareas; j++)
257 {
258 if (AAS_AreaReachability(areas[j])) return areas[j];
259 } //end for
260 bestdist = 999999;
261 bestareanum = 0;
262 for (z = 1; z >= -1; z -= 1)
263 {
264 for (x = 1; x >= -1; x -= 1)
265 {
266 for (y = 1; y >= -1; y -= 1)
267 {
268 VectorCopy(origin, end);
269 end[0] += x * 8;
270 end[1] += y * 8;
271 end[2] += z * 12;
272 numareas = AAS_TraceAreas(origin, end, areas, points, 10);
273 for (j = 0; j < numareas; j++)
274 {
275 if (AAS_AreaReachability(areas[j]))
276 {
277 VectorSubtract(points[j], origin, v);
278 dist = VectorLength(v);
279 if (dist < bestdist)
280 {
281 bestareanum = areas[j];
282 bestdist = dist;
283 } //end if
284 } //end if
285 if (!firstareanum) firstareanum = areas[j];
286 } //end for
287 } //end for
288 } //end for
289 if (bestareanum) return bestareanum;
290 } //end for
291 return firstareanum;
292 } //end of the function BotFuzzyPointReachabilityArea
293 //===========================================================================
294 //
295 // Parameter: -
296 // Returns: -
297 // Changes Globals: -
298 //===========================================================================
BotReachabilityArea(vec3_t origin,int client)299 int BotReachabilityArea(vec3_t origin, int client)
300 {
301 int modelnum, modeltype, reachnum, areanum;
302 aas_reachability_t reach;
303 vec3_t org, end, mins, maxs, up = {0, 0, 1};
304 bsp_trace_t bsptrace;
305 aas_trace_t trace;
306
307 //check if the bot is standing on something
308 AAS_PresenceTypeBoundingBox(PRESENCE_CROUCH, mins, maxs);
309 VectorMA(origin, -3, up, end);
310 bsptrace = AAS_Trace(origin, mins, maxs, end, client, CONTENTS_SOLID|CONTENTS_PLAYERCLIP);
311 if (!bsptrace.startsolid && bsptrace.fraction < 1 && bsptrace.ent != ENTITYNUM_NONE)
312 {
313 //if standing on the world the bot should be in a valid area
314 if (bsptrace.ent == ENTITYNUM_WORLD)
315 {
316 return BotFuzzyPointReachabilityArea(origin);
317 } //end if
318
319 modelnum = AAS_EntityModelindex(bsptrace.ent);
320 modeltype = modeltypes[modelnum];
321
322 //if standing on a func_plat or func_bobbing then the bot is assumed to be
323 //in the area the reachability points to
324 if (modeltype == MODELTYPE_FUNC_PLAT || modeltype == MODELTYPE_FUNC_BOB)
325 {
326 reachnum = AAS_NextModelReachability(0, modelnum);
327 if (reachnum)
328 {
329 AAS_ReachabilityFromNum(reachnum, &reach);
330 return reach.areanum;
331 } //end if
332 } //end else if
333
334 //if the bot is swimming the bot should be in a valid area
335 if (AAS_Swimming(origin))
336 {
337 return BotFuzzyPointReachabilityArea(origin);
338 } //end if
339 //
340 areanum = BotFuzzyPointReachabilityArea(origin);
341 //if the bot is in an area with reachabilities
342 if (areanum && AAS_AreaReachability(areanum)) return areanum;
343 //trace down till the ground is hit because the bot is standing on some other entity
344 VectorCopy(origin, org);
345 VectorCopy(org, end);
346 end[2] -= 800;
347 trace = AAS_TraceClientBBox(org, end, PRESENCE_CROUCH, -1);
348 if (!trace.startsolid)
349 {
350 VectorCopy(trace.endpos, org);
351 } //end if
352 //
353 return BotFuzzyPointReachabilityArea(org);
354 } //end if
355 //
356 return BotFuzzyPointReachabilityArea(origin);
357 } //end of the function BotReachabilityArea
358 //===========================================================================
359 // returns the reachability area the bot is in
360 //
361 // Parameter: -
362 // Returns: -
363 // Changes Globals: -
364 //===========================================================================
365 /*
366 int BotReachabilityArea(vec3_t origin, int testground)
367 {
368 int firstareanum, i, j, x, y, z;
369 int areas[10], numareas, areanum, bestareanum;
370 float dist, bestdist;
371 vec3_t org, end, points[10], v;
372 aas_trace_t trace;
373
374 firstareanum = 0;
375 for (i = 0; i < 2; i++)
376 {
377 VectorCopy(origin, org);
378 //if test at the ground (used when bot is standing on an entity)
379 if (i > 0)
380 {
381 VectorCopy(origin, end);
382 end[2] -= 800;
383 trace = AAS_TraceClientBBox(origin, end, PRESENCE_CROUCH, -1);
384 if (!trace.startsolid)
385 {
386 VectorCopy(trace.endpos, org);
387 } //end if
388 } //end if
389
390 firstareanum = 0;
391 areanum = AAS_PointAreaNum(org);
392 if (areanum)
393 {
394 firstareanum = areanum;
395 if (AAS_AreaReachability(areanum)) return areanum;
396 } //end if
397 bestdist = 999999;
398 bestareanum = 0;
399 for (z = 1; z >= -1; z -= 1)
400 {
401 for (x = 1; x >= -1; x -= 1)
402 {
403 for (y = 1; y >= -1; y -= 1)
404 {
405 VectorCopy(org, end);
406 end[0] += x * 8;
407 end[1] += y * 8;
408 end[2] += z * 12;
409 numareas = AAS_TraceAreas(org, end, areas, points, 10);
410 for (j = 0; j < numareas; j++)
411 {
412 if (AAS_AreaReachability(areas[j]))
413 {
414 VectorSubtract(points[j], org, v);
415 dist = VectorLength(v);
416 if (dist < bestdist)
417 {
418 bestareanum = areas[j];
419 bestdist = dist;
420 } //end if
421 } //end if
422 } //end for
423 } //end for
424 } //end for
425 if (bestareanum) return bestareanum;
426 } //end for
427 if (!testground) break;
428 } //end for
429 //#ifdef DEBUG
430 //botimport.Print(PRT_MESSAGE, "no reachability area\n");
431 //#endif //DEBUG
432 return firstareanum;
433 } //end of the function BotReachabilityArea*/
434 //===========================================================================
435 //
436 // Parameter: -
437 // Returns: -
438 // Changes Globals: -
439 //===========================================================================
BotOnMover(vec3_t origin,int entnum,aas_reachability_t * reach)440 int BotOnMover(vec3_t origin, int entnum, aas_reachability_t *reach)
441 {
442 int i, modelnum;
443 vec3_t mins, maxs, modelorigin, org, end;
444 vec3_t angles = {0, 0, 0};
445 vec3_t boxmins = {-16, -16, -8}, boxmaxs = {16, 16, 8};
446 bsp_trace_t trace;
447
448 modelnum = reach->facenum & 0x0000FFFF;
449 //get some bsp model info
450 AAS_BSPModelMinsMaxsOrigin(modelnum, angles, mins, maxs, NULL);
451 //
452 if (!AAS_OriginOfMoverWithModelNum(modelnum, modelorigin))
453 {
454 botimport.Print(PRT_MESSAGE, "no entity with model %d\n", modelnum);
455 return qfalse;
456 } //end if
457 //
458 for (i = 0; i < 2; i++)
459 {
460 if (origin[i] > modelorigin[i] + maxs[i] + 16) return qfalse;
461 if (origin[i] < modelorigin[i] + mins[i] - 16) return qfalse;
462 } //end for
463 //
464 VectorCopy(origin, org);
465 org[2] += 24;
466 VectorCopy(origin, end);
467 end[2] -= 48;
468 //
469 trace = AAS_Trace(org, boxmins, boxmaxs, end, entnum, CONTENTS_SOLID|CONTENTS_PLAYERCLIP);
470 if (!trace.startsolid && !trace.allsolid)
471 {
472 //NOTE: the reachability face number is the model number of the elevator
473 if (trace.ent != ENTITYNUM_NONE && AAS_EntityModelNum(trace.ent) == modelnum)
474 {
475 return qtrue;
476 } //end if
477 } //end if
478 return qfalse;
479 } //end of the function BotOnMover
480 //===========================================================================
481 //
482 // Parameter: -
483 // Returns: -
484 // Changes Globals: -
485 //===========================================================================
MoverDown(aas_reachability_t * reach)486 int MoverDown(aas_reachability_t *reach)
487 {
488 int modelnum;
489 vec3_t mins, maxs, origin;
490 vec3_t angles = {0, 0, 0};
491
492 modelnum = reach->facenum & 0x0000FFFF;
493 //get some bsp model info
494 AAS_BSPModelMinsMaxsOrigin(modelnum, angles, mins, maxs, origin);
495 //
496 if (!AAS_OriginOfMoverWithModelNum(modelnum, origin))
497 {
498 botimport.Print(PRT_MESSAGE, "no entity with model %d\n", modelnum);
499 return qfalse;
500 } //end if
501 //if the top of the plat is below the reachability start point
502 if (origin[2] + maxs[2] < reach->start[2]) return qtrue;
503 return qfalse;
504 } //end of the function MoverDown
505 //========================================================================
506 //
507 // Parameter: -
508 // Returns: -
509 // Changes Globals: -
510 //========================================================================
BotSetBrushModelTypes(void)511 void BotSetBrushModelTypes(void)
512 {
513 int ent, modelnum;
514 char classname[MAX_EPAIRKEY], model[MAX_EPAIRKEY];
515
516 Com_Memset(modeltypes, 0, MAX_MODELS * sizeof(int));
517 //
518 for (ent = AAS_NextBSPEntity(0); ent; ent = AAS_NextBSPEntity(ent))
519 {
520 if (!AAS_ValueForBSPEpairKey(ent, "classname", classname, MAX_EPAIRKEY)) continue;
521 if (!AAS_ValueForBSPEpairKey(ent, "model", model, MAX_EPAIRKEY)) continue;
522 if (model[0]) modelnum = atoi(model+1);
523 else modelnum = 0;
524
525 if (modelnum < 0 || modelnum > MAX_MODELS)
526 {
527 botimport.Print(PRT_MESSAGE, "entity %s model number out of range\n", classname);
528 continue;
529 } //end if
530
531 if (!Q_stricmp(classname, "func_bobbing"))
532 modeltypes[modelnum] = MODELTYPE_FUNC_BOB;
533 else if (!Q_stricmp(classname, "func_plat"))
534 modeltypes[modelnum] = MODELTYPE_FUNC_PLAT;
535 else if (!Q_stricmp(classname, "func_door"))
536 modeltypes[modelnum] = MODELTYPE_FUNC_DOOR;
537 else if (!Q_stricmp(classname, "func_static"))
538 modeltypes[modelnum] = MODELTYPE_FUNC_STATIC;
539 } //end for
540 } //end of the function BotSetBrushModelTypes
541 //===========================================================================
542 //
543 // Parameter: -
544 // Returns: -
545 // Changes Globals: -
546 //===========================================================================
BotOnTopOfEntity(bot_movestate_t * ms)547 int BotOnTopOfEntity(bot_movestate_t *ms)
548 {
549 vec3_t mins, maxs, end, up = {0, 0, 1};
550 bsp_trace_t trace;
551
552 AAS_PresenceTypeBoundingBox(ms->presencetype, mins, maxs);
553 VectorMA(ms->origin, -3, up, end);
554 trace = AAS_Trace(ms->origin, mins, maxs, end, ms->entitynum, CONTENTS_SOLID|CONTENTS_PLAYERCLIP);
555 if (!trace.startsolid && (trace.ent != ENTITYNUM_WORLD && trace.ent != ENTITYNUM_NONE) )
556 {
557 return trace.ent;
558 } //end if
559 return -1;
560 } //end of the function BotOnTopOfEntity
561 //===========================================================================
562 //
563 // Parameter: -
564 // Returns: -
565 // Changes Globals: -
566 //===========================================================================
BotValidTravel(vec3_t origin,aas_reachability_t * reach,int travelflags)567 int BotValidTravel(vec3_t origin, aas_reachability_t *reach, int travelflags)
568 {
569 //if the reachability uses an unwanted travel type
570 if (AAS_TravelFlagForType(reach->traveltype) & ~travelflags) return qfalse;
571 //don't go into areas with bad travel types
572 if (AAS_AreaContentsTravelFlags(reach->areanum) & ~travelflags) return qfalse;
573 return qtrue;
574 } //end of the function BotValidTravel
575 //===========================================================================
576 //
577 // Parameter: -
578 // Returns: -
579 // Changes Globals: -
580 //===========================================================================
BotAddToAvoidReach(bot_movestate_t * ms,int number,float avoidtime)581 void BotAddToAvoidReach(bot_movestate_t *ms, int number, float avoidtime)
582 {
583 int i;
584
585 for (i = 0; i < MAX_AVOIDREACH; i++)
586 {
587 if (ms->avoidreach[i] == number)
588 {
589 if (ms->avoidreachtimes[i] > AAS_Time()) ms->avoidreachtries[i]++;
590 else ms->avoidreachtries[i] = 1;
591 ms->avoidreachtimes[i] = AAS_Time() + avoidtime;
592 return;
593 } //end if
594 } //end for
595 //add the reachability to the reachabilities to avoid for a while
596 for (i = 0; i < MAX_AVOIDREACH; i++)
597 {
598 if (ms->avoidreachtimes[i] < AAS_Time())
599 {
600 ms->avoidreach[i] = number;
601 ms->avoidreachtimes[i] = AAS_Time() + avoidtime;
602 ms->avoidreachtries[i] = 1;
603 return;
604 } //end if
605 } //end for
606 } //end of the function BotAddToAvoidReach
607 //===========================================================================
608 //
609 // Parameter: -
610 // Returns: -
611 // Changes Globals: -
612 //===========================================================================
DistanceFromLineSquared(vec3_t p,vec3_t lp1,vec3_t lp2)613 float DistanceFromLineSquared(vec3_t p, vec3_t lp1, vec3_t lp2)
614 {
615 vec3_t proj, dir;
616 int j;
617
618 AAS_ProjectPointOntoVector(p, lp1, lp2, proj);
619 for (j = 0; j < 3; j++)
620 if ((proj[j] > lp1[j] && proj[j] > lp2[j]) ||
621 (proj[j] < lp1[j] && proj[j] < lp2[j]))
622 break;
623 if (j < 3) {
624 if (fabs(proj[j] - lp1[j]) < fabs(proj[j] - lp2[j]))
625 VectorSubtract(p, lp1, dir);
626 else
627 VectorSubtract(p, lp2, dir);
628 return VectorLengthSquared(dir);
629 }
630 VectorSubtract(p, proj, dir);
631 return VectorLengthSquared(dir);
632 } //end of the function DistanceFromLineSquared
633 //===========================================================================
634 //
635 // Parameter: -
636 // Returns: -
637 // Changes Globals: -
638 //===========================================================================
VectorDistanceSquared(vec3_t p1,vec3_t p2)639 float VectorDistanceSquared(vec3_t p1, vec3_t p2)
640 {
641 vec3_t dir;
642 VectorSubtract(p2, p1, dir);
643 return VectorLengthSquared(dir);
644 } //end of the function VectorDistanceSquared
645 //===========================================================================
646 //
647 // Parameter: -
648 // Returns: -
649 // Changes Globals: -
650 //===========================================================================
BotAvoidSpots(vec3_t origin,aas_reachability_t * reach,bot_avoidspot_t * avoidspots,int numavoidspots)651 int BotAvoidSpots(vec3_t origin, aas_reachability_t *reach, bot_avoidspot_t *avoidspots, int numavoidspots)
652 {
653 int checkbetween, i, type;
654 float squareddist, squaredradius;
655
656 switch(reach->traveltype & TRAVELTYPE_MASK)
657 {
658 case TRAVEL_WALK: checkbetween = qtrue; break;
659 case TRAVEL_CROUCH: checkbetween = qtrue; break;
660 case TRAVEL_BARRIERJUMP: checkbetween = qtrue; break;
661 case TRAVEL_LADDER: checkbetween = qtrue; break;
662 case TRAVEL_WALKOFFLEDGE: checkbetween = qfalse; break;
663 case TRAVEL_JUMP: checkbetween = qfalse; break;
664 case TRAVEL_SWIM: checkbetween = qtrue; break;
665 case TRAVEL_WATERJUMP: checkbetween = qtrue; break;
666 case TRAVEL_TELEPORT: checkbetween = qfalse; break;
667 case TRAVEL_ELEVATOR: checkbetween = qfalse; break;
668 case TRAVEL_GRAPPLEHOOK: checkbetween = qfalse; break;
669 case TRAVEL_ROCKETJUMP: checkbetween = qfalse; break;
670 case TRAVEL_BFGJUMP: checkbetween = qfalse; break;
671 case TRAVEL_JUMPPAD: checkbetween = qfalse; break;
672 case TRAVEL_FUNCBOB: checkbetween = qfalse; break;
673 default: checkbetween = qtrue; break;
674 } //end switch
675
676 type = AVOID_CLEAR;
677 for (i = 0; i < numavoidspots; i++)
678 {
679 squaredradius = Square(avoidspots[i].radius);
680 squareddist = DistanceFromLineSquared(avoidspots[i].origin, origin, reach->start);
681 // if moving towards the avoid spot
682 if (squareddist < squaredradius &&
683 VectorDistanceSquared(avoidspots[i].origin, origin) > squareddist)
684 {
685 type = avoidspots[i].type;
686 } //end if
687 else if (checkbetween) {
688 squareddist = DistanceFromLineSquared(avoidspots[i].origin, reach->start, reach->end);
689 // if moving towards the avoid spot
690 if (squareddist < squaredradius &&
691 VectorDistanceSquared(avoidspots[i].origin, reach->start) > squareddist)
692 {
693 type = avoidspots[i].type;
694 } //end if
695 } //end if
696 else
697 {
698 VectorDistanceSquared(avoidspots[i].origin, reach->end);
699 // if the reachability leads closer to the avoid spot
700 if (squareddist < squaredradius &&
701 VectorDistanceSquared(avoidspots[i].origin, reach->start) > squareddist)
702 {
703 type = avoidspots[i].type;
704 } //end if
705 } //end else
706 if (type == AVOID_ALWAYS)
707 return type;
708 } //end for
709 return type;
710 } //end of the function BotAvoidSpots
711 //===========================================================================
712 //
713 // Parameter: -
714 // Returns: -
715 // Changes Globals: -
716 //===========================================================================
BotAddAvoidSpot(int movestate,vec3_t origin,float radius,int type)717 void BotAddAvoidSpot(int movestate, vec3_t origin, float radius, int type)
718 {
719 bot_movestate_t *ms;
720
721 ms = BotMoveStateFromHandle(movestate);
722 if (!ms) return;
723 if (type == AVOID_CLEAR)
724 {
725 ms->numavoidspots = 0;
726 return;
727 } //end if
728
729 if (ms->numavoidspots >= MAX_AVOIDSPOTS)
730 return;
731 VectorCopy(origin, ms->avoidspots[ms->numavoidspots].origin);
732 ms->avoidspots[ms->numavoidspots].radius = radius;
733 ms->avoidspots[ms->numavoidspots].type = type;
734 ms->numavoidspots++;
735 } //end of the function BotAddAvoidSpot
736 //===========================================================================
737 //
738 // Parameter: -
739 // Returns: -
740 // Changes Globals: -
741 //===========================================================================
BotGetReachabilityToGoal(vec3_t origin,int areanum,int lastgoalareanum,int lastareanum,int * avoidreach,float * avoidreachtimes,int * avoidreachtries,bot_goal_t * goal,int travelflags,int movetravelflags,struct bot_avoidspot_s * avoidspots,int numavoidspots,int * flags)742 int BotGetReachabilityToGoal(vec3_t origin, int areanum,
743 int lastgoalareanum, int lastareanum,
744 int *avoidreach, float *avoidreachtimes, int *avoidreachtries,
745 bot_goal_t *goal, int travelflags, int movetravelflags,
746 struct bot_avoidspot_s *avoidspots, int numavoidspots, int *flags)
747 {
748 int i, t, besttime, bestreachnum, reachnum;
749 aas_reachability_t reach;
750
751 //if not in a valid area
752 if (!areanum) return 0;
753 //
754 if (AAS_AreaDoNotEnter(areanum) || AAS_AreaDoNotEnter(goal->areanum))
755 {
756 travelflags |= TFL_DONOTENTER;
757 movetravelflags |= TFL_DONOTENTER;
758 } //end if
759 //use the routing to find the next area to go to
760 besttime = 0;
761 bestreachnum = 0;
762 //
763 for (reachnum = AAS_NextAreaReachability(areanum, 0); reachnum;
764 reachnum = AAS_NextAreaReachability(areanum, reachnum))
765 {
766 #ifdef AVOIDREACH
767 //check if it isn't an reachability to avoid
768 for (i = 0; i < MAX_AVOIDREACH; i++)
769 {
770 if (avoidreach[i] == reachnum && avoidreachtimes[i] >= AAS_Time()) break;
771 } //end for
772 if (i != MAX_AVOIDREACH && avoidreachtries[i] > AVOIDREACH_TRIES)
773 {
774 #ifdef DEBUG
775 if (bot_developer)
776 {
777 botimport.Print(PRT_MESSAGE, "avoiding reachability %d\n", avoidreach[i]);
778 } //end if
779 #endif //DEBUG
780 continue;
781 } //end if
782 #endif //AVOIDREACH
783 //get the reachability from the number
784 AAS_ReachabilityFromNum(reachnum, &reach);
785 //NOTE: do not go back to the previous area if the goal didn't change
786 //NOTE: is this actually avoidance of local routing minima between two areas???
787 if (lastgoalareanum == goal->areanum && reach.areanum == lastareanum) continue;
788 //if (AAS_AreaContentsTravelFlags(reach.areanum) & ~travelflags) continue;
789 //if the travel isn't valid
790 if (!BotValidTravel(origin, &reach, movetravelflags)) continue;
791 //get the travel time
792 t = AAS_AreaTravelTimeToGoalArea(reach.areanum, reach.end, goal->areanum, travelflags);
793 //if the goal area isn't reachable from the reachable area
794 if (!t) continue;
795 //if the bot should not use this reachability to avoid bad spots
796 if (BotAvoidSpots(origin, &reach, avoidspots, numavoidspots)) {
797 if (flags) {
798 *flags |= MOVERESULT_BLOCKEDBYAVOIDSPOT;
799 }
800 continue;
801 }
802 //add the travel time towards the area
803 t += reach.traveltime;// + AAS_AreaTravelTime(areanum, origin, reach.start);
804 //if the travel time is better than the ones already found
805 if (!besttime || t < besttime)
806 {
807 besttime = t;
808 bestreachnum = reachnum;
809 } //end if
810 } //end for
811 //
812 return bestreachnum;
813 } //end of the function BotGetReachabilityToGoal
814 //===========================================================================
815 //
816 // Parameter: -
817 // Returns: -
818 // Changes Globals: -
819 //===========================================================================
BotAddToTarget(vec3_t start,vec3_t end,float maxdist,float * dist,vec3_t target)820 int BotAddToTarget(vec3_t start, vec3_t end, float maxdist, float *dist, vec3_t target)
821 {
822 vec3_t dir;
823 float curdist;
824
825 VectorSubtract(end, start, dir);
826 curdist = VectorNormalize(dir);
827 if (*dist + curdist < maxdist)
828 {
829 VectorCopy(end, target);
830 *dist += curdist;
831 return qfalse;
832 } //end if
833 else
834 {
835 VectorMA(start, maxdist - *dist, dir, target);
836 *dist = maxdist;
837 return qtrue;
838 } //end else
839 } //end of the function BotAddToTarget
840
BotMovementViewTarget(int movestate,bot_goal_t * goal,int travelflags,float lookahead,vec3_t target)841 int BotMovementViewTarget(int movestate, bot_goal_t *goal, int travelflags, float lookahead, vec3_t target)
842 {
843 aas_reachability_t reach;
844 int reachnum, lastareanum;
845 bot_movestate_t *ms;
846 vec3_t end;
847 float dist;
848
849 ms = BotMoveStateFromHandle(movestate);
850 if (!ms) return qfalse;
851 reachnum = 0;
852 //if the bot has no goal or no last reachability
853 if (!ms->lastreachnum || !goal) return qfalse;
854
855 reachnum = ms->lastreachnum;
856 VectorCopy(ms->origin, end);
857 lastareanum = ms->lastareanum;
858 dist = 0;
859 while(reachnum && dist < lookahead)
860 {
861 AAS_ReachabilityFromNum(reachnum, &reach);
862 if (BotAddToTarget(end, reach.start, lookahead, &dist, target)) return qtrue;
863 //never look beyond teleporters
864 if ((reach.traveltype & TRAVELTYPE_MASK) == TRAVEL_TELEPORT) return qtrue;
865 //never look beyond the weapon jump point
866 if ((reach.traveltype & TRAVELTYPE_MASK) == TRAVEL_ROCKETJUMP) return qtrue;
867 if ((reach.traveltype & TRAVELTYPE_MASK) == TRAVEL_BFGJUMP) return qtrue;
868 //don't add jump pad distances
869 if ((reach.traveltype & TRAVELTYPE_MASK) != TRAVEL_JUMPPAD &&
870 (reach.traveltype & TRAVELTYPE_MASK) != TRAVEL_ELEVATOR &&
871 (reach.traveltype & TRAVELTYPE_MASK) != TRAVEL_FUNCBOB)
872 {
873 if (BotAddToTarget(reach.start, reach.end, lookahead, &dist, target)) return qtrue;
874 } //end if
875 reachnum = BotGetReachabilityToGoal(reach.end, reach.areanum,
876 ms->lastgoalareanum, lastareanum,
877 ms->avoidreach, ms->avoidreachtimes, ms->avoidreachtries,
878 goal, travelflags, travelflags, NULL, 0, NULL);
879 VectorCopy(reach.end, end);
880 lastareanum = reach.areanum;
881 if (lastareanum == goal->areanum)
882 {
883 BotAddToTarget(reach.end, goal->origin, lookahead, &dist, target);
884 return qtrue;
885 } //end if
886 } //end while
887 //
888 return qfalse;
889 } //end of the function BotMovementViewTarget
890 //===========================================================================
891 //
892 // Parameter: -
893 // Returns: -
894 // Changes Globals: -
895 //===========================================================================
BotVisible(int ent,vec3_t eye,vec3_t target)896 int BotVisible(int ent, vec3_t eye, vec3_t target)
897 {
898 bsp_trace_t trace;
899
900 trace = AAS_Trace(eye, NULL, NULL, target, ent, CONTENTS_SOLID|CONTENTS_PLAYERCLIP);
901 if (trace.fraction >= 1) return qtrue;
902 return qfalse;
903 } //end of the function BotVisible
904 //===========================================================================
905 //
906 // Parameter: -
907 // Returns: -
908 // Changes Globals: -
909 //===========================================================================
BotPredictVisiblePosition(vec3_t origin,int areanum,bot_goal_t * goal,int travelflags,vec3_t target)910 int BotPredictVisiblePosition(vec3_t origin, int areanum, bot_goal_t *goal, int travelflags, vec3_t target)
911 {
912 aas_reachability_t reach;
913 int reachnum, lastgoalareanum, lastareanum, i;
914 int avoidreach[MAX_AVOIDREACH];
915 float avoidreachtimes[MAX_AVOIDREACH];
916 int avoidreachtries[MAX_AVOIDREACH];
917 vec3_t end;
918
919 //if the bot has no goal or no last reachability
920 if (!goal) return qfalse;
921 //if the areanum is not valid
922 if (!areanum) return qfalse;
923 //if the goal areanum is not valid
924 if (!goal->areanum) return qfalse;
925
926 Com_Memset(avoidreach, 0, MAX_AVOIDREACH * sizeof(int));
927 lastgoalareanum = goal->areanum;
928 lastareanum = areanum;
929 VectorCopy(origin, end);
930 //only do 20 hops
931 for (i = 0; i < 20 && (areanum != goal->areanum); i++)
932 {
933 //
934 reachnum = BotGetReachabilityToGoal(end, areanum,
935 lastgoalareanum, lastareanum,
936 avoidreach, avoidreachtimes, avoidreachtries,
937 goal, travelflags, travelflags, NULL, 0, NULL);
938 if (!reachnum) return qfalse;
939 AAS_ReachabilityFromNum(reachnum, &reach);
940 //
941 if (BotVisible(goal->entitynum, goal->origin, reach.start))
942 {
943 VectorCopy(reach.start, target);
944 return qtrue;
945 } //end if
946 //
947 if (BotVisible(goal->entitynum, goal->origin, reach.end))
948 {
949 VectorCopy(reach.end, target);
950 return qtrue;
951 } //end if
952 //
953 if (reach.areanum == goal->areanum)
954 {
955 VectorCopy(reach.end, target);
956 return qtrue;
957 } //end if
958 //
959 lastareanum = areanum;
960 areanum = reach.areanum;
961 VectorCopy(reach.end, end);
962 //
963 } //end while
964 //
965 return qfalse;
966 } //end of the function BotPredictVisiblePosition
967 //===========================================================================
968 //
969 // Parameter: -
970 // Returns: -
971 // Changes Globals: -
972 //===========================================================================
MoverBottomCenter(aas_reachability_t * reach,vec3_t bottomcenter)973 void MoverBottomCenter(aas_reachability_t *reach, vec3_t bottomcenter)
974 {
975 int modelnum;
976 vec3_t mins, maxs, origin, mids;
977 vec3_t angles = {0, 0, 0};
978
979 modelnum = reach->facenum & 0x0000FFFF;
980 //get some bsp model info
981 AAS_BSPModelMinsMaxsOrigin(modelnum, angles, mins, maxs, origin);
982 //
983 if (!AAS_OriginOfMoverWithModelNum(modelnum, origin))
984 {
985 botimport.Print(PRT_MESSAGE, "no entity with model %d\n", modelnum);
986 } //end if
987 //get a point just above the plat in the bottom position
988 VectorAdd(mins, maxs, mids);
989 VectorMA(origin, 0.5, mids, bottomcenter);
990 bottomcenter[2] = reach->start[2];
991 } //end of the function MoverBottomCenter
992 //===========================================================================
993 //
994 // Parameter: -
995 // Returns: -
996 // Changes Globals: -
997 //===========================================================================
BotGapDistance(vec3_t origin,vec3_t hordir,int entnum)998 float BotGapDistance(vec3_t origin, vec3_t hordir, int entnum)
999 {
1000 float dist, startz;
1001 vec3_t start, end;
1002 aas_trace_t trace;
1003
1004 //do gap checking
1005 startz = origin[2];
1006 //this enables walking down stairs more fluidly
1007 {
1008 VectorCopy(origin, start);
1009 VectorCopy(origin, end);
1010 end[2] -= 60;
1011 trace = AAS_TraceClientBBox(start, end, PRESENCE_CROUCH, entnum);
1012 if (trace.fraction >= 1) return 1;
1013 startz = trace.endpos[2] + 1;
1014 }
1015 //
1016 for (dist = 8; dist <= 100; dist += 8)
1017 {
1018 VectorMA(origin, dist, hordir, start);
1019 start[2] = startz + 24;
1020 VectorCopy(start, end);
1021 end[2] -= 48 + sv_maxbarrier->value;
1022 trace = AAS_TraceClientBBox(start, end, PRESENCE_CROUCH, entnum);
1023 //if solid is found the bot can't walk any further and fall into a gap
1024 if (!trace.startsolid)
1025 {
1026 //if it is a gap
1027 if (trace.endpos[2] < startz - sv_maxstep->value - 8)
1028 {
1029 VectorCopy(trace.endpos, end);
1030 end[2] -= 20;
1031 if (AAS_PointContents(end) & CONTENTS_WATER) break;
1032 //if a gap is found slow down
1033 //botimport.Print(PRT_MESSAGE, "gap at %f\n", dist);
1034 return dist;
1035 } //end if
1036 startz = trace.endpos[2];
1037 } //end if
1038 } //end for
1039 return 0;
1040 } //end of the function BotGapDistance
1041 //===========================================================================
1042 //
1043 // Parameter: -
1044 // Returns: -
1045 // Changes Globals: -
1046 //===========================================================================
BotCheckBarrierJump(bot_movestate_t * ms,vec3_t dir,float speed)1047 int BotCheckBarrierJump(bot_movestate_t *ms, vec3_t dir, float speed)
1048 {
1049 vec3_t start, hordir, end;
1050 aas_trace_t trace;
1051
1052 VectorCopy(ms->origin, end);
1053 end[2] += sv_maxbarrier->value;
1054 //trace right up
1055 trace = AAS_TraceClientBBox(ms->origin, end, PRESENCE_NORMAL, ms->entitynum);
1056 //this shouldn't happen... but we check anyway
1057 if (trace.startsolid) return qfalse;
1058 //if very low ceiling it isn't possible to jump up to a barrier
1059 if (trace.endpos[2] - ms->origin[2] < sv_maxstep->value) return qfalse;
1060 //
1061 hordir[0] = dir[0];
1062 hordir[1] = dir[1];
1063 hordir[2] = 0;
1064 VectorNormalize(hordir);
1065 VectorMA(ms->origin, ms->thinktime * speed * 0.5, hordir, end);
1066 VectorCopy(trace.endpos, start);
1067 end[2] = trace.endpos[2];
1068 //trace from previous trace end pos horizontally in the move direction
1069 trace = AAS_TraceClientBBox(start, end, PRESENCE_NORMAL, ms->entitynum);
1070 //again this shouldn't happen
1071 if (trace.startsolid) return qfalse;
1072 //
1073 VectorCopy(trace.endpos, start);
1074 VectorCopy(trace.endpos, end);
1075 end[2] = ms->origin[2];
1076 //trace down from the previous trace end pos
1077 trace = AAS_TraceClientBBox(start, end, PRESENCE_NORMAL, ms->entitynum);
1078 //if solid
1079 if (trace.startsolid) return qfalse;
1080 //if no obstacle at all
1081 if (trace.fraction >= 1.0) return qfalse;
1082 //if less than the maximum step height
1083 if (trace.endpos[2] - ms->origin[2] < sv_maxstep->value) return qfalse;
1084 //
1085 EA_Jump(ms->client);
1086 EA_Move(ms->client, hordir, speed);
1087 ms->moveflags |= MFL_BARRIERJUMP;
1088 //there is a barrier
1089 return qtrue;
1090 } //end of the function BotCheckBarrierJump
1091 //===========================================================================
1092 //
1093 // Parameter: -
1094 // Returns: -
1095 // Changes Globals: -
1096 //===========================================================================
BotSwimInDirection(bot_movestate_t * ms,vec3_t dir,float speed,int type)1097 int BotSwimInDirection(bot_movestate_t *ms, vec3_t dir, float speed, int type)
1098 {
1099 vec3_t normdir;
1100
1101 VectorCopy(dir, normdir);
1102 VectorNormalize(normdir);
1103 EA_Move(ms->client, normdir, speed);
1104 return qtrue;
1105 } //end of the function BotSwimInDirection
1106 //===========================================================================
1107 //
1108 // Parameter: -
1109 // Returns: -
1110 // Changes Globals: -
1111 //===========================================================================
BotWalkInDirection(bot_movestate_t * ms,vec3_t dir,float speed,int type)1112 int BotWalkInDirection(bot_movestate_t *ms, vec3_t dir, float speed, int type)
1113 {
1114 vec3_t hordir, cmdmove, velocity, tmpdir, origin;
1115 int presencetype, maxframes, cmdframes, stopevent;
1116 aas_clientmove_t move;
1117 float dist;
1118
1119 if (AAS_OnGround(ms->origin, ms->presencetype, ms->entitynum)) ms->moveflags |= MFL_ONGROUND;
1120 //if the bot is on the ground
1121 if (ms->moveflags & MFL_ONGROUND)
1122 {
1123 //if there is a barrier the bot can jump on
1124 if (BotCheckBarrierJump(ms, dir, speed)) return qtrue;
1125 //remove barrier jump flag
1126 ms->moveflags &= ~MFL_BARRIERJUMP;
1127 //get the presence type for the movement
1128 if ((type & MOVE_CROUCH) && !(type & MOVE_JUMP)) presencetype = PRESENCE_CROUCH;
1129 else presencetype = PRESENCE_NORMAL;
1130 //horizontal direction
1131 hordir[0] = dir[0];
1132 hordir[1] = dir[1];
1133 hordir[2] = 0;
1134 VectorNormalize(hordir);
1135 //if the bot is not supposed to jump
1136 if (!(type & MOVE_JUMP))
1137 {
1138 //if there is a gap, try to jump over it
1139 if (BotGapDistance(ms->origin, hordir, ms->entitynum) > 0) type |= MOVE_JUMP;
1140 } //end if
1141 //get command movement
1142 VectorScale(hordir, speed, cmdmove);
1143 VectorCopy(ms->velocity, velocity);
1144 //
1145 if (type & MOVE_JUMP)
1146 {
1147 //botimport.Print(PRT_MESSAGE, "trying jump\n");
1148 cmdmove[2] = 400;
1149 maxframes = PREDICTIONTIME_JUMP / 0.1;
1150 cmdframes = 1;
1151 stopevent = SE_HITGROUND|SE_HITGROUNDDAMAGE|
1152 SE_ENTERWATER|SE_ENTERSLIME|SE_ENTERLAVA;
1153 } //end if
1154 else
1155 {
1156 maxframes = 2;
1157 cmdframes = 2;
1158 stopevent = SE_HITGROUNDDAMAGE|
1159 SE_ENTERWATER|SE_ENTERSLIME|SE_ENTERLAVA;
1160 } //end else
1161 //AAS_ClearShownDebugLines();
1162 //
1163 VectorCopy(ms->origin, origin);
1164 origin[2] += 0.5;
1165 AAS_PredictClientMovement(&move, ms->entitynum, origin, presencetype, qtrue,
1166 velocity, cmdmove, cmdframes, maxframes, 0.1f,
1167 stopevent, 0, qfalse);//qtrue);
1168 //if prediction time wasn't enough to fully predict the movement
1169 if (move.frames >= maxframes && (type & MOVE_JUMP))
1170 {
1171 //botimport.Print(PRT_MESSAGE, "client %d: max prediction frames\n", ms->client);
1172 return qfalse;
1173 } //end if
1174 //don't enter slime or lava and don't fall from too high
1175 if (move.stopevent & (SE_ENTERSLIME|SE_ENTERLAVA|SE_HITGROUNDDAMAGE))
1176 {
1177 //botimport.Print(PRT_MESSAGE, "client %d: would be hurt ", ms->client);
1178 //if (move.stopevent & SE_ENTERSLIME) botimport.Print(PRT_MESSAGE, "slime\n");
1179 //if (move.stopevent & SE_ENTERLAVA) botimport.Print(PRT_MESSAGE, "lava\n");
1180 //if (move.stopevent & SE_HITGROUNDDAMAGE) botimport.Print(PRT_MESSAGE, "hitground\n");
1181 return qfalse;
1182 } //end if
1183 //if ground was hit
1184 if (move.stopevent & SE_HITGROUND)
1185 {
1186 //check for nearby gap
1187 VectorNormalize2(move.velocity, tmpdir);
1188 dist = BotGapDistance(move.endpos, tmpdir, ms->entitynum);
1189 if (dist > 0) return qfalse;
1190 //
1191 dist = BotGapDistance(move.endpos, hordir, ms->entitynum);
1192 if (dist > 0) return qfalse;
1193 } //end if
1194 //get horizontal movement
1195 tmpdir[0] = move.endpos[0] - ms->origin[0];
1196 tmpdir[1] = move.endpos[1] - ms->origin[1];
1197 tmpdir[2] = 0;
1198 //
1199 //AAS_DrawCross(move.endpos, 4, LINECOLOR_BLUE);
1200 //the bot is blocked by something
1201 if (VectorLength(tmpdir) < speed * ms->thinktime * 0.5) return qfalse;
1202 //perform the movement
1203 if (type & MOVE_JUMP) EA_Jump(ms->client);
1204 if (type & MOVE_CROUCH) EA_Crouch(ms->client);
1205 EA_Move(ms->client, hordir, speed);
1206 //movement was succesfull
1207 return qtrue;
1208 } //end if
1209 else
1210 {
1211 if (ms->moveflags & MFL_BARRIERJUMP)
1212 {
1213 //if near the top or going down
1214 if (ms->velocity[2] < 50)
1215 {
1216 EA_Move(ms->client, dir, speed);
1217 } //end if
1218 } //end if
1219 //FIXME: do air control to avoid hazards
1220 return qtrue;
1221 } //end else
1222 } //end of the function BotWalkInDirection
1223 //===========================================================================
1224 //
1225 // Parameter: -
1226 // Returns: -
1227 // Changes Globals: -
1228 //===========================================================================
BotMoveInDirection(int movestate,vec3_t dir,float speed,int type)1229 int BotMoveInDirection(int movestate, vec3_t dir, float speed, int type)
1230 {
1231 bot_movestate_t *ms;
1232
1233 ms = BotMoveStateFromHandle(movestate);
1234 if (!ms) return qfalse;
1235 //if swimming
1236 if (AAS_Swimming(ms->origin))
1237 {
1238 return BotSwimInDirection(ms, dir, speed, type);
1239 } //end if
1240 else
1241 {
1242 return BotWalkInDirection(ms, dir, speed, type);
1243 } //end else
1244 } //end of the function BotMoveInDirection
1245 //===========================================================================
1246 //
1247 // Parameter: -
1248 // Returns: -
1249 // Changes Globals: -
1250 //===========================================================================
Intersection(vec2_t p1,vec2_t p2,vec2_t p3,vec2_t p4,vec2_t out)1251 int Intersection(vec2_t p1, vec2_t p2, vec2_t p3, vec2_t p4, vec2_t out)
1252 {
1253 float x1, dx1, dy1, x2, dx2, dy2, d;
1254
1255 dx1 = p2[0] - p1[0];
1256 dy1 = p2[1] - p1[1];
1257 dx2 = p4[0] - p3[0];
1258 dy2 = p4[1] - p3[1];
1259
1260 d = dy1 * dx2 - dx1 * dy2;
1261 if (d != 0)
1262 {
1263 x1 = p1[1] * dx1 - p1[0] * dy1;
1264 x2 = p3[1] * dx2 - p3[0] * dy2;
1265 out[0] = (int) ((dx1 * x2 - dx2 * x1) / d);
1266 out[1] = (int) ((dy1 * x2 - dy2 * x1) / d);
1267 return qtrue;
1268 } //end if
1269 else
1270 {
1271 return qfalse;
1272 } //end else
1273 } //end of the function Intersection
1274 //===========================================================================
1275 //
1276 // Parameter: -
1277 // Returns: -
1278 // Changes Globals: -
1279 //===========================================================================
BotCheckBlocked(bot_movestate_t * ms,vec3_t dir,int checkbottom,bot_moveresult_t * result)1280 void BotCheckBlocked(bot_movestate_t *ms, vec3_t dir, int checkbottom, bot_moveresult_t *result)
1281 {
1282 vec3_t mins, maxs, end, up = {0, 0, 1};
1283 bsp_trace_t trace;
1284
1285 //test for entities obstructing the bot's path
1286 AAS_PresenceTypeBoundingBox(ms->presencetype, mins, maxs);
1287 //
1288 if (fabs(DotProduct(dir, up)) < 0.7)
1289 {
1290 mins[2] += sv_maxstep->value; //if the bot can step on
1291 maxs[2] -= 10; //a little lower to avoid low ceiling
1292 } //end if
1293 VectorMA(ms->origin, 3, dir, end);
1294 trace = AAS_Trace(ms->origin, mins, maxs, end, ms->entitynum, CONTENTS_SOLID|CONTENTS_PLAYERCLIP|CONTENTS_BODY);
1295 //if not started in solid and not hitting the world entity
1296 if (!trace.startsolid && (trace.ent != ENTITYNUM_WORLD && trace.ent != ENTITYNUM_NONE) )
1297 {
1298 result->blocked = qtrue;
1299 result->blockentity = trace.ent;
1300 #ifdef DEBUG
1301 //botimport.Print(PRT_MESSAGE, "%d: BotCheckBlocked: I'm blocked\n", ms->client);
1302 #endif //DEBUG
1303 } //end if
1304 //if not in an area with reachability
1305 else if (checkbottom && !AAS_AreaReachability(ms->areanum))
1306 {
1307 //check if the bot is standing on something
1308 AAS_PresenceTypeBoundingBox(ms->presencetype, mins, maxs);
1309 VectorMA(ms->origin, -3, up, end);
1310 trace = AAS_Trace(ms->origin, mins, maxs, end, ms->entitynum, CONTENTS_SOLID|CONTENTS_PLAYERCLIP);
1311 if (!trace.startsolid && (trace.ent != ENTITYNUM_WORLD && trace.ent != ENTITYNUM_NONE) )
1312 {
1313 result->blocked = qtrue;
1314 result->blockentity = trace.ent;
1315 result->flags |= MOVERESULT_ONTOPOFOBSTACLE;
1316 #ifdef DEBUG
1317 //botimport.Print(PRT_MESSAGE, "%d: BotCheckBlocked: I'm blocked\n", ms->client);
1318 #endif //DEBUG
1319 } //end if
1320 } //end else
1321 } //end of the function BotCheckBlocked
1322 //===========================================================================
1323 //
1324 // Parameter: -
1325 // Returns: -
1326 // Changes Globals: -
1327 //===========================================================================
BotTravel_Walk(bot_movestate_t * ms,aas_reachability_t * reach)1328 bot_moveresult_t BotTravel_Walk(bot_movestate_t *ms, aas_reachability_t *reach)
1329 {
1330 float dist, speed;
1331 vec3_t hordir;
1332 bot_moveresult_t_cleared( result );
1333
1334 //first walk straight to the reachability start
1335 hordir[0] = reach->start[0] - ms->origin[0];
1336 hordir[1] = reach->start[1] - ms->origin[1];
1337 hordir[2] = 0;
1338 dist = VectorNormalize(hordir);
1339 //
1340 BotCheckBlocked(ms, hordir, qtrue, &result);
1341 //
1342 if (dist < 10)
1343 {
1344 //walk straight to the reachability end
1345 hordir[0] = reach->end[0] - ms->origin[0];
1346 hordir[1] = reach->end[1] - ms->origin[1];
1347 hordir[2] = 0;
1348 dist = VectorNormalize(hordir);
1349 } //end if
1350 //if going towards a crouch area
1351 if (!(AAS_AreaPresenceType(reach->areanum) & PRESENCE_NORMAL))
1352 {
1353 //if pretty close to the reachable area
1354 if (dist < 20) EA_Crouch(ms->client);
1355 } //end if
1356 //
1357 dist = BotGapDistance(ms->origin, hordir, ms->entitynum);
1358 //
1359 if (ms->moveflags & MFL_WALK)
1360 {
1361 if (dist > 0) speed = 200 - (180 - 1 * dist);
1362 else speed = 200;
1363 EA_Walk(ms->client);
1364 } //end if
1365 else
1366 {
1367 if (dist > 0) speed = 400 - (360 - 2 * dist);
1368 else speed = 400;
1369 } //end else
1370 //elemantary action move in direction
1371 EA_Move(ms->client, hordir, speed);
1372 VectorCopy(hordir, result.movedir);
1373 //
1374 return result;
1375 } //end of the function BotTravel_Walk
1376 //===========================================================================
1377 //
1378 // Parameter: -
1379 // Returns: -
1380 // Changes Globals: -
1381 //===========================================================================
BotFinishTravel_Walk(bot_movestate_t * ms,aas_reachability_t * reach)1382 bot_moveresult_t BotFinishTravel_Walk(bot_movestate_t *ms, aas_reachability_t *reach)
1383 {
1384 vec3_t hordir;
1385 float dist, speed;
1386 bot_moveresult_t_cleared( result );
1387 //if not on the ground and changed areas... don't walk back!!
1388 //(doesn't seem to help)
1389 /*
1390 ms->areanum = BotFuzzyPointReachabilityArea(ms->origin);
1391 if (ms->areanum == reach->areanum)
1392 {
1393 #ifdef DEBUG
1394 botimport.Print(PRT_MESSAGE, "BotFinishTravel_Walk: already in reach area\n");
1395 #endif //DEBUG
1396 return result;
1397 } //end if*/
1398 //go straight to the reachability end
1399 hordir[0] = reach->end[0] - ms->origin[0];
1400 hordir[1] = reach->end[1] - ms->origin[1];
1401 hordir[2] = 0;
1402 dist = VectorNormalize(hordir);
1403 //
1404 if (dist > 100) dist = 100;
1405 speed = 400 - (400 - 3 * dist);
1406 //
1407 EA_Move(ms->client, hordir, speed);
1408 VectorCopy(hordir, result.movedir);
1409 //
1410 return result;
1411 } //end of the function BotFinishTravel_Walk
1412 //===========================================================================
1413 //
1414 // Parameter: -
1415 // Returns: -
1416 // Changes Globals: -
1417 //===========================================================================
BotTravel_Crouch(bot_movestate_t * ms,aas_reachability_t * reach)1418 bot_moveresult_t BotTravel_Crouch(bot_movestate_t *ms, aas_reachability_t *reach)
1419 {
1420 float speed;
1421 vec3_t hordir;
1422 bot_moveresult_t_cleared( result );
1423
1424 //
1425 speed = 400;
1426 //walk straight to reachability end
1427 hordir[0] = reach->end[0] - ms->origin[0];
1428 hordir[1] = reach->end[1] - ms->origin[1];
1429 hordir[2] = 0;
1430 VectorNormalize(hordir);
1431 //
1432 BotCheckBlocked(ms, hordir, qtrue, &result);
1433 //elemantary actions
1434 EA_Crouch(ms->client);
1435 EA_Move(ms->client, hordir, speed);
1436 //
1437 VectorCopy(hordir, result.movedir);
1438 //
1439 return result;
1440 } //end of the function BotTravel_Crouch
1441 //===========================================================================
1442 //
1443 // Parameter: -
1444 // Returns: -
1445 // Changes Globals: -
1446 //===========================================================================
BotTravel_BarrierJump(bot_movestate_t * ms,aas_reachability_t * reach)1447 bot_moveresult_t BotTravel_BarrierJump(bot_movestate_t *ms, aas_reachability_t *reach)
1448 {
1449 float dist, speed;
1450 vec3_t hordir;
1451 bot_moveresult_t_cleared( result );
1452
1453 //walk straight to reachability start
1454 hordir[0] = reach->start[0] - ms->origin[0];
1455 hordir[1] = reach->start[1] - ms->origin[1];
1456 hordir[2] = 0;
1457 dist = VectorNormalize(hordir);
1458 //
1459 BotCheckBlocked(ms, hordir, qtrue, &result);
1460 //if pretty close to the barrier
1461 if (dist < 9)
1462 {
1463 EA_Jump(ms->client);
1464 } //end if
1465 else
1466 {
1467 if (dist > 60) dist = 60;
1468 speed = 360 - (360 - 6 * dist);
1469 EA_Move(ms->client, hordir, speed);
1470 } //end else
1471 VectorCopy(hordir, result.movedir);
1472 //
1473 return result;
1474 } //end of the function BotTravel_BarrierJump
1475 //===========================================================================
1476 //
1477 // Parameter: -
1478 // Returns: -
1479 // Changes Globals: -
1480 //===========================================================================
BotFinishTravel_BarrierJump(bot_movestate_t * ms,aas_reachability_t * reach)1481 bot_moveresult_t BotFinishTravel_BarrierJump(bot_movestate_t *ms, aas_reachability_t *reach)
1482 {
1483 float dist;
1484 vec3_t hordir;
1485 bot_moveresult_t_cleared( result );
1486
1487 //if near the top or going down
1488 if (ms->velocity[2] < 250)
1489 {
1490 hordir[0] = reach->end[0] - ms->origin[0];
1491 hordir[1] = reach->end[1] - ms->origin[1];
1492 hordir[2] = 0;
1493 dist = VectorNormalize(hordir);
1494 //
1495 BotCheckBlocked(ms, hordir, qtrue, &result);
1496 //
1497 EA_Move(ms->client, hordir, 400);
1498 VectorCopy(hordir, result.movedir);
1499 } //end if
1500 //
1501 return result;
1502 } //end of the function BotFinishTravel_BarrierJump
1503 //===========================================================================
1504 //
1505 // Parameter: -
1506 // Returns: -
1507 // Changes Globals: -
1508 //===========================================================================
BotTravel_Swim(bot_movestate_t * ms,aas_reachability_t * reach)1509 bot_moveresult_t BotTravel_Swim(bot_movestate_t *ms, aas_reachability_t *reach)
1510 {
1511 vec3_t dir;
1512 bot_moveresult_t_cleared( result );
1513
1514 //swim straight to reachability end
1515 VectorSubtract(reach->start, ms->origin, dir);
1516 VectorNormalize(dir);
1517 //
1518 BotCheckBlocked(ms, dir, qtrue, &result);
1519 //elemantary actions
1520 EA_Move(ms->client, dir, 400);
1521 //
1522 VectorCopy(dir, result.movedir);
1523 Vector2Angles(dir, result.ideal_viewangles);
1524 result.flags |= MOVERESULT_SWIMVIEW;
1525 //
1526 return result;
1527 } //end of the function BotTravel_Swim
1528 //===========================================================================
1529 //
1530 // Parameter: -
1531 // Returns: -
1532 // Changes Globals: -
1533 //===========================================================================
BotTravel_WaterJump(bot_movestate_t * ms,aas_reachability_t * reach)1534 bot_moveresult_t BotTravel_WaterJump(bot_movestate_t *ms, aas_reachability_t *reach)
1535 {
1536 vec3_t dir, hordir;
1537 float dist;
1538 bot_moveresult_t_cleared( result );
1539
1540 //swim straight to reachability end
1541 VectorSubtract(reach->end, ms->origin, dir);
1542 VectorCopy(dir, hordir);
1543 hordir[2] = 0;
1544 dir[2] += 15 + crandom() * 40;
1545 //botimport.Print(PRT_MESSAGE, "BotTravel_WaterJump: dir[2] = %f\n", dir[2]);
1546 VectorNormalize(dir);
1547 dist = VectorNormalize(hordir);
1548 //elemantary actions
1549 //EA_Move(ms->client, dir, 400);
1550 EA_MoveForward(ms->client);
1551 //move up if close to the actual out of water jump spot
1552 if (dist < 40) EA_MoveUp(ms->client);
1553 //set the ideal view angles
1554 Vector2Angles(dir, result.ideal_viewangles);
1555 result.flags |= MOVERESULT_MOVEMENTVIEW;
1556 //
1557 VectorCopy(dir, result.movedir);
1558 //
1559 return result;
1560 } //end of the function BotTravel_WaterJump
1561 //===========================================================================
1562 //
1563 // Parameter: -
1564 // Returns: -
1565 // Changes Globals: -
1566 //===========================================================================
BotFinishTravel_WaterJump(bot_movestate_t * ms,aas_reachability_t * reach)1567 bot_moveresult_t BotFinishTravel_WaterJump(bot_movestate_t *ms, aas_reachability_t *reach)
1568 {
1569 vec3_t dir, pnt;
1570 float dist;
1571 bot_moveresult_t_cleared( result );
1572
1573 //botimport.Print(PRT_MESSAGE, "BotFinishTravel_WaterJump\n");
1574 //if waterjumping there's nothing to do
1575 if (ms->moveflags & MFL_WATERJUMP) return result;
1576 //if not touching any water anymore don't do anything
1577 //otherwise the bot sometimes keeps jumping?
1578 VectorCopy(ms->origin, pnt);
1579 pnt[2] -= 32; //extra for q2dm4 near red armor/mega health
1580 if (!(AAS_PointContents(pnt) & (CONTENTS_LAVA|CONTENTS_SLIME|CONTENTS_WATER))) return result;
1581 //swim straight to reachability end
1582 VectorSubtract(reach->end, ms->origin, dir);
1583 dir[0] += crandom() * 10;
1584 dir[1] += crandom() * 10;
1585 dir[2] += 70 + crandom() * 10;
1586 dist = VectorNormalize(dir);
1587 //elemantary actions
1588 EA_Move(ms->client, dir, 400);
1589 //set the ideal view angles
1590 Vector2Angles(dir, result.ideal_viewangles);
1591 result.flags |= MOVERESULT_MOVEMENTVIEW;
1592 //
1593 VectorCopy(dir, result.movedir);
1594 //
1595 return result;
1596 } //end of the function BotFinishTravel_WaterJump
1597 //===========================================================================
1598 //
1599 // Parameter: -
1600 // Returns: -
1601 // Changes Globals: -
1602 //===========================================================================
BotTravel_WalkOffLedge(bot_movestate_t * ms,aas_reachability_t * reach)1603 bot_moveresult_t BotTravel_WalkOffLedge(bot_movestate_t *ms, aas_reachability_t *reach)
1604 {
1605 vec3_t hordir, dir;
1606 float dist, speed, reachhordist;
1607 bot_moveresult_t_cleared( result );
1608
1609 //check if the bot is blocked by anything
1610 VectorSubtract(reach->start, ms->origin, dir);
1611 VectorNormalize(dir);
1612 BotCheckBlocked(ms, dir, qtrue, &result);
1613 //if the reachability start and end are practially above each other
1614 VectorSubtract(reach->end, reach->start, dir);
1615 dir[2] = 0;
1616 reachhordist = VectorLength(dir);
1617 //walk straight to the reachability start
1618 hordir[0] = reach->start[0] - ms->origin[0];
1619 hordir[1] = reach->start[1] - ms->origin[1];
1620 hordir[2] = 0;
1621 dist = VectorNormalize(hordir);
1622 //if pretty close to the start focus on the reachability end
1623 if (dist < 48)
1624 {
1625 hordir[0] = reach->end[0] - ms->origin[0];
1626 hordir[1] = reach->end[1] - ms->origin[1];
1627 hordir[2] = 0;
1628 VectorNormalize(hordir);
1629 //
1630 if (reachhordist < 20)
1631 {
1632 speed = 100;
1633 } //end if
1634 else if (!AAS_HorizontalVelocityForJump(0, reach->start, reach->end, &speed))
1635 {
1636 speed = 400;
1637 } //end if
1638 } //end if
1639 else
1640 {
1641 if (reachhordist < 20)
1642 {
1643 if (dist > 64) dist = 64;
1644 speed = 400 - (256 - 4 * dist);
1645 } //end if
1646 else
1647 {
1648 speed = 400;
1649 } //end else
1650 } //end else
1651 //
1652 BotCheckBlocked(ms, hordir, qtrue, &result);
1653 //elemantary action
1654 EA_Move(ms->client, hordir, speed);
1655 VectorCopy(hordir, result.movedir);
1656 //
1657 return result;
1658 } //end of the function BotTravel_WalkOffLedge
1659 //===========================================================================
1660 //
1661 // Parameter: -
1662 // Returns: -
1663 // Changes Globals: -
1664 //===========================================================================
BotAirControl(vec3_t origin,vec3_t velocity,vec3_t goal,vec3_t dir,float * speed)1665 int BotAirControl(vec3_t origin, vec3_t velocity, vec3_t goal, vec3_t dir, float *speed)
1666 {
1667 vec3_t org, vel;
1668 float dist;
1669 int i;
1670
1671 VectorCopy(origin, org);
1672 VectorScale(velocity, 0.1, vel);
1673 for (i = 0; i < 50; i++)
1674 {
1675 vel[2] -= sv_gravity->value * 0.01;
1676 //if going down and next position would be below the goal
1677 if (vel[2] < 0 && org[2] + vel[2] < goal[2])
1678 {
1679 VectorScale(vel, (goal[2] - org[2]) / vel[2], vel);
1680 VectorAdd(org, vel, org);
1681 VectorSubtract(goal, org, dir);
1682 dist = VectorNormalize(dir);
1683 if (dist > 32) dist = 32;
1684 *speed = 400 - (400 - 13 * dist);
1685 return qtrue;
1686 } //end if
1687 else
1688 {
1689 VectorAdd(org, vel, org);
1690 } //end else
1691 } //end for
1692 VectorSet(dir, 0, 0, 0);
1693 *speed = 400;
1694 return qfalse;
1695 } //end of the function BotAirControl
1696 //===========================================================================
1697 //
1698 // Parameter: -
1699 // Returns: -
1700 // Changes Globals: -
1701 //===========================================================================
BotFinishTravel_WalkOffLedge(bot_movestate_t * ms,aas_reachability_t * reach)1702 bot_moveresult_t BotFinishTravel_WalkOffLedge(bot_movestate_t *ms, aas_reachability_t *reach)
1703 {
1704 vec3_t dir, hordir, end, v;
1705 float dist, speed;
1706 bot_moveresult_t_cleared( result );
1707
1708 //
1709 VectorSubtract(reach->end, ms->origin, dir);
1710 BotCheckBlocked(ms, dir, qtrue, &result);
1711 //
1712 VectorSubtract(reach->end, ms->origin, v);
1713 v[2] = 0;
1714 dist = VectorNormalize(v);
1715 if (dist > 16) VectorMA(reach->end, 16, v, end);
1716 else VectorCopy(reach->end, end);
1717 //
1718 if (!BotAirControl(ms->origin, ms->velocity, end, hordir, &speed))
1719 {
1720 //go straight to the reachability end
1721 VectorCopy(dir, hordir);
1722 hordir[2] = 0;
1723 //
1724 dist = VectorNormalize(hordir);
1725 speed = 400;
1726 } //end if
1727 //
1728 EA_Move(ms->client, hordir, speed);
1729 VectorCopy(hordir, result.movedir);
1730 //
1731 return result;
1732 } //end of the function BotFinishTravel_WalkOffLedge
1733 //===========================================================================
1734 //
1735 // Parameter: -
1736 // Returns: -
1737 // Changes Globals: -
1738 //===========================================================================
1739 /*
1740 bot_moveresult_t BotTravel_Jump(bot_movestate_t *ms, aas_reachability_t *reach)
1741 {
1742 vec3_t hordir;
1743 float dist, gapdist, speed, horspeed, sv_jumpvel;
1744 bot_moveresult_t_cleared( result );
1745
1746 //
1747 sv_jumpvel = botlibglobals.sv_jumpvel->value;
1748 //walk straight to the reachability start
1749 hordir[0] = reach->start[0] - ms->origin[0];
1750 hordir[1] = reach->start[1] - ms->origin[1];
1751 hordir[2] = 0;
1752 dist = VectorNormalize(hordir);
1753 //
1754 speed = 350;
1755 //
1756 gapdist = BotGapDistance(ms, hordir, ms->entitynum);
1757 //if pretty close to the start focus on the reachability end
1758 if (dist < 50 || (gapdist && gapdist < 50))
1759 {
1760 //NOTE: using max speed (400) works best
1761 //if (AAS_HorizontalVelocityForJump(sv_jumpvel, ms->origin, reach->end, &horspeed))
1762 //{
1763 // speed = horspeed * 400 / botlibglobals.sv_maxwalkvelocity->value;
1764 //} //end if
1765 hordir[0] = reach->end[0] - ms->origin[0];
1766 hordir[1] = reach->end[1] - ms->origin[1];
1767 VectorNormalize(hordir);
1768 //elemantary action jump
1769 EA_Jump(ms->client);
1770 //
1771 ms->jumpreach = ms->lastreachnum;
1772 speed = 600;
1773 } //end if
1774 else
1775 {
1776 if (AAS_HorizontalVelocityForJump(sv_jumpvel, reach->start, reach->end, &horspeed))
1777 {
1778 speed = horspeed * 400 / botlibglobals.sv_maxwalkvelocity->value;
1779 } //end if
1780 } //end else
1781 //elemantary action
1782 EA_Move(ms->client, hordir, speed);
1783 VectorCopy(hordir, result.movedir);
1784 //
1785 return result;
1786 } //end of the function BotTravel_Jump*/
1787 /*
1788 bot_moveresult_t BotTravel_Jump(bot_movestate_t *ms, aas_reachability_t *reach)
1789 {
1790 vec3_t hordir, dir1, dir2, mins, maxs, start, end;
1791 float dist1, dist2, speed;
1792 bot_moveresult_t_cleared( result );
1793 bsp_trace_t trace;
1794
1795 //
1796 hordir[0] = reach->start[0] - reach->end[0];
1797 hordir[1] = reach->start[1] - reach->end[1];
1798 hordir[2] = 0;
1799 VectorNormalize(hordir);
1800 //
1801 VectorCopy(reach->start, start);
1802 start[2] += 1;
1803 //minus back the bouding box size plus 16
1804 VectorMA(reach->start, 80, hordir, end);
1805 //
1806 AAS_PresenceTypeBoundingBox(PRESENCE_NORMAL, mins, maxs);
1807 //check for solids
1808 trace = AAS_Trace(start, mins, maxs, end, ms->entitynum, MASK_PLAYERSOLID);
1809 if (trace.startsolid) VectorCopy(start, trace.endpos);
1810 //check for a gap
1811 for (dist1 = 0; dist1 < 80; dist1 += 10)
1812 {
1813 VectorMA(start, dist1+10, hordir, end);
1814 end[2] += 1;
1815 if (AAS_PointAreaNum(end) != ms->reachareanum) break;
1816 } //end for
1817 if (dist1 < 80) VectorMA(reach->start, dist1, hordir, trace.endpos);
1818 // dist1 = BotGapDistance(start, hordir, ms->entitynum);
1819 // if (dist1 && dist1 <= trace.fraction * 80) VectorMA(reach->start, dist1-20, hordir, trace.endpos);
1820 //
1821 VectorSubtract(ms->origin, reach->start, dir1);
1822 dir1[2] = 0;
1823 dist1 = VectorNormalize(dir1);
1824 VectorSubtract(ms->origin, trace.endpos, dir2);
1825 dir2[2] = 0;
1826 dist2 = VectorNormalize(dir2);
1827 //if just before the reachability start
1828 if (DotProduct(dir1, dir2) < -0.8 || dist2 < 5)
1829 {
1830 //botimport.Print(PRT_MESSAGE, "between jump start and run to point\n");
1831 hordir[0] = reach->end[0] - ms->origin[0];
1832 hordir[1] = reach->end[1] - ms->origin[1];
1833 hordir[2] = 0;
1834 VectorNormalize(hordir);
1835 //elemantary action jump
1836 if (dist1 < 24) EA_Jump(ms->client);
1837 else if (dist1 < 32) EA_DelayedJump(ms->client);
1838 EA_Move(ms->client, hordir, 600);
1839 //
1840 ms->jumpreach = ms->lastreachnum;
1841 } //end if
1842 else
1843 {
1844 //botimport.Print(PRT_MESSAGE, "going towards run to point\n");
1845 hordir[0] = trace.endpos[0] - ms->origin[0];
1846 hordir[1] = trace.endpos[1] - ms->origin[1];
1847 hordir[2] = 0;
1848 VectorNormalize(hordir);
1849 //
1850 if (dist2 > 80) dist2 = 80;
1851 speed = 400 - (400 - 5 * dist2);
1852 EA_Move(ms->client, hordir, speed);
1853 } //end else
1854 VectorCopy(hordir, result.movedir);
1855 //
1856 return result;
1857 } //end of the function BotTravel_Jump*/
1858 //*
BotTravel_Jump(bot_movestate_t * ms,aas_reachability_t * reach)1859 bot_moveresult_t BotTravel_Jump(bot_movestate_t *ms, aas_reachability_t *reach)
1860 {
1861 vec3_t hordir, dir1, dir2, start, end, runstart;
1862 // vec3_t runstart, dir1, dir2, hordir;
1863 float dist1, dist2, speed;
1864 bot_moveresult_t_cleared( result );
1865
1866 //
1867 AAS_JumpReachRunStart(reach, runstart);
1868 //*
1869 hordir[0] = runstart[0] - reach->start[0];
1870 hordir[1] = runstart[1] - reach->start[1];
1871 hordir[2] = 0;
1872 VectorNormalize(hordir);
1873 //
1874 VectorCopy(reach->start, start);
1875 start[2] += 1;
1876 VectorMA(reach->start, 80, hordir, runstart);
1877 //check for a gap
1878 for (dist1 = 0; dist1 < 80; dist1 += 10)
1879 {
1880 VectorMA(start, dist1+10, hordir, end);
1881 end[2] += 1;
1882 if (AAS_PointAreaNum(end) != ms->reachareanum) break;
1883 } //end for
1884 if (dist1 < 80) VectorMA(reach->start, dist1, hordir, runstart);
1885 //
1886 VectorSubtract(ms->origin, reach->start, dir1);
1887 dir1[2] = 0;
1888 dist1 = VectorNormalize(dir1);
1889 VectorSubtract(ms->origin, runstart, dir2);
1890 dir2[2] = 0;
1891 dist2 = VectorNormalize(dir2);
1892 //if just before the reachability start
1893 if (DotProduct(dir1, dir2) < -0.8 || dist2 < 5)
1894 {
1895 // botimport.Print(PRT_MESSAGE, "between jump start and run start point\n");
1896 hordir[0] = reach->end[0] - ms->origin[0];
1897 hordir[1] = reach->end[1] - ms->origin[1];
1898 hordir[2] = 0;
1899 VectorNormalize(hordir);
1900 //elemantary action jump
1901 if (dist1 < 24) EA_Jump(ms->client);
1902 else if (dist1 < 32) EA_DelayedJump(ms->client);
1903 EA_Move(ms->client, hordir, 600);
1904 //
1905 ms->jumpreach = ms->lastreachnum;
1906 } //end if
1907 else
1908 {
1909 // botimport.Print(PRT_MESSAGE, "going towards run start point\n");
1910 hordir[0] = runstart[0] - ms->origin[0];
1911 hordir[1] = runstart[1] - ms->origin[1];
1912 hordir[2] = 0;
1913 VectorNormalize(hordir);
1914 //
1915 if (dist2 > 80) dist2 = 80;
1916 speed = 400 - (400 - 5 * dist2);
1917 EA_Move(ms->client, hordir, speed);
1918 } //end else
1919 VectorCopy(hordir, result.movedir);
1920 //
1921 return result;
1922 } //end of the function BotTravel_Jump*/
1923 //===========================================================================
1924 //
1925 // Parameter: -
1926 // Returns: -
1927 // Changes Globals: -
1928 //===========================================================================
BotFinishTravel_Jump(bot_movestate_t * ms,aas_reachability_t * reach)1929 bot_moveresult_t BotFinishTravel_Jump(bot_movestate_t *ms, aas_reachability_t *reach)
1930 {
1931 vec3_t hordir, hordir2;
1932 float speed, dist;
1933 bot_moveresult_t_cleared( result );
1934
1935 //if not jumped yet
1936 if (!ms->jumpreach) return result;
1937 //go straight to the reachability end
1938 hordir[0] = reach->end[0] - ms->origin[0];
1939 hordir[1] = reach->end[1] - ms->origin[1];
1940 hordir[2] = 0;
1941 dist = VectorNormalize(hordir);
1942 //
1943 hordir2[0] = reach->end[0] - reach->start[0];
1944 hordir2[1] = reach->end[1] - reach->start[1];
1945 hordir2[2] = 0;
1946 VectorNormalize(hordir2);
1947 //
1948 if (DotProduct(hordir, hordir2) < -0.5 && dist < 24) return result;
1949 //always use max speed when traveling through the air
1950 speed = 800;
1951 //
1952 EA_Move(ms->client, hordir, speed);
1953 VectorCopy(hordir, result.movedir);
1954 //
1955 return result;
1956 } //end of the function BotFinishTravel_Jump
1957 //===========================================================================
1958 //
1959 // Parameter: -
1960 // Returns: -
1961 // Changes Globals: -
1962 //===========================================================================
BotTravel_Ladder(bot_movestate_t * ms,aas_reachability_t * reach)1963 bot_moveresult_t BotTravel_Ladder(bot_movestate_t *ms, aas_reachability_t *reach)
1964 {
1965 //float dist, speed;
1966 vec3_t dir, viewdir;//, hordir;
1967 vec3_t origin = {0, 0, 0};
1968 // vec3_t up = {0, 0, 1};
1969 bot_moveresult_t_cleared( result );
1970
1971 //
1972 // if ((ms->moveflags & MFL_AGAINSTLADDER))
1973 //NOTE: not a good idea for ladders starting in water
1974 // || !(ms->moveflags & MFL_ONGROUND))
1975 {
1976 //botimport.Print(PRT_MESSAGE, "against ladder or not on ground\n");
1977 VectorSubtract(reach->end, ms->origin, dir);
1978 VectorNormalize(dir);
1979 //set the ideal view angles, facing the ladder up or down
1980 viewdir[0] = dir[0];
1981 viewdir[1] = dir[1];
1982 viewdir[2] = 3 * dir[2];
1983 Vector2Angles(viewdir, result.ideal_viewangles);
1984 //elemantary action
1985 EA_Move(ms->client, origin, 0);
1986 EA_MoveForward(ms->client);
1987 //set movement view flag so the AI can see the view is focussed
1988 result.flags |= MOVERESULT_MOVEMENTVIEW;
1989 } //end if
1990 /* else
1991 {
1992 //botimport.Print(PRT_MESSAGE, "moving towards ladder\n");
1993 VectorSubtract(reach->end, ms->origin, dir);
1994 //make sure the horizontal movement is large anough
1995 VectorCopy(dir, hordir);
1996 hordir[2] = 0;
1997 dist = VectorNormalize(hordir);
1998 //
1999 dir[0] = hordir[0];
2000 dir[1] = hordir[1];
2001 if (dir[2] > 0) dir[2] = 1;
2002 else dir[2] = -1;
2003 if (dist > 50) dist = 50;
2004 speed = 400 - (200 - 4 * dist);
2005 EA_Move(ms->client, dir, speed);
2006 } //end else*/
2007 //save the movement direction
2008 VectorCopy(dir, result.movedir);
2009 //
2010 return result;
2011 } //end of the function BotTravel_Ladder
2012 //===========================================================================
2013 //
2014 // Parameter: -
2015 // Returns: -
2016 // Changes Globals: -
2017 //===========================================================================
BotTravel_Teleport(bot_movestate_t * ms,aas_reachability_t * reach)2018 bot_moveresult_t BotTravel_Teleport(bot_movestate_t *ms, aas_reachability_t *reach)
2019 {
2020 vec3_t hordir;
2021 float dist;
2022 bot_moveresult_t_cleared( result );
2023
2024 //if the bot is being teleported
2025 if (ms->moveflags & MFL_TELEPORTED) return result;
2026
2027 //walk straight to center of the teleporter
2028 VectorSubtract(reach->start, ms->origin, hordir);
2029 if (!(ms->moveflags & MFL_SWIMMING)) hordir[2] = 0;
2030 dist = VectorNormalize(hordir);
2031 //
2032 BotCheckBlocked(ms, hordir, qtrue, &result);
2033
2034 if (dist < 30) EA_Move(ms->client, hordir, 200);
2035 else EA_Move(ms->client, hordir, 400);
2036
2037 if (ms->moveflags & MFL_SWIMMING) result.flags |= MOVERESULT_SWIMVIEW;
2038
2039 VectorCopy(hordir, result.movedir);
2040 return result;
2041 } //end of the function BotTravel_Teleport
2042 //===========================================================================
2043 //
2044 // Parameter: -
2045 // Returns: -
2046 // Changes Globals: -
2047 //===========================================================================
BotTravel_Elevator(bot_movestate_t * ms,aas_reachability_t * reach)2048 bot_moveresult_t BotTravel_Elevator(bot_movestate_t *ms, aas_reachability_t *reach)
2049 {
2050 vec3_t dir, dir1, dir2, hordir, bottomcenter;
2051 float dist, dist1, dist2, speed;
2052 bot_moveresult_t_cleared( result );
2053
2054 //if standing on the plat
2055 if (BotOnMover(ms->origin, ms->entitynum, reach))
2056 {
2057 #ifdef DEBUG_ELEVATOR
2058 botimport.Print(PRT_MESSAGE, "bot on elevator\n");
2059 #endif //DEBUG_ELEVATOR
2060 //if vertically not too far from the end point
2061 if (abs(ms->origin[2] - reach->end[2]) < sv_maxbarrier->value)
2062 {
2063 #ifdef DEBUG_ELEVATOR
2064 botimport.Print(PRT_MESSAGE, "bot moving to end\n");
2065 #endif //DEBUG_ELEVATOR
2066 //move to the end point
2067 VectorSubtract(reach->end, ms->origin, hordir);
2068 hordir[2] = 0;
2069 VectorNormalize(hordir);
2070 if (!BotCheckBarrierJump(ms, hordir, 100))
2071 {
2072 EA_Move(ms->client, hordir, 400);
2073 } //end if
2074 VectorCopy(hordir, result.movedir);
2075 } //end else
2076 //if not really close to the center of the elevator
2077 else
2078 {
2079 MoverBottomCenter(reach, bottomcenter);
2080 VectorSubtract(bottomcenter, ms->origin, hordir);
2081 hordir[2] = 0;
2082 dist = VectorNormalize(hordir);
2083 //
2084 if (dist > 10)
2085 {
2086 #ifdef DEBUG_ELEVATOR
2087 botimport.Print(PRT_MESSAGE, "bot moving to center\n");
2088 #endif //DEBUG_ELEVATOR
2089 //move to the center of the plat
2090 if (dist > 100) dist = 100;
2091 speed = 400 - (400 - 4 * dist);
2092 //
2093 EA_Move(ms->client, hordir, speed);
2094 VectorCopy(hordir, result.movedir);
2095 } //end if
2096 } //end else
2097 } //end if
2098 else
2099 {
2100 #ifdef DEBUG_ELEVATOR
2101 botimport.Print(PRT_MESSAGE, "bot not on elevator\n");
2102 #endif //DEBUG_ELEVATOR
2103 //if very near the reachability end
2104 VectorSubtract(reach->end, ms->origin, dir);
2105 dist = VectorLength(dir);
2106 if (dist < 64)
2107 {
2108 if (dist > 60) dist = 60;
2109 speed = 360 - (360 - 6 * dist);
2110 //
2111 if ((ms->moveflags & MFL_SWIMMING) || !BotCheckBarrierJump(ms, dir, 50))
2112 {
2113 if (speed > 5) EA_Move(ms->client, dir, speed);
2114 } //end if
2115 VectorCopy(dir, result.movedir);
2116 //
2117 if (ms->moveflags & MFL_SWIMMING) result.flags |= MOVERESULT_SWIMVIEW;
2118 //stop using this reachability
2119 ms->reachability_time = 0;
2120 return result;
2121 } //end if
2122 //get direction and distance to reachability start
2123 VectorSubtract(reach->start, ms->origin, dir1);
2124 if (!(ms->moveflags & MFL_SWIMMING)) dir1[2] = 0;
2125 dist1 = VectorNormalize(dir1);
2126 //if the elevator isn't down
2127 if (!MoverDown(reach))
2128 {
2129 #ifdef DEBUG_ELEVATOR
2130 botimport.Print(PRT_MESSAGE, "elevator not down\n");
2131 #endif //DEBUG_ELEVATOR
2132 dist = dist1;
2133 VectorCopy(dir1, dir);
2134 //
2135 BotCheckBlocked(ms, dir, qfalse, &result);
2136 //
2137 if (dist > 60) dist = 60;
2138 speed = 360 - (360 - 6 * dist);
2139 //
2140 if (!(ms->moveflags & MFL_SWIMMING) && !BotCheckBarrierJump(ms, dir, 50))
2141 {
2142 if (speed > 5) EA_Move(ms->client, dir, speed);
2143 } //end if
2144 VectorCopy(dir, result.movedir);
2145 //
2146 if (ms->moveflags & MFL_SWIMMING) result.flags |= MOVERESULT_SWIMVIEW;
2147 //this isn't a failure... just wait till the elevator comes down
2148 result.type = RESULTTYPE_ELEVATORUP;
2149 result.flags |= MOVERESULT_WAITING;
2150 return result;
2151 } //end if
2152 //get direction and distance to elevator bottom center
2153 MoverBottomCenter(reach, bottomcenter);
2154 VectorSubtract(bottomcenter, ms->origin, dir2);
2155 if (!(ms->moveflags & MFL_SWIMMING)) dir2[2] = 0;
2156 dist2 = VectorNormalize(dir2);
2157 //if very close to the reachability start or
2158 //closer to the elevator center or
2159 //between reachability start and elevator center
2160 if (dist1 < 20 || dist2 < dist1 || DotProduct(dir1, dir2) < 0)
2161 {
2162 #ifdef DEBUG_ELEVATOR
2163 botimport.Print(PRT_MESSAGE, "bot moving to center\n");
2164 #endif //DEBUG_ELEVATOR
2165 dist = dist2;
2166 VectorCopy(dir2, dir);
2167 } //end if
2168 else //closer to the reachability start
2169 {
2170 #ifdef DEBUG_ELEVATOR
2171 botimport.Print(PRT_MESSAGE, "bot moving to start\n");
2172 #endif //DEBUG_ELEVATOR
2173 dist = dist1;
2174 VectorCopy(dir1, dir);
2175 } //end else
2176 //
2177 BotCheckBlocked(ms, dir, qfalse, &result);
2178 //
2179 if (dist > 60) dist = 60;
2180 speed = 400 - (400 - 6 * dist);
2181 //
2182 if (!(ms->moveflags & MFL_SWIMMING) && !BotCheckBarrierJump(ms, dir, 50))
2183 {
2184 EA_Move(ms->client, dir, speed);
2185 } //end if
2186 VectorCopy(dir, result.movedir);
2187 //
2188 if (ms->moveflags & MFL_SWIMMING) result.flags |= MOVERESULT_SWIMVIEW;
2189 } //end else
2190 return result;
2191 } //end of the function BotTravel_Elevator
2192 //===========================================================================
2193 //
2194 // Parameter: -
2195 // Returns: -
2196 // Changes Globals: -
2197 //===========================================================================
BotFinishTravel_Elevator(bot_movestate_t * ms,aas_reachability_t * reach)2198 bot_moveresult_t BotFinishTravel_Elevator(bot_movestate_t *ms, aas_reachability_t *reach)
2199 {
2200 vec3_t bottomcenter, bottomdir, topdir;
2201 bot_moveresult_t_cleared( result );
2202
2203 //
2204 MoverBottomCenter(reach, bottomcenter);
2205 VectorSubtract(bottomcenter, ms->origin, bottomdir);
2206 //
2207 VectorSubtract(reach->end, ms->origin, topdir);
2208 //
2209 if (fabs(bottomdir[2]) < fabs(topdir[2]))
2210 {
2211 VectorNormalize(bottomdir);
2212 EA_Move(ms->client, bottomdir, 300);
2213 } //end if
2214 else
2215 {
2216 VectorNormalize(topdir);
2217 EA_Move(ms->client, topdir, 300);
2218 } //end else
2219 return result;
2220 } //end of the function BotFinishTravel_Elevator
2221 //===========================================================================
2222 //
2223 // Parameter: -
2224 // Returns: -
2225 // Changes Globals: -
2226 //===========================================================================
BotFuncBobStartEnd(aas_reachability_t * reach,vec3_t start,vec3_t end,vec3_t origin)2227 void BotFuncBobStartEnd(aas_reachability_t *reach, vec3_t start, vec3_t end, vec3_t origin)
2228 {
2229 int spawnflags, modelnum;
2230 vec3_t mins, maxs, mid, angles = {0, 0, 0};
2231 int num0, num1;
2232
2233 modelnum = reach->facenum & 0x0000FFFF;
2234 if (!AAS_OriginOfMoverWithModelNum(modelnum, origin))
2235 {
2236 botimport.Print(PRT_MESSAGE, "BotFuncBobStartEnd: no entity with model %d\n", modelnum);
2237 VectorSet(start, 0, 0, 0);
2238 VectorSet(end, 0, 0, 0);
2239 return;
2240 } //end if
2241 AAS_BSPModelMinsMaxsOrigin(modelnum, angles, mins, maxs, NULL);
2242 VectorAdd(mins, maxs, mid);
2243 VectorScale(mid, 0.5, mid);
2244 VectorCopy(mid, start);
2245 VectorCopy(mid, end);
2246 spawnflags = reach->facenum >> 16;
2247 num0 = reach->edgenum >> 16;
2248 if (num0 > 0x00007FFF) num0 |= 0xFFFF0000;
2249 num1 = reach->edgenum & 0x0000FFFF;
2250 if (num1 > 0x00007FFF) num1 |= 0xFFFF0000;
2251 if (spawnflags & 1)
2252 {
2253 start[0] = num0;
2254 end[0] = num1;
2255 //
2256 origin[0] += mid[0];
2257 origin[1] = mid[1];
2258 origin[2] = mid[2];
2259 } //end if
2260 else if (spawnflags & 2)
2261 {
2262 start[1] = num0;
2263 end[1] = num1;
2264 //
2265 origin[0] = mid[0];
2266 origin[1] += mid[1];
2267 origin[2] = mid[2];
2268 } //end else if
2269 else
2270 {
2271 start[2] = num0;
2272 end[2] = num1;
2273 //
2274 origin[0] = mid[0];
2275 origin[1] = mid[1];
2276 origin[2] += mid[2];
2277 } //end else
2278 } //end of the function BotFuncBobStartEnd
2279 //===========================================================================
2280 //
2281 // Parameter: -
2282 // Returns: -
2283 // Changes Globals: -
2284 //===========================================================================
BotTravel_FuncBobbing(bot_movestate_t * ms,aas_reachability_t * reach)2285 bot_moveresult_t BotTravel_FuncBobbing(bot_movestate_t *ms, aas_reachability_t *reach)
2286 {
2287 vec3_t dir, dir1, dir2, hordir, bottomcenter, bob_start, bob_end, bob_origin;
2288 float dist, dist1, dist2, speed;
2289 bot_moveresult_t_cleared( result );
2290
2291 //
2292 BotFuncBobStartEnd(reach, bob_start, bob_end, bob_origin);
2293 //if standing ontop of the func_bobbing
2294 if (BotOnMover(ms->origin, ms->entitynum, reach))
2295 {
2296 #ifdef DEBUG_FUNCBOB
2297 botimport.Print(PRT_MESSAGE, "bot on func_bobbing\n");
2298 #endif
2299 //if near end point of reachability
2300 VectorSubtract(bob_origin, bob_end, dir);
2301 if (VectorLength(dir) < 24)
2302 {
2303 #ifdef DEBUG_FUNCBOB
2304 botimport.Print(PRT_MESSAGE, "bot moving to reachability end\n");
2305 #endif
2306 //move to the end point
2307 VectorSubtract(reach->end, ms->origin, hordir);
2308 hordir[2] = 0;
2309 VectorNormalize(hordir);
2310 if (!BotCheckBarrierJump(ms, hordir, 100))
2311 {
2312 EA_Move(ms->client, hordir, 400);
2313 } //end if
2314 VectorCopy(hordir, result.movedir);
2315 } //end else
2316 //if not really close to the center of the elevator
2317 else
2318 {
2319 MoverBottomCenter(reach, bottomcenter);
2320 VectorSubtract(bottomcenter, ms->origin, hordir);
2321 hordir[2] = 0;
2322 dist = VectorNormalize(hordir);
2323 //
2324 if (dist > 10)
2325 {
2326 #ifdef DEBUG_FUNCBOB
2327 botimport.Print(PRT_MESSAGE, "bot moving to func_bobbing center\n");
2328 #endif
2329 //move to the center of the plat
2330 if (dist > 100) dist = 100;
2331 speed = 400 - (400 - 4 * dist);
2332 //
2333 EA_Move(ms->client, hordir, speed);
2334 VectorCopy(hordir, result.movedir);
2335 } //end if
2336 } //end else
2337 } //end if
2338 else
2339 {
2340 #ifdef DEBUG_FUNCBOB
2341 botimport.Print(PRT_MESSAGE, "bot not ontop of func_bobbing\n");
2342 #endif
2343 //if very near the reachability end
2344 VectorSubtract(reach->end, ms->origin, dir);
2345 dist = VectorLength(dir);
2346 if (dist < 64)
2347 {
2348 #ifdef DEBUG_FUNCBOB
2349 botimport.Print(PRT_MESSAGE, "bot moving to end\n");
2350 #endif
2351 if (dist > 60) dist = 60;
2352 speed = 360 - (360 - 6 * dist);
2353 //if swimming or no barrier jump
2354 if ((ms->moveflags & MFL_SWIMMING) || !BotCheckBarrierJump(ms, dir, 50))
2355 {
2356 if (speed > 5) EA_Move(ms->client, dir, speed);
2357 } //end if
2358 VectorCopy(dir, result.movedir);
2359 //
2360 if (ms->moveflags & MFL_SWIMMING) result.flags |= MOVERESULT_SWIMVIEW;
2361 //stop using this reachability
2362 ms->reachability_time = 0;
2363 return result;
2364 } //end if
2365 //get direction and distance to reachability start
2366 VectorSubtract(reach->start, ms->origin, dir1);
2367 if (!(ms->moveflags & MFL_SWIMMING)) dir1[2] = 0;
2368 dist1 = VectorNormalize(dir1);
2369 //if func_bobbing is Not it's start position
2370 VectorSubtract(bob_origin, bob_start, dir);
2371 if (VectorLength(dir) > 16)
2372 {
2373 #ifdef DEBUG_FUNCBOB
2374 botimport.Print(PRT_MESSAGE, "func_bobbing not at start\n");
2375 #endif
2376 dist = dist1;
2377 VectorCopy(dir1, dir);
2378 //
2379 BotCheckBlocked(ms, dir, qfalse, &result);
2380 //
2381 if (dist > 60) dist = 60;
2382 speed = 360 - (360 - 6 * dist);
2383 //
2384 if (!(ms->moveflags & MFL_SWIMMING) && !BotCheckBarrierJump(ms, dir, 50))
2385 {
2386 if (speed > 5) EA_Move(ms->client, dir, speed);
2387 } //end if
2388 VectorCopy(dir, result.movedir);
2389 //
2390 if (ms->moveflags & MFL_SWIMMING) result.flags |= MOVERESULT_SWIMVIEW;
2391 //this isn't a failure... just wait till the func_bobbing arrives
2392 result.type = RESULTTYPE_WAITFORFUNCBOBBING;
2393 result.flags |= MOVERESULT_WAITING;
2394 return result;
2395 } //end if
2396 //get direction and distance to func_bob bottom center
2397 MoverBottomCenter(reach, bottomcenter);
2398 VectorSubtract(bottomcenter, ms->origin, dir2);
2399 if (!(ms->moveflags & MFL_SWIMMING)) dir2[2] = 0;
2400 dist2 = VectorNormalize(dir2);
2401 //if very close to the reachability start or
2402 //closer to the elevator center or
2403 //between reachability start and func_bobbing center
2404 if (dist1 < 20 || dist2 < dist1 || DotProduct(dir1, dir2) < 0)
2405 {
2406 #ifdef DEBUG_FUNCBOB
2407 botimport.Print(PRT_MESSAGE, "bot moving to func_bobbing center\n");
2408 #endif
2409 dist = dist2;
2410 VectorCopy(dir2, dir);
2411 } //end if
2412 else //closer to the reachability start
2413 {
2414 #ifdef DEBUG_FUNCBOB
2415 botimport.Print(PRT_MESSAGE, "bot moving to reachability start\n");
2416 #endif
2417 dist = dist1;
2418 VectorCopy(dir1, dir);
2419 } //end else
2420 //
2421 BotCheckBlocked(ms, dir, qfalse, &result);
2422 //
2423 if (dist > 60) dist = 60;
2424 speed = 400 - (400 - 6 * dist);
2425 //
2426 if (!(ms->moveflags & MFL_SWIMMING) && !BotCheckBarrierJump(ms, dir, 50))
2427 {
2428 EA_Move(ms->client, dir, speed);
2429 } //end if
2430 VectorCopy(dir, result.movedir);
2431 //
2432 if (ms->moveflags & MFL_SWIMMING) result.flags |= MOVERESULT_SWIMVIEW;
2433 } //end else
2434 return result;
2435 } //end of the function BotTravel_FuncBobbing
2436 //===========================================================================
2437 //
2438 // Parameter: -
2439 // Returns: -
2440 // Changes Globals: -
2441 //===========================================================================
BotFinishTravel_FuncBobbing(bot_movestate_t * ms,aas_reachability_t * reach)2442 bot_moveresult_t BotFinishTravel_FuncBobbing(bot_movestate_t *ms, aas_reachability_t *reach)
2443 {
2444 vec3_t bob_origin, bob_start, bob_end, dir, hordir, bottomcenter;
2445 bot_moveresult_t_cleared( result );
2446 float dist, speed;
2447
2448 //
2449 BotFuncBobStartEnd(reach, bob_start, bob_end, bob_origin);
2450 //
2451 VectorSubtract(bob_origin, bob_end, dir);
2452 dist = VectorLength(dir);
2453 //if the func_bobbing is near the end
2454 if (dist < 16)
2455 {
2456 VectorSubtract(reach->end, ms->origin, hordir);
2457 if (!(ms->moveflags & MFL_SWIMMING)) hordir[2] = 0;
2458 dist = VectorNormalize(hordir);
2459 //
2460 if (dist > 60) dist = 60;
2461 speed = 360 - (360 - 6 * dist);
2462 //
2463 if (speed > 5) EA_Move(ms->client, dir, speed);
2464 VectorCopy(dir, result.movedir);
2465 //
2466 if (ms->moveflags & MFL_SWIMMING) result.flags |= MOVERESULT_SWIMVIEW;
2467 } //end if
2468 else
2469 {
2470 MoverBottomCenter(reach, bottomcenter);
2471 VectorSubtract(bottomcenter, ms->origin, hordir);
2472 if (!(ms->moveflags & MFL_SWIMMING)) hordir[2] = 0;
2473 dist = VectorNormalize(hordir);
2474 //
2475 if (dist > 5)
2476 {
2477 //move to the center of the plat
2478 if (dist > 100) dist = 100;
2479 speed = 400 - (400 - 4 * dist);
2480 //
2481 EA_Move(ms->client, hordir, speed);
2482 VectorCopy(hordir, result.movedir);
2483 } //end if
2484 } //end else
2485 return result;
2486 } //end of the function BotFinishTravel_FuncBobbing
2487 //===========================================================================
2488 // 0 no valid grapple hook visible
2489 // 1 the grapple hook is still flying
2490 // 2 the grapple hooked into a wall
2491 //
2492 // Parameter: -
2493 // Returns: -
2494 // Changes Globals: -
2495 //===========================================================================
GrappleState(bot_movestate_t * ms,aas_reachability_t * reach)2496 int GrappleState(bot_movestate_t *ms, aas_reachability_t *reach)
2497 {
2498 int i;
2499 aas_entityinfo_t entinfo;
2500
2501 //if the grapple hook is pulling
2502 if (ms->moveflags & MFL_GRAPPLEPULL)
2503 return 2;
2504 //check for a visible grapple missile entity
2505 //or visible grapple entity
2506 for (i = AAS_NextEntity(0); i; i = AAS_NextEntity(i))
2507 {
2508 if (AAS_EntityType(i) == (int) entitytypemissile->value)
2509 {
2510 AAS_EntityInfo(i, &entinfo);
2511 if (entinfo.weapon == (int) weapindex_grapple->value)
2512 {
2513 return 1;
2514 } //end if
2515 } //end if
2516 } //end for
2517 //no valid grapple at all
2518 return 0;
2519 } //end of the function GrappleState
2520 //===========================================================================
2521 //
2522 // Parameter: -
2523 // Returns: -
2524 // Changes Globals: -
2525 //===========================================================================
BotResetGrapple(bot_movestate_t * ms)2526 void BotResetGrapple(bot_movestate_t *ms)
2527 {
2528 aas_reachability_t reach;
2529
2530 AAS_ReachabilityFromNum(ms->lastreachnum, &reach);
2531 //if not using the grapple hook reachability anymore
2532 if ((reach.traveltype & TRAVELTYPE_MASK) != TRAVEL_GRAPPLEHOOK)
2533 {
2534 if ((ms->moveflags & MFL_ACTIVEGRAPPLE) || ms->grapplevisible_time)
2535 {
2536 if (offhandgrapple->value)
2537 EA_Command(ms->client, cmd_grappleoff->string);
2538 ms->moveflags &= ~MFL_ACTIVEGRAPPLE;
2539 ms->grapplevisible_time = 0;
2540 #ifdef DEBUG_GRAPPLE
2541 botimport.Print(PRT_MESSAGE, "reset grapple\n");
2542 #endif //DEBUG_GRAPPLE
2543 } //end if
2544 } //end if
2545 } //end of the function BotResetGrapple
2546 //===========================================================================
2547 //
2548 // Parameter: -
2549 // Returns: -
2550 // Changes Globals: -
2551 //===========================================================================
BotTravel_Grapple(bot_movestate_t * ms,aas_reachability_t * reach)2552 bot_moveresult_t BotTravel_Grapple(bot_movestate_t *ms, aas_reachability_t *reach)
2553 {
2554 bot_moveresult_t_cleared( result );
2555 float dist, speed;
2556 vec3_t dir, viewdir, org;
2557 int state, areanum;
2558 bsp_trace_t trace;
2559
2560 #ifdef DEBUG_GRAPPLE
2561 static int debugline;
2562 if (!debugline) debugline = botimport.DebugLineCreate();
2563 botimport.DebugLineShow(debugline, reach->start, reach->end, LINECOLOR_BLUE);
2564 #endif //DEBUG_GRAPPLE
2565
2566 //
2567 if (ms->moveflags & MFL_GRAPPLERESET)
2568 {
2569 if (offhandgrapple->value)
2570 EA_Command(ms->client, cmd_grappleoff->string);
2571 ms->moveflags &= ~MFL_ACTIVEGRAPPLE;
2572 return result;
2573 } //end if
2574 //
2575 if (!(int) offhandgrapple->value)
2576 {
2577 result.weapon = weapindex_grapple->value;
2578 result.flags |= MOVERESULT_MOVEMENTWEAPON;
2579 } //end if
2580 //
2581 if (ms->moveflags & MFL_ACTIVEGRAPPLE)
2582 {
2583 #ifdef DEBUG_GRAPPLE
2584 botimport.Print(PRT_MESSAGE, "BotTravel_Grapple: active grapple\n");
2585 #endif //DEBUG_GRAPPLE
2586 //
2587 state = GrappleState(ms, reach);
2588 //
2589 VectorSubtract(reach->end, ms->origin, dir);
2590 dir[2] = 0;
2591 dist = VectorLength(dir);
2592 //if very close to the grapple end or the grappled is hooked and
2593 //the bot doesn't get any closer
2594 if (state && dist < 48)
2595 {
2596 if (ms->lastgrappledist - dist < 1)
2597 {
2598 #ifdef DEBUG_GRAPPLE
2599 botimport.Print(PRT_ERROR, "grapple normal end\n");
2600 #endif //DEBUG_GRAPPLE
2601 if (offhandgrapple->value)
2602 EA_Command(ms->client, cmd_grappleoff->string);
2603 ms->moveflags &= ~MFL_ACTIVEGRAPPLE;
2604 ms->moveflags |= MFL_GRAPPLERESET;
2605 ms->reachability_time = 0; //end the reachability
2606 return result;
2607 } //end if
2608 } //end if
2609 //if no valid grapple at all, or the grapple hooked and the bot
2610 //isn't moving anymore
2611 else if (!state || (state == 2 && dist > ms->lastgrappledist - 2))
2612 {
2613 if (ms->grapplevisible_time < AAS_Time() - 0.4)
2614 {
2615 #ifdef DEBUG_GRAPPLE
2616 botimport.Print(PRT_ERROR, "grapple not visible\n");
2617 #endif //DEBUG_GRAPPLE
2618 if (offhandgrapple->value)
2619 EA_Command(ms->client, cmd_grappleoff->string);
2620 ms->moveflags &= ~MFL_ACTIVEGRAPPLE;
2621 ms->moveflags |= MFL_GRAPPLERESET;
2622 ms->reachability_time = 0; //end the reachability
2623 return result;
2624 } //end if
2625 } //end if
2626 else
2627 {
2628 ms->grapplevisible_time = AAS_Time();
2629 } //end else
2630 //
2631 if (!(int) offhandgrapple->value)
2632 {
2633 EA_Attack(ms->client);
2634 } //end if
2635 //remember the current grapple distance
2636 ms->lastgrappledist = dist;
2637 } //end if
2638 else
2639 {
2640 #ifdef DEBUG_GRAPPLE
2641 botimport.Print(PRT_MESSAGE, "BotTravel_Grapple: inactive grapple\n");
2642 #endif //DEBUG_GRAPPLE
2643 //
2644 ms->grapplevisible_time = AAS_Time();
2645 //
2646 VectorSubtract(reach->start, ms->origin, dir);
2647 if (!(ms->moveflags & MFL_SWIMMING)) dir[2] = 0;
2648 VectorAdd(ms->origin, ms->viewoffset, org);
2649 VectorSubtract(reach->end, org, viewdir);
2650 //
2651 dist = VectorNormalize(dir);
2652 Vector2Angles(viewdir, result.ideal_viewangles);
2653 result.flags |= MOVERESULT_MOVEMENTVIEW;
2654 //
2655 if (dist < 5 &&
2656 fabs(AngleDiff(result.ideal_viewangles[0], ms->viewangles[0])) < 2 &&
2657 fabs(AngleDiff(result.ideal_viewangles[1], ms->viewangles[1])) < 2)
2658 {
2659 #ifdef DEBUG_GRAPPLE
2660 botimport.Print(PRT_MESSAGE, "BotTravel_Grapple: activating grapple\n");
2661 #endif //DEBUG_GRAPPLE
2662 //check if the grapple missile path is clear
2663 VectorAdd(ms->origin, ms->viewoffset, org);
2664 trace = AAS_Trace(org, NULL, NULL, reach->end, ms->entitynum, CONTENTS_SOLID);
2665 VectorSubtract(reach->end, trace.endpos, dir);
2666 if (VectorLength(dir) > 16)
2667 {
2668 result.failure = qtrue;
2669 return result;
2670 } //end if
2671 //activate the grapple
2672 if (offhandgrapple->value)
2673 {
2674 EA_Command(ms->client, cmd_grappleon->string);
2675 } //end if
2676 else
2677 {
2678 EA_Attack(ms->client);
2679 } //end else
2680 ms->moveflags |= MFL_ACTIVEGRAPPLE;
2681 ms->lastgrappledist = 999999;
2682 } //end if
2683 else
2684 {
2685 if (dist < 70) speed = 300 - (300 - 4 * dist);
2686 else speed = 400;
2687 //
2688 BotCheckBlocked(ms, dir, qtrue, &result);
2689 //elemantary action move in direction
2690 EA_Move(ms->client, dir, speed);
2691 VectorCopy(dir, result.movedir);
2692 } //end else
2693 //if in another area before actually grappling
2694 areanum = AAS_PointAreaNum(ms->origin);
2695 if (areanum && areanum != ms->reachareanum) ms->reachability_time = 0;
2696 } //end else
2697 return result;
2698 } //end of the function BotTravel_Grapple
2699 //===========================================================================
2700 //
2701 // Parameter: -
2702 // Returns: -
2703 // Changes Globals: -
2704 //===========================================================================
BotTravel_RocketJump(bot_movestate_t * ms,aas_reachability_t * reach)2705 bot_moveresult_t BotTravel_RocketJump(bot_movestate_t *ms, aas_reachability_t *reach)
2706 {
2707 vec3_t hordir;
2708 float dist, speed;
2709 bot_moveresult_t_cleared( result );
2710
2711 //botimport.Print(PRT_MESSAGE, "BotTravel_RocketJump: bah\n");
2712 //
2713 hordir[0] = reach->start[0] - ms->origin[0];
2714 hordir[1] = reach->start[1] - ms->origin[1];
2715 hordir[2] = 0;
2716 //
2717 dist = VectorNormalize(hordir);
2718 //look in the movement direction
2719 Vector2Angles(hordir, result.ideal_viewangles);
2720 //look straight down
2721 result.ideal_viewangles[PITCH] = 90;
2722 //
2723 if (dist < 5 &&
2724 fabs(AngleDiff(result.ideal_viewangles[0], ms->viewangles[0])) < 5 &&
2725 fabs(AngleDiff(result.ideal_viewangles[1], ms->viewangles[1])) < 5)
2726 {
2727 //botimport.Print(PRT_MESSAGE, "between jump start and run start point\n");
2728 hordir[0] = reach->end[0] - ms->origin[0];
2729 hordir[1] = reach->end[1] - ms->origin[1];
2730 hordir[2] = 0;
2731 VectorNormalize(hordir);
2732 //elemantary action jump
2733 EA_Jump(ms->client);
2734 EA_Attack(ms->client);
2735 EA_Move(ms->client, hordir, 800);
2736 //
2737 ms->jumpreach = ms->lastreachnum;
2738 } //end if
2739 else
2740 {
2741 if (dist > 80) dist = 80;
2742 speed = 400 - (400 - 5 * dist);
2743 EA_Move(ms->client, hordir, speed);
2744 } //end else
2745 //look in the movement direction
2746 Vector2Angles(hordir, result.ideal_viewangles);
2747 //look straight down
2748 result.ideal_viewangles[PITCH] = 90;
2749 //set the view angles directly
2750 EA_View(ms->client, result.ideal_viewangles);
2751 //view is important for the movment
2752 result.flags |= MOVERESULT_MOVEMENTVIEWSET;
2753 //select the rocket launcher
2754 EA_SelectWeapon(ms->client, (int) weapindex_rocketlauncher->value);
2755 //weapon is used for movement
2756 result.weapon = (int) weapindex_rocketlauncher->value;
2757 result.flags |= MOVERESULT_MOVEMENTWEAPON;
2758 //
2759 VectorCopy(hordir, result.movedir);
2760 //
2761 return result;
2762 } //end of the function BotTravel_RocketJump
2763 //===========================================================================
2764 //
2765 // Parameter: -
2766 // Returns: -
2767 // Changes Globals: -
2768 //===========================================================================
BotTravel_BFGJump(bot_movestate_t * ms,aas_reachability_t * reach)2769 bot_moveresult_t BotTravel_BFGJump(bot_movestate_t *ms, aas_reachability_t *reach)
2770 {
2771 vec3_t hordir;
2772 float dist, speed;
2773 bot_moveresult_t_cleared( result );
2774
2775 //botimport.Print(PRT_MESSAGE, "BotTravel_BFGJump: bah\n");
2776 //
2777 hordir[0] = reach->start[0] - ms->origin[0];
2778 hordir[1] = reach->start[1] - ms->origin[1];
2779 hordir[2] = 0;
2780 //
2781 dist = VectorNormalize(hordir);
2782 //
2783 if (dist < 5 &&
2784 fabs(AngleDiff(result.ideal_viewangles[0], ms->viewangles[0])) < 5 &&
2785 fabs(AngleDiff(result.ideal_viewangles[1], ms->viewangles[1])) < 5)
2786 {
2787 //botimport.Print(PRT_MESSAGE, "between jump start and run start point\n");
2788 hordir[0] = reach->end[0] - ms->origin[0];
2789 hordir[1] = reach->end[1] - ms->origin[1];
2790 hordir[2] = 0;
2791 VectorNormalize(hordir);
2792 //elemantary action jump
2793 EA_Jump(ms->client);
2794 EA_Attack(ms->client);
2795 EA_Move(ms->client, hordir, 800);
2796 //
2797 ms->jumpreach = ms->lastreachnum;
2798 } //end if
2799 else
2800 {
2801 if (dist > 80) dist = 80;
2802 speed = 400 - (400 - 5 * dist);
2803 EA_Move(ms->client, hordir, speed);
2804 } //end else
2805 //look in the movement direction
2806 Vector2Angles(hordir, result.ideal_viewangles);
2807 //look straight down
2808 result.ideal_viewangles[PITCH] = 90;
2809 //set the view angles directly
2810 EA_View(ms->client, result.ideal_viewangles);
2811 //view is important for the movment
2812 result.flags |= MOVERESULT_MOVEMENTVIEWSET;
2813 //select the rocket launcher
2814 EA_SelectWeapon(ms->client, (int) weapindex_bfg10k->value);
2815 //weapon is used for movement
2816 result.weapon = (int) weapindex_bfg10k->value;
2817 result.flags |= MOVERESULT_MOVEMENTWEAPON;
2818 //
2819 VectorCopy(hordir, result.movedir);
2820 //
2821 return result;
2822 } //end of the function BotTravel_BFGJump
2823 //===========================================================================
2824 //
2825 // Parameter: -
2826 // Returns: -
2827 // Changes Globals: -
2828 //===========================================================================
BotFinishTravel_WeaponJump(bot_movestate_t * ms,aas_reachability_t * reach)2829 bot_moveresult_t BotFinishTravel_WeaponJump(bot_movestate_t *ms, aas_reachability_t *reach)
2830 {
2831 vec3_t hordir;
2832 float speed;
2833 bot_moveresult_t_cleared( result );
2834
2835 //if not jumped yet
2836 if (!ms->jumpreach) return result;
2837 /*
2838 //go straight to the reachability end
2839 hordir[0] = reach->end[0] - ms->origin[0];
2840 hordir[1] = reach->end[1] - ms->origin[1];
2841 hordir[2] = 0;
2842 VectorNormalize(hordir);
2843 //always use max speed when traveling through the air
2844 EA_Move(ms->client, hordir, 800);
2845 VectorCopy(hordir, result.movedir);
2846 */
2847 //
2848 if (!BotAirControl(ms->origin, ms->velocity, reach->end, hordir, &speed))
2849 {
2850 //go straight to the reachability end
2851 VectorSubtract(reach->end, ms->origin, hordir);
2852 hordir[2] = 0;
2853 VectorNormalize(hordir);
2854 speed = 400;
2855 } //end if
2856 //
2857 EA_Move(ms->client, hordir, speed);
2858 VectorCopy(hordir, result.movedir);
2859 //
2860 return result;
2861 } //end of the function BotFinishTravel_WeaponJump
2862 //===========================================================================
2863 //
2864 // Parameter: -
2865 // Returns: -
2866 // Changes Globals: -
2867 //===========================================================================
BotTravel_JumpPad(bot_movestate_t * ms,aas_reachability_t * reach)2868 bot_moveresult_t BotTravel_JumpPad(bot_movestate_t *ms, aas_reachability_t *reach)
2869 {
2870 float dist, speed;
2871 vec3_t hordir;
2872 bot_moveresult_t_cleared( result );
2873
2874 //first walk straight to the reachability start
2875 hordir[0] = reach->start[0] - ms->origin[0];
2876 hordir[1] = reach->start[1] - ms->origin[1];
2877 hordir[2] = 0;
2878 dist = VectorNormalize(hordir);
2879 //
2880 BotCheckBlocked(ms, hordir, qtrue, &result);
2881 speed = 400;
2882 //elemantary action move in direction
2883 EA_Move(ms->client, hordir, speed);
2884 VectorCopy(hordir, result.movedir);
2885 //
2886 return result;
2887 } //end of the function BotTravel_JumpPad
2888 //===========================================================================
2889 //
2890 // Parameter: -
2891 // Returns: -
2892 // Changes Globals: -
2893 //===========================================================================
BotFinishTravel_JumpPad(bot_movestate_t * ms,aas_reachability_t * reach)2894 bot_moveresult_t BotFinishTravel_JumpPad(bot_movestate_t *ms, aas_reachability_t *reach)
2895 {
2896 float speed;
2897 vec3_t hordir;
2898 bot_moveresult_t_cleared( result );
2899
2900 if (!BotAirControl(ms->origin, ms->velocity, reach->end, hordir, &speed))
2901 {
2902 hordir[0] = reach->end[0] - ms->origin[0];
2903 hordir[1] = reach->end[1] - ms->origin[1];
2904 hordir[2] = 0;
2905 VectorNormalize(hordir);
2906 speed = 400;
2907 } //end if
2908 BotCheckBlocked(ms, hordir, qtrue, &result);
2909 //elemantary action move in direction
2910 EA_Move(ms->client, hordir, speed);
2911 VectorCopy(hordir, result.movedir);
2912 //
2913 return result;
2914 } //end of the function BotFinishTravel_JumpPad
2915 //===========================================================================
2916 // time before the reachability times out
2917 //
2918 // Parameter: -
2919 // Returns: -
2920 // Changes Globals: -
2921 //===========================================================================
BotReachabilityTime(aas_reachability_t * reach)2922 int BotReachabilityTime(aas_reachability_t *reach)
2923 {
2924 switch(reach->traveltype & TRAVELTYPE_MASK)
2925 {
2926 case TRAVEL_WALK: return 5;
2927 case TRAVEL_CROUCH: return 5;
2928 case TRAVEL_BARRIERJUMP: return 5;
2929 case TRAVEL_LADDER: return 6;
2930 case TRAVEL_WALKOFFLEDGE: return 5;
2931 case TRAVEL_JUMP: return 5;
2932 case TRAVEL_SWIM: return 5;
2933 case TRAVEL_WATERJUMP: return 5;
2934 case TRAVEL_TELEPORT: return 5;
2935 case TRAVEL_ELEVATOR: return 10;
2936 case TRAVEL_GRAPPLEHOOK: return 8;
2937 case TRAVEL_ROCKETJUMP: return 6;
2938 case TRAVEL_BFGJUMP: return 6;
2939 case TRAVEL_JUMPPAD: return 10;
2940 case TRAVEL_FUNCBOB: return 10;
2941 default:
2942 {
2943 botimport.Print(PRT_ERROR, "travel type %d not implemented yet\n", reach->traveltype);
2944 return 8;
2945 } //end case
2946 } //end switch
2947 } //end of the function BotReachabilityTime
2948 //===========================================================================
2949 //
2950 // Parameter: -
2951 // Returns: -
2952 // Changes Globals: -
2953 //===========================================================================
BotMoveInGoalArea(bot_movestate_t * ms,bot_goal_t * goal)2954 bot_moveresult_t BotMoveInGoalArea(bot_movestate_t *ms, bot_goal_t *goal)
2955 {
2956 bot_moveresult_t_cleared( result );
2957 vec3_t dir;
2958 float dist, speed;
2959
2960 #ifdef DEBUG
2961 //botimport.Print(PRT_MESSAGE, "%s: moving straight to goal\n", ClientName(ms->entitynum-1));
2962 //AAS_ClearShownDebugLines();
2963 //AAS_DebugLine(ms->origin, goal->origin, LINECOLOR_RED);
2964 #endif //DEBUG
2965 //walk straight to the goal origin
2966 dir[0] = goal->origin[0] - ms->origin[0];
2967 dir[1] = goal->origin[1] - ms->origin[1];
2968 if (ms->moveflags & MFL_SWIMMING)
2969 {
2970 dir[2] = goal->origin[2] - ms->origin[2];
2971 result.traveltype = TRAVEL_SWIM;
2972 } //end if
2973 else
2974 {
2975 dir[2] = 0;
2976 result.traveltype = TRAVEL_WALK;
2977 } //endif
2978 //
2979 dist = VectorNormalize(dir);
2980 if (dist > 100) dist = 100;
2981 speed = 400 - (400 - 4 * dist);
2982 if (speed < 10) speed = 0;
2983 //
2984 BotCheckBlocked(ms, dir, qtrue, &result);
2985 //elemantary action move in direction
2986 EA_Move(ms->client, dir, speed);
2987 VectorCopy(dir, result.movedir);
2988 //
2989 if (ms->moveflags & MFL_SWIMMING)
2990 {
2991 Vector2Angles(dir, result.ideal_viewangles);
2992 result.flags |= MOVERESULT_SWIMVIEW;
2993 } //end if
2994 //if (!debugline) debugline = botimport.DebugLineCreate();
2995 //botimport.DebugLineShow(debugline, ms->origin, goal->origin, LINECOLOR_BLUE);
2996 //
2997 ms->lastreachnum = 0;
2998 ms->lastareanum = 0;
2999 ms->lastgoalareanum = goal->areanum;
3000 VectorCopy(ms->origin, ms->lastorigin);
3001 //
3002 return result;
3003 } //end of the function BotMoveInGoalArea
3004 //===========================================================================
3005 //
3006 // Parameter: -
3007 // Returns: -
3008 // Changes Globals: -
3009 //===========================================================================
BotMoveToGoal(bot_moveresult_t * result,int movestate,bot_goal_t * goal,int travelflags)3010 void BotMoveToGoal(bot_moveresult_t *result, int movestate, bot_goal_t *goal, int travelflags)
3011 {
3012 int reachnum, lastreachnum, foundjumppad, ent, resultflags;
3013 aas_reachability_t reach, lastreach;
3014 bot_movestate_t *ms;
3015 //vec3_t mins, maxs, up = {0, 0, 1};
3016 //bsp_trace_t trace;
3017 //static int debugline;
3018
3019 result->failure = qfalse;
3020 result->type = 0;
3021 result->blocked = qfalse;
3022 result->blockentity = 0;
3023 result->traveltype = 0;
3024 result->flags = 0;
3025
3026 //
3027 ms = BotMoveStateFromHandle(movestate);
3028 if (!ms) return;
3029 //reset the grapple before testing if the bot has a valid goal
3030 //because the bot could loose all it's goals when stuck to a wall
3031 BotResetGrapple(ms);
3032 //
3033 if (!goal)
3034 {
3035 #ifdef DEBUG
3036 botimport.Print(PRT_MESSAGE, "client %d: movetogoal -> no goal\n", ms->client);
3037 #endif //DEBUG
3038 result->failure = qtrue;
3039 return;
3040 } //end if
3041 //botimport.Print(PRT_MESSAGE, "numavoidreach = %d\n", ms->numavoidreach);
3042 //remove some of the move flags
3043 ms->moveflags &= ~(MFL_SWIMMING|MFL_AGAINSTLADDER);
3044 //set some of the move flags
3045 //NOTE: the MFL_ONGROUND flag is also set in the higher AI
3046 if (AAS_OnGround(ms->origin, ms->presencetype, ms->entitynum)) ms->moveflags |= MFL_ONGROUND;
3047 //
3048 if (ms->moveflags & MFL_ONGROUND)
3049 {
3050 int modeltype, modelnum;
3051
3052 ent = BotOnTopOfEntity(ms);
3053
3054 if (ent != -1)
3055 {
3056 modelnum = AAS_EntityModelindex(ent);
3057 if (modelnum >= 0 && modelnum < MAX_MODELS)
3058 {
3059 modeltype = modeltypes[modelnum];
3060
3061 if (modeltype == MODELTYPE_FUNC_PLAT)
3062 {
3063 AAS_ReachabilityFromNum(ms->lastreachnum, &reach);
3064 //if the bot is Not using the elevator
3065 if ((reach.traveltype & TRAVELTYPE_MASK) != TRAVEL_ELEVATOR ||
3066 //NOTE: the face number is the plat model number
3067 (reach.facenum & 0x0000FFFF) != modelnum)
3068 {
3069 reachnum = AAS_NextModelReachability(0, modelnum);
3070 if (reachnum)
3071 {
3072 //botimport.Print(PRT_MESSAGE, "client %d: accidentally ended up on func_plat\n", ms->client);
3073 AAS_ReachabilityFromNum(reachnum, &reach);
3074 ms->lastreachnum = reachnum;
3075 ms->reachability_time = AAS_Time() + BotReachabilityTime(&reach);
3076 } //end if
3077 else
3078 {
3079 if (bot_developer)
3080 {
3081 botimport.Print(PRT_MESSAGE, "client %d: on func_plat without reachability\n", ms->client);
3082 } //end if
3083 result->blocked = qtrue;
3084 result->blockentity = ent;
3085 result->flags |= MOVERESULT_ONTOPOFOBSTACLE;
3086 return;
3087 } //end else
3088 } //end if
3089 result->flags |= MOVERESULT_ONTOPOF_ELEVATOR;
3090 } //end if
3091 else if (modeltype == MODELTYPE_FUNC_BOB)
3092 {
3093 AAS_ReachabilityFromNum(ms->lastreachnum, &reach);
3094 //if the bot is Not using the func bobbing
3095 if ((reach.traveltype & TRAVELTYPE_MASK) != TRAVEL_FUNCBOB ||
3096 //NOTE: the face number is the func_bobbing model number
3097 (reach.facenum & 0x0000FFFF) != modelnum)
3098 {
3099 reachnum = AAS_NextModelReachability(0, modelnum);
3100 if (reachnum)
3101 {
3102 //botimport.Print(PRT_MESSAGE, "client %d: accidentally ended up on func_bobbing\n", ms->client);
3103 AAS_ReachabilityFromNum(reachnum, &reach);
3104 ms->lastreachnum = reachnum;
3105 ms->reachability_time = AAS_Time() + BotReachabilityTime(&reach);
3106 } //end if
3107 else
3108 {
3109 if (bot_developer)
3110 {
3111 botimport.Print(PRT_MESSAGE, "client %d: on func_bobbing without reachability\n", ms->client);
3112 } //end if
3113 result->blocked = qtrue;
3114 result->blockentity = ent;
3115 result->flags |= MOVERESULT_ONTOPOFOBSTACLE;
3116 return;
3117 } //end else
3118 } //end if
3119 result->flags |= MOVERESULT_ONTOPOF_FUNCBOB;
3120 } //end if
3121 else if (modeltype == MODELTYPE_FUNC_STATIC || modeltype == MODELTYPE_FUNC_DOOR)
3122 {
3123 // check if ontop of a door bridge ?
3124 ms->areanum = BotFuzzyPointReachabilityArea(ms->origin);
3125 // if not in a reachability area
3126 if (!AAS_AreaReachability(ms->areanum))
3127 {
3128 result->blocked = qtrue;
3129 result->blockentity = ent;
3130 result->flags |= MOVERESULT_ONTOPOFOBSTACLE;
3131 return;
3132 } //end if
3133 } //end else if
3134 else
3135 {
3136 result->blocked = qtrue;
3137 result->blockentity = ent;
3138 result->flags |= MOVERESULT_ONTOPOFOBSTACLE;
3139 return;
3140 } //end else
3141 } //end if
3142 } //end if
3143 } //end if
3144 //if swimming
3145 if (AAS_Swimming(ms->origin)) ms->moveflags |= MFL_SWIMMING;
3146 //if against a ladder
3147 if (AAS_AgainstLadder(ms->origin)) ms->moveflags |= MFL_AGAINSTLADDER;
3148 //if the bot is on the ground, swimming or against a ladder
3149 if (ms->moveflags & (MFL_ONGROUND|MFL_SWIMMING|MFL_AGAINSTLADDER))
3150 {
3151 //botimport.Print(PRT_MESSAGE, "%s: onground, swimming or against ladder\n", ClientName(ms->entitynum-1));
3152 //
3153 AAS_ReachabilityFromNum(ms->lastreachnum, &lastreach);
3154 //reachability area the bot is in
3155 //ms->areanum = BotReachabilityArea(ms->origin, ((lastreach.traveltype & TRAVELTYPE_MASK) != TRAVEL_ELEVATOR));
3156 ms->areanum = BotFuzzyPointReachabilityArea(ms->origin);
3157 //
3158 if ( !ms->areanum )
3159 {
3160 result->failure = qtrue;
3161 result->blocked = qtrue;
3162 result->blockentity = 0;
3163 result->type = RESULTTYPE_INSOLIDAREA;
3164 return;
3165 } //end if
3166 //if the bot is in the goal area
3167 if (ms->areanum == goal->areanum)
3168 {
3169 *result = BotMoveInGoalArea(ms, goal);
3170 return;
3171 } //end if
3172 //assume we can use the reachability from the last frame
3173 reachnum = ms->lastreachnum;
3174 //if there is a last reachability
3175 if (reachnum)
3176 {
3177 AAS_ReachabilityFromNum(reachnum, &reach);
3178 //check if the reachability is still valid
3179 if (!(AAS_TravelFlagForType(reach.traveltype) & travelflags))
3180 {
3181 reachnum = 0;
3182 } //end if
3183 //special grapple hook case
3184 else if ((reach.traveltype & TRAVELTYPE_MASK) == TRAVEL_GRAPPLEHOOK)
3185 {
3186 if (ms->reachability_time < AAS_Time() ||
3187 (ms->moveflags & MFL_GRAPPLERESET))
3188 {
3189 reachnum = 0;
3190 } //end if
3191 } //end if
3192 //special elevator case
3193 else if ((reach.traveltype & TRAVELTYPE_MASK) == TRAVEL_ELEVATOR ||
3194 (reach.traveltype & TRAVELTYPE_MASK) == TRAVEL_FUNCBOB)
3195 {
3196 if ((result->flags & MOVERESULT_ONTOPOF_FUNCBOB) ||
3197 (result->flags & MOVERESULT_ONTOPOF_FUNCBOB))
3198 {
3199 ms->reachability_time = AAS_Time() + 5;
3200 } //end if
3201 //if the bot was going for an elevator and reached the reachability area
3202 if (ms->areanum == reach.areanum ||
3203 ms->reachability_time < AAS_Time())
3204 {
3205 reachnum = 0;
3206 } //end if
3207 } //end if
3208 else
3209 {
3210 #ifdef DEBUG
3211 if (bot_developer)
3212 {
3213 if (ms->reachability_time < AAS_Time())
3214 {
3215 botimport.Print(PRT_MESSAGE, "client %d: reachability timeout in ", ms->client);
3216 AAS_PrintTravelType(reach.traveltype & TRAVELTYPE_MASK);
3217 botimport.Print(PRT_MESSAGE, "\n");
3218 } //end if
3219 /*
3220 if (ms->lastareanum != ms->areanum)
3221 {
3222 botimport.Print(PRT_MESSAGE, "changed from area %d to %d\n", ms->lastareanum, ms->areanum);
3223 } //end if*/
3224 } //end if
3225 #endif //DEBUG
3226 //if the goal area changed or the reachability timed out
3227 //or the area changed
3228 if (ms->lastgoalareanum != goal->areanum ||
3229 ms->reachability_time < AAS_Time() ||
3230 ms->lastareanum != ms->areanum)
3231 {
3232 reachnum = 0;
3233 //botimport.Print(PRT_MESSAGE, "area change or timeout\n");
3234 } //end else if
3235 } //end else
3236 } //end if
3237 resultflags = 0;
3238 //if the bot needs a new reachability
3239 if (!reachnum)
3240 {
3241 //if the area has no reachability links
3242 if (!AAS_AreaReachability(ms->areanum))
3243 {
3244 #ifdef DEBUG
3245 if (bot_developer)
3246 {
3247 botimport.Print(PRT_MESSAGE, "area %d no reachability\n", ms->areanum);
3248 } //end if
3249 #endif //DEBUG
3250 } //end if
3251 //get a new reachability leading towards the goal
3252 reachnum = BotGetReachabilityToGoal(ms->origin, ms->areanum,
3253 ms->lastgoalareanum, ms->lastareanum,
3254 ms->avoidreach, ms->avoidreachtimes, ms->avoidreachtries,
3255 goal, travelflags, travelflags,
3256 ms->avoidspots, ms->numavoidspots, &resultflags);
3257 //the area number the reachability starts in
3258 ms->reachareanum = ms->areanum;
3259 //reset some state variables
3260 ms->jumpreach = 0; //for TRAVEL_JUMP
3261 ms->moveflags &= ~MFL_GRAPPLERESET; //for TRAVEL_GRAPPLEHOOK
3262 //if there is a reachability to the goal
3263 if (reachnum)
3264 {
3265 AAS_ReachabilityFromNum(reachnum, &reach);
3266 //set a timeout for this reachability
3267 ms->reachability_time = AAS_Time() + BotReachabilityTime(&reach);
3268 //
3269 #ifdef AVOIDREACH
3270 //add the reachability to the reachabilities to avoid for a while
3271 BotAddToAvoidReach(ms, reachnum, AVOIDREACH_TIME);
3272 #endif //AVOIDREACH
3273 } //end if
3274 #ifdef DEBUG
3275
3276 else if (bot_developer)
3277 {
3278 botimport.Print(PRT_MESSAGE, "goal not reachable\n");
3279 Com_Memset(&reach, 0, sizeof(aas_reachability_t)); //make compiler happy
3280 } //end else
3281 if (bot_developer)
3282 {
3283 //if still going for the same goal
3284 if (ms->lastgoalareanum == goal->areanum)
3285 {
3286 if (ms->lastareanum == reach.areanum)
3287 {
3288 botimport.Print(PRT_MESSAGE, "same goal, going back to previous area\n");
3289 } //end if
3290 } //end if
3291 } //end if
3292 #endif //DEBUG
3293 } //end else
3294 //
3295 ms->lastreachnum = reachnum;
3296 ms->lastgoalareanum = goal->areanum;
3297 ms->lastareanum = ms->areanum;
3298 //if the bot has a reachability
3299 if (reachnum)
3300 {
3301 //get the reachability from the number
3302 AAS_ReachabilityFromNum(reachnum, &reach);
3303 result->traveltype = reach.traveltype;
3304 //
3305 #ifdef DEBUG_AI_MOVE
3306 AAS_ClearShownDebugLines();
3307 AAS_PrintTravelType(reach.traveltype & TRAVELTYPE_MASK);
3308 AAS_ShowReachability(&reach);
3309 #endif //DEBUG_AI_MOVE
3310 //
3311 #ifdef DEBUG
3312 //botimport.Print(PRT_MESSAGE, "client %d: ", ms->client);
3313 //AAS_PrintTravelType(reach.traveltype);
3314 //botimport.Print(PRT_MESSAGE, "\n");
3315 #endif //DEBUG
3316 switch(reach.traveltype & TRAVELTYPE_MASK)
3317 {
3318 case TRAVEL_WALK: *result = BotTravel_Walk(ms, &reach); break;
3319 case TRAVEL_CROUCH: *result = BotTravel_Crouch(ms, &reach); break;
3320 case TRAVEL_BARRIERJUMP: *result = BotTravel_BarrierJump(ms, &reach); break;
3321 case TRAVEL_LADDER: *result = BotTravel_Ladder(ms, &reach); break;
3322 case TRAVEL_WALKOFFLEDGE: *result = BotTravel_WalkOffLedge(ms, &reach); break;
3323 case TRAVEL_JUMP: *result = BotTravel_Jump(ms, &reach); break;
3324 case TRAVEL_SWIM: *result = BotTravel_Swim(ms, &reach); break;
3325 case TRAVEL_WATERJUMP: *result = BotTravel_WaterJump(ms, &reach); break;
3326 case TRAVEL_TELEPORT: *result = BotTravel_Teleport(ms, &reach); break;
3327 case TRAVEL_ELEVATOR: *result = BotTravel_Elevator(ms, &reach); break;
3328 case TRAVEL_GRAPPLEHOOK: *result = BotTravel_Grapple(ms, &reach); break;
3329 case TRAVEL_ROCKETJUMP: *result = BotTravel_RocketJump(ms, &reach); break;
3330 case TRAVEL_BFGJUMP: *result = BotTravel_BFGJump(ms, &reach); break;
3331 case TRAVEL_JUMPPAD: *result = BotTravel_JumpPad(ms, &reach); break;
3332 case TRAVEL_FUNCBOB: *result = BotTravel_FuncBobbing(ms, &reach); break;
3333 default:
3334 {
3335 botimport.Print(PRT_FATAL, "travel type %d not implemented yet\n", (reach.traveltype & TRAVELTYPE_MASK));
3336 break;
3337 } //end case
3338 } //end switch
3339 result->traveltype = reach.traveltype;
3340 result->flags |= resultflags;
3341 } //end if
3342 else
3343 {
3344 result->failure = qtrue;
3345 result->flags |= resultflags;
3346 Com_Memset(&reach, 0, sizeof(aas_reachability_t));
3347 } //end else
3348 #ifdef DEBUG
3349 if (bot_developer)
3350 {
3351 if (result->failure)
3352 {
3353 botimport.Print(PRT_MESSAGE, "client %d: movement failure in ", ms->client);
3354 AAS_PrintTravelType(reach.traveltype & TRAVELTYPE_MASK);
3355 botimport.Print(PRT_MESSAGE, "\n");
3356 } //end if
3357 } //end if
3358 #endif //DEBUG
3359 } //end if
3360 else
3361 {
3362 int i, numareas, areas[16];
3363 vec3_t end;
3364
3365 //special handling of jump pads when the bot uses a jump pad without knowing it
3366 foundjumppad = qfalse;
3367 VectorMA(ms->origin, -2 * ms->thinktime, ms->velocity, end);
3368 numareas = AAS_TraceAreas(ms->origin, end, areas, NULL, 16);
3369 for (i = numareas-1; i >= 0; i--)
3370 {
3371 if (AAS_AreaJumpPad(areas[i]))
3372 {
3373 //botimport.Print(PRT_MESSAGE, "client %d used a jumppad without knowing, area %d\n", ms->client, areas[i]);
3374 foundjumppad = qtrue;
3375 lastreachnum = BotGetReachabilityToGoal(end, areas[i],
3376 ms->lastgoalareanum, ms->lastareanum,
3377 ms->avoidreach, ms->avoidreachtimes, ms->avoidreachtries,
3378 goal, travelflags, TFL_JUMPPAD, ms->avoidspots, ms->numavoidspots, NULL);
3379 if (lastreachnum)
3380 {
3381 ms->lastreachnum = lastreachnum;
3382 ms->lastareanum = areas[i];
3383 //botimport.Print(PRT_MESSAGE, "found jumppad reachability\n");
3384 break;
3385 } //end if
3386 else
3387 {
3388 for (lastreachnum = AAS_NextAreaReachability(areas[i], 0); lastreachnum;
3389 lastreachnum = AAS_NextAreaReachability(areas[i], lastreachnum))
3390 {
3391 //get the reachability from the number
3392 AAS_ReachabilityFromNum(lastreachnum, &reach);
3393 if ((reach.traveltype & TRAVELTYPE_MASK) == TRAVEL_JUMPPAD)
3394 {
3395 ms->lastreachnum = lastreachnum;
3396 ms->lastareanum = areas[i];
3397 //botimport.Print(PRT_MESSAGE, "found jumppad reachability hard!!\n");
3398 break;
3399 } //end if
3400 } //end for
3401 if (lastreachnum) break;
3402 } //end else
3403 } //end if
3404 } //end for
3405 if (bot_developer)
3406 {
3407 //if a jumppad is found with the trace but no reachability is found
3408 if (foundjumppad && !ms->lastreachnum)
3409 {
3410 botimport.Print(PRT_MESSAGE, "client %d didn't find jumppad reachability\n", ms->client);
3411 } //end if
3412 } //end if
3413 //
3414 if (ms->lastreachnum)
3415 {
3416 //botimport.Print(PRT_MESSAGE, "%s: NOT onground, swimming or against ladder\n", ClientName(ms->entitynum-1));
3417 AAS_ReachabilityFromNum(ms->lastreachnum, &reach);
3418 result->traveltype = reach.traveltype;
3419 #ifdef DEBUG
3420 //botimport.Print(PRT_MESSAGE, "client %d finish: ", ms->client);
3421 //AAS_PrintTravelType(reach.traveltype & TRAVELTYPE_MASK);
3422 //botimport.Print(PRT_MESSAGE, "\n");
3423 #endif //DEBUG
3424 //
3425 switch(reach.traveltype & TRAVELTYPE_MASK)
3426 {
3427 case TRAVEL_WALK: *result = BotTravel_Walk(ms, &reach); break;//BotFinishTravel_Walk(ms, &reach); break;
3428 case TRAVEL_CROUCH: /*do nothing*/ break;
3429 case TRAVEL_BARRIERJUMP: *result = BotFinishTravel_BarrierJump(ms, &reach); break;
3430 case TRAVEL_LADDER: *result = BotTravel_Ladder(ms, &reach); break;
3431 case TRAVEL_WALKOFFLEDGE: *result = BotFinishTravel_WalkOffLedge(ms, &reach); break;
3432 case TRAVEL_JUMP: *result = BotFinishTravel_Jump(ms, &reach); break;
3433 case TRAVEL_SWIM: *result = BotTravel_Swim(ms, &reach); break;
3434 case TRAVEL_WATERJUMP: *result = BotFinishTravel_WaterJump(ms, &reach); break;
3435 case TRAVEL_TELEPORT: /*do nothing*/ break;
3436 case TRAVEL_ELEVATOR: *result = BotFinishTravel_Elevator(ms, &reach); break;
3437 case TRAVEL_GRAPPLEHOOK: *result = BotTravel_Grapple(ms, &reach); break;
3438 case TRAVEL_ROCKETJUMP:
3439 case TRAVEL_BFGJUMP: *result = BotFinishTravel_WeaponJump(ms, &reach); break;
3440 case TRAVEL_JUMPPAD: *result = BotFinishTravel_JumpPad(ms, &reach); break;
3441 case TRAVEL_FUNCBOB: *result = BotFinishTravel_FuncBobbing(ms, &reach); break;
3442 default:
3443 {
3444 botimport.Print(PRT_FATAL, "(last) travel type %d not implemented yet\n", (reach.traveltype & TRAVELTYPE_MASK));
3445 break;
3446 } //end case
3447 } //end switch
3448 result->traveltype = reach.traveltype;
3449 #ifdef DEBUG
3450 if (bot_developer)
3451 {
3452 if (result->failure)
3453 {
3454 botimport.Print(PRT_MESSAGE, "client %d: movement failure in finish ", ms->client);
3455 AAS_PrintTravelType(reach.traveltype & TRAVELTYPE_MASK);
3456 botimport.Print(PRT_MESSAGE, "\n");
3457 } //end if
3458 } //end if
3459 #endif //DEBUG
3460 } //end if
3461 } //end else
3462 //FIXME: is it right to do this here?
3463 if (result->blocked) ms->reachability_time -= 10 * ms->thinktime;
3464 //copy the last origin
3465 VectorCopy(ms->origin, ms->lastorigin);
3466 //return the movement result
3467 return;
3468 } //end of the function BotMoveToGoal
3469 //===========================================================================
3470 //
3471 // Parameter: -
3472 // Returns: -
3473 // Changes Globals: -
3474 //===========================================================================
BotResetAvoidReach(int movestate)3475 void BotResetAvoidReach(int movestate)
3476 {
3477 bot_movestate_t *ms;
3478
3479 ms = BotMoveStateFromHandle(movestate);
3480 if (!ms) return;
3481 Com_Memset(ms->avoidreach, 0, MAX_AVOIDREACH * sizeof(int));
3482 Com_Memset(ms->avoidreachtimes, 0, MAX_AVOIDREACH * sizeof(float));
3483 Com_Memset(ms->avoidreachtries, 0, MAX_AVOIDREACH * sizeof(int));
3484 } //end of the function BotResetAvoidReach
3485 //===========================================================================
3486 //
3487 // Parameter: -
3488 // Returns: -
3489 // Changes Globals: -
3490 //===========================================================================
BotResetLastAvoidReach(int movestate)3491 void BotResetLastAvoidReach(int movestate)
3492 {
3493 int i, latest;
3494 float latesttime;
3495 bot_movestate_t *ms;
3496
3497 ms = BotMoveStateFromHandle(movestate);
3498 if (!ms) return;
3499 latesttime = 0;
3500 latest = 0;
3501 for (i = 0; i < MAX_AVOIDREACH; i++)
3502 {
3503 if (ms->avoidreachtimes[i] > latesttime)
3504 {
3505 latesttime = ms->avoidreachtimes[i];
3506 latest = i;
3507 } //end if
3508 } //end for
3509 if (latesttime)
3510 {
3511 ms->avoidreachtimes[latest] = 0;
3512 if (ms->avoidreachtries[i] > 0) ms->avoidreachtries[latest]--;
3513 } //end if
3514 } //end of the function BotResetLastAvoidReach
3515 //===========================================================================
3516 //
3517 // Parameter: -
3518 // Returns: -
3519 // Changes Globals: -
3520 //===========================================================================
BotResetMoveState(int movestate)3521 void BotResetMoveState(int movestate)
3522 {
3523 bot_movestate_t *ms;
3524
3525 ms = BotMoveStateFromHandle(movestate);
3526 if (!ms) return;
3527 Com_Memset(ms, 0, sizeof(bot_movestate_t));
3528 } //end of the function BotResetMoveState
3529 //===========================================================================
3530 //
3531 // Parameter: -
3532 // Returns: -
3533 // Changes Globals: -
3534 //===========================================================================
BotSetupMoveAI(void)3535 int BotSetupMoveAI(void)
3536 {
3537 BotSetBrushModelTypes();
3538 sv_maxstep = LibVar("sv_step", "18");
3539 sv_maxbarrier = LibVar("sv_maxbarrier", "32");
3540 sv_gravity = LibVar("sv_gravity", "800");
3541 weapindex_rocketlauncher = LibVar("weapindex_rocketlauncher", "5");
3542 weapindex_bfg10k = LibVar("weapindex_bfg10k", "9");
3543 weapindex_grapple = LibVar("weapindex_grapple", "10");
3544 entitytypemissile = LibVar("entitytypemissile", "3");
3545 offhandgrapple = LibVar("offhandgrapple", "0");
3546 cmd_grappleon = LibVar("cmd_grappleon", "grappleon");
3547 cmd_grappleoff = LibVar("cmd_grappleoff", "grappleoff");
3548 return BLERR_NOERROR;
3549 } //end of the function BotSetupMoveAI
3550 //===========================================================================
3551 //
3552 // Parameter: -
3553 // Returns: -
3554 // Changes Globals: -
3555 //===========================================================================
BotShutdownMoveAI(void)3556 void BotShutdownMoveAI(void)
3557 {
3558 int i;
3559
3560 for (i = 1; i <= MAX_CLIENTS; i++)
3561 {
3562 if (botmovestates[i])
3563 {
3564 FreeMemory(botmovestates[i]);
3565 botmovestates[i] = NULL;
3566 } //end if
3567 } //end for
3568 } //end of the function BotShutdownMoveAI
3569
3570
3571