Main Page | Class Hierarchy | Alphabetical List | Data Structures | Directories | File List | Data Fields | Globals

be_ai_move.c

Go to the documentation of this file.
00001 /*
00002 ===========================================================================
00003 Copyright (C) 1999-2005 Id Software, Inc.
00004 
00005 This file is part of Quake III Arena source code.
00006 
00007 Quake III Arena source code is free software; you can redistribute it
00008 and/or modify it under the terms of the GNU General Public License as
00009 published by the Free Software Foundation; either version 2 of the License,
00010 or (at your option) any later version.
00011 
00012 Quake III Arena source code is distributed in the hope that it will be
00013 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
00014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015 GNU General Public License for more details.
00016 
00017 You should have received a copy of the GNU General Public License
00018 along with Foobar; if not, write to the Free Software
00019 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00020 ===========================================================================
00021 */
00022 
00023 /*****************************************************************************
00024  * name:        be_ai_move.c
00025  *
00026  * desc:        bot movement AI
00027  *
00028  * $Archive: /MissionPack/code/botlib/be_ai_move.c $
00029  *
00030  *****************************************************************************/
00031 
00032 #include "../game/q_shared.h"
00033 #include "l_memory.h"
00034 #include "l_libvar.h"
00035 #include "l_utils.h"
00036 #include "l_script.h"
00037 #include "l_precomp.h"
00038 #include "l_struct.h"
00039 #include "aasfile.h"
00040 #include "../game/botlib.h"
00041 #include "../game/be_aas.h"
00042 #include "be_aas_funcs.h"
00043 #include "be_interface.h"
00044 
00045 #include "../game/be_ea.h"
00046 #include "../game/be_ai_goal.h"
00047 #include "../game/be_ai_move.h"
00048 
00049 
00050 //#define DEBUG_AI_MOVE
00051 //#define DEBUG_ELEVATOR
00052 //#define DEBUG_GRAPPLE
00053 
00054 // bk001204 - redundant bot_avoidspot_t, see ../game/be_ai_move.h
00055 
00056 //movement state
00057 //NOTE: the moveflags MFL_ONGROUND, MFL_TELEPORTED, MFL_WATERJUMP and
00058 //      MFL_GRAPPLEPULL must be set outside the movement code
00059 typedef struct bot_movestate_s
00060 {
00061     //input vars (all set outside the movement code)
00062     vec3_t origin;                              //origin of the bot
00063     vec3_t velocity;                            //velocity of the bot
00064     vec3_t viewoffset;                          //view offset
00065     int entitynum;                              //entity number of the bot
00066     int client;                                 //client number of the bot
00067     float thinktime;                            //time the bot thinks
00068     int presencetype;                           //presencetype of the bot
00069     vec3_t viewangles;                          //view angles of the bot
00070     //state vars
00071     int areanum;                                //area the bot is in
00072     int lastareanum;                            //last area the bot was in
00073     int lastgoalareanum;                        //last goal area number
00074     int lastreachnum;                           //last reachability number
00075     vec3_t lastorigin;                          //origin previous cycle
00076     int reachareanum;                           //area number of the reachabilty
00077     int moveflags;                              //movement flags
00078     int jumpreach;                              //set when jumped
00079     float grapplevisible_time;                  //last time the grapple was visible
00080     float lastgrappledist;                      //last distance to the grapple end
00081     float reachability_time;                    //time to use current reachability
00082     int avoidreach[MAX_AVOIDREACH];             //reachabilities to avoid
00083     float avoidreachtimes[MAX_AVOIDREACH];      //times to avoid the reachabilities
00084     int avoidreachtries[MAX_AVOIDREACH];        //number of tries before avoiding
00085     //
00086     bot_avoidspot_t avoidspots[MAX_AVOIDSPOTS]; //spots to avoid
00087     int numavoidspots;
00088 } bot_movestate_t;
00089 
00090 //used to avoid reachability links for some time after being used
00091 #define AVOIDREACH
00092 #define AVOIDREACH_TIME         6       //avoid links for 6 seconds after use
00093 #define AVOIDREACH_TRIES        4
00094 //prediction times
00095 #define PREDICTIONTIME_JUMP 3       //in seconds
00096 #define PREDICTIONTIME_MOVE 2       //in seconds
00097 //weapon indexes for weapon jumping
00098 #define WEAPONINDEX_ROCKET_LAUNCHER     5
00099 #define WEAPONINDEX_BFG                 9
00100 
00101 #define MODELTYPE_FUNC_PLAT     1
00102 #define MODELTYPE_FUNC_BOB      2
00103 #define MODELTYPE_FUNC_DOOR     3
00104 #define MODELTYPE_FUNC_STATIC   4
00105 
00106 libvar_t *sv_maxstep;
00107 libvar_t *sv_maxbarrier;
00108 libvar_t *sv_gravity;
00109 libvar_t *weapindex_rocketlauncher;
00110 libvar_t *weapindex_bfg10k;
00111 libvar_t *weapindex_grapple;
00112 libvar_t *entitytypemissile;
00113 libvar_t *offhandgrapple;
00114 libvar_t *cmd_grappleoff;
00115 libvar_t *cmd_grappleon;
00116 //type of model, func_plat or func_bobbing
00117 int modeltypes[MAX_MODELS];
00118 
00119 bot_movestate_t *botmovestates[MAX_CLIENTS+1];
00120 
00121 //========================================================================
00122 //
00123 // Parameter:           -
00124 // Returns:             -
00125 // Changes Globals:     -
00126 //========================================================================
00127 int BotAllocMoveState(void)
00128 {
00129     int i;
00130 
00131     for (i = 1; i <= MAX_CLIENTS; i++)
00132     {
00133         if (!botmovestates[i])
00134         {
00135             botmovestates[i] = GetClearedMemory(sizeof(bot_movestate_t));
00136             return i;
00137         } //end if
00138     } //end for
00139     return 0;
00140 } //end of the function BotAllocMoveState
00141 //========================================================================
00142 //
00143 // Parameter:           -
00144 // Returns:             -
00145 // Changes Globals:     -
00146 //========================================================================
00147 void BotFreeMoveState(int handle)
00148 {
00149     if (handle <= 0 || handle > MAX_CLIENTS)
00150     {
00151         botimport.Print(PRT_FATAL, "move state handle %d out of range\n", handle);
00152         return;
00153     } //end if
00154     if (!botmovestates[handle])
00155     {
00156         botimport.Print(PRT_FATAL, "invalid move state %d\n", handle);
00157         return;
00158     } //end if
00159     FreeMemory(botmovestates[handle]);
00160     botmovestates[handle] = NULL;
00161 } //end of the function BotFreeMoveState
00162 //========================================================================
00163 //
00164 // Parameter:               -
00165 // Returns:                 -
00166 // Changes Globals:     -
00167 //========================================================================
00168 bot_movestate_t *BotMoveStateFromHandle(int handle)
00169 {
00170     if (handle <= 0 || handle > MAX_CLIENTS)
00171     {
00172         botimport.Print(PRT_FATAL, "move state handle %d out of range\n", handle);
00173         return NULL;
00174     } //end if
00175     if (!botmovestates[handle])
00176     {
00177         botimport.Print(PRT_FATAL, "invalid move state %d\n", handle);
00178         return NULL;
00179     } //end if
00180     return botmovestates[handle];
00181 } //end of the function BotMoveStateFromHandle
00182 //========================================================================
00183 //
00184 // Parameter:           -
00185 // Returns:             -
00186 // Changes Globals:     -
00187 //========================================================================
00188 void BotInitMoveState(int handle, bot_initmove_t *initmove)
00189 {
00190     bot_movestate_t *ms;
00191 
00192     ms = BotMoveStateFromHandle(handle);
00193     if (!ms) return;
00194     VectorCopy(initmove->origin, ms->origin);
00195     VectorCopy(initmove->velocity, ms->velocity);
00196     VectorCopy(initmove->viewoffset, ms->viewoffset);
00197     ms->entitynum = initmove->entitynum;
00198     ms->client = initmove->client;
00199     ms->thinktime = initmove->thinktime;
00200     ms->presencetype = initmove->presencetype;
00201     VectorCopy(initmove->viewangles, ms->viewangles);
00202     //
00203     ms->moveflags &= ~MFL_ONGROUND;
00204     if (initmove->or_moveflags & MFL_ONGROUND) ms->moveflags |= MFL_ONGROUND;
00205     ms->moveflags &= ~MFL_TELEPORTED;   
00206     if (initmove->or_moveflags & MFL_TELEPORTED) ms->moveflags |= MFL_TELEPORTED;
00207     ms->moveflags &= ~MFL_WATERJUMP;
00208     if (initmove->or_moveflags & MFL_WATERJUMP) ms->moveflags |= MFL_WATERJUMP;
00209     ms->moveflags &= ~MFL_WALK;
00210     if (initmove->or_moveflags & MFL_WALK) ms->moveflags |= MFL_WALK;
00211     ms->moveflags &= ~MFL_GRAPPLEPULL;
00212     if (initmove->or_moveflags & MFL_GRAPPLEPULL) ms->moveflags |= MFL_GRAPPLEPULL;
00213 } //end of the function BotInitMoveState
00214 //========================================================================
00215 //
00216 // Parameter:           -
00217 // Returns:             -
00218 // Changes Globals:     -
00219 //========================================================================
00220 float AngleDiff(float ang1, float ang2)
00221 {
00222     float diff;
00223 
00224     diff = ang1 - ang2;
00225     if (ang1 > ang2)
00226     {
00227         if (diff > 180.0) diff -= 360.0;
00228     } //end if
00229     else
00230     {
00231         if (diff < -180.0) diff += 360.0;
00232     } //end else
00233     return diff;
00234 } //end of the function AngleDiff
00235 //===========================================================================
00236 //
00237 // Parameter:           -
00238 // Returns:             -
00239 // Changes Globals:     -
00240 //===========================================================================
00241 int BotFuzzyPointReachabilityArea(vec3_t origin)
00242 {
00243     int firstareanum, j, x, y, z;
00244     int areas[10], numareas, areanum, bestareanum;
00245     float dist, bestdist;
00246     vec3_t points[10], v, end;
00247 
00248     firstareanum = 0;
00249     areanum = AAS_PointAreaNum(origin);
00250     if (areanum)
00251     {
00252         firstareanum = areanum;
00253         if (AAS_AreaReachability(areanum)) return areanum;
00254     } //end if
00255     VectorCopy(origin, end);
00256     end[2] += 4;
00257     numareas = AAS_TraceAreas(origin, end, areas, points, 10);
00258     for (j = 0; j < numareas; j++)
00259     {
00260         if (AAS_AreaReachability(areas[j])) return areas[j];
00261     } //end for
00262     bestdist = 999999;
00263     bestareanum = 0;
00264     for (z = 1; z >= -1; z -= 1)
00265     {
00266         for (x = 1; x >= -1; x -= 1)
00267         {
00268             for (y = 1; y >= -1; y -= 1)
00269             {
00270                 VectorCopy(origin, end);
00271                 end[0] += x * 8;
00272                 end[1] += y * 8;
00273                 end[2] += z * 12;
00274                 numareas = AAS_TraceAreas(origin, end, areas, points, 10);
00275                 for (j = 0; j < numareas; j++)
00276                 {
00277                     if (AAS_AreaReachability(areas[j]))
00278                     {
00279                         VectorSubtract(points[j], origin, v);
00280                         dist = VectorLength(v);
00281                         if (dist < bestdist)
00282                         {
00283                             bestareanum = areas[j];
00284                             bestdist = dist;
00285                         } //end if
00286                     } //end if
00287                     if (!firstareanum) firstareanum = areas[j];
00288                 } //end for
00289             } //end for
00290         } //end for
00291         if (bestareanum) return bestareanum;
00292     } //end for
00293     return firstareanum;
00294 } //end of the function BotFuzzyPointReachabilityArea
00295 //===========================================================================
00296 //
00297 // Parameter:           -
00298 // Returns:             -
00299 // Changes Globals:     -
00300 //===========================================================================
00301 int BotReachabilityArea(vec3_t origin, int client)
00302 {
00303     int modelnum, modeltype, reachnum, areanum;
00304     aas_reachability_t reach;
00305     vec3_t org, end, mins, maxs, up = {0, 0, 1};
00306     bsp_trace_t bsptrace;
00307     aas_trace_t trace;
00308 
00309     //check if the bot is standing on something
00310     AAS_PresenceTypeBoundingBox(PRESENCE_CROUCH, mins, maxs);
00311     VectorMA(origin, -3, up, end);
00312     bsptrace = AAS_Trace(origin, mins, maxs, end, client, CONTENTS_SOLID|CONTENTS_PLAYERCLIP);
00313     if (!bsptrace.startsolid && bsptrace.fraction < 1 && bsptrace.ent != ENTITYNUM_NONE)
00314     {
00315         //if standing on the world the bot should be in a valid area
00316         if (bsptrace.ent == ENTITYNUM_WORLD)
00317         {
00318             return BotFuzzyPointReachabilityArea(origin);
00319         } //end if
00320 
00321         modelnum = AAS_EntityModelindex(bsptrace.ent);
00322         modeltype = modeltypes[modelnum];
00323 
00324         //if standing on a func_plat or func_bobbing then the bot is assumed to be
00325         //in the area the reachability points to
00326         if (modeltype == MODELTYPE_FUNC_PLAT || modeltype == MODELTYPE_FUNC_BOB)
00327         {
00328             reachnum = AAS_NextModelReachability(0, modelnum);
00329             if (reachnum)
00330             {
00331                 AAS_ReachabilityFromNum(reachnum, &reach);
00332                 return reach.areanum;
00333             } //end if
00334         } //end else if
00335 
00336         //if the bot is swimming the bot should be in a valid area
00337         if (AAS_Swimming(origin))
00338         {
00339             return BotFuzzyPointReachabilityArea(origin);
00340         } //end if
00341         //
00342         areanum = BotFuzzyPointReachabilityArea(origin);
00343         //if the bot is in an area with reachabilities
00344         if (areanum && AAS_AreaReachability(areanum)) return areanum;
00345         //trace down till the ground is hit because the bot is standing on some other entity
00346         VectorCopy(origin, org);
00347         VectorCopy(org, end);
00348         end[2] -= 800;
00349         trace = AAS_TraceClientBBox(org, end, PRESENCE_CROUCH, -1);
00350         if (!trace.startsolid)
00351         {
00352             VectorCopy(trace.endpos, org);
00353         } //end if
00354         //
00355         return BotFuzzyPointReachabilityArea(org);
00356     } //end if
00357     //
00358     return BotFuzzyPointReachabilityArea(origin);
00359 } //end of the function BotReachabilityArea
00360 //===========================================================================
00361 // returns the reachability area the bot is in
00362 //
00363 // Parameter:               -
00364 // Returns:                 -
00365 // Changes Globals:     -
00366 //===========================================================================
00367 /*
00368 int BotReachabilityArea(vec3_t origin, int testground)
00369 {
00370     int firstareanum, i, j, x, y, z;
00371     int areas[10], numareas, areanum, bestareanum;
00372     float dist, bestdist;
00373     vec3_t org, end, points[10], v;
00374     aas_trace_t trace;
00375 
00376     firstareanum = 0;
00377     for (i = 0; i < 2; i++)
00378     {
00379         VectorCopy(origin, org);
00380         //if test at the ground (used when bot is standing on an entity)
00381         if (i > 0)
00382         {
00383             VectorCopy(origin, end);
00384             end[2] -= 800;
00385             trace = AAS_TraceClientBBox(origin, end, PRESENCE_CROUCH, -1);
00386             if (!trace.startsolid)
00387             {
00388                 VectorCopy(trace.endpos, org);
00389             } //end if
00390         } //end if
00391 
00392         firstareanum = 0;
00393         areanum = AAS_PointAreaNum(org);
00394         if (areanum)
00395         {
00396             firstareanum = areanum;
00397             if (AAS_AreaReachability(areanum)) return areanum;
00398         } //end if
00399         bestdist = 999999;
00400         bestareanum = 0;
00401         for (z = 1; z >= -1; z -= 1)
00402         {
00403             for (x = 1; x >= -1; x -= 1)
00404             {
00405                 for (y = 1; y >= -1; y -= 1)
00406                 {
00407                     VectorCopy(org, end);
00408                     end[0] += x * 8;
00409                     end[1] += y * 8;
00410                     end[2] += z * 12;
00411                     numareas = AAS_TraceAreas(org, end, areas, points, 10);
00412                     for (j = 0; j < numareas; j++)
00413                     {
00414                         if (AAS_AreaReachability(areas[j]))
00415                         {
00416                             VectorSubtract(points[j], org, v);
00417                             dist = VectorLength(v);
00418                             if (dist < bestdist)
00419                             {
00420                                 bestareanum = areas[j];
00421                                 bestdist = dist;
00422                             } //end if
00423                         } //end if
00424                     } //end for
00425                 } //end for
00426             } //end for
00427             if (bestareanum) return bestareanum;
00428         } //end for
00429         if (!testground) break;
00430     } //end for
00431 //#ifdef DEBUG
00432     //botimport.Print(PRT_MESSAGE, "no reachability area\n");
00433 //#endif //DEBUG
00434     return firstareanum;
00435 } //end of the function BotReachabilityArea*/
00436 //===========================================================================
00437 //
00438 // Parameter:           -
00439 // Returns:             -
00440 // Changes Globals:     -
00441 //===========================================================================
00442 int BotOnMover(vec3_t origin, int entnum, aas_reachability_t *reach)
00443 {
00444     int i, modelnum;
00445     vec3_t mins, maxs, modelorigin, org, end;
00446     vec3_t angles = {0, 0, 0};
00447     vec3_t boxmins = {-16, -16, -8}, boxmaxs = {16, 16, 8};
00448     bsp_trace_t trace;
00449 
00450     modelnum = reach->facenum & 0x0000FFFF;
00451     //get some bsp model info
00452     AAS_BSPModelMinsMaxsOrigin(modelnum, angles, mins, maxs, NULL);
00453     //
00454     if (!AAS_OriginOfMoverWithModelNum(modelnum, modelorigin))
00455     {
00456         botimport.Print(PRT_MESSAGE, "no entity with model %d\n", modelnum);
00457         return qfalse;
00458     } //end if
00459     //
00460     for (i = 0; i < 2; i++)
00461     {
00462         if (origin[i] > modelorigin[i] + maxs[i] + 16) return qfalse;
00463         if (origin[i] < modelorigin[i] + mins[i] - 16) return qfalse;
00464     } //end for
00465     //
00466     VectorCopy(origin, org);
00467     org[2] += 24;
00468     VectorCopy(origin, end);
00469     end[2] -= 48;
00470     //
00471     trace = AAS_Trace(org, boxmins, boxmaxs, end, entnum, CONTENTS_SOLID|CONTENTS_PLAYERCLIP);
00472     if (!trace.startsolid && !trace.allsolid)
00473     {
00474         //NOTE: the reachability face number is the model number of the elevator
00475         if (trace.ent != ENTITYNUM_NONE && AAS_EntityModelNum(trace.ent) == modelnum)
00476         {
00477             return qtrue;
00478         } //end if
00479     } //end if
00480     return qfalse;
00481 } //end of the function BotOnMover
00482 //===========================================================================
00483 //
00484 // Parameter:           -
00485 // Returns:             -
00486 // Changes Globals:     -
00487 //===========================================================================
00488 int MoverDown(aas_reachability_t *reach)
00489 {
00490     int modelnum;
00491     vec3_t mins, maxs, origin;
00492     vec3_t angles = {0, 0, 0};
00493 
00494     modelnum = reach->facenum & 0x0000FFFF;
00495     //get some bsp model info
00496     AAS_BSPModelMinsMaxsOrigin(modelnum, angles, mins, maxs, origin);
00497     //
00498     if (!AAS_OriginOfMoverWithModelNum(modelnum, origin))
00499     {
00500         botimport.Print(PRT_MESSAGE, "no entity with model %d\n", modelnum);
00501         return qfalse;
00502     } //end if
00503     //if the top of the plat is below the reachability start point
00504     if (origin[2] + maxs[2] < reach->start[2]) return qtrue;
00505     return qfalse;
00506 } //end of the function MoverDown
00507 //========================================================================
00508 //
00509 // Parameter:           -
00510 // Returns:             -
00511 // Changes Globals:     -
00512 //========================================================================
00513 void BotSetBrushModelTypes(void)
00514 {
00515     int ent, modelnum;
00516     char classname[MAX_EPAIRKEY], model[MAX_EPAIRKEY];
00517 
00518     Com_Memset(modeltypes, 0, MAX_MODELS * sizeof(int));
00519     //
00520     for (ent = AAS_NextBSPEntity(0); ent; ent = AAS_NextBSPEntity(ent))
00521     {
00522         if (!AAS_ValueForBSPEpairKey(ent, "classname", classname, MAX_EPAIRKEY)) continue;
00523         if (!AAS_ValueForBSPEpairKey(ent, "model", model, MAX_EPAIRKEY)) continue;
00524         if (model[0]) modelnum = atoi(model+1);
00525         else modelnum = 0;
00526 
00527         if (modelnum < 0 || modelnum > MAX_MODELS)
00528         {
00529             botimport.Print(PRT_MESSAGE, "entity %s model number out of range\n", classname);
00530             continue;
00531         } //end if
00532 
00533         if (!Q_stricmp(classname, "func_bobbing"))
00534             modeltypes[modelnum] = MODELTYPE_FUNC_BOB;
00535         else if (!Q_stricmp(classname, "func_plat"))
00536             modeltypes[modelnum] = MODELTYPE_FUNC_PLAT;
00537         else if (!Q_stricmp(classname, "func_door"))
00538             modeltypes[modelnum] = MODELTYPE_FUNC_DOOR;
00539         else if (!Q_stricmp(classname, "func_static"))
00540             modeltypes[modelnum] = MODELTYPE_FUNC_STATIC;
00541     } //end for
00542 } //end of the function BotSetBrushModelTypes
00543 //===========================================================================
00544 //
00545 // Parameter:           -
00546 // Returns:             -
00547 // Changes Globals:     -
00548 //===========================================================================
00549 int BotOnTopOfEntity(bot_movestate_t *ms)
00550 {
00551     vec3_t mins, maxs, end, up = {0, 0, 1};
00552     bsp_trace_t trace;
00553 
00554     AAS_PresenceTypeBoundingBox(ms->presencetype, mins, maxs);
00555     VectorMA(ms->origin, -3, up, end);
00556     trace = AAS_Trace(ms->origin, mins, maxs, end, ms->entitynum, CONTENTS_SOLID|CONTENTS_PLAYERCLIP);
00557     if (!trace.startsolid && (trace.ent != ENTITYNUM_WORLD && trace.ent != ENTITYNUM_NONE) )
00558     {
00559         return trace.ent;
00560     } //end if
00561     return -1;
00562 } //end of the function BotOnTopOfEntity
00563 //===========================================================================
00564 //
00565 // Parameter:           -
00566 // Returns:             -
00567 // Changes Globals:     -
00568 //===========================================================================
00569 int BotValidTravel(vec3_t origin, aas_reachability_t *reach, int travelflags)
00570 {
00571     //if the reachability uses an unwanted travel type
00572     if (AAS_TravelFlagForType(reach->traveltype) & ~travelflags) return qfalse;
00573     //don't go into areas with bad travel types
00574     if (AAS_AreaContentsTravelFlags(reach->areanum) & ~travelflags) return qfalse;
00575     return qtrue;
00576 } //end of the function BotValidTravel
00577 //===========================================================================
00578 //
00579 // Parameter:               -
00580 // Returns:                 -
00581 // Changes Globals:     -
00582 //===========================================================================
00583 void BotAddToAvoidReach(bot_movestate_t *ms, int number, float avoidtime)
00584 {
00585     int i;
00586 
00587     for (i = 0; i < MAX_AVOIDREACH; i++)
00588     {
00589         if (ms->avoidreach[i] == number)
00590         {
00591             if (ms->avoidreachtimes[i] > AAS_Time()) ms->avoidreachtries[i]++;
00592             else ms->avoidreachtries[i] = 1;
00593             ms->avoidreachtimes[i] = AAS_Time() + avoidtime;
00594             return;
00595         } //end if
00596     } //end for
00597     //add the reachability to the reachabilities to avoid for a while
00598     for (i = 0; i < MAX_AVOIDREACH; i++)
00599     {
00600         if (ms->avoidreachtimes[i] < AAS_Time())
00601         {
00602             ms->avoidreach[i] = number;
00603             ms->avoidreachtimes[i] = AAS_Time() + avoidtime;
00604             ms->avoidreachtries[i] = 1;
00605             return;
00606         } //end if
00607     } //end for
00608 } //end of the function BotAddToAvoidReach
00609 //===========================================================================
00610 //
00611 // Parameter:           -
00612 // Returns:             -
00613 // Changes Globals:     -
00614 //===========================================================================
00615 float DistanceFromLineSquared(vec3_t p, vec3_t lp1, vec3_t lp2)
00616 {
00617     vec3_t proj, dir;
00618     int j;
00619 
00620     AAS_ProjectPointOntoVector(p, lp1, lp2, proj);
00621     for (j = 0; j < 3; j++)
00622         if ((proj[j] > lp1[j] && proj[j] > lp2[j]) ||
00623             (proj[j] < lp1[j] && proj[j] < lp2[j]))
00624             break;
00625     if (j < 3) {
00626         if (fabs(proj[j] - lp1[j]) < fabs(proj[j] - lp2[j]))
00627             VectorSubtract(p, lp1, dir);
00628         else
00629             VectorSubtract(p, lp2, dir);
00630         return VectorLengthSquared(dir);
00631     }
00632     VectorSubtract(p, proj, dir);
00633     return VectorLengthSquared(dir);
00634 } //end of the function DistanceFromLineSquared
00635 //===========================================================================
00636 //
00637 // Parameter:           -
00638 // Returns:             -
00639 // Changes Globals:     -
00640 //===========================================================================
00641 float VectorDistanceSquared(vec3_t p1, vec3_t p2)
00642 {
00643     vec3_t dir;
00644     VectorSubtract(p2, p1, dir);
00645     return VectorLengthSquared(dir);
00646 } //end of the function VectorDistanceSquared
00647 //===========================================================================
00648 //
00649 // Parameter:           -
00650 // Returns:             -
00651 // Changes Globals:     -
00652 //===========================================================================
00653 int BotAvoidSpots(vec3_t origin, aas_reachability_t *reach, bot_avoidspot_t *avoidspots, int numavoidspots)
00654 {
00655     int checkbetween, i, type;
00656     float squareddist, squaredradius;
00657 
00658     switch(reach->traveltype & TRAVELTYPE_MASK)
00659     {
00660         case TRAVEL_WALK: checkbetween = qtrue; break;
00661         case TRAVEL_CROUCH: checkbetween = qtrue; break;
00662         case TRAVEL_BARRIERJUMP: checkbetween = qtrue; break;
00663         case TRAVEL_LADDER: checkbetween = qtrue; break;
00664         case TRAVEL_WALKOFFLEDGE: checkbetween = qfalse; break;
00665         case TRAVEL_JUMP: checkbetween = qfalse; break;
00666         case TRAVEL_SWIM: checkbetween = qtrue; break;
00667         case TRAVEL_WATERJUMP: checkbetween = qtrue; break;
00668         case TRAVEL_TELEPORT: checkbetween = qfalse; break;
00669         case TRAVEL_ELEVATOR: checkbetween = qfalse; break;
00670         case TRAVEL_GRAPPLEHOOK: checkbetween = qfalse; break;
00671         case TRAVEL_ROCKETJUMP: checkbetween = qfalse; break;
00672         case TRAVEL_BFGJUMP: checkbetween = qfalse; break;
00673         case TRAVEL_JUMPPAD: checkbetween = qfalse; break;
00674         case TRAVEL_FUNCBOB: checkbetween = qfalse; break;
00675         default: checkbetween = qtrue; break;
00676     } //end switch
00677 
00678     type = AVOID_CLEAR;
00679     for (i = 0; i < numavoidspots; i++)
00680     {
00681         squaredradius = Square(avoidspots[i].radius);
00682         squareddist = DistanceFromLineSquared(avoidspots[i].origin, origin, reach->start);
00683         // if moving towards the avoid spot
00684         if (squareddist < squaredradius &&
00685             VectorDistanceSquared(avoidspots[i].origin, origin) > squareddist)
00686         {
00687             type = avoidspots[i].type;
00688         } //end if
00689         else if (checkbetween) {
00690             squareddist = DistanceFromLineSquared(avoidspots[i].origin, reach->start, reach->end);
00691             // if moving towards the avoid spot
00692             if (squareddist < squaredradius &&
00693                 VectorDistanceSquared(avoidspots[i].origin, reach->start) > squareddist)
00694             {
00695                 type = avoidspots[i].type;
00696             } //end if
00697         } //end if
00698         else
00699         {
00700             VectorDistanceSquared(avoidspots[i].origin, reach->end);
00701             // if the reachability leads closer to the avoid spot
00702             if (squareddist < squaredradius && 
00703                 VectorDistanceSquared(avoidspots[i].origin, reach->start) > squareddist)
00704             {
00705                 type = avoidspots[i].type;
00706             } //end if
00707         } //end else
00708         if (type == AVOID_ALWAYS)
00709             return type;
00710     } //end for
00711     return type;
00712 } //end of the function BotAvoidSpots
00713 //===========================================================================
00714 //
00715 // Parameter:           -
00716 // Returns:             -
00717 // Changes Globals:     -
00718 //===========================================================================
00719 void BotAddAvoidSpot(int movestate, vec3_t origin, float radius, int type)
00720 {
00721     bot_movestate_t *ms;
00722 
00723     ms = BotMoveStateFromHandle(movestate);
00724     if (!ms) return;
00725     if (type == AVOID_CLEAR)
00726     {
00727         ms->numavoidspots = 0;
00728         return;
00729     } //end if
00730 
00731     if (ms->numavoidspots >= MAX_AVOIDSPOTS)
00732         return;
00733     VectorCopy(origin, ms->avoidspots[ms->numavoidspots].origin);
00734     ms->avoidspots[ms->numavoidspots].radius = radius;
00735     ms->avoidspots[ms->numavoidspots].type = type;
00736     ms->numavoidspots++;
00737 } //end of the function BotAddAvoidSpot
00738 //===========================================================================
00739 //
00740 // Parameter:           -
00741 // Returns:             -
00742 // Changes Globals:     -
00743 //===========================================================================
00744 int BotGetReachabilityToGoal(vec3_t origin, int areanum,
00745                                       int lastgoalareanum, int lastareanum,
00746                                       int *avoidreach, float *avoidreachtimes, int *avoidreachtries,
00747                                       bot_goal_t *goal, int travelflags, int movetravelflags,
00748                                       struct bot_avoidspot_s *avoidspots, int numavoidspots, int *flags)
00749 {
00750     int i, t, besttime, bestreachnum, reachnum;
00751     aas_reachability_t reach;
00752 
00753     //if not in a valid area
00754     if (!areanum) return 0;
00755     //
00756     if (AAS_AreaDoNotEnter(areanum) || AAS_AreaDoNotEnter(goal->areanum))
00757     {
00758         travelflags |= TFL_DONOTENTER;
00759         movetravelflags |= TFL_DONOTENTER;
00760     } //end if
00761     //use the routing to find the next area to go to
00762     besttime = 0;
00763     bestreachnum = 0;
00764     //
00765     for (reachnum = AAS_NextAreaReachability(areanum, 0); reachnum;
00766         reachnum = AAS_NextAreaReachability(areanum, reachnum))
00767     {
00768 #ifdef AVOIDREACH
00769         //check if it isn't an reachability to avoid
00770         for (i = 0; i < MAX_AVOIDREACH; i++)
00771         {
00772             if (avoidreach[i] == reachnum && avoidreachtimes[i] >= AAS_Time()) break;
00773         } //end for
00774         if (i != MAX_AVOIDREACH && avoidreachtries[i] > AVOIDREACH_TRIES)
00775         {
00776 #ifdef DEBUG
00777             if (bot_developer)
00778             {
00779                 botimport.Print(PRT_MESSAGE, "avoiding reachability %d\n", avoidreach[i]);
00780             } //end if
00781 #endif //DEBUG
00782             continue;
00783         } //end if
00784 #endif //AVOIDREACH
00785         //get the reachability from the number
00786         AAS_ReachabilityFromNum(reachnum, &reach);
00787         //NOTE: do not go back to the previous area if the goal didn't change
00788         //NOTE: is this actually avoidance of local routing minima between two areas???
00789         if (lastgoalareanum == goal->areanum && reach.areanum == lastareanum) continue;
00790         //if (AAS_AreaContentsTravelFlags(reach.areanum) & ~travelflags) continue;
00791         //if the travel isn't valid
00792         if (!BotValidTravel(origin, &reach, movetravelflags)) continue;
00793         //get the travel time
00794         t = AAS_AreaTravelTimeToGoalArea(reach.areanum, reach.end, goal->areanum, travelflags);
00795         //if the goal area isn't reachable from the reachable area
00796         if (!t) continue;
00797         //if the bot should not use this reachability to avoid bad spots
00798         if (BotAvoidSpots(origin, &reach, avoidspots, numavoidspots)) {
00799             if (flags) {
00800                 *flags |= MOVERESULT_BLOCKEDBYAVOIDSPOT;
00801             }
00802             continue;
00803         }
00804         //add the travel time towards the area
00805         t += reach.traveltime;// + AAS_AreaTravelTime(areanum, origin, reach.start);
00806         //if the travel time is better than the ones already found
00807         if (!besttime || t < besttime)
00808         {
00809             besttime = t;
00810             bestreachnum = reachnum;
00811         } //end if
00812     } //end for
00813     //
00814     return bestreachnum;
00815 } //end of the function BotGetReachabilityToGoal
00816 //===========================================================================
00817 //
00818 // Parameter:               -
00819 // Returns:                 -
00820 // Changes Globals:     -
00821 //===========================================================================
00822 int BotAddToTarget(vec3_t start, vec3_t end, float maxdist, float *dist, vec3_t target)
00823 {
00824     vec3_t dir;
00825     float curdist;
00826 
00827     VectorSubtract(end, start, dir);
00828     curdist = VectorNormalize(dir);
00829     if (*dist + curdist < maxdist)
00830     {
00831         VectorCopy(end, target);
00832         *dist += curdist;
00833         return qfalse;
00834     } //end if
00835     else
00836     {
00837         VectorMA(start, maxdist - *dist, dir, target);
00838         *dist = maxdist;
00839         return qtrue;
00840     } //end else
00841 } //end of the function BotAddToTarget
00842 
00843 int BotMovementViewTarget(int movestate, bot_goal_t *goal, int travelflags, float lookahead, vec3_t target)
00844 {
00845     aas_reachability_t reach;
00846     int reachnum, lastareanum;
00847     bot_movestate_t *ms;
00848     vec3_t end;
00849     float dist;
00850 
00851     ms = BotMoveStateFromHandle(movestate);
00852     if (!ms) return qfalse;
00853     reachnum = 0;
00854     //if the bot has no goal or no last reachability
00855     if (!ms->lastreachnum || !goal) return qfalse;
00856 
00857     reachnum = ms->lastreachnum;
00858     VectorCopy(ms->origin, end);
00859     lastareanum = ms->lastareanum;
00860     dist = 0;
00861     while(reachnum && dist < lookahead)
00862     {
00863         AAS_ReachabilityFromNum(reachnum, &reach);
00864         if (BotAddToTarget(end, reach.start, lookahead, &dist, target)) return qtrue;
00865         //never look beyond teleporters
00866         if ((reach.traveltype & TRAVELTYPE_MASK) == TRAVEL_TELEPORT) return qtrue;
00867         //never look beyond the weapon jump point
00868         if ((reach.traveltype & TRAVELTYPE_MASK) == TRAVEL_ROCKETJUMP) return qtrue;
00869         if ((reach.traveltype & TRAVELTYPE_MASK) == TRAVEL_BFGJUMP) return qtrue;
00870         //don't add jump pad distances
00871         if ((reach.traveltype & TRAVELTYPE_MASK) != TRAVEL_JUMPPAD &&
00872             (reach.traveltype & TRAVELTYPE_MASK) != TRAVEL_ELEVATOR &&
00873             (reach.traveltype & TRAVELTYPE_MASK) != TRAVEL_FUNCBOB)
00874         {
00875             if (BotAddToTarget(reach.start, reach.end, lookahead, &dist, target)) return qtrue;
00876         } //end if
00877         reachnum = BotGetReachabilityToGoal(reach.end, reach.areanum,
00878                         ms->lastgoalareanum, lastareanum,
00879                             ms->avoidreach, ms->avoidreachtimes, ms->avoidreachtries,
00880                                     goal, travelflags, travelflags, NULL, 0, NULL);
00881         VectorCopy(reach.end, end);
00882         lastareanum = reach.areanum;
00883         if (lastareanum == goal->areanum)
00884         {
00885             BotAddToTarget(reach.end, goal->origin, lookahead, &dist, target);
00886             return qtrue;
00887         } //end if
00888     } //end while
00889     //
00890     return qfalse;
00891 } //end of the function BotMovementViewTarget
00892 //===========================================================================
00893 //
00894 // Parameter:           -
00895 // Returns:             -
00896 // Changes Globals:     -
00897 //===========================================================================
00898 int BotVisible(int ent, vec3_t eye, vec3_t target)
00899 {
00900     bsp_trace_t trace;
00901 
00902     trace = AAS_Trace(eye, NULL, NULL, target, ent, CONTENTS_SOLID|CONTENTS_PLAYERCLIP);
00903     if (trace.fraction >= 1) return qtrue;
00904     return qfalse;
00905 } //end of the function BotVisible
00906 //===========================================================================
00907 //
00908 // Parameter:           -
00909 // Returns:             -
00910 // Changes Globals:     -
00911 //===========================================================================
00912 int BotPredictVisiblePosition(vec3_t origin, int areanum, bot_goal_t *goal, int travelflags, vec3_t target)
00913 {
00914     aas_reachability_t reach;
00915     int reachnum, lastgoalareanum, lastareanum, i;
00916     int avoidreach[MAX_AVOIDREACH];
00917     float avoidreachtimes[MAX_AVOIDREACH];
00918     int avoidreachtries[MAX_AVOIDREACH];
00919     vec3_t end;
00920 
00921     //if the bot has no goal or no last reachability
00922     if (!goal) return qfalse;
00923     //if the areanum is not valid
00924     if (!areanum) return qfalse;
00925     //if the goal areanum is not valid
00926     if (!goal->areanum) return qfalse;
00927 
00928     Com_Memset(avoidreach, 0, MAX_AVOIDREACH * sizeof(int));
00929     lastgoalareanum = goal->areanum;
00930     lastareanum = areanum;
00931     VectorCopy(origin, end);
00932     //only do 20 hops
00933     for (i = 0; i < 20 && (areanum != goal->areanum); i++)
00934     {
00935         //
00936         reachnum = BotGetReachabilityToGoal(end, areanum,
00937                         lastgoalareanum, lastareanum,
00938                             avoidreach, avoidreachtimes, avoidreachtries,
00939                                     goal, travelflags, travelflags, NULL, 0, NULL);
00940         if (!reachnum) return qfalse;
00941         AAS_ReachabilityFromNum(reachnum, &reach);
00942         //
00943         if (BotVisible(goal->entitynum, goal->origin, reach.start))
00944         {
00945             VectorCopy(reach.start, target);
00946             return qtrue;
00947         } //end if
00948         //
00949         if (BotVisible(goal->entitynum, goal->origin, reach.end))
00950         {
00951             VectorCopy(reach.end, target);
00952             return qtrue;
00953         } //end if
00954         //
00955         if (reach.areanum == goal->areanum)
00956         {
00957             VectorCopy(reach.end, target);
00958             return qtrue;
00959         } //end if
00960         //
00961         lastareanum = areanum;
00962         areanum = reach.areanum;
00963         VectorCopy(reach.end, end);
00964         //
00965     } //end while
00966     //
00967     return qfalse;
00968 } //end of the function BotPredictVisiblePosition
00969 //===========================================================================
00970 //
00971 // Parameter:           -
00972 // Returns:             -
00973 // Changes Globals:     -
00974 //===========================================================================
00975 void MoverBottomCenter(aas_reachability_t *reach, vec3_t bottomcenter)
00976 {
00977     int modelnum;
00978     vec3_t mins, maxs, origin, mids;
00979     vec3_t angles = {0, 0, 0};
00980 
00981     modelnum = reach->facenum & 0x0000FFFF;
00982     //get some bsp model info
00983     AAS_BSPModelMinsMaxsOrigin(modelnum, angles, mins, maxs, origin);
00984     //
00985     if (!AAS_OriginOfMoverWithModelNum(modelnum, origin))
00986     {
00987         botimport.Print(PRT_MESSAGE, "no entity with model %d\n", modelnum);
00988     } //end if
00989     //get a point just above the plat in the bottom position
00990     VectorAdd(mins, maxs, mids);
00991     VectorMA(origin, 0.5, mids, bottomcenter);
00992     bottomcenter[2] = reach->start[2];
00993 } //end of the function MoverBottomCenter
00994 //===========================================================================
00995 //
00996 // Parameter:           -
00997 // Returns:             -
00998 // Changes Globals:     -
00999 //===========================================================================
01000 float BotGapDistance(vec3_t origin, vec3_t hordir, int entnum)
01001 {
01002     float dist, startz;
01003     vec3_t start, end;
01004     aas_trace_t trace;
01005 
01006     //do gap checking
01007     startz = origin[2];
01008     //this enables walking down stairs more fluidly
01009     {
01010         VectorCopy(origin, start);
01011         VectorCopy(origin, end);
01012         end[2] -= 60;
01013         trace = AAS_TraceClientBBox(start, end, PRESENCE_CROUCH, entnum);
01014         if (trace.fraction >= 1) return 1;
01015         startz = trace.endpos[2] + 1;
01016     }
01017     //
01018     for (dist = 8; dist <= 100; dist += 8)
01019     {
01020         VectorMA(origin, dist, hordir, start);
01021         start[2] = startz + 24;
01022         VectorCopy(start, end);
01023         end[2] -= 48 + sv_maxbarrier->value;
01024         trace = AAS_TraceClientBBox(start, end, PRESENCE_CROUCH, entnum);
01025         //if solid is found the bot can't walk any further and fall into a gap
01026         if (!trace.startsolid)
01027         {
01028             //if it is a gap
01029             if (trace.endpos[2] < startz - sv_maxstep->value - 8)
01030             {
01031                 VectorCopy(trace.endpos, end);
01032                 end[2] -= 20;
01033                 if (AAS_PointContents(end) & CONTENTS_WATER) break;
01034                 //if a gap is found slow down
01035                 //botimport.Print(PRT_MESSAGE, "gap at %f\n", dist);
01036                 return dist;
01037             } //end if
01038             startz = trace.endpos[2];
01039         } //end if
01040     } //end for
01041     return 0;
01042 } //end of the function BotGapDistance
01043 //===========================================================================
01044 //
01045 // Parameter:           -
01046 // Returns:             -
01047 // Changes Globals:     -
01048 //===========================================================================
01049 int BotCheckBarrierJump(bot_movestate_t *ms, vec3_t dir, float speed)
01050 {
01051     vec3_t start, hordir, end;
01052     aas_trace_t trace;
01053 
01054     VectorCopy(ms->origin, end);
01055     end[2] += sv_maxbarrier->value;
01056     //trace right up
01057     trace = AAS_TraceClientBBox(ms->origin, end, PRESENCE_NORMAL, ms->entitynum);
01058     //this shouldn't happen... but we check anyway
01059     if (trace.startsolid) return qfalse;
01060     //if very low ceiling it isn't possible to jump up to a barrier
01061     if (trace.endpos[2] - ms->origin[2] < sv_maxstep->value) return qfalse;
01062     //
01063     hordir[0] = dir[0];
01064     hordir[1] = dir[1];
01065     hordir[2] = 0;
01066     VectorNormalize(hordir);
01067     VectorMA(ms->origin, ms->thinktime * speed * 0.5, hordir, end);
01068     VectorCopy(trace.endpos, start);
01069     end[2] = trace.endpos[2];
01070     //trace from previous trace end pos horizontally in the move direction
01071     trace = AAS_TraceClientBBox(start, end, PRESENCE_NORMAL, ms->entitynum);
01072     //again this shouldn't happen
01073     if (trace.startsolid) return qfalse;
01074     //
01075     VectorCopy(trace.endpos, start);
01076     VectorCopy(trace.endpos, end);
01077     end[2] = ms->origin[2];
01078     //trace down from the previous trace end pos
01079     trace = AAS_TraceClientBBox(start, end, PRESENCE_NORMAL, ms->entitynum);
01080     //if solid
01081     if (trace.startsolid) return qfalse;
01082     //if no obstacle at all
01083     if (trace.fraction >= 1.0) return qfalse;
01084     //if less than the maximum step height
01085     if (trace.endpos[2] - ms->origin[2] < sv_maxstep->value) return qfalse;
01086     //
01087     EA_Jump(ms->client);
01088     EA_Move(ms->client, hordir, speed);
01089     ms->moveflags |= MFL_BARRIERJUMP;
01090     //there is a barrier
01091     return qtrue;
01092 } //end of the function BotCheckBarrierJump
01093 //===========================================================================
01094 //
01095 // Parameter:           -
01096 // Returns:             -
01097 // Changes Globals:     -
01098 //===========================================================================
01099 int BotSwimInDirection(bot_movestate_t *ms, vec3_t dir, float speed, int type)
01100 {
01101     vec3_t normdir;
01102 
01103     VectorCopy(dir, normdir);
01104     VectorNormalize(normdir);
01105     EA_Move(ms->client, normdir, speed);
01106     return qtrue;
01107 } //end of the function BotSwimInDirection
01108 //===========================================================================
01109 //
01110 // Parameter:           -
01111 // Returns:             -
01112 // Changes Globals:     -
01113 //===========================================================================
01114 int BotWalkInDirection(bot_movestate_t *ms, vec3_t dir, float speed, int type)
01115 {
01116     vec3_t hordir, cmdmove, velocity, tmpdir, origin;
01117     int presencetype, maxframes, cmdframes, stopevent;
01118     aas_clientmove_t move;
01119     float dist;
01120 
01121     if (AAS_OnGround(ms->origin, ms->presencetype, ms->entitynum)) ms->moveflags |= MFL_ONGROUND;
01122     //if the bot is on the ground
01123     if (ms->moveflags & MFL_ONGROUND)
01124     {
01125         //if there is a barrier the bot can jump on
01126         if (BotCheckBarrierJump(ms, dir, speed)) return qtrue;
01127         //remove barrier jump flag
01128         ms->moveflags &= ~MFL_BARRIERJUMP;
01129         //get the presence type for the movement
01130         if ((type & MOVE_CROUCH) && !(type & MOVE_JUMP)) presencetype = PRESENCE_CROUCH;
01131         else presencetype = PRESENCE_NORMAL;
01132         //horizontal direction
01133         hordir[0] = dir[0];
01134         hordir[1] = dir[1];
01135         hordir[2] = 0;
01136         VectorNormalize(hordir);
01137         //if the bot is not supposed to jump
01138         if (!(type & MOVE_JUMP))
01139         {
01140             //if there is a gap, try to jump over it
01141             if (BotGapDistance(ms->origin, hordir, ms->entitynum) > 0) type |= MOVE_JUMP;
01142         } //end if
01143         //get command movement
01144         VectorScale(hordir, speed, cmdmove);
01145         VectorCopy(ms->velocity, velocity);
01146         //
01147         if (type & MOVE_JUMP)
01148         {
01149             //botimport.Print(PRT_MESSAGE, "trying jump\n");
01150             cmdmove[2] = 400;
01151             maxframes = PREDICTIONTIME_JUMP / 0.1;
01152             cmdframes = 1;
01153             stopevent = SE_HITGROUND|SE_HITGROUNDDAMAGE|
01154                         SE_ENTERWATER|SE_ENTERSLIME|SE_ENTERLAVA;
01155         } //end if
01156         else
01157         {
01158             maxframes = 2;
01159             cmdframes = 2;
01160             stopevent = SE_HITGROUNDDAMAGE|
01161                         SE_ENTERWATER|SE_ENTERSLIME|SE_ENTERLAVA;
01162         } //end else
01163         //AAS_ClearShownDebugLines();
01164         //
01165         VectorCopy(ms->origin, origin);
01166         origin[2] += 0.5;
01167         AAS_PredictClientMovement(&move, ms->entitynum, origin, presencetype, qtrue,
01168                                     velocity, cmdmove, cmdframes, maxframes, 0.1f,
01169                                     stopevent, 0, qfalse);//qtrue);
01170         //if prediction time wasn't enough to fully predict the movement
01171         if (move.frames >= maxframes && (type & MOVE_JUMP))
01172         {
01173             //botimport.Print(PRT_MESSAGE, "client %d: max prediction frames\n", ms->client);
01174             return qfalse;
01175         } //end if
01176         //don't enter slime or lava and don't fall from too high
01177         if (move.stopevent & (SE_ENTERSLIME|SE_ENTERLAVA|SE_HITGROUNDDAMAGE))
01178         {
01179             //botimport.Print(PRT_MESSAGE, "client %d: would be hurt ", ms->client);
01180             //if (move.stopevent & SE_ENTERSLIME) botimport.Print(PRT_MESSAGE, "slime\n");
01181             //if (move.stopevent & SE_ENTERLAVA) botimport.Print(PRT_MESSAGE, "lava\n");
01182             //if (move.stopevent & SE_HITGROUNDDAMAGE) botimport.Print(PRT_MESSAGE, "hitground\n");
01183             return qfalse;
01184         } //end if
01185         //if ground was hit
01186         if (move.stopevent & SE_HITGROUND)
01187         {
01188             //check for nearby gap
01189             VectorNormalize2(move.velocity, tmpdir);
01190             dist = BotGapDistance(move.endpos, tmpdir, ms->entitynum);
01191             if (dist > 0) return qfalse;
01192             //
01193             dist = BotGapDistance(move.endpos, hordir, ms->entitynum);
01194             if (dist > 0) return qfalse;
01195         } //end if
01196         //get horizontal movement
01197         tmpdir[0] = move.endpos[0] - ms->origin[0];
01198         tmpdir[1] = move.endpos[1] - ms->origin[1];
01199         tmpdir[2] = 0;
01200         //
01201         //AAS_DrawCross(move.endpos, 4, LINECOLOR_BLUE);
01202         //the bot is blocked by something
01203         if (VectorLength(tmpdir) < speed * ms->thinktime * 0.5) return qfalse;
01204         //perform the movement
01205         if (type & MOVE_JUMP) EA_Jump(ms->client);
01206         if (type & MOVE_CROUCH) EA_Crouch(ms->client);
01207         EA_Move(ms->client, hordir, speed);
01208         //movement was succesfull
01209         return qtrue;
01210     } //end if
01211     else
01212     {
01213         if (ms->moveflags & MFL_BARRIERJUMP)
01214         {
01215             //if near the top or going down
01216             if (ms->velocity[2] < 50)
01217             {
01218                 EA_Move(ms->client, dir, speed);
01219             } //end if
01220         } //end if
01221         //FIXME: do air control to avoid hazards
01222         return qtrue;
01223     } //end else
01224 } //end of the function BotWalkInDirection
01225 //===========================================================================
01226 //
01227 // Parameter:           -
01228 // Returns:             -
01229 // Changes Globals:     -
01230 //===========================================================================
01231 int BotMoveInDirection(int movestate, vec3_t dir, float speed, int type)
01232 {
01233     bot_movestate_t *ms;
01234 
01235     ms = BotMoveStateFromHandle(movestate);
01236     if (!ms) return qfalse;
01237     //if swimming
01238     if (AAS_Swimming(ms->origin))
01239     {
01240         return BotSwimInDirection(ms, dir, speed, type);
01241     } //end if
01242     else
01243     {
01244         return BotWalkInDirection(ms, dir, speed, type);
01245     } //end else
01246 } //end of the function BotMoveInDirection
01247 //===========================================================================
01248 //
01249 // Parameter:           -
01250 // Returns:             -
01251 // Changes Globals:     -
01252 //===========================================================================
01253 int Intersection(vec2_t p1, vec2_t p2, vec2_t p3, vec2_t p4, vec2_t out)
01254 {
01255    float x1, dx1, dy1, x2, dx2, dy2, d;
01256 
01257    dx1 = p2[0] - p1[0];
01258    dy1 = p2[1] - p1[1];
01259    dx2 = p4[0] - p3[0];
01260    dy2 = p4[1] - p3[1];
01261 
01262    d = dy1 * dx2 - dx1 * dy2;
01263    if (d != 0)
01264    {
01265       x1 = p1[1] * dx1 - p1[0] * dy1;
01266       x2 = p3[1] * dx2 - p3[0] * dy2;
01267       out[0] = (int) ((dx1 * x2 - dx2 * x1) / d);
01268       out[1] = (int) ((dy1 * x2 - dy2 * x1) / d);
01269         return qtrue;
01270    } //end if
01271    else
01272    {
01273       return qfalse;
01274    } //end else
01275 } //end of the function Intersection
01276 //===========================================================================
01277 //
01278 // Parameter:           -
01279 // Returns:             -
01280 // Changes Globals:     -
01281 //===========================================================================
01282 void BotCheckBlocked(bot_movestate_t *ms, vec3_t dir, int checkbottom, bot_moveresult_t *result)
01283 {
01284     vec3_t mins, maxs, end, up = {0, 0, 1};
01285     bsp_trace_t trace;
01286 
01287     //test for entities obstructing the bot's path
01288     AAS_PresenceTypeBoundingBox(ms->presencetype, mins, maxs);
01289     //
01290     if (fabs(DotProduct(dir, up)) < 0.7)
01291     {
01292         mins[2] += sv_maxstep->value; //if the bot can step on
01293         maxs[2] -= 10; //a little lower to avoid low ceiling
01294     } //end if
01295     VectorMA(ms->origin, 3, dir, end);
01296     trace = AAS_Trace(ms->origin, mins, maxs, end, ms->entitynum, CONTENTS_SOLID|CONTENTS_PLAYERCLIP|CONTENTS_BODY);
01297     //if not started in solid and not hitting the world entity
01298     if (!trace.startsolid && (trace.ent != ENTITYNUM_WORLD && trace.ent != ENTITYNUM_NONE) )
01299     {
01300         result->blocked = qtrue;
01301         result->blockentity = trace.ent;
01302 #ifdef DEBUG
01303         //botimport.Print(PRT_MESSAGE, "%d: BotCheckBlocked: I'm blocked\n", ms->client);
01304 #endif //DEBUG
01305     } //end if
01306     //if not in an area with reachability
01307     else if (checkbottom && !AAS_AreaReachability(ms->areanum))
01308     {
01309         //check if the bot is standing on something
01310         AAS_PresenceTypeBoundingBox(ms->presencetype, mins, maxs);
01311         VectorMA(ms->origin, -3, up, end);
01312         trace = AAS_Trace(ms->origin, mins, maxs, end, ms->entitynum, CONTENTS_SOLID|CONTENTS_PLAYERCLIP);
01313         if (!trace.startsolid && (trace.ent != ENTITYNUM_WORLD && trace.ent != ENTITYNUM_NONE) )
01314         {
01315             result->blocked = qtrue;
01316             result->blockentity = trace.ent;
01317             result->flags |= MOVERESULT_ONTOPOFOBSTACLE;
01318 #ifdef DEBUG
01319             //botimport.Print(PRT_MESSAGE, "%d: BotCheckBlocked: I'm blocked\n", ms->client);
01320 #endif //DEBUG
01321         } //end if
01322     } //end else
01323 } //end of the function BotCheckBlocked
01324 //===========================================================================
01325 //
01326 // Parameter:           -
01327 // Returns:             -
01328 // Changes Globals:     -
01329 //===========================================================================
01330 void BotClearMoveResult(bot_moveresult_t *moveresult)
01331 {
01332     moveresult->failure = qfalse;
01333     moveresult->type = 0;
01334     moveresult->blocked = qfalse;
01335     moveresult->blockentity = 0;
01336     moveresult->traveltype = 0;
01337     moveresult->flags = 0;
01338 } //end of the function BotClearMoveResult
01339 //===========================================================================
01340 //
01341 // Parameter:           -
01342 // Returns:             -
01343 // Changes Globals:     -
01344 //===========================================================================
01345 bot_moveresult_t BotTravel_Walk(bot_movestate_t *ms, aas_reachability_t *reach)
01346 {
01347     float dist, speed;
01348     vec3_t hordir;
01349     bot_moveresult_t result;
01350 
01351     BotClearMoveResult(&result);
01352     //first walk straight to the reachability start
01353     hordir[0] = reach->start[0] - ms->origin[0];
01354     hordir[1] = reach->start[1] - ms->origin[1];
01355     hordir[2] = 0;
01356     dist = VectorNormalize(hordir);
01357     //
01358     BotCheckBlocked(ms, hordir, qtrue, &result);
01359     //
01360     if (dist < 10)
01361     {
01362         //walk straight to the reachability end
01363         hordir[0] = reach->end[0] - ms->origin[0];
01364         hordir[1] = reach->end[1] - ms->origin[1];
01365         hordir[2] = 0;
01366         dist = VectorNormalize(hordir);
01367     } //end if
01368     //if going towards a crouch area
01369     if (!(AAS_AreaPresenceType(reach->areanum) & PRESENCE_NORMAL))
01370     {
01371         //if pretty close to the reachable area
01372         if (dist < 20) EA_Crouch(ms->client);
01373     } //end if
01374     //
01375     dist = BotGapDistance(ms->origin, hordir, ms->entitynum);
01376     //
01377     if (ms->moveflags & MFL_WALK)
01378     {
01379         if (dist > 0) speed = 200 - (180 - 1 * dist);
01380         else speed = 200;
01381         EA_Walk(ms->client);
01382     } //end if
01383     else
01384     {
01385         if (dist > 0) speed = 400 - (360 - 2 * dist);
01386         else speed = 400;
01387     } //end else
01388     //elemantary action move in direction
01389     EA_Move(ms->client, hordir, speed);
01390     VectorCopy(hordir, result.movedir);
01391     //
01392     return result;
01393 } //end of the function BotTravel_Walk
01394 //===========================================================================
01395 //
01396 // Parameter:           -
01397 // Returns:             -
01398 // Changes Globals:     -
01399 //===========================================================================
01400 bot_moveresult_t BotFinishTravel_Walk(bot_movestate_t *ms, aas_reachability_t *reach)
01401 {
01402     vec3_t hordir;
01403     float dist, speed;
01404     bot_moveresult_t result;
01405 
01406     BotClearMoveResult(&result);
01407     //if not on the ground and changed areas... don't walk back!!
01408     //(doesn't seem to help)
01409     /*
01410     ms->areanum = BotFuzzyPointReachabilityArea(ms->origin);
01411     if (ms->areanum == reach->areanum)
01412     {
01413 #ifdef DEBUG
01414         botimport.Print(PRT_MESSAGE, "BotFinishTravel_Walk: already in reach area\n");
01415 #endif //DEBUG
01416         return result;
01417     } //end if*/
01418     //go straight to the reachability end
01419     hordir[0] = reach->end[0] - ms->origin[0];
01420     hordir[1] = reach->end[1] - ms->origin[1];
01421     hordir[2] = 0;
01422     dist = VectorNormalize(hordir);
01423     //
01424     if (dist > 100) dist = 100;
01425     speed = 400 - (400 - 3 * dist);
01426     //
01427     EA_Move(ms->client, hordir, speed);
01428     VectorCopy(hordir, result.movedir);
01429     //
01430     return result;
01431 } //end of the function BotFinishTravel_Walk
01432 //===========================================================================
01433 //
01434 // Parameter:               -
01435 // Returns:                 -
01436 // Changes Globals:     -
01437 //===========================================================================
01438 bot_moveresult_t BotTravel_Crouch(bot_movestate_t *ms, aas_reachability_t *reach)
01439 {
01440     float speed;
01441     vec3_t hordir;
01442     bot_moveresult_t result;
01443 
01444     BotClearMoveResult(&result);
01445     //
01446     speed = 400;
01447     //walk straight to reachability end
01448     hordir[0] = reach->end[0] - ms->origin[0];
01449     hordir[1] = reach->end[1] - ms->origin[1];
01450     hordir[2] = 0;
01451     VectorNormalize(hordir);
01452     //
01453     BotCheckBlocked(ms, hordir, qtrue, &result);
01454     //elemantary actions
01455     EA_Crouch(ms->client);
01456     EA_Move(ms->client, hordir, speed);
01457     //
01458     VectorCopy(hordir, result.movedir);
01459     //
01460     return result;
01461 } //end of the function BotTravel_Crouch
01462 //===========================================================================
01463 //
01464 // Parameter:               -
01465 // Returns:                 -
01466 // Changes Globals:     -
01467 //===========================================================================
01468 bot_moveresult_t BotTravel_BarrierJump(bot_movestate_t *ms, aas_reachability_t *reach)
01469 {
01470     float dist, speed;
01471     vec3_t hordir;
01472     bot_moveresult_t result;
01473 
01474     BotClearMoveResult(&result);
01475     //walk straight to reachability start
01476     hordir[0] = reach->start[0] - ms->origin[0];
01477     hordir[1] = reach->start[1] - ms->origin[1];
01478     hordir[2] = 0;
01479     dist = VectorNormalize(hordir);
01480     //
01481     BotCheckBlocked(ms, hordir, qtrue, &result);
01482     //if pretty close to the barrier
01483     if (dist < 9)
01484     {
01485         EA_Jump(ms->client);
01486     } //end if
01487     else
01488     {
01489         if (dist > 60) dist = 60;
01490         speed = 360 - (360 - 6 * dist);
01491         EA_Move(ms->client, hordir, speed);
01492     } //end else
01493     VectorCopy(hordir, result.movedir);
01494     //
01495     return result;
01496 } //end of the function BotTravel_BarrierJump
01497 //===========================================================================
01498 //
01499 // Parameter:               -
01500 // Returns:                 -
01501 // Changes Globals:     -
01502 //===========================================================================
01503 bot_moveresult_t BotFinishTravel_BarrierJump(bot_movestate_t *ms, aas_reachability_t *reach)
01504 {
01505     float dist;
01506     vec3_t hordir;
01507     bot_moveresult_t result;
01508 
01509     BotClearMoveResult(&result);
01510     //if near the top or going down
01511     if (ms->velocity[2] < 250)
01512     {
01513         hordir[0] = reach->end[0] - ms->origin[0];
01514         hordir[1] = reach->end[1] - ms->origin[1];
01515         hordir[2] = 0;
01516         dist = VectorNormalize(hordir);
01517         //
01518         BotCheckBlocked(ms, hordir, qtrue, &result);
01519         //
01520         EA_Move(ms->client, hordir, 400);
01521         VectorCopy(hordir, result.movedir);
01522     } //end if
01523     //
01524     return result;
01525 } //end of the function BotFinishTravel_BarrierJump
01526 //===========================================================================
01527 //
01528 // Parameter:               -
01529 // Returns:                 -
01530 // Changes Globals:     -
01531 //===========================================================================
01532 bot_moveresult_t BotTravel_Swim(bot_movestate_t *ms, aas_reachability_t *reach)
01533 {
01534     vec3_t dir;
01535     bot_moveresult_t result;
01536 
01537     BotClearMoveResult(&result);
01538     //swim straight to reachability end
01539     VectorSubtract(reach->start, ms->origin, dir);
01540     VectorNormalize(dir);
01541     //
01542     BotCheckBlocked(ms, dir, qtrue, &result);
01543     //elemantary actions
01544     EA_Move(ms->client, dir, 400);
01545     //
01546     VectorCopy(dir, result.movedir);
01547     Vector2Angles(dir, result.ideal_viewangles);
01548     result.flags |= MOVERESULT_SWIMVIEW;
01549     //
01550     return result;
01551 } //end of the function BotTravel_Swim
01552 //===========================================================================
01553 //
01554 // Parameter:               -
01555 // Returns:                 -
01556 // Changes Globals:     -
01557 //===========================================================================
01558 bot_moveresult_t BotTravel_WaterJump(bot_movestate_t *ms, aas_reachability_t *reach)
01559 {
01560     vec3_t dir, hordir;
01561     float dist;
01562     bot_moveresult_t result;
01563 
01564     BotClearMoveResult(&result);
01565     //swim straight to reachability end
01566     VectorSubtract(reach->end, ms->origin, dir);
01567     VectorCopy(dir, hordir);
01568     hordir[2] = 0;
01569     dir[2] += 15 + crandom() * 40;
01570     //botimport.Print(PRT_MESSAGE, "BotTravel_WaterJump: dir[2] = %f\n", dir[2]);
01571     VectorNormalize(dir);
01572     dist = VectorNormalize(hordir);
01573     //elemantary actions
01574     //EA_Move(ms->client, dir, 400);
01575     EA_MoveForward(ms->client);
01576     //move up if close to the actual out of water jump spot
01577     if (dist < 40) EA_MoveUp(ms->client);
01578     //set the ideal view angles
01579     Vector2Angles(dir, result.ideal_viewangles);
01580     result.flags |= MOVERESULT_MOVEMENTVIEW;
01581     //
01582     VectorCopy(dir, result.movedir);
01583     //
01584     return result;
01585 } //end of the function BotTravel_WaterJump
01586 //===========================================================================
01587 //
01588 // Parameter:               -
01589 // Returns:                 -
01590 // Changes Globals:     -
01591 //===========================================================================
01592 bot_moveresult_t BotFinishTravel_WaterJump(bot_movestate_t *ms, aas_reachability_t *reach)
01593 {
01594     vec3_t dir, pnt;
01595     float dist;
01596     bot_moveresult_t result;
01597 
01598     //botimport.Print(PRT_MESSAGE, "BotFinishTravel_WaterJump\n");
01599     BotClearMoveResult(&result);
01600     //if waterjumping there's nothing to do
01601     if (ms->moveflags & MFL_WATERJUMP) return result;
01602     //if not touching any water anymore don't do anything
01603     //otherwise the bot sometimes keeps jumping?
01604     VectorCopy(ms->origin, pnt);
01605     pnt[2] -= 32;   //extra for q2dm4 near red armor/mega health
01606     if (!(AAS_PointContents(pnt) & (CONTENTS_LAVA|CONTENTS_SLIME|CONTENTS_WATER))) return result;
01607     //swim straight to reachability end
01608     VectorSubtract(reach->end, ms->origin, dir);
01609     dir[0] += crandom() * 10;
01610     dir[1] += crandom() * 10;
01611     dir[2] += 70 + crandom() * 10;
01612     dist = VectorNormalize(dir);
01613     //elemantary actions
01614     EA_Move(ms->client, dir, 400);
01615     //set the ideal view angles
01616     Vector2Angles(dir, result.ideal_viewangles);
01617     result.flags |= MOVERESULT_MOVEMENTVIEW;
01618     //
01619     VectorCopy(dir, result.movedir);
01620     //
01621     return result;
01622 } //end of the function BotFinishTravel_WaterJump
01623 //===========================================================================
01624 //
01625 // Parameter:               -
01626 // Returns:                 -
01627 // Changes Globals:     -
01628 //===========================================================================
01629 bot_moveresult_t BotTravel_WalkOffLedge(bot_movestate_t *ms, aas_reachability_t *reach)
01630 {
01631     vec3_t hordir, dir;
01632     float dist, speed, reachhordist;
01633     bot_moveresult_t result;
01634 
01635     BotClearMoveResult(&result);
01636     //check if the bot is blocked by anything
01637     VectorSubtract(reach->start, ms->origin, dir);
01638     VectorNormalize(dir);
01639     BotCheckBlocked(ms, dir, qtrue, &result);
01640     //if the reachability start and end are practially above each other
01641     VectorSubtract(reach->end, reach->start, dir);
01642     dir[2] = 0;
01643     reachhordist = VectorLength(dir);
01644     //walk straight to the reachability start
01645     hordir[0] = reach->start[0] - ms->origin[0];
01646     hordir[1] = reach->start[1] - ms->origin[1];
01647     hordir[2] = 0;
01648     dist = VectorNormalize(hordir);
01649     //if pretty close to the start focus on the reachability end
01650     if (dist < 48)
01651     {
01652         hordir[0] = reach->end[0] - ms->origin[0];
01653         hordir[1] = reach->end[1] - ms->origin[1];
01654         hordir[2] = 0;
01655         VectorNormalize(hordir);
01656         //
01657         if (reachhordist < 20)
01658         {
01659             speed = 100;
01660         } //end if
01661         else if (!AAS_HorizontalVelocityForJump(0, reach->start, reach->end, &speed))
01662         {
01663             speed = 400;
01664         } //end if
01665     } //end if
01666     else
01667     {
01668         if (reachhordist < 20)
01669         {
01670             if (dist > 64) dist = 64;
01671             speed = 400 - (256 - 4 * dist);
01672         } //end if
01673         else
01674         {
01675             speed = 400;
01676         } //end else
01677     } //end else
01678     //
01679     BotCheckBlocked(ms, hordir, qtrue, &result);
01680     //elemantary action
01681     EA_Move(ms->client, hordir, speed);
01682     VectorCopy(hordir, result.movedir);
01683     //
01684     return result;
01685 } //end of the function BotTravel_WalkOffLedge
01686 //===========================================================================
01687 //
01688 // Parameter:           -
01689 // Returns:             -
01690 // Changes Globals:     -
01691 //===========================================================================
01692 int BotAirControl(vec3_t origin, vec3_t velocity, vec3_t goal, vec3_t dir, float *speed)
01693 {
01694     vec3_t org, vel;
01695     float dist;
01696     int i;
01697 
01698     VectorCopy(origin, org);
01699     VectorScale(velocity, 0.1, vel);
01700     for (i = 0; i < 50; i++)
01701     {
01702         vel[2] -= sv_gravity->value * 0.01;
01703         //if going down and next position would be below the goal
01704         if (vel[2] < 0 && org[2] + vel[2] < goal[2])
01705         {
01706             VectorScale(vel, (goal[2] - org[2]) / vel[2], vel);
01707             VectorAdd(org, vel, org);
01708             VectorSubtract(goal, org, dir);
01709             dist = VectorNormalize(dir);
01710             if (dist > 32) dist = 32;
01711             *speed = 400 - (400 - 13 * dist);
01712             return qtrue;
01713         } //end if
01714         else
01715         {
01716             VectorAdd(org, vel, org);
01717         } //end else
01718     } //end for
01719     VectorSet(dir, 0, 0, 0);
01720     *speed = 400;
01721     return qfalse;
01722 } //end of the function BotAirControl
01723 //===========================================================================
01724 //
01725 // Parameter:               -
01726 // Returns:                 -
01727 // Changes Globals:     -
01728 //===========================================================================
01729 bot_moveresult_t BotFinishTravel_WalkOffLedge(bot_movestate_t *ms, aas_reachability_t *reach)
01730 {
01731     vec3_t dir, hordir, end, v;
01732     float dist, speed;
01733     bot_moveresult_t result;
01734 
01735     BotClearMoveResult(&result);
01736     //
01737     VectorSubtract(reach->end, ms->origin, dir);
01738     BotCheckBlocked(ms, dir, qtrue, &result);
01739     //
01740     VectorSubtract(reach->end, ms->origin, v);
01741     v[2] = 0;
01742     dist = VectorNormalize(v);
01743     if (dist > 16) VectorMA(reach->end, 16, v, end);
01744     else VectorCopy(reach->end, end);
01745     //
01746     if (!BotAirControl(ms->origin, ms->velocity, end, hordir, &speed))
01747     {
01748         //go straight to the reachability end
01749         VectorCopy(dir, hordir);
01750         hordir[2] = 0;
01751         //
01752         dist = VectorNormalize(hordir);
01753         speed = 400;
01754     } //end if
01755     //
01756     EA_Move(ms->client, hordir, speed);
01757     VectorCopy(hordir, result.movedir);
01758     //
01759     return result;
01760 } //end of the function BotFinishTravel_WalkOffLedge
01761 //===========================================================================
01762 //
01763 // Parameter:               -
01764 // Returns:                 -
01765 // Changes Globals:     -
01766 //===========================================================================
01767 /*
01768 bot_moveresult_t BotTravel_Jump(bot_movestate_t *ms, aas_reachability_t *reach)
01769 {
01770     vec3_t hordir;
01771     float dist, gapdist, speed, horspeed, sv_jumpvel;
01772     bot_moveresult_t result;
01773 
01774     BotClearMoveResult(&result);
01775     //
01776     sv_jumpvel = botlibglobals.sv_jumpvel->value;
01777     //walk straight to the reachability start
01778     hordir[0] = reach->start[0] - ms->origin[0];
01779     hordir[1] = reach->start[1] - ms->origin[1];
01780     hordir[2] = 0;
01781     dist = VectorNormalize(hordir);
01782     //
01783     speed = 350;
01784     //
01785     gapdist = BotGapDistance(ms, hordir, ms->entitynum);
01786     //if pretty close to the start focus on the reachability end
01787     if (dist < 50 || (gapdist && gapdist < 50))
01788     {
01789         //NOTE: using max speed (400) works best
01790         //if (AAS_HorizontalVelocityForJump(sv_jumpvel, ms->origin, reach->end, &horspeed))
01791         //{
01792         //  speed = horspeed * 400 / botlibglobals.sv_maxwalkvelocity->value;
01793         //} //end if
01794         hordir[0] = reach->end[0] - ms->origin[0];
01795         hordir[1] = reach->end[1] - ms->origin[1];
01796         VectorNormalize(hordir);
01797         //elemantary action jump
01798         EA_Jump(ms->client);
01799         //
01800         ms->jumpreach = ms->lastreachnum;
01801         speed = 600;
01802     } //end if
01803     else
01804     {
01805         if (AAS_HorizontalVelocityForJump(sv_jumpvel, reach->start, reach->end, &horspeed))
01806         {
01807             speed = horspeed * 400 / botlibglobals.sv_maxwalkvelocity->value;
01808         } //end if
01809     } //end else
01810     //elemantary action
01811     EA_Move(ms->client, hordir, speed);
01812     VectorCopy(hordir, result.movedir);
01813     //
01814     return result;
01815 } //end of the function BotTravel_Jump*/
01816 /*
01817 bot_moveresult_t BotTravel_Jump(bot_movestate_t *ms, aas_reachability_t *reach)
01818 {
01819     vec3_t hordir, dir1, dir2, mins, maxs, start, end;
01820     float dist1, dist2, speed;
01821     bot_moveresult_t result;
01822     bsp_trace_t trace;
01823 
01824     BotClearMoveResult(&result);
01825     //
01826     hordir[0] = reach->start[0] - reach->end[0];
01827     hordir[1] = reach->start[1] - reach->end[1];
01828     hordir[2] = 0;
01829     VectorNormalize(hordir);
01830     //
01831     VectorCopy(reach->start, start);
01832     start[2] += 1;
01833     //minus back the bouding box size plus 16
01834     VectorMA(reach->start, 80, hordir, end);
01835     //
01836     AAS_PresenceTypeBoundingBox(PRESENCE_NORMAL, mins, maxs);
01837     //check for solids
01838     trace = AAS_Trace(start, mins, maxs, end, ms->entitynum, MASK_PLAYERSOLID);
01839     if (trace.startsolid) VectorCopy(start, trace.endpos);
01840     //check for a gap
01841     for (dist1 = 0; dist1 < 80; dist1 += 10)
01842     {
01843         VectorMA(start, dist1+10, hordir, end);
01844         end[2] += 1;
01845         if (AAS_PointAreaNum(end) != ms->reachareanum) break;
01846     } //end for
01847     if (dist1 < 80) VectorMA(reach->start, dist1, hordir, trace.endpos);
01848 //  dist1 = BotGapDistance(start, hordir, ms->entitynum);
01849 //  if (dist1 && dist1 <= trace.fraction * 80) VectorMA(reach->start, dist1-20, hordir, trace.endpos);
01850     //
01851     VectorSubtract(ms->origin, reach->start, dir1);
01852     dir1[2] = 0;
01853     dist1 = VectorNormalize(dir1);
01854     VectorSubtract(ms->origin, trace.endpos, dir2);
01855     dir2[2] = 0;
01856     dist2 = VectorNormalize(dir2);
01857     //if just before the reachability start
01858     if (DotProduct(dir1, dir2) < -0.8 || dist2 < 5)
01859     {
01860         //botimport.Print(PRT_MESSAGE, "between jump start and run to point\n");
01861         hordir[0] = reach->end[0] - ms->origin[0];
01862         hordir[1] = reach->end[1] - ms->origin[1];
01863         hordir[2] = 0;
01864         VectorNormalize(hordir);
01865         //elemantary action jump
01866         if (dist1 < 24) EA_Jump(ms->client);
01867         else if (dist1 < 32) EA_DelayedJump(ms->client);
01868         EA_Move(ms->client, hordir, 600);
01869         //
01870         ms->jumpreach = ms->lastreachnum;
01871     } //end if
01872     else
01873     {
01874         //botimport.Print(PRT_MESSAGE, "going towards run to point\n");
01875         hordir[0] = trace.endpos[0] - ms->origin[0];
01876         hordir[1] = trace.endpos[1] - ms->origin[1];
01877         hordir[2] = 0;
01878         VectorNormalize(hordir);
01879         //
01880         if (dist2 > 80) dist2 = 80;
01881         speed = 400 - (400 - 5 * dist2);
01882         EA_Move(ms->client, hordir, speed);
01883     } //end else
01884     VectorCopy(hordir, result.movedir);
01885     //
01886     return result;
01887 } //end of the function BotTravel_Jump*/
01888 //*
01889 bot_moveresult_t BotTravel_Jump(bot_movestate_t *ms, aas_reachability_t *reach)
01890 {
01891     vec3_t hordir, dir1, dir2, start, end, runstart;
01892 //  vec3_t runstart, dir1, dir2, hordir;
01893     float dist1, dist2, speed;
01894     bot_moveresult_t result;
01895 
01896     BotClearMoveResult(&result);
01897     //
01898     AAS_JumpReachRunStart(reach, runstart);
01899     //*
01900     hordir[0] = runstart[0] - reach->start[0];
01901     hordir[1] = runstart[1] - reach->start[1];
01902     hordir[2] = 0;
01903     VectorNormalize(hordir);
01904     //
01905     VectorCopy(reach->start, start);
01906     start[2] += 1;
01907     VectorMA(reach->start, 80, hordir, runstart);
01908     //check for a gap
01909     for (dist1 = 0; dist1 < 80; dist1 += 10)
01910     {
01911         VectorMA(start, dist1+10, hordir, end);
01912         end[2] += 1;
01913         if (AAS_PointAreaNum(end) != ms->reachareanum) break;
01914     } //end for
01915     if (dist1 < 80) VectorMA(reach->start, dist1, hordir, runstart);
01916     //
01917     VectorSubtract(ms->origin, reach->start, dir1);
01918     dir1[2] = 0;
01919     dist1 = VectorNormalize(dir1);
01920     VectorSubtract(ms->origin, runstart, dir2);
01921     dir2[2] = 0;
01922     dist2 = VectorNormalize(dir2);
01923     //if just before the reachability start
01924     if (DotProduct(dir1, dir2) < -0.8 || dist2 < 5)
01925     {
01926 //      botimport.Print(PRT_MESSAGE, "between jump start and run start point\n");
01927         hordir[0] = reach->end[0] - ms->origin[0];
01928         hordir[1] = reach->end[1] - ms->origin[1];
01929         hordir[2] = 0;
01930         VectorNormalize(hordir);
01931         //elemantary action jump
01932         if (dist1 < 24) EA_Jump(ms->client);
01933         else if (dist1 < 32) EA_DelayedJump(ms->client);
01934         EA_Move(ms->client, hordir, 600);
01935         //
01936         ms->jumpreach = ms->lastreachnum;
01937     } //end if
01938     else
01939     {
01940 //      botimport.Print(PRT_MESSAGE, "going towards run start point\n");
01941         hordir[0] = runstart[0] - ms->origin[0];
01942         hordir[1] = runstart[1] - ms->origin[1];
01943         hordir[2] = 0;
01944         VectorNormalize(hordir);
01945         //
01946         if (dist2 > 80) dist2 = 80;
01947         speed = 400 - (400 - 5 * dist2);
01948         EA_Move(ms->client, hordir, speed);
01949     } //end else
01950     VectorCopy(hordir, result.movedir);
01951     //
01952     return result;
01953 } //end of the function BotTravel_Jump*/
01954 //===========================================================================
01955 //
01956 // Parameter:               -
01957 // Returns:                 -
01958 // Changes Globals:     -
01959 //===========================================================================
01960 bot_moveresult_t BotFinishTravel_Jump(bot_movestate_t *ms, aas_reachability_t *reach)
01961 {
01962     vec3_t hordir, hordir2;
01963     float speed, dist;
01964     bot_moveresult_t result;
01965 
01966     BotClearMoveResult(&result);
01967     //if not jumped yet
01968     if (!ms->jumpreach) return result;
01969     //go straight to the reachability end
01970     hordir[0] = reach->end[0] - ms->origin[0];
01971     hordir[1] = reach->end[1] - ms->origin[1];
01972     hordir[2] = 0;
01973     dist = VectorNormalize(hordir);
01974     //
01975     hordir2[0] = reach->end[0] - reach->start[0];
01976     hordir2[1] = reach->end[1] - reach->start[1];
01977     hordir2[2] = 0;
01978     VectorNormalize(hordir2);
01979     //
01980     if (DotProduct(hordir, hordir2) < -0.5 && dist < 24) return result;
01981     //always use max speed when traveling through the air
01982     speed = 800;
01983     //
01984     EA_Move(ms->client, hordir, speed);
01985     VectorCopy(hordir, result.movedir);
01986     //
01987     return result;
01988 } //end of the function BotFinishTravel_Jump
01989 //===========================================================================
01990 //
01991 // Parameter:               -
01992 // Returns:                 -
01993 // Changes Globals:     -
01994 //===========================================================================
01995 bot_moveresult_t BotTravel_Ladder(bot_movestate_t *ms, aas_reachability_t *reach)
01996 {
01997     //float dist, speed;
01998     vec3_t dir, viewdir;//, hordir;
01999     vec3_t origin = {0, 0, 0};
02000 //  vec3_t up = {0, 0, 1};
02001     bot_moveresult_t result;
02002 
02003     BotClearMoveResult(&result);
02004     //
02005 //  if ((ms->moveflags & MFL_AGAINSTLADDER))
02006         //NOTE: not a good idea for ladders starting in water
02007         // || !(ms->moveflags & MFL_ONGROUND))
02008     {
02009         //botimport.Print(PRT_MESSAGE, "against ladder or not on ground\n");
02010         VectorSubtract(reach->end, ms->origin, dir);
02011         VectorNormalize(dir);
02012         //set the ideal view angles, facing the ladder up or down
02013         viewdir[0] = dir[0];
02014         viewdir[1] = dir[1];
02015         viewdir[2] = 3 * dir[2];
02016         Vector2Angles(viewdir, result.ideal_viewangles);
02017         //elemantary action
02018         EA_Move(ms->client, origin, 0);
02019         EA_MoveForward(ms->client);
02020         //set movement view flag so the AI can see the view is focussed
02021         result.flags |= MOVERESULT_MOVEMENTVIEW;
02022     } //end if
02023 /*  else
02024     {
02025         //botimport.Print(PRT_MESSAGE, "moving towards ladder\n");
02026         VectorSubtract(reach->end, ms->origin, dir);
02027         //make sure the horizontal movement is large anough
02028         VectorCopy(dir, hordir);
02029         hordir[2] = 0;
02030         dist = VectorNormalize(hordir);
02031         //
02032         dir[0] = hordir[0];
02033         dir[1] = hordir[1];
02034         if (dir[2] > 0) dir[2] = 1;
02035         else dir[2] = -1;
02036         if (dist > 50) dist = 50;
02037         speed = 400 - (200 - 4 * dist);
02038         EA_Move(ms->client, dir, speed);
02039     } //end else*/
02040     //save the movement direction
02041     VectorCopy(dir, result.movedir);
02042     //
02043     return result;
02044 } //end of the function BotTravel_Ladder
02045 //===========================================================================
02046 //
02047 // Parameter:               -
02048 // Returns:                 -
02049 // Changes Globals:     -
02050 //===========================================================================
02051 bot_moveresult_t BotTravel_Teleport(bot_movestate_t *ms, aas_reachability_t *reach)
02052 {
02053     vec3_t hordir;
02054     float dist;
02055     bot_moveresult_t result;
02056 
02057     BotClearMoveResult(&result);
02058     //if the bot is being teleported
02059     if (ms->moveflags & MFL_TELEPORTED) return result;
02060 
02061     //walk straight to center of the teleporter
02062     VectorSubtract(reach->start, ms->origin, hordir);
02063     if (!(ms->moveflags & MFL_SWIMMING)) hordir[2] = 0;
02064     dist = VectorNormalize(hordir);
02065     //
02066     BotCheckBlocked(ms, hordir, qtrue, &result);
02067 
02068     if (dist < 30) EA_Move(ms->client, hordir, 200);
02069     else EA_Move(ms->client, hordir, 400);
02070 
02071     if (ms->moveflags & MFL_SWIMMING) result.flags |= MOVERESULT_SWIMVIEW;
02072 
02073     VectorCopy(hordir, result.movedir);
02074     return result;
02075 } //end of the function BotTravel_Teleport
02076 //===========================================================================
02077 //
02078 // Parameter:               -
02079 // Returns:                 -
02080 // Changes Globals:     -
02081 //===========================================================================
02082 bot_moveresult_t BotTravel_Elevator(bot_movestate_t *ms, aas_reachability_t *reach)
02083 {
02084     vec3_t dir, dir1, dir2, hordir, bottomcenter;
02085     float dist, dist1, dist2, speed;
02086     bot_moveresult_t result;
02087 
02088     BotClearMoveResult(&result);
02089     //if standing on the plat
02090     if (BotOnMover(ms->origin, ms->entitynum, reach))
02091     {
02092 #ifdef DEBUG_ELEVATOR
02093         botimport.Print(PRT_MESSAGE, "bot on elevator\n");
02094 #endif //DEBUG_ELEVATOR
02095         //if vertically not too far from the end point
02096         if (abs(ms->origin[2] - reach->end[2]) < sv_maxbarrier->value)
02097         {
02098 #ifdef DEBUG_ELEVATOR
02099             botimport.Print(PRT_MESSAGE, "bot moving to end\n");
02100 #endif //DEBUG_ELEVATOR
02101             //move to the end point
02102             VectorSubtract(reach->end, ms->origin, hordir);
02103             hordir[2] = 0;
02104             VectorNormalize(hordir);
02105             if (!BotCheckBarrierJump(ms, hordir, 100))
02106             {
02107                 EA_Move(ms->client, hordir, 400);
02108             } //end if
02109             VectorCopy(hordir, result.movedir);
02110         } //end else
02111         //if not really close to the center of the elevator
02112         else
02113         {
02114             MoverBottomCenter(reach, bottomcenter);
02115             VectorSubtract(bottomcenter, ms->origin, hordir);
02116             hordir[2] = 0;
02117             dist = VectorNormalize(hordir);
02118             //
02119             if (dist > 10)
02120             {
02121 #ifdef DEBUG_ELEVATOR
02122                 botimport.Print(PRT_MESSAGE, "bot moving to center\n");
02123 #endif //DEBUG_ELEVATOR
02124                 //move to the center of the plat
02125                 if (dist > 100) dist = 100;
02126                 speed = 400 - (400 - 4 * dist);
02127                 //
02128                 EA_Move(ms->client, hordir, speed);
02129                 VectorCopy(hordir, result.movedir);
02130             } //end if
02131         } //end else
02132     } //end if
02133     else
02134     {
02135 #ifdef DEBUG_ELEVATOR
02136         botimport.Print(PRT_MESSAGE, "bot not on elevator\n");
02137 #endif //DEBUG_ELEVATOR
02138         //if very near the reachability end
02139         VectorSubtract(reach->end, ms->origin, dir);
02140         dist = VectorLength(dir);
02141         if (dist < 64)
02142         {
02143             if (dist > 60) dist = 60;
02144             speed = 360 - (360 - 6 * dist);
02145             //
02146             if ((ms->moveflags & MFL_SWIMMING) || !BotCheckBarrierJump(ms, dir, 50))
02147             {
02148                 if (speed > 5) EA_Move(ms->client, dir, speed);
02149             } //end if
02150             VectorCopy(dir, result.movedir);
02151             //
02152             if (ms->moveflags & MFL_SWIMMING) result.flags |= MOVERESULT_SWIMVIEW;
02153             //stop using this reachability
02154             ms->reachability_time = 0;
02155             return result;
02156         } //end if
02157         //get direction and distance to reachability start
02158         VectorSubtract(reach->start, ms->origin, dir1);
02159         if (!(ms->moveflags & MFL_SWIMMING)) dir1[2] = 0;
02160         dist1 = VectorNormalize(dir1);
02161         //if the elevator isn't down
02162         if (!MoverDown(reach))
02163         {
02164 #ifdef DEBUG_ELEVATOR
02165             botimport.Print(PRT_MESSAGE, "elevator not down\n");
02166 #endif //DEBUG_ELEVATOR
02167             dist = dist1;
02168             VectorCopy(dir1, dir);
02169             //
02170             BotCheckBlocked(ms, dir, qfalse, &result);
02171             //
02172             if (dist > 60) dist = 60;
02173             speed = 360 - (360 - 6 * dist);
02174             //
02175             if (!(ms->moveflags & MFL_SWIMMING) && !BotCheckBarrierJump(ms, dir, 50))
02176             {
02177                 if (speed > 5) EA_Move(ms->client, dir, speed);
02178             } //end if
02179             VectorCopy(dir, result.movedir);
02180             //
02181             if (ms->moveflags & MFL_SWIMMING) result.flags |= MOVERESULT_SWIMVIEW;
02182             //this isn't a failure... just wait till the elevator comes down
02183             result.type = RESULTTYPE_ELEVATORUP;
02184             result.flags |= MOVERESULT_WAITING;
02185             return result;
02186         } //end if
02187         //get direction and distance to elevator bottom center
02188         MoverBottomCenter(reach, bottomcenter);
02189         VectorSubtract(bottomcenter, ms->origin, dir2);
02190         if (!(ms->moveflags & MFL_SWIMMING)) dir2[2] = 0;
02191         dist2 = VectorNormalize(dir2);
02192         //if very close to the reachability start or
02193         //closer to the elevator center or
02194         //between reachability start and elevator center
02195         if (dist1 < 20 || dist2 < dist1 || DotProduct(dir1, dir2) < 0)
02196         {
02197 #ifdef DEBUG_ELEVATOR
02198             botimport.Print(PRT_MESSAGE, "bot moving to center\n");
02199 #endif //DEBUG_ELEVATOR
02200             dist = dist2;
02201             VectorCopy(dir2, dir);
02202         } //end if
02203         else //closer to the reachability start
02204         {
02205 #ifdef DEBUG_ELEVATOR
02206             botimport.Print(PRT_MESSAGE, "bot moving to start\n");
02207 #endif //DEBUG_ELEVATOR
02208             dist = dist1;
02209             VectorCopy(dir1, dir);
02210         } //end else
02211         //
02212         BotCheckBlocked(ms, dir, qfalse, &result);
02213         //
02214         if (dist > 60) dist = 60;
02215         speed = 400 - (400 - 6 * dist);
02216         //
02217         if (!(ms->moveflags & MFL_SWIMMING) && !BotCheckBarrierJump(ms, dir, 50))
02218         {
02219             EA_Move(ms->client, dir, speed);
02220         } //end if
02221         VectorCopy(dir, result.movedir);
02222         //
02223         if (ms->moveflags & MFL_SWIMMING) result.flags |= MOVERESULT_SWIMVIEW;
02224     } //end else
02225     return result;
02226 } //end of the function BotTravel_Elevator
02227 //===========================================================================
02228 //
02229 // Parameter:               -
02230 // Returns:                 -
02231 // Changes Globals:     -
02232 //===========================================================================
02233 bot_moveresult_t BotFinishTravel_Elevator(bot_movestate_t *ms, aas_reachability_t *reach)
02234 {
02235     vec3_t bottomcenter, bottomdir, topdir;
02236     bot_moveresult_t result;
02237 
02238     BotClearMoveResult(&result);
02239     //
02240     MoverBottomCenter(reach, bottomcenter);
02241     VectorSubtract(bottomcenter, ms->origin, bottomdir);
02242     //
02243     VectorSubtract(reach->end, ms->origin, topdir);
02244     //
02245     if (fabs(bottomdir[2]) < fabs(topdir[2]))
02246     {
02247         VectorNormalize(bottomdir);
02248         EA_Move(ms->client, bottomdir, 300);
02249     } //end if
02250     else
02251     {
02252         VectorNormalize(topdir);
02253         EA_Move(ms->client, topdir, 300);
02254     } //end else
02255     return result;
02256 } //end of the function BotFinishTravel_Elevator
02257 //===========================================================================
02258 //
02259 // Parameter:           -
02260 // Returns:             -
02261 // Changes Globals:     -
02262 //===========================================================================
02263 void BotFuncBobStartEnd(aas_reachability_t *reach, vec3_t start, vec3_t end, vec3_t origin)
02264 {
02265     int spawnflags, modelnum;
02266     vec3_t mins, maxs, mid, angles = {0, 0, 0};
02267     int num0, num1;
02268 
02269     modelnum = reach->facenum & 0x0000FFFF;
02270     if (!AAS_OriginOfMoverWithModelNum(modelnum, origin))
02271     {
02272         botimport.Print(PRT_MESSAGE, "BotFuncBobStartEnd: no entity with model %d\n", modelnum);
02273         VectorSet(start, 0, 0, 0);
02274         VectorSet(end, 0, 0, 0);
02275         return;
02276     } //end if
02277     AAS_BSPModelMinsMaxsOrigin(modelnum, angles, mins, maxs, NULL);
02278     VectorAdd(mins, maxs, mid);
02279     VectorScale(mid, 0.5, mid);
02280     VectorCopy(mid, start);
02281     VectorCopy(mid, end);
02282     spawnflags = reach->facenum >> 16;
02283     num0 = reach->edgenum >> 16;
02284     if (num0 > 0x00007FFF) num0 |= 0xFFFF0000;
02285     num1 = reach->edgenum & 0x0000FFFF;
02286     if (num1 > 0x00007FFF) num1 |= 0xFFFF0000;
02287     if (spawnflags & 1)
02288     {
02289         start[0] = num0;
02290         end[0] = num1;
02291         //
02292         origin[0] += mid[0];
02293         origin[1] = mid[1];
02294         origin[2] = mid[2];
02295     } //end if
02296     else if (spawnflags & 2)
02297     {
02298         start[1] = num0;
02299         end[1] = num1;
02300         //
02301         origin[0] = mid[0];
02302         origin[1] += mid[1];
02303         origin[2] = mid[2];
02304     } //end else if
02305     else
02306     {
02307         start[2] = num0;
02308         end[2] = num1;
02309         //
02310         origin[0] = mid[0];
02311         origin[1] = mid[1];
02312         origin[2] += mid[2];
02313     } //end else
02314 } //end of the function BotFuncBobStartEnd
02315 //===========================================================================
02316 //
02317 // Parameter:           -
02318 // Returns:             -
02319 // Changes Globals:     -
02320 //===========================================================================
02321 bot_moveresult_t BotTravel_FuncBobbing(bot_movestate_t *ms, aas_reachability_t *reach)
02322 {
02323     vec3_t dir, dir1, dir2, hordir, bottomcenter, bob_start, bob_end, bob_origin;
02324     float dist, dist1, dist2, speed;
02325     bot_moveresult_t result;
02326 
02327     BotClearMoveResult(&result);
02328     //
02329     BotFuncBobStartEnd(reach, bob_start, bob_end, bob_origin);
02330     //if standing ontop of the func_bobbing
02331     if (BotOnMover(ms->origin, ms->entitynum, reach))
02332     {
02333 #ifdef DEBUG_FUNCBOB
02334         botimport.Print(PRT_MESSAGE, "bot on func_bobbing\n");
02335 #endif
02336         //if near end point of reachability
02337         VectorSubtract(bob_origin, bob_end, dir);
02338         if (VectorLength(dir) < 24)
02339         {
02340 #ifdef DEBUG_FUNCBOB
02341             botimport.Print(PRT_MESSAGE, "bot moving to reachability end\n");
02342 #endif
02343             //move to the end point
02344             VectorSubtract(reach->end, ms->origin, hordir);
02345             hordir[2] = 0;
02346             VectorNormalize(hordir);
02347             if (!BotCheckBarrierJump(ms, hordir, 100))
02348             {
02349                 EA_Move(ms->client, hordir, 400);
02350             } //end if
02351             VectorCopy(hordir, result.movedir);
02352         } //end else
02353         //if not really close to the center of the elevator
02354         else
02355         {
02356             MoverBottomCenter(reach, bottomcenter);
02357             VectorSubtract(bottomcenter, ms->origin, hordir);
02358             hordir[2] = 0;
02359             dist = VectorNormalize(hordir);
02360             //
02361             if (dist > 10)
02362             {
02363 #ifdef DEBUG_FUNCBOB
02364                 botimport.Print(PRT_MESSAGE, "bot moving to func_bobbing center\n");
02365 #endif
02366                 //move to the center of the plat
02367                 if (dist > 100) dist = 100;
02368                 speed = 400 - (400 - 4 * dist);
02369                 //
02370                 EA_Move(ms->client, hordir, speed);
02371                 VectorCopy(hordir, result.movedir);
02372             } //end if
02373         } //end else
02374     } //end if
02375     else
02376     {
02377 #ifdef DEBUG_FUNCBOB
02378         botimport.Print(PRT_MESSAGE, "bot not ontop of func_bobbing\n");
02379 #endif
02380         //if very near the reachability end
02381         VectorSubtract(reach->end, ms->origin, dir);
02382         dist = VectorLength(dir);
02383         if (dist < 64)
02384         {
02385 #ifdef DEBUG_FUNCBOB
02386             botimport.Print(PRT_MESSAGE, "bot moving to end\n");
02387 #endif
02388             if (dist > 60) dist = 60;
02389             speed = 360 - (360 - 6 * dist);
02390             //if swimming or no barrier jump
02391             if ((ms->moveflags & MFL_SWIMMING) || !BotCheckBarrierJump(ms, dir, 50))
02392             {
02393                 if (speed > 5) EA_Move(ms->client, dir, speed);
02394             } //end if
02395             VectorCopy(dir, result.movedir);
02396             //
02397             if (ms->moveflags & MFL_SWIMMING) result.flags |= MOVERESULT_SWIMVIEW;
02398             //stop using this reachability
02399             ms->reachability_time = 0;
02400             return result;
02401         } //end if
02402         //get direction and distance to reachability start
02403         VectorSubtract(reach->start, ms->origin, dir1);
02404         if (!(ms->moveflags & MFL_SWIMMING)) dir1[2] = 0;
02405         dist1 = VectorNormalize(dir1);
02406         //if func_bobbing is Not it's start position
02407         VectorSubtract(bob_origin, bob_start, dir);
02408         if (VectorLength(dir) > 16)
02409         {
02410 #ifdef DEBUG_FUNCBOB
02411             botimport.Print(PRT_MESSAGE, "func_bobbing not at start\n");
02412 #endif
02413             dist = dist1;
02414             VectorCopy(dir1, dir);
02415             //
02416             BotCheckBlocked(ms, dir, qfalse, &result);
02417             //
02418             if (dist > 60) dist = 60;
02419             speed = 360 - (360 - 6 * dist);
02420             //
02421             if (!(ms->moveflags & MFL_SWIMMING) && !BotCheckBarrierJump(ms, dir, 50))
02422             {
02423                 if (speed > 5) EA_Move(ms->client, dir, speed);
02424             } //end if
02425             VectorCopy(dir, result.movedir);
02426             //
02427             if (ms->moveflags & MFL_SWIMMING) result.flags |= MOVERESULT_SWIMVIEW;
02428             //this isn't a failure... just wait till the func_bobbing arrives
02429             result.type = RESULTTYPE_WAITFORFUNCBOBBING;
02430             result.flags |= MOVERESULT_WAITING;
02431             return result;
02432         } //end if
02433         //get direction and distance to func_bob bottom center
02434         MoverBottomCenter(reach, bottomcenter);
02435         VectorSubtract(bottomcenter, ms->origin, dir2);
02436         if (!(ms->moveflags & MFL_SWIMMING)) dir2[2] = 0;
02437         dist2 = VectorNormalize(dir2);
02438         //if very close to the reachability start or
02439         //closer to the elevator center or
02440         //between reachability start and func_bobbing center
02441         if (dist1 < 20 || dist2 < dist1 || DotProduct(dir1, dir2) < 0)
02442         {
02443 #ifdef DEBUG_FUNCBOB
02444             botimport.Print(PRT_MESSAGE, "bot moving to func_bobbing center\n");
02445 #endif
02446             dist = dist2;
02447             VectorCopy(dir2, dir);
02448         } //end if
02449         else //closer to the reachability start
02450         {
02451 #ifdef DEBUG_FUNCBOB
02452             botimport.Print(PRT_MESSAGE, "bot moving to reachability start\n");
02453 #endif
02454             dist = dist1;
02455             VectorCopy(dir1, dir);
02456         } //end else
02457         //
02458         BotCheckBlocked(ms, dir, qfalse, &result);
02459         //
02460         if (dist > 60) dist = 60;
02461         speed = 400 - (400 - 6 * dist);
02462         //
02463         if (!(ms->moveflags & MFL_SWIMMING) && !BotCheckBarrierJump(ms, dir, 50))
02464         {
02465             EA_Move(ms->client, dir, speed);
02466         } //end if
02467         VectorCopy(dir, result.movedir);
02468         //
02469         if (ms->moveflags & MFL_SWIMMING) result.flags |= MOVERESULT_SWIMVIEW;
02470     } //end else
02471     return result;
02472 } //end of the function BotTravel_FuncBobbing
02473 //===========================================================================
02474 //
02475 // Parameter:           -
02476 // Returns:             -
02477 // Changes Globals:     -
02478 //===========================================================================
02479 bot_moveresult_t BotFinishTravel_FuncBobbing(bot_movestate_t *ms, aas_reachability_t *reach)
02480 {
02481     vec3_t bob_origin, bob_start, bob_end, dir, hordir, bottomcenter;
02482     bot_moveresult_t result;
02483     float dist, speed;
02484 
02485     BotClearMoveResult(&result);
02486     //
02487     BotFuncBobStartEnd(reach, bob_start, bob_end, bob_origin);
02488     //
02489     VectorSubtract(bob_origin, bob_end, dir);
02490     dist = VectorLength(dir);
02491     //if the func_bobbing is near the end
02492     if (dist < 16)
02493     {
02494         VectorSubtract(reach->end, ms->origin, hordir);
02495         if (!(ms->moveflags & MFL_SWIMMING)) hordir[2] = 0;
02496         dist = VectorNormalize(hordir);
02497         //
02498         if (dist > 60) dist = 60;
02499         speed = 360 - (360 - 6 * dist);
02500         //
02501         if (speed > 5) EA_Move(ms->client, dir, speed);
02502         VectorCopy(dir, result.movedir);
02503         //
02504         if (ms->moveflags & MFL_SWIMMING) result.flags |= MOVERESULT_SWIMVIEW;
02505     } //end if
02506     else
02507     {
02508         MoverBottomCenter(reach, bottomcenter);
02509         VectorSubtract(bottomcenter, ms->origin, hordir);
02510         if (!(ms->moveflags & MFL_SWIMMING)) hordir[2] = 0;
02511         dist = VectorNormalize(hordir);
02512         //
02513         if (dist > 5)
02514         {
02515             //move to the center of the plat
02516             if (dist > 100) dist = 100;
02517             speed = 400 - (400 - 4 * dist);
02518             //
02519             EA_Move(ms->client, hordir, speed);
02520             VectorCopy(hordir, result.movedir);
02521         } //end if
02522     } //end else
02523     return result;
02524 } //end of the function BotFinishTravel_FuncBobbing
02525 //===========================================================================
02526 // 0  no valid grapple hook visible
02527 // 1  the grapple hook is still flying
02528 // 2  the grapple hooked into a wall
02529 //
02530 // Parameter:               -
02531 // Returns:                 -
02532 // Changes Globals:     -
02533 //===========================================================================
02534 int GrappleState(bot_movestate_t *ms, aas_reachability_t *reach)
02535 {
02536     int i;
02537     aas_entityinfo_t entinfo;
02538 
02539     //if the grapple hook is pulling
02540     if (ms->moveflags & MFL_GRAPPLEPULL)
02541         return 2;
02542     //check for a visible grapple missile entity
02543     //or visible grapple entity
02544     for (i = AAS_NextEntity(0); i; i = AAS_NextEntity(i))
02545     {
02546         if (AAS_EntityType(i) == (int) entitytypemissile->value)
02547         {
02548             AAS_EntityInfo(i, &entinfo);
02549             if (entinfo.weapon == (int) weapindex_grapple->value)
02550             {
02551                 return 1;
02552             } //end if
02553         } //end if
02554     } //end for
02555     //no valid grapple at all
02556     return 0;
02557 } //end of the function GrappleState
02558 //===========================================================================
02559 //
02560 // Parameter:               -
02561 // Returns:                 -
02562 // Changes Globals:     -
02563 //===========================================================================
02564 void BotResetGrapple(bot_movestate_t *ms)
02565 {
02566     aas_reachability_t reach;
02567 
02568     AAS_ReachabilityFromNum(ms->lastreachnum, &reach);
02569     //if not using the grapple hook reachability anymore
02570     if ((reach.traveltype & TRAVELTYPE_MASK) != TRAVEL_GRAPPLEHOOK)
02571     {
02572         if ((ms->moveflags & MFL_ACTIVEGRAPPLE) || ms->grapplevisible_time)
02573         {
02574             if (offhandgrapple->value)
02575                 EA_Command(ms->client, cmd_grappleoff->string);
02576             ms->moveflags &= ~MFL_ACTIVEGRAPPLE;
02577             ms->grapplevisible_time = 0;
02578 #ifdef DEBUG_GRAPPLE
02579             botimport.Print(PRT_MESSAGE, "reset grapple\n");
02580 #endif //DEBUG_GRAPPLE
02581         } //end if
02582     } //end if
02583 } //end of the function BotResetGrapple
02584 //===========================================================================
02585 //
02586 // Parameter:           -
02587 // Returns:             -
02588 // Changes Globals:     -
02589 //===========================================================================
02590 bot_moveresult_t BotTravel_Grapple(bot_movestate_t *ms, aas_reachability_t *reach)
02591 {
02592     bot_moveresult_t result;
02593     float dist, speed;
02594     vec3_t dir, viewdir, org;
02595     int state, areanum;
02596     bsp_trace_t trace;
02597 
02598 #ifdef DEBUG_GRAPPLE
02599     static int debugline;
02600     if (!debugline) debugline = botimport.DebugLineCreate();
02601     botimport.DebugLineShow(debugline, reach->start, reach->end, LINECOLOR_BLUE);
02602 #endif //DEBUG_GRAPPLE
02603 
02604     BotClearMoveResult(&result);
02605     //
02606     if (ms->moveflags & MFL_GRAPPLERESET)
02607     {
02608         if (offhandgrapple->value)
02609             EA_Command(ms->client, cmd_grappleoff->string);
02610         ms->moveflags &= ~MFL_ACTIVEGRAPPLE;
02611         return result;
02612     } //end if
02613     //
02614     if (!(int) offhandgrapple->value)
02615     {
02616         result.weapon = weapindex_grapple->value;
02617         result.flags |= MOVERESULT_MOVEMENTWEAPON;
02618     } //end if
02619     //
02620     if (ms->moveflags & MFL_ACTIVEGRAPPLE)
02621     {
02622 #ifdef DEBUG_GRAPPLE
02623         botimport.Print(PRT_MESSAGE, "BotTravel_Grapple: active grapple\n");
02624 #endif //DEBUG_GRAPPLE
02625         //
02626         state = GrappleState(ms, reach);
02627         //
02628         VectorSubtract(reach->end, ms->origin, dir);
02629         dir[2] = 0;
02630         dist = VectorLength(dir);
02631         //if very close to the grapple end or the grappled is hooked and
02632         //the bot doesn't get any closer
02633         if (state && dist < 48)
02634         {
02635             if (ms->lastgrappledist - dist < 1)
02636             {
02637 #ifdef DEBUG_GRAPPLE
02638                 botimport.Print(PRT_ERROR, "grapple normal end\n");
02639 #endif //DEBUG_GRAPPLE
02640                 if (offhandgrapple->value)
02641                     EA_Command(ms->client, cmd_grappleoff->string);
02642                 ms->moveflags &= ~MFL_ACTIVEGRAPPLE;
02643                 ms->moveflags |= MFL_GRAPPLERESET;
02644                 ms->reachability_time = 0;  //end the reachability
02645                 return result;
02646             } //end if
02647         } //end if
02648         //if no valid grapple at all, or the grapple hooked and the bot
02649         //isn't moving anymore
02650         else if (!state || (state == 2 && dist > ms->lastgrappledist - 2))
02651         {
02652             if (ms->grapplevisible_time < AAS_Time() - 0.4)
02653             {
02654 #ifdef DEBUG_GRAPPLE
02655                 botimport.Print(PRT_ERROR, "grapple not visible\n");
02656 #endif //DEBUG_GRAPPLE
02657                 if (offhandgrapple->value)
02658                     EA_Command(ms->client, cmd_grappleoff->string);
02659                 ms->moveflags &= ~MFL_ACTIVEGRAPPLE;
02660                 ms->moveflags |= MFL_GRAPPLERESET;
02661                 ms->reachability_time = 0;  //end the reachability
02662                 return result;
02663             } //end if
02664         } //end if
02665         else
02666         {
02667             ms->grapplevisible_time = AAS_Time();
02668         } //end else
02669         //
02670         if (!(int) offhandgrapple->value)
02671         {
02672             EA_Attack(ms->client);
02673         } //end if
02674         //remember the current grapple distance
02675         ms->lastgrappledist = dist;
02676     } //end if
02677     else
02678     {
02679 #ifdef DEBUG_GRAPPLE
02680         botimport.Print(PRT_MESSAGE, "BotTravel_Grapple: inactive grapple\n");
02681 #endif //DEBUG_GRAPPLE
02682         //
02683         ms->grapplevisible_time = AAS_Time();
02684         //
02685         VectorSubtract(reach->start, ms->origin, dir);
02686         if (!(ms->moveflags & MFL_SWIMMING)) dir[2] = 0;
02687         VectorAdd(ms->origin, ms->viewoffset, org);
02688         VectorSubtract(reach->end, org, viewdir);
02689         //
02690         dist = VectorNormalize(dir);
02691         Vector2Angles(viewdir, result.ideal_viewangles);
02692         result.flags |= MOVERESULT_MOVEMENTVIEW;
02693         //
02694         if (dist < 5 &&
02695             fabs(AngleDiff(result.ideal_viewangles[0], ms->viewangles[0])) < 2 &&
02696             fabs(AngleDiff(result.ideal_viewangles[1], ms->viewangles[1])) < 2)
02697         {
02698 #ifdef DEBUG_GRAPPLE
02699             botimport.Print(PRT_MESSAGE, "BotTravel_Grapple: activating grapple\n");
02700 #endif //DEBUG_GRAPPLE
02701             //check if the grapple missile path is clear
02702             VectorAdd(ms->origin, ms->viewoffset, org);
02703             trace = AAS_Trace(org, NULL, NULL, reach->end, ms->entitynum, CONTENTS_SOLID);
02704             VectorSubtract(reach->end, trace.endpos, dir);
02705             if (VectorLength(dir) > 16)
02706             {
02707                 result.failure = qtrue;
02708                 return result;
02709             } //end if
02710             //activate the grapple
02711             if (offhandgrapple->value)
02712             {
02713                 EA_Command(ms->client, cmd_grappleon->string);
02714             } //end if
02715             else
02716             {
02717                 EA_Attack(ms->client);
02718             } //end else
02719             ms->moveflags |= MFL_ACTIVEGRAPPLE;
02720             ms->lastgrappledist = 999999;
02721         } //end if
02722         else
02723         {
02724             if (dist < 70) speed = 300 - (300 - 4 * dist);
02725             else speed = 400;
02726             //
02727             BotCheckBlocked(ms, dir, qtrue, &result);
02728             //elemantary action move in direction
02729             EA_Move(ms->client, dir, speed);
02730             VectorCopy(dir, result.movedir);
02731         } //end else
02732         //if in another area before actually grappling
02733         areanum = AAS_PointAreaNum(ms->origin);
02734         if (areanum && areanum != ms->reachareanum) ms->reachability_time = 0;
02735     } //end else
02736     return result;
02737 } //end of the function BotTravel_Grapple
02738 //===========================================================================
02739 //
02740 // Parameter:               -
02741 // Returns:                 -
02742 // Changes Globals:         -
02743 //===========================================================================
02744 bot_moveresult_t BotTravel_RocketJump(bot_movestate_t *ms, aas_reachability_t *reach)
02745 {
02746     vec3_t hordir;
02747     float dist, speed;
02748     bot_moveresult_t result;
02749 
02750     //botimport.Print(PRT_MESSAGE, "BotTravel_RocketJump: bah\n");
02751     BotClearMoveResult(&result);
02752     //
02753     hordir[0] = reach->start[0] - ms->origin[0];
02754     hordir[1] = reach->start[1] - ms->origin[1];
02755     hordir[2] = 0;
02756     //
02757     dist = VectorNormalize(hordir);
02758     //look in the movement direction
02759     Vector2Angles(hordir, result.ideal_viewangles);
02760     //look straight down
02761     result.ideal_viewangles[PITCH] = 90;
02762     //
02763     if (dist < 5 &&
02764             fabs(AngleDiff(result.ideal_viewangles[0], ms->viewangles[0])) < 5 &&
02765             fabs(AngleDiff(result.ideal_viewangles[1], ms->viewangles[1])) < 5)
02766     {
02767         //botimport.Print(PRT_MESSAGE, "between jump start and run start point\n");
02768         hordir[0] = reach->end[0] - ms->origin[0];
02769         hordir[1] = reach->end[1] - ms->origin[1];
02770         hordir[2] = 0;
02771         VectorNormalize(hordir);
02772         //elemantary action jump
02773         EA_Jump(ms->client);
02774         EA_Attack(ms->client);
02775         EA_Move(ms->client, hordir, 800);
02776         //
02777         ms->jumpreach = ms->lastreachnum;
02778     } //end if
02779     else
02780     {
02781         if (dist > 80) dist = 80;
02782         speed = 400 - (400 - 5 * dist);
02783         EA_Move(ms->client, hordir, speed);
02784     } //end else
02785     //look in the movement direction
02786     Vector2Angles(hordir, result.ideal_viewangles);
02787     //look straight down
02788     result.ideal_viewangles[PITCH] = 90;
02789     //set the view angles directly
02790     EA_View(ms->client, result.ideal_viewangles);
02791     //view is important for the movment
02792     result.flags |= MOVERESULT_MOVEMENTVIEWSET;
02793     //select the rocket launcher
02794     EA_SelectWeapon(ms->client, (int) weapindex_rocketlauncher->value);
02795     //weapon is used for movement
02796     result.weapon = (int) weapindex_rocketlauncher->value;
02797     result.flags |= MOVERESULT_MOVEMENTWEAPON;
02798     //
02799     VectorCopy(hordir, result.movedir);
02800     //
02801     return result;
02802 } //end of the function BotTravel_RocketJump
02803 //===========================================================================
02804 //
02805 // Parameter:               -
02806 // Returns:                 -
02807 // Changes Globals:     -
02808 //===========================================================================
02809 bot_moveresult_t BotTravel_BFGJump(bot_movestate_t *ms, aas_reachability_t *reach)
02810 {
02811     vec3_t hordir;
02812     float dist, speed;
02813     bot_moveresult_t result;
02814 
02815     //botimport.Print(PRT_MESSAGE, "BotTravel_BFGJump: bah\n");
02816     BotClearMoveResult(&result);
02817     //
02818     hordir[0] = reach->start[0] - ms->origin[0];
02819     hordir[1] = reach->start[1] - ms->origin[1];
02820     hordir[2] = 0;
02821     //
02822     dist = VectorNormalize(hordir);
02823     //
02824     if (dist < 5 &&
02825             fabs(AngleDiff(result.ideal_viewangles[0], ms->viewangles[0])) < 5 &&
02826             fabs(AngleDiff(result.ideal_viewangles[1], ms->viewangles[1])) < 5)
02827     {
02828         //botimport.Print(PRT_MESSAGE, "between jump start and run start point\n");
02829         hordir[0] = reach->end[0] - ms->origin[0];
02830         hordir[1] = reach->end[1] - ms->origin[1];
02831         hordir[2] = 0;
02832         VectorNormalize(hordir);
02833         //elemantary action jump
02834         EA_Jump(ms->client);
02835         EA_Attack(ms->client);
02836         EA_Move(ms->client, hordir, 800);
02837         //
02838         ms->jumpreach = ms->lastreachnum;
02839     } //end if
02840     else
02841     {
02842         if (dist > 80) dist = 80;
02843         speed = 400 - (400 - 5 * dist);
02844         EA_Move(ms->client, hordir, speed);
02845     } //end else
02846     //look in the movement direction
02847     Vector2Angles(hordir, result.ideal_viewangles);
02848     //look straight down
02849     result.ideal_viewangles[PITCH] = 90;
02850     //set the view angles directly
02851     EA_View(ms->client, result.ideal_viewangles);
02852     //view is important for the movment
02853     result.flags |= MOVERESULT_MOVEMENTVIEWSET;
02854     //select the rocket launcher
02855     EA_SelectWeapon(ms->client, (int) weapindex_bfg10k->value);
02856     //weapon is used for movement
02857     result.weapon = (int) weapindex_bfg10k->value;
02858     result.flags |= MOVERESULT_MOVEMENTWEAPON;
02859     //
02860     VectorCopy(hordir, result.movedir);
02861     //
02862     return result;
02863 } //end of the function BotTravel_BFGJump
02864 //===========================================================================
02865 //
02866 // Parameter:               -
02867 // Returns:                 -
02868 // Changes Globals:     -
02869 //===========================================================================
02870 bot_moveresult_t BotFinishTravel_WeaponJump(bot_movestate_t *ms, aas_reachability_t *reach)
02871 {
02872     vec3_t hordir;
02873     float speed;
02874     bot_moveresult_t result;
02875 
02876     BotClearMoveResult(&result);
02877     //if not jumped yet
02878     if (!ms->jumpreach) return result;
02879     /*
02880     //go straight to the reachability end
02881     hordir[0] = reach->end[0] - ms->origin[0];
02882     hordir[1] = reach->end[1] - ms->origin[1];
02883     hordir[2] = 0;
02884     VectorNormalize(hordir);
02885     //always use max speed when traveling through the air
02886     EA_Move(ms->client, hordir, 800);
02887     VectorCopy(hordir, result.movedir);
02888     */
02889     //
02890     if (!BotAirControl(ms->origin, ms->velocity, reach->end, hordir, &speed))
02891     {
02892         //go straight to the reachability end
02893         VectorSubtract(reach->end, ms->origin, hordir);
02894         hordir[2] = 0;
02895         VectorNormalize(hordir);
02896         speed = 400;
02897     } //end if
02898     //
02899     EA_Move(ms->client, hordir, speed);
02900     VectorCopy(hordir, result.movedir);
02901     //
02902     return result;
02903 } //end of the function BotFinishTravel_WeaponJump
02904 //===========================================================================
02905 //
02906 // Parameter:               -
02907 // Returns:                 -
02908 // Changes Globals:     -
02909 //===========================================================================
02910 bot_moveresult_t BotTravel_JumpPad(bot_movestate_t *ms, aas_reachability_t *reach)
02911 {
02912     float dist, speed;
02913     vec3_t hordir;
02914     bot_moveresult_t result;
02915 
02916     BotClearMoveResult(&result);
02917     //first walk straight to the reachability start
02918     hordir[0] = reach->start[0] - ms->origin[0];
02919     hordir[1] = reach->start[1] - ms->origin[1];
02920     hordir[2] = 0;
02921     dist = VectorNormalize(hordir);
02922     //
02923     BotCheckBlocked(ms, hordir, qtrue, &result);
02924     speed = 400;
02925     //elemantary action move in direction
02926     EA_Move(ms->client, hordir, speed);
02927     VectorCopy(hordir, result.movedir);
02928     //
02929     return result;
02930 } //end of the function BotTravel_JumpPad
02931 //===========================================================================
02932 //
02933 // Parameter:           -
02934 // Returns:             -
02935 // Changes Globals:     -
02936 //===========================================================================
02937 bot_moveresult_t BotFinishTravel_JumpPad(bot_movestate_t *ms, aas_reachability_t *reach)
02938 {
02939     float speed;
02940     vec3_t hordir;
02941     bot_moveresult_t result;
02942 
02943     BotClearMoveResult(&result);
02944     if (!BotAirControl(ms->origin, ms->velocity, reach->end, hordir, &speed))
02945     {
02946         hordir[0] = reach->end[0] - ms->origin[0];
02947         hordir[1] = reach->end[1] - ms->origin[1];
02948         hordir[2] = 0;
02949         VectorNormalize(hordir);
02950         speed = 400;
02951     } //end if
02952     BotCheckBlocked(ms, hordir, qtrue, &result);
02953     //elemantary action move in direction
02954     EA_Move(ms->client, hordir, speed);
02955     VectorCopy(hordir, result.movedir);
02956     //
02957     return result;
02958 } //end of the function BotFinishTravel_JumpPad
02959 //===========================================================================
02960 // time before the reachability times out
02961 //
02962 // Parameter:               -
02963 // Returns:                 -
02964 // Changes Globals:     -
02965 //===========================================================================
02966 int BotReachabilityTime(aas_reachability_t *reach)
02967 {
02968     switch(reach->traveltype & TRAVELTYPE_MASK)
02969     {
02970         case TRAVEL_WALK: return 5;
02971         case TRAVEL_CROUCH: return 5;
02972         case TRAVEL_BARRIERJUMP: return 5;
02973         case TRAVEL_LADDER: return 6;
02974         case TRAVEL_WALKOFFLEDGE: return 5;
02975         case TRAVEL_JUMP: return 5;
02976         case TRAVEL_SWIM: return 5;
02977         case TRAVEL_WATERJUMP: return 5;
02978         case TRAVEL_TELEPORT: return 5;
02979         case TRAVEL_ELEVATOR: return 10;
02980         case TRAVEL_GRAPPLEHOOK: return 8;
02981         case TRAVEL_ROCKETJUMP: return 6;
02982         case TRAVEL_BFGJUMP: return 6;
02983         case TRAVEL_JUMPPAD: return 10;
02984         case TRAVEL_FUNCBOB: return 10;
02985         default:
02986         {
02987             botimport.Print(PRT_ERROR, "travel type %d not implemented yet\n", reach->traveltype);
02988             return 8;
02989         } //end case
02990     } //end switch
02991 } //end of the function BotReachabilityTime
02992 //===========================================================================
02993 //
02994 // Parameter:               -
02995 // Returns:                 -
02996 // Changes Globals:     -
02997 //===========================================================================
02998 bot_moveresult_t BotMoveInGoalArea(bot_movestate_t *ms, bot_goal_t *goal)
02999 {
03000     bot_moveresult_t result;
03001     vec3_t dir;
03002     float dist, speed;
03003 
03004 #ifdef DEBUG
03005     //botimport.Print(PRT_MESSAGE, "%s: moving straight to goal\n", ClientName(ms->entitynum-1));
03006     //AAS_ClearShownDebugLines();
03007     //AAS_DebugLine(ms->origin, goal->origin, LINECOLOR_RED);
03008 #endif //DEBUG
03009     BotClearMoveResult(&result);
03010     //walk straight to the goal origin
03011     dir[0] = goal->origin[0] - ms->origin[0];
03012     dir[1] = goal->origin[1] - ms->origin[1];
03013     if (ms->moveflags & MFL_SWIMMING)
03014     {
03015         dir[2] = goal->origin[2] - ms->origin[2];
03016         result.traveltype = TRAVEL_SWIM;
03017     } //end if
03018     else
03019     {
03020         dir[2] = 0;
03021         result.traveltype = TRAVEL_WALK;
03022     } //endif
03023     //
03024     dist = VectorNormalize(dir);
03025     if (dist > 100) dist = 100;
03026     speed = 400 - (400 - 4 * dist);
03027     if (speed < 10) speed = 0;
03028     //
03029     BotCheckBlocked(ms, dir, qtrue, &result);
03030     //elemantary action move in direction
03031     EA_Move(ms->client, dir, speed);
03032     VectorCopy(dir, result.movedir);
03033     //
03034     if (ms->moveflags & MFL_SWIMMING)
03035     {
03036         Vector2Angles(dir, result.ideal_viewangles);
03037         result.flags |= MOVERESULT_SWIMVIEW;
03038     } //end if
03039     //if (!debugline) debugline = botimport.DebugLineCreate();
03040     //botimport.DebugLineShow(debugline, ms->origin, goal->origin, LINECOLOR_BLUE);
03041     //
03042     ms->lastreachnum = 0;
03043     ms->lastareanum = 0;
03044     ms->lastgoalareanum = goal->areanum;
03045     VectorCopy(ms->origin, ms->lastorigin);
03046     //
03047     return result;
03048 } //end of the function BotMoveInGoalArea
03049 //===========================================================================
03050 //
03051 // Parameter:               -
03052 // Returns:                 -
03053 // Changes Globals:     -
03054 //===========================================================================
03055 void BotMoveToGoal(bot_moveresult_t *result, int movestate, bot_goal_t *goal, int travelflags)
03056 {
03057     int reachnum, lastreachnum, foundjumppad, ent, resultflags;
03058     aas_reachability_t reach, lastreach;
03059     bot_movestate_t *ms;
03060     //vec3_t mins, maxs, up = {0, 0, 1};
03061     //bsp_trace_t trace;
03062     //static int debugline;
03063 
03064 
03065     BotClearMoveResult(result);
03066     //
03067     ms = BotMoveStateFromHandle(movestate);
03068     if (!ms) return;
03069     //reset the grapple before testing if the bot has a valid goal
03070     //because the bot could loose all it's goals when stuck to a wall
03071     BotResetGrapple(ms);
03072     //
03073     if (!goal)
03074     {
03075 #ifdef DEBUG
03076         botimport.Print(PRT_MESSAGE, "client %d: movetogoal -> no goal\n", ms->client);
03077 #endif //DEBUG
03078         result->failure = qtrue;
03079         return;
03080     } //end if
03081     //botimport.Print(PRT_MESSAGE, "numavoidreach = %d\n", ms->numavoidreach);
03082     //remove some of the move flags
03083     ms->moveflags &= ~(MFL_SWIMMING|MFL_AGAINSTLADDER);
03084     //set some of the move flags
03085     //NOTE: the MFL_ONGROUND flag is also set in the higher AI
03086     if (AAS_OnGround(ms->origin, ms->presencetype, ms->entitynum)) ms->moveflags |= MFL_ONGROUND;
03087     //
03088     if (ms->moveflags & MFL_ONGROUND)
03089     {
03090         int modeltype, modelnum;
03091 
03092         ent = BotOnTopOfEntity(ms);
03093 
03094         if (ent != -1)
03095         {
03096             modelnum = AAS_EntityModelindex(ent);
03097             if (modelnum >= 0 && modelnum < MAX_MODELS)
03098             {
03099                 modeltype = modeltypes[modelnum];
03100 
03101                 if (modeltype == MODELTYPE_FUNC_PLAT)
03102                 {
03103                     AAS_ReachabilityFromNum(ms->lastreachnum, &reach);
03104                     //if the bot is Not using the elevator
03105                     if ((reach.traveltype & TRAVELTYPE_MASK) != TRAVEL_ELEVATOR ||
03106                         //NOTE: the face number is the plat model number
03107                         (reach.facenum & 0x0000FFFF) != modelnum)
03108                     {
03109                         reachnum = AAS_NextModelReachability(0, modelnum);
03110                         if (reachnum)
03111                         {
03112                             //botimport.Print(PRT_MESSAGE, "client %d: accidentally ended up on func_plat\n", ms->client);
03113                             AAS_ReachabilityFromNum(reachnum, &reach);
03114                             ms->lastreachnum = reachnum;
03115                             ms->reachability_time = AAS_Time() + BotReachabilityTime(&reach);
03116                         } //end if
03117                         else
03118                         {
03119                             if (bot_developer)
03120                             {
03121                                 botimport.Print(PRT_MESSAGE, "client %d: on func_plat without reachability\n", ms->client);
03122                             } //end if
03123                             result->blocked = qtrue;
03124                             result->blockentity = ent;
03125                             result->flags |= MOVERESULT_ONTOPOFOBSTACLE;
03126                             return;
03127                         } //end else
03128                     } //end if
03129                     result->flags |= MOVERESULT_ONTOPOF_ELEVATOR;
03130                 } //end if
03131                 else if (modeltype == MODELTYPE_FUNC_BOB)
03132                 {
03133                     AAS_ReachabilityFromNum(ms->lastreachnum, &reach);
03134                     //if the bot is Not using the func bobbing
03135                     if ((reach.traveltype & TRAVELTYPE_MASK) != TRAVEL_FUNCBOB ||
03136                         //NOTE: the face number is the func_bobbing model number
03137                         (reach.facenum & 0x0000FFFF) != modelnum)
03138                     {
03139                         reachnum = AAS_NextModelReachability(0, modelnum);
03140                         if (reachnum)
03141                         {
03142                             //botimport.Print(PRT_MESSAGE, "client %d: accidentally ended up on func_bobbing\n", ms->client);
03143                             AAS_ReachabilityFromNum(reachnum, &reach);
03144                             ms->lastreachnum = reachnum;
03145                             ms->reachability_time = AAS_Time() + BotReachabilityTime(&reach);
03146                         } //end if
03147                         else
03148                         {
03149                             if (bot_developer)
03150                             {
03151                                 botimport.Print(PRT_MESSAGE, "client %d: on func_bobbing without reachability\n", ms->client);
03152                             } //end if
03153                             result->blocked = qtrue;
03154                             result->blockentity = ent;
03155                             result->flags |= MOVERESULT_ONTOPOFOBSTACLE;
03156                             return;
03157                         } //end else
03158                     } //end if
03159                     result->flags |= MOVERESULT_ONTOPOF_FUNCBOB;
03160                 } //end if
03161                 else if (modeltype == MODELTYPE_FUNC_STATIC || modeltype == MODELTYPE_FUNC_DOOR)
03162                 {
03163                     // check if ontop of a door bridge ?
03164                     ms->areanum = BotFuzzyPointReachabilityArea(ms->origin);
03165                     // if not in a reachability area
03166                     if (!AAS_AreaReachability(ms->areanum))
03167                     {
03168                         result->blocked = qtrue;
03169                         result->blockentity = ent;
03170                         result->flags |= MOVERESULT_ONTOPOFOBSTACLE;
03171                         return;
03172                     } //end if
03173                 } //end else if
03174                 else
03175                 {
03176                     result->blocked = qtrue;
03177                     result->blockentity = ent;
03178                     result->flags |= MOVERESULT_ONTOPOFOBSTACLE;
03179                     return;
03180                 } //end else
03181             } //end if
03182         } //end if
03183     } //end if
03184     //if swimming
03185     if (AAS_Swimming(ms->origin)) ms->moveflags |= MFL_SWIMMING;
03186     //if against a ladder
03187     if (AAS_AgainstLadder(ms->origin)) ms->moveflags |= MFL_AGAINSTLADDER;
03188     //if the bot is on the ground, swimming or against a ladder
03189     if (ms->moveflags & (MFL_ONGROUND|MFL_SWIMMING|MFL_AGAINSTLADDER))
03190     {
03191         //botimport.Print(PRT_MESSAGE, "%s: onground, swimming or against ladder\n", ClientName(ms->entitynum-1));
03192         //
03193         AAS_ReachabilityFromNum(ms->lastreachnum, &lastreach);
03194         //reachability area the bot is in
03195         //ms->areanum = BotReachabilityArea(ms->origin, ((lastreach.traveltype & TRAVELTYPE_MASK) != TRAVEL_ELEVATOR));
03196         ms->areanum = BotFuzzyPointReachabilityArea(ms->origin);
03197         //
03198         if ( !ms->areanum )
03199         {
03200             result->failure = qtrue;
03201             result->blocked = qtrue;
03202             result->blockentity = 0;
03203             result->type = RESULTTYPE_INSOLIDAREA;
03204             return;
03205         } //end if
03206         //if the bot is in the goal area
03207         if (ms->areanum == goal->areanum)
03208         {
03209             *result = BotMoveInGoalArea(ms, goal);
03210             return;
03211         } //end if
03212         //assume we can use the reachability from the last frame
03213         reachnum = ms->lastreachnum;
03214         //if there is a last reachability
03215         if (reachnum)
03216         {
03217             AAS_ReachabilityFromNum(reachnum, &reach);
03218             //check if the reachability is still valid
03219             if (!(AAS_TravelFlagForType(reach.traveltype) & travelflags))
03220             {
03221                 reachnum = 0;
03222             } //end if
03223             //special grapple hook case
03224             else if ((reach.traveltype & TRAVELTYPE_MASK) == TRAVEL_GRAPPLEHOOK)
03225             {
03226                 if (ms->reachability_time < AAS_Time() ||
03227                     (ms->moveflags & MFL_GRAPPLERESET))
03228                 {
03229                     reachnum = 0;
03230                 } //end if
03231             } //end if
03232             //special elevator case
03233             else if ((reach.traveltype & TRAVELTYPE_MASK) == TRAVEL_ELEVATOR ||
03234                 (reach.traveltype & TRAVELTYPE_MASK) == TRAVEL_FUNCBOB)
03235             {
03236                 if ((result->flags & MOVERESULT_ONTOPOF_FUNCBOB) ||
03237                     (result->flags & MOVERESULT_ONTOPOF_FUNCBOB))
03238                 {
03239                     ms->reachability_time = AAS_Time() + 5;
03240                 } //end if
03241                 //if the bot was going for an elevator and reached the reachability area
03242                 if (ms->areanum == reach.areanum ||
03243                     ms->reachability_time < AAS_Time())
03244                 {
03245                     reachnum = 0;
03246                 } //end if
03247             } //end if
03248             else
03249             {
03250 #ifdef DEBUG
03251                 if (bot_developer)
03252                 {
03253                     if (ms->reachability_time < AAS_Time())
03254                     {
03255                         botimport.Print(PRT_MESSAGE, "client %d: reachability timeout in ", ms->client);
03256                         AAS_PrintTravelType(reach.traveltype & TRAVELTYPE_MASK);
03257                         botimport.Print(PRT_MESSAGE, "\n");
03258                     } //end if
03259                     /*
03260                     if (ms->lastareanum != ms->areanum)
03261                     {
03262                         botimport.Print(PRT_MESSAGE, "changed from area %d to %d\n", ms->lastareanum, ms->areanum);
03263                     } //end if*/
03264                 } //end if
03265 #endif //DEBUG
03266                 //if the goal area changed or the reachability timed out
03267                 //or the area changed
03268                 if (ms->lastgoalareanum != goal->areanum ||
03269                         ms->reachability_time < AAS_Time() ||
03270                         ms->lastareanum != ms->areanum)
03271                 {
03272                     reachnum = 0;
03273                     //botimport.Print(PRT_MESSAGE, "area change or timeout\n");
03274                 } //end else if
03275             } //end else
03276         } //end if
03277         resultflags = 0;
03278         //if the bot needs a new reachability
03279         if (!reachnum)
03280         {
03281             //if the area has no reachability links
03282             if (!AAS_AreaReachability(ms->areanum))
03283             {
03284 #ifdef DEBUG
03285                 if (bot_developer)
03286                 {
03287                     botimport.Print(PRT_MESSAGE, "area %d no reachability\n", ms->areanum);
03288                 } //end if
03289 #endif //DEBUG
03290             } //end if
03291             //get a new reachability leading towards the goal
03292             reachnum = BotGetReachabilityToGoal(ms->origin, ms->areanum,
03293                                 ms->lastgoalareanum, ms->lastareanum,
03294                                             ms->avoidreach, ms->avoidreachtimes, ms->avoidreachtries,
03295                                                         goal, travelflags, travelflags,
03296                                                                 ms->avoidspots, ms->numavoidspots, &resultflags);
03297             //the area number the reachability starts in
03298             ms->reachareanum = ms->areanum;
03299             //reset some state variables
03300             ms->jumpreach = 0;                      //for TRAVEL_JUMP
03301             ms->moveflags &= ~MFL_GRAPPLERESET; //for TRAVEL_GRAPPLEHOOK
03302             //if there is a reachability to the goal
03303             if (reachnum)
03304             {
03305                 AAS_ReachabilityFromNum(reachnum, &reach);
03306                 //set a timeout for this reachability
03307                 ms->reachability_time = AAS_Time() + BotReachabilityTime(&reach);
03308                 //
03309 #ifdef AVOIDREACH
03310                 //add the reachability to the reachabilities to avoid for a while
03311                 BotAddToAvoidReach(ms, reachnum, AVOIDREACH_TIME);
03312 #endif //AVOIDREACH
03313             } //end if
03314 #ifdef DEBUG
03315             
03316             else if (bot_developer)
03317             {
03318                 botimport.Print(PRT_MESSAGE, "goal not reachable\n");
03319                 Com_Memset(&reach, 0, sizeof(aas_reachability_t)); //make compiler happy
03320             } //end else
03321             if (bot_developer)
03322             {
03323                 //if still going for the same goal
03324                 if (ms->lastgoalareanum == goal->areanum)
03325                 {
03326                     if (ms->lastareanum == reach.areanum)
03327                     {
03328                         botimport.Print(PRT_MESSAGE, "same goal, going back to previous area\n");
03329                     } //end if
03330                 } //end if
03331             } //end if
03332 #endif //DEBUG
03333         } //end else
03334         //
03335         ms->lastreachnum = reachnum;
03336         ms->lastgoalareanum = goal->areanum;
03337         ms->lastareanum = ms->areanum;
03338         //if the bot has a reachability
03339         if (reachnum)
03340         {
03341             //get the reachability from the number
03342             AAS_ReachabilityFromNum(reachnum, &reach);
03343             result->traveltype = reach.traveltype;
03344             //
03345 #ifdef DEBUG_AI_MOVE
03346             AAS_ClearShownDebugLines();
03347             AAS_PrintTravelType(reach.traveltype & TRAVELTYPE_MASK);
03348             AAS_ShowReachability(&reach);
03349 #endif //DEBUG_AI_MOVE
03350             //
03351 #ifdef DEBUG
03352             //botimport.Print(PRT_MESSAGE, "client %d: ", ms->client);
03353             //AAS_PrintTravelType(reach.traveltype);
03354             //botimport.Print(PRT_MESSAGE, "\n");
03355 #endif //DEBUG
03356             switch(reach.traveltype & TRAVELTYPE_MASK)
03357             {
03358                 case TRAVEL_WALK: *result = BotTravel_Walk(ms, &reach); break;
03359                 case TRAVEL_CROUCH: *result = BotTravel_Crouch(ms, &reach); break;
03360                 case TRAVEL_BARRIERJUMP: *result = BotTravel_BarrierJump(ms, &reach); break;
03361                 case TRAVEL_LADDER: *result = BotTravel_Ladder(ms, &reach); break;
03362                 case TRAVEL_WALKOFFLEDGE: *result = BotTravel_WalkOffLedge(ms, &reach); break;
03363                 case TRAVEL_JUMP: *result = BotTravel_Jump(ms, &reach); break;
03364                 case TRAVEL_SWIM: *result = BotTravel_Swim(ms, &reach); break;
03365                 case TRAVEL_WATERJUMP: *result = BotTravel_WaterJump(ms, &reach); break;
03366                 case TRAVEL_TELEPORT: *result = BotTravel_Teleport(ms, &reach); break;
03367                 case TRAVEL_ELEVATOR: *result = BotTravel_Elevator(ms, &reach); break;
03368                 case TRAVEL_GRAPPLEHOOK: *result = BotTravel_Grapple(ms, &reach); break;
03369                 case TRAVEL_ROCKETJUMP: *result = BotTravel_RocketJump(ms, &reach); break;
03370                 case TRAVEL_BFGJUMP: *result = BotTravel_BFGJump(ms, &reach); break;
03371                 case TRAVEL_JUMPPAD: *result = BotTravel_JumpPad(ms, &reach); break;
03372                 case TRAVEL_FUNCBOB: *result = BotTravel_FuncBobbing(ms, &reach); break;
03373                 default:
03374                 {
03375                     botimport.Print(PRT_FATAL, "travel type %d not implemented yet\n", (reach.traveltype & TRAVELTYPE_MASK));
03376                     break;
03377                 } //end case
03378             } //end switch
03379             result->traveltype = reach.traveltype;
03380             result->flags |= resultflags;
03381         } //end if
03382         else
03383         {
03384             result->failure = qtrue;
03385             result->flags |= resultflags;
03386             Com_Memset(&reach, 0, sizeof(aas_reachability_t));
03387         } //end else
03388 #ifdef DEBUG
03389         if (bot_developer)
03390         {
03391             if (result->failure)
03392             {
03393                 botimport.Print(PRT_MESSAGE, "client %d: movement failure in ", ms->client);
03394                 AAS_PrintTravelType(reach.traveltype & TRAVELTYPE_MASK);
03395                 botimport.Print(PRT_MESSAGE, "\n");
03396             } //end if
03397         } //end if
03398 #endif //DEBUG
03399     } //end if
03400     else
03401     {
03402         int i, numareas, areas[16];
03403         vec3_t end;
03404 
03405         //special handling of jump pads when the bot uses a jump pad without knowing it
03406         foundjumppad = qfalse;
03407         VectorMA(ms->origin, -2 * ms->thinktime, ms->velocity, end);
03408         numareas = AAS_TraceAreas(ms->origin, end, areas, NULL, 16);
03409         for (i = numareas-1; i >= 0; i--)
03410         {
03411             if (AAS_AreaJumpPad(areas[i]))
03412             {
03413                 //botimport.Print(PRT_MESSAGE, "client %d used a jumppad without knowing, area %d\n", ms->client, areas[i]);
03414                 foundjumppad = qtrue;
03415                 lastreachnum = BotGetReachabilityToGoal(end, areas[i],
03416                             ms->lastgoalareanum, ms->lastareanum,
03417                             ms->avoidreach, ms->avoidreachtimes, ms->avoidreachtries,
03418                             goal, travelflags, TFL_JUMPPAD, ms->avoidspots, ms->numavoidspots, NULL);
03419                 if (lastreachnum)
03420                 {
03421                     ms->lastreachnum = lastreachnum;
03422                     ms->lastareanum = areas[i];
03423                     //botimport.Print(PRT_MESSAGE, "found jumppad reachability\n");
03424                     break;
03425                 } //end if
03426                 else
03427                 {
03428                     for (lastreachnum = AAS_NextAreaReachability(areas[i], 0); lastreachnum;
03429                         lastreachnum = AAS_NextAreaReachability(areas[i], lastreachnum))
03430                     {
03431                         //get the reachability from the number
03432                         AAS_ReachabilityFromNum(lastreachnum, &reach);
03433                         if ((reach.traveltype & TRAVELTYPE_MASK) == TRAVEL_JUMPPAD)
03434                         {
03435                             ms->lastreachnum = lastreachnum;
03436                             ms->lastareanum = areas[i];
03437                             //botimport.Print(PRT_MESSAGE, "found jumppad reachability hard!!\n");
03438                             break;
03439                         } //end if
03440                     } //end for
03441                     if (lastreachnum) break;
03442                 } //end else
03443             } //end if
03444         } //end for
03445         if (bot_developer)
03446         {
03447             //if a jumppad is found with the trace but no reachability is found
03448             if (foundjumppad && !ms->lastreachnum)
03449             {
03450                 botimport.Print(PRT_MESSAGE, "client %d didn't find jumppad reachability\n", ms->client);
03451             } //end if
03452         } //end if
03453         //
03454         if (ms->lastreachnum)
03455         {
03456             //botimport.Print(PRT_MESSAGE, "%s: NOT onground, swimming or against ladder\n", ClientName(ms->entitynum-1));
03457             AAS_ReachabilityFromNum(ms->lastreachnum, &reach);
03458             result->traveltype = reach.traveltype;
03459 #ifdef DEBUG
03460             //botimport.Print(PRT_MESSAGE, "client %d finish: ", ms->client);
03461             //AAS_PrintTravelType(reach.traveltype & TRAVELTYPE_MASK);
03462             //botimport.Print(PRT_MESSAGE, "\n");
03463 #endif //DEBUG
03464             //
03465             switch(reach.traveltype & TRAVELTYPE_MASK)
03466             {
03467                 case TRAVEL_WALK: *result = BotTravel_Walk(ms, &reach); break;//BotFinishTravel_Walk(ms, &reach); break;
03468                 case TRAVEL_CROUCH: /*do nothing*/ break;
03469                 case TRAVEL_BARRIERJUMP: *result = BotFinishTravel_BarrierJump(ms, &reach); break;
03470                 case TRAVEL_LADDER: *result = BotTravel_Ladder(ms, &reach); break;
03471                 case TRAVEL_WALKOFFLEDGE: *result = BotFinishTravel_WalkOffLedge(ms, &reach); break;
03472                 case TRAVEL_JUMP: *result = BotFinishTravel_Jump(ms, &reach); break;
03473                 case TRAVEL_SWIM: *result = BotTravel_Swim(ms, &reach); break;
03474                 case TRAVEL_WATERJUMP: *result = BotFinishTravel_WaterJump(ms, &reach); break;
03475                 case TRAVEL_TELEPORT: /*do nothing*/ break;
03476                 case TRAVEL_ELEVATOR: *result = BotFinishTravel_Elevator(ms, &reach); break;
03477                 case TRAVEL_GRAPPLEHOOK: *result = BotTravel_Grapple(ms, &reach); break;
03478                 case TRAVEL_ROCKETJUMP:
03479                 case TRAVEL_BFGJUMP: *result = BotFinishTravel_WeaponJump(ms, &reach); break;
03480                 case TRAVEL_JUMPPAD: *result = BotFinishTravel_JumpPad(ms, &reach); break;
03481                 case TRAVEL_FUNCBOB: *result = BotFinishTravel_FuncBobbing(ms, &reach); break;
03482                 default:
03483                 {
03484                     botimport.Print(PRT_FATAL, "(last) travel type %d not implemented yet\n", (reach.traveltype & TRAVELTYPE_MASK));
03485                     break;
03486                 } //end case
03487             } //end switch
03488             result->traveltype = reach.traveltype;
03489 #ifdef DEBUG
03490             if (bot_developer)
03491             {
03492                 if (result->failure)
03493                 {
03494                     botimport.Print(PRT_MESSAGE, "client %d: movement failure in finish ", ms->client);
03495                     AAS_PrintTravelType(reach.traveltype & TRAVELTYPE_MASK);
03496                     botimport.Print(PRT_MESSAGE, "\n");
03497                 } //end if
03498             } //end if
03499 #endif //DEBUG
03500         } //end if
03501     } //end else
03502     //FIXME: is it right to do this here?
03503     if (result->blocked) ms->reachability_time -= 10 * ms->thinktime;
03504     //copy the last origin
03505     VectorCopy(ms->origin, ms->lastorigin);
03506     //return the movement result
03507     return;
03508 } //end of the function BotMoveToGoal
03509 //===========================================================================
03510 //
03511 // Parameter:               -
03512 // Returns:                 -
03513 // Changes Globals:     -
03514 //===========================================================================
03515 void BotResetAvoidReach(int movestate)
03516 {
03517     bot_movestate_t *ms;
03518 
03519     ms = BotMoveStateFromHandle(movestate);
03520     if (!ms) return;
03521     Com_Memset(ms->avoidreach, 0, MAX_AVOIDREACH * sizeof(int));
03522     Com_Memset(ms->avoidreachtimes, 0, MAX_AVOIDREACH * sizeof(float));
03523     Com_Memset(ms->avoidreachtries, 0, MAX_AVOIDREACH * sizeof(int));
03524 } //end of the function BotResetAvoidReach
03525 //===========================================================================
03526 //
03527 // Parameter:               -
03528 // Returns:                 -
03529 // Changes Globals:     -
03530 //===========================================================================
03531 void BotResetLastAvoidReach(int movestate)
03532 {
03533     int i, latest;
03534     float latesttime;
03535     bot_movestate_t *ms;
03536 
03537     ms = BotMoveStateFromHandle(movestate);
03538     if (!ms) return;
03539     latesttime = 0;
03540     latest = 0;
03541     for (i = 0; i < MAX_AVOIDREACH; i++)
03542     {
03543         if (ms->avoidreachtimes[i] > latesttime)
03544         {
03545             latesttime = ms->avoidreachtimes[i];
03546             latest = i;
03547         } //end if
03548     } //end for
03549     if (latesttime)
03550     {
03551         ms->avoidreachtimes[latest] = 0;
03552         if (ms->avoidreachtries[i] > 0) ms->avoidreachtries[latest]--;
03553     } //end if
03554 } //end of the function BotResetLastAvoidReach
03555 //===========================================================================
03556 //
03557 // Parameter:           -
03558 // Returns:             -
03559 // Changes Globals:     -
03560 //===========================================================================
03561 void BotResetMoveState(int movestate)
03562 {
03563     bot_movestate_t *ms;
03564 
03565     ms = BotMoveStateFromHandle(movestate);
03566     if (!ms) return;
03567     Com_Memset(ms, 0, sizeof(bot_movestate_t));
03568 } //end of the function BotResetMoveState
03569 //===========================================================================
03570 //
03571 // Parameter:           -
03572 // Returns:             -
03573 // Changes Globals:     -
03574 //===========================================================================
03575 int BotSetupMoveAI(void)
03576 {
03577     BotSetBrushModelTypes();
03578     sv_maxstep = LibVar("sv_step", "18");
03579     sv_maxbarrier = LibVar("sv_maxbarrier", "32");
03580     sv_gravity = LibVar("sv_gravity", "800");
03581     weapindex_rocketlauncher = LibVar("weapindex_rocketlauncher", "5");
03582     weapindex_bfg10k = LibVar("weapindex_bfg10k", "9");
03583     weapindex_grapple = LibVar("weapindex_grapple", "10");
03584     entitytypemissile = LibVar("entitytypemissile", "3");
03585     offhandgrapple = LibVar("offhandgrapple", "0");
03586     cmd_grappleon = LibVar("cmd_grappleon", "grappleon");
03587     cmd_grappleoff = LibVar("cmd_grappleoff", "grappleoff");
03588     return BLERR_NOERROR;
03589 } //end of the function BotSetupMoveAI
03590 //===========================================================================
03591 //
03592 // Parameter:           -
03593 // Returns:             -
03594 // Changes Globals:     -
03595 //===========================================================================
03596 void BotShutdownMoveAI(void)
03597 {
03598     int i;
03599 
03600     for (i = 1; i <= MAX_CLIENTS; i++)
03601     {
03602         if (botmovestates[i])
03603         {
03604             FreeMemory(botmovestates[i]);
03605             botmovestates[i] = NULL;
03606         } //end if
03607     } //end for
03608 } //end of the function BotShutdownMoveAI
03609 
03610 

Generated on Thu Aug 25 12:37:12 2005 for Quake III Arena by  doxygen 1.3.9.1