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