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