~ubuntu-branches/ubuntu/precise/openarena/precise

« back to all changes in this revision

Viewing changes to code/botlib/be_ai_move.c

  • Committer: Bazaar Package Importer
  • Author(s): Bruno "Fuddl" Kleinert
  • Date: 2007-01-20 12:28:09 UTC
  • Revision ID: james.westby@ubuntu.com-20070120122809-2yza5ojt7nqiyiam
Tags: upstream-0.6.0
ImportĀ upstreamĀ versionĀ 0.6.0

Show diffs side-by-side

added added

removed removed

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