Main Page | Alphabetical List | Compound List | File List | Compound Members | File Members

bot.c

Go to the documentation of this file.
00001 /****************************************************************************/
00002 /*    FILE: Bot.c                                                                                                               */
00003 /****************************************************************************/
00004 #include <Windows.h>
00005 #include <Assert.h>
00006 #include <Math.h>
00007 
00008 #include "GMain.h"
00009 
00010 #include "_bot.h"
00011 #include "track.h"
00012 #include "Bot.h"
00013 #include "botmatch.h"
00014 #include "botact.h"
00015 
00016 extern void GenVS_Error(const char *Msg, ...);
00017 #define NEW_WANDER
00018 //#define WANDER_TEST
00019 
00020 geBoolean Bot_TrackAction(GenVSI *VSI, void *PlayerData, const TrackPt* ThisPoint, const TrackPt* NextPoint, float Time);
00021 
00022 //=====================================================================================
00023 //=====================================================================================
00024 //
00025 //      Forward function declarations
00026 //
00027 //=====================================================================================
00028 //=====================================================================================
00029 
00030 geBoolean Bot_ModeChange(GenVSI *VSI, void *PlayerData, int32 NewMode, geBoolean Think, float Time);
00031 geBoolean Bot_ClearTrack(GenVSI *VSI, void *PlayerData);
00032 geBoolean Bot_FinishTrack(GenVSI *VSI, void *PlayerData);
00033 
00034 geBoolean Bot_InitGenericMove(GenVSI *VSI, void *PlayerData, float Time);
00035 geBoolean Bot_FindNewMoveVec(GenVSI *VSI, void *PlayerData, const geVec3d *TargetPos, int32 dir, float DistToMove, geVec3d *);
00036 geBoolean Bot_Physics(GenVSI *VSI, void *PlayerData, float Time);
00037 geBoolean Bot_OverLedge(GenVSI *VSI, void *PlayerData, geVec3d*);
00038 GPlayer *Bot_PickTgtPlayer(GenVSI *VSI, void *PlayerData, geBoolean);
00039 geBoolean Bot_LeaveTrack(GenVSI *VSI, void *PlayerData, float Time);
00040 
00041 geBoolean Bot_Animate(GenVSI *VSI, void *PlayerData, float Time);
00042 geBoolean Bot_GetContents(GenVSI *VSI, void *PlayerData, float Time);
00043 int16 Bot_ComparePlayers(GenVSI *VSI, void *PlayerData1, void *PlayerData2);
00044 int32 Bot_CompareWeapons(GenVSI *VSI, void *PlayerData, void *TgtPlayerData);
00045 geBoolean Bot_SetupXForm(GenVSI *VSI, void *PlayerData, geVec3d *OrientVec);
00046 geBoolean Bot_Shoot(GenVSI *VSI, void *PlayerData, geVec3d *ShootPosition, float Time);
00047 geBoolean Bot_Keys(GenVSI *VSI, void *PlayerData, float Time);
00048 
00049 geBoolean Bot_MoveToPoint(GenVSI *VSI, void *PlayerData, float Time);
00050 geBoolean Bot_InitMoveFree(GenVSI *VSI, void *PlayerData, geVec3d *Pos);
00051 geBoolean Bot_MoveFree(GenVSI *VSI, void *PlayerData, float Time);
00052 geBoolean Bot_InitMoveToPoint(GenVSI *VSI, void *PlayerData, geVec3d *Pos);
00053 geBoolean Bot_PastPoint(geVec3d *Pos, geVec3d *MoveVector, geVec3d *TgtPos);
00054 geBoolean Bot_CheckPosition(GenVSI *VSI, void *PlayerData);
00055 int32 Bot_GetRank(GenVSI *VSI, void *PlayerData);
00056 
00057 geBoolean Bot_InitWaitForPlayer(GenVSI *VSI, void *PlayerData, float Time);
00058 geBoolean Bot_WaitForPlayer(GenVSI *VSI, void *PlayerData, float Time);
00059 
00060 geBoolean Bot_InitWaitForEntityVisible(GenVSI *VSI, void *PlayerData, float Time);
00061 geBoolean Bot_WaitForEntityVisible(GenVSI *VSI, void *PlayerData, float Time);
00062 
00063 geBoolean Bot_InitWaitForEntityDist(GenVSI *VSI, void *PlayerData, float Time);
00064 geBoolean Bot_WaitForEntityDist(GenVSI *VSI, void *PlayerData, float Time);
00065 
00066 geBoolean Bot_InitShootPoint(GenVSI *VSI, void *PlayerData, float Time);
00067 geBoolean Bot_ShootPoint(GenVSI *VSI, void *PlayerData, float Time);
00068 
00069 geBoolean Bot_Reposition(GenVSI *VSI, void *PlayerData, geVec3d *, int32);
00070 void Bot_WeaponSetFromArray(GenVSI *VSI, void *PlayerData, int32 *WeaponArr);
00071 geBoolean Bot_SetWeapon(GenVSI *VSI, void *PlayerData, int16 WeaponNum);
00072 
00073 geBoolean Bot_SetupShootXForm(GenVSI *VSI, void *PlayerData, geVec3d *TargetVec);
00074 int32 Bot_GetRangeIndex(GenVSI *VSI, void *PlayerData);
00075 int32 Bot_GetStrengthIndex(GenVSI *VSI, void *PlayerData);
00076 
00077 geBoolean Bot_CanSeePointToPoint(geWorld *World, geVec3d *Pos1, geVec3d *Pos2);
00078 geBoolean Bot_CanSeePlayerToPlayer(geWorld *World, geVec3d *Pos1, geVec3d *Pos2);
00079 geBoolean Bot_CanSeePlayerToPoint(geWorld *World, geVec3d *Pos1, geVec3d *Pos2);
00080 Track *Bot_FindTrackToGoal(GenVSI *VSI, void *PlayerData, float Time);
00081 geBoolean Bot_ValidateTrackPoints(GenVSI *VSI, void *PlayerData, Track* t);
00082 geBoolean Bot_ValidateMultiTrackPoints(GenVSI *VSI, void *PlayerData, Track* t);
00083 
00084 geBoolean Bot_FireWeapon(GenVSI *VSI, void *PlayerData, float Time);
00085 geBoolean Bot_InitFindMultiTrack(GenVSI *VSI, void *PlayerData, geVec3d *DestPos, float Time);
00086 Track *Bot_FindTrack(GenVSI *VSI, void *PlayerData, int32 TrackArr[]);
00087 
00088 GPlayer *GetBotMatchSpawn(GenVSI *VSI);
00089 BotActorStart *Bot_GetActorStart(GenVSI *VSI, void *PlayerData);
00090 geBoolean BlockActor_Spawn(GenVSI *VSI, void *PlayerData, void *ClassData, char *EntityName);
00091 geBoolean Bot_ActionGetHealth(GenVSI *VSI, void *PlayerData, float Range, float Time);
00092 geBoolean Bot_ActionGetWeapon(GenVSI *VSI, void *PlayerData, float Range, float Time);
00093 GPlayer *Bot_FindRandomItem(GenVSI *VSI, geVec3d *Pos, char *ClassList[]);
00094 Track *Bot_FindRandomTrack(GenVSI *VSI, geVec3d *Pos, int32 *TrackTypeList);
00095 
00096 // Bot_Init functions 
00097 geBoolean Bot_InitRunCloser(GenVSI *VSI, void *PlayerData, float Time);
00098 geBoolean Bot_InitMoveCloser(GenVSI *VSI, void *PlayerData, float Time);
00099 geBoolean Bot_InitTrackToGoal(GenVSI *VSI, void *PlayerData, float Time);
00100 geBoolean Bot_InitTrackAwayGoal(GenVSI *VSI, void *PlayerData, float Time);
00101 geBoolean Bot_InitMaintain(GenVSI *VSI, void *PlayerData, float Time);
00102 geBoolean Bot_InitMoveAway(GenVSI *VSI, void *PlayerData, float Time);
00103 geBoolean Bot_InitRunAway(GenVSI *VSI, void *PlayerData, float Time);
00104 geBoolean Bot_InitUnload(GenVSI *VSI, void *PlayerData, float Time);
00105 geBoolean Bot_InitFindPlayer(GenVSI *VSI, void *PlayerData, float Time);
00106 geBoolean Bot_InitWander(GenVSI *VSI, void *PlayerData, float Time);
00107 geBoolean Bot_InitHide(GenVSI *VSI, void *PlayerData, float Time);
00108 geBoolean Bot_InitFindMultiTrackAway(GenVSI *VSI, void *PlayerData, geVec3d *, float Time);
00109 
00110 // ModeThink functions - called when a)finished with action b)encountered somthing unexpected
00111 geBoolean Bot_ModeThink(GenVSI *VSI, void *PlayerData, float Time);
00112 geBoolean Bot_ModeThinkAttack(GenVSI *VSI, void *PlayerData, float Time);
00113 geBoolean Bot_ModeThinkRetreat(GenVSI *VSI, void *PlayerData, float Time);
00114 geBoolean Bot_ModeThinkWander(GenVSI *VSI, void *PlayerData, float Time);
00115 geBoolean Bot_ModeThinkFindPlayer(GenVSI *VSI, void *PlayerData, float Time);
00116 geBoolean Bot_ModeThinkFindPlayerQuick(GenVSI *VSI, void *PlayerData, float Time);
00117 geBoolean Bot_ModeThinkCrowdPlayer(GenVSI *VSI, void *PlayerData, float Time);
00118 geBoolean Bot_ModeThinkGoalPoint(GenVSI *VSI, void *PlayerData, float Time);
00119 geBoolean Bot_ModeThinkOnTrack(GenVSI *VSI, void *PlayerData, float Time);
00120 geBoolean Bot_ModeThinkUnstick(GenVSI *VSI, void *PlayerData, float Time);
00121 geBoolean Bot_ModeThinkWanderGoal(GenVSI *VSI, void *PlayerData, float Time);
00122 int32 Bot_RankWeapons(GenVSI *VSI, void *PlayerData);
00123 
00124 // ModeAction functions - called every iteration after the Action functions
00125 geBoolean Bot_ModeActionRetreat(GenVSI *VSI, void *PlayerData, float Time);
00126 
00127 void *ChooseAction(DECISION decision[]);
00128 geBoolean Bot_SuicideTest(GenVSI *VSI, void *PlayerData, float Time);
00129 
00130 // Game functions I need to call
00131 geBoolean MovePlayerUpStep(GenVSI *VSI, void *PlayerData, GE_Collision *Collision);
00132 void SwitchToNextBestWeapon(GenVSI *VSI, void *PlayerData);
00133 geBoolean PlayerDead(GPlayer *Player);
00134 int32 PlayerLiquid(GPlayer *Player);
00135 void ValidateWeapon(GenVSI *VSI, void *PlayerData);
00136 void FireBlaster(GenVSI *VSI, void *PlayerData, float Time);
00137 void FireShredder(GenVSI *VSI, void *PlayerData, float Time);
00138 
00139 //=====================================================================================
00140 //=====================================================================================
00141 //
00142 //      Bot - Data and Defines
00143 //
00144 //=====================================================================================
00145 //=====================================================================================
00146 
00147 #define BOT_DIR_AWAY    -1
00148 #define BOT_DIR_TOWARD   1
00149 #define BOT_DIR_NONE     0
00150 
00151 #define BOT_SEARCH_Y_RANGE 40.0f
00152 
00153 #define BOT_STRENGTH_LOW(hd, wd) ((hd) < -30 && (wd) < -30)
00154 #define BOT_STRENGTH_HIGH(hd, wd) ((hd) > 30 && (wd) > 30)
00155 
00156 #define CONTENTS_WATER          GE_CONTENTS_USER1
00157 #define CONTENTS_LAVA           GE_CONTENTS_USER2
00158 
00159 #define BOT_GROUND_FRICTION             7.0f
00160 #define BOT_LIQUID_FRICTION             2.5f
00161 #define BOT_AIR_FRICTION                1.00f
00162 #define BOT_GRAVITY                             1600.0f
00163 #define BOT_JUMP_THRUST                 700//17000.0f
00164 #define BOT_SIDE_SPEED                  4000.0f
00165 #define BOT_RUN_SPEED                   3700.0f
00166 
00167 #define CLOSE_RANGE_DIST 400.0f
00168 #define MED_RANGE_DIST   900.0f
00169 #define LONG_RANGE_DIST  1600.0f
00170 
00171 #define CLOSE_RANGE      0 
00172 #define MED_RANGE        1
00173 #define LONG_RANGE       2
00174 
00175 char *ItemHealthList[] = {"ItemHealth", "ItemArmor", NULL};
00176 char *ItemWeaponList[] = {"ItemRocket", "ItemGrenade", "ItemShredder", NULL};
00177 char *ItemAmmoList[] = {"ItemRocketAmmo", "ItemGrenadeAmmo", "ItemShredderAmmo", NULL};
00178 
00179 int32 HealthTrackList[] =
00180     {
00181         //TRACK_TYPE_SCAN_HEALTH,
00182         -1
00183     };
00184 
00185 int32 WeaponTrackList[] =
00186     {
00187         //TRACK_TYPE_SCAN_WEAPON_AMMO,
00188     //TRACK_TYPE_SCAN,
00189     -1
00190     };
00191 
00192 int32 HideTrackList[] =
00193     {
00194         TRACK_TYPE_HIDE,
00195     -1
00196     };
00197 
00198 static int32 WeaponSetClose[] = {3, 0, 1, 2};
00199 static int32 WeaponSetMed[]   = {3, 1, 2, 0};
00200 static int32 WeaponSetLong[]  = {3, 2, 1, 0};
00201 static int32 *WeaponSetRange[] = {WeaponSetClose, WeaponSetMed, WeaponSetLong};
00202 
00203 static GPlayer *BotDeathMatchStart = NULL;
00204 
00205 typedef struct
00206 {
00207         float           RunSpeed;               // Scale value for running speed
00208         CONTROLp    Action;                     // Function that's called every thing
00209     TrackData   TrackInfo;              // Current track info - track/point/direction
00210     TrackData   TrackInfoPrev;  // Last point track info
00211     int32       Dir;                    // TOWARD/AWAY from player - Should prob be MODE
00212         geVec3d         TgtPos;                 // Current point you are moving towards
00213     GPlayer             *TgtPlayer;             // The player you are aware of at the moment
00214         geVec3d     MoveVec;            // Current Movement Vector
00215         float           TimeOut;                // Limit certain actions to a maximum time
00216         float           ModeTimeOut;    // Limit modes to a maximum time
00217         int32           ShootCount;             // Current number of shots
00218         float       TimeSeen;           // Time the player has been in view
00219         float       TimeNotSeen;    // Time the player has been out of view
00220         float       ModeTimeSeen;       // For Mode Routines only - Get reset on mode changes
00221         float       ModeTimeNotSeen;// For Mode Routines only - Get reset on mode changes
00222         float           ActiveTime;     // For Actor Bots only - limits movement when not in view
00223     int32       Mode;           // Current Mode of Bot
00224         int32           Bumps;                  // Number of bumps in a row
00225         int32           LedgeBumps;             // Number of Ledge bumbs in a row
00226         geVec3d         GoalPos;            // Current goal - could be the player or any other
00227                                                             // point.
00228         int8            BotType;        // Multi-player or Actor
00229         geBoolean       PastFirstTrackPoint; //Flag - sort of self documenting :Q
00230         int32           WeaponDiff;
00231         int32           HealthDiff;
00232     Stack       TrackStack;     // Stack of Tracks
00233         int32           HealthCheck;    // health check
00234         float           PickTimeout;
00235         float           TimeSinceTrack;
00236         GPlayer         *ClientPlayer;
00237         geBoolean       FaceTgtPlayerOnRetreat;
00238         int32           BotTgtPicked;
00239 
00240 } Bot_Var;
00241 
00242 geVec3d RayMins = {-1.0f,-1.0f,-1.0f}, RayMaxs = {1.0f,1.0f,1.0f};
00243 
00244 enum {  
00245         MODE_NULL = -1,
00246         MODE_ATTACK = 0, 
00247         MODE_RETREAT, 
00248         MODE_WANDER, 
00249         MODE_FIND_PLAYER, 
00250         MODE_FIND_PLAYER_QUICK, 
00251     MODE_CROWD_PLAYER,
00252     MODE_GOAL_POINT,
00253         MODE_ON_TRACK,
00254     MODE_RETREAT_ON_TRACK,
00255     MODE_UNSTICK,
00256         MODE_WANDER_ON_TRACK,
00257         MODE_MAX,
00258         };
00259 
00260 int32 ModeTable[MODE_MAX] =
00261     {
00262         MODE_ATTACK, 
00263         MODE_RETREAT, 
00264         MODE_WANDER, 
00265         MODE_FIND_PLAYER, 
00266         MODE_FIND_PLAYER_QUICK,
00267     MODE_CROWD_PLAYER,
00268     MODE_GOAL_POINT,
00269         MODE_ON_TRACK,
00270     MODE_RETREAT_ON_TRACK,
00271     MODE_UNSTICK,
00272         MODE_WANDER_ON_TRACK,
00273     };
00274 
00275 // debug strings
00276 char *ModeText[] = 
00277         {
00278         "MODE_ATTACK", 
00279         "MODE_RETREAT", 
00280         "MODE_WANDER", 
00281         "MODE_FIND_PLAYER", 
00282         "MODE_FIND_PLAYER_QUICK",
00283     "MODE_CROWD_PLAYER",
00284     "MODE_GOAL_POINT",
00285         "MODE_ON_TRACK",
00286     "MODE_RETREAT_ON_TRACK",
00287     "MODE_UNSTICK",
00288         "MODE_WANDER_ON_TRACK",
00289         };
00290 
00291 CONTROLp Bot_ModeThinkFunc[MODE_MAX] = 
00292         {
00293         Bot_ModeThinkAttack,
00294         Bot_ModeThinkRetreat,
00295         Bot_ModeThinkWander,
00296         Bot_ModeThinkFindPlayer,
00297         Bot_ModeThinkFindPlayerQuick,
00298     Bot_ModeThinkCrowdPlayer,
00299     Bot_ModeThinkGoalPoint,
00300         Bot_ModeThinkOnTrack,
00301         Bot_ModeThinkOnTrack,//RetreatOnTrack,
00302         Bot_ModeThinkUnstick,
00303         Bot_ModeThinkOnTrack,//WanderGoal,
00304         };
00305 
00306 CONTROLp Bot_ModeAction[MODE_MAX] = 
00307         {
00308         NULL,//Attack,
00309         Bot_ModeActionRetreat,//Retreat,
00310         NULL,//Wander,
00311         NULL,//FindPlayer,
00312         NULL,//FindPlayerQuick,
00313     NULL,//CrowdPlayer,
00314     NULL,//GoalPoint,
00315         NULL,//OnTrack,
00316         Bot_ModeActionRetreat,//RetreatOnTrack,
00317         NULL,//Unstick,
00318         NULL,//WanderGoal,
00319         };
00320 
00321 
00322 RankTable[3][3] = 
00323 {//close    med     long
00324         {0,             2,              4},             //weak
00325         {5,     6,      7},             //med
00326         {6,             10,             9},         //strong
00327 };
00328 
00329 #if 0
00330 //formula for leading a player - would be too deadly I think
00331 dist = Distance(sp->x, sp->y, hp->x, hp->y);
00332 time_to_target = dist/wp->xvel;
00333 lead_dist = time_to_target*hp->vel;
00334 #endif
00335 
00336 // Global Debug vars
00337 geBoolean GodMode = GE_FALSE;
00338 geBoolean PathLight = GE_FALSE;
00339 geBoolean BotDebugPrint = GE_FALSE;
00340 geBoolean MultiPathLight = GE_FALSE;
00341 
00342 void Bot_SetLighting(GenVSI *VSI, void *PlayerData);
00343 geBoolean Bot_TargetTest(GenVSI *VSI, void *PlayerData, float Time);
00344 geBoolean Bot_ShootFoot(GenVSI *VSI, void *PlayerData, float Time);
00345 geBoolean Bot_Suicide(GenVSI *VSI, void *PlayerData, float Time);
00346 //=====================================================================================
00347 //=====================================================================================
00348 //
00349 //      Bot_Control
00350 //
00351 //=====================================================================================
00352 //=====================================================================================
00353 geBoolean Bot_Control(GenVSI *VSI, void *PlayerData, float Time)
00354 {
00355         GPlayer                 *Player;
00356         Bot_Var                 *DBot;
00357         geWorld                 *World;
00358         geBoolean               CanSee;
00359 
00360         World = GenVSI_GetWorld(VSI);
00361         assert(World);
00362 
00363         Player = (GPlayer*)PlayerData;
00364         assert(Player);
00365 
00366         DBot = (Bot_Var*)Player->userData;
00367 
00368         assert(DBot);
00369 
00370         Player->Time += Time;
00371         DBot->ModeTimeOut += Time;
00372         DBot->TimeSinceTrack += Time;
00373 
00374         //Bot_SetLighting(VSI, Player);
00375 
00376         if (Bot_SuicideTest(VSI, Player, Time))
00377                 return GE_TRUE;
00378 
00379         Bot_TargetTest(VSI, Player, Time);
00380 
00381     assert(DBot->TgtPlayer);
00382 
00383     CanSee = Bot_CanSeePlayerToPlayer(World, &Player->XForm.Translation, &DBot->TgtPlayer->XForm.Translation);
00384     if (CanSee)
00385                 {
00386                 DBot->TimeNotSeen = 0.0f;
00387                 DBot->TimeSeen += Time;
00388                 DBot->ModeTimeSeen += Time;
00389                 }
00390         else
00391                 {
00392                 DBot->TimeSeen = 0.0f;
00393                 DBot->TimeNotSeen += Time;
00394                 DBot->ModeTimeNotSeen += Time;
00395                 }
00396 
00397         // Actor Bot
00398         if (DBot->BotType == 1)
00399                 {
00400             if (CanSee)
00401                         {
00402                         // stay active for 20 seconds after bot goes from ALL players views
00403                         DBot->ActiveTime = 20.0f;
00404                         }
00405                 else
00406                         {
00407                         if (DBot->ActiveTime <= 0.0f)
00408                                 return GE_TRUE;
00409 
00410                         DBot->ActiveTime -= Time;
00411                         }
00412                 }
00413         
00414         Bot_Keys(VSI, Player, Time);
00415 
00416         // default goal to target player if not on a track or similar circumstance
00417         if (!Track_OnTrack(&DBot->TrackInfo) && !(DBot->Mode == MODE_GOAL_POINT))
00418                 DBot->GoalPos = DBot->TgtPlayer->XForm.Translation; 
00419 
00420         // Purely for debug purposes so we can break at any point
00421     #if BOT_DEBUG
00422         if (GetAsyncKeyState('M') & 0x8000)
00423                 Player = Player;
00424     #endif
00425 
00426     assert(DBot->Action);
00427     DBot->Action(VSI, PlayerData, Time);
00428 
00429         // mode specific action testing - called every time through the loop
00430         // for certain modes
00431         if (Bot_ModeAction[DBot->Mode])
00432                 Bot_ModeAction[DBot->Mode](VSI, PlayerData, Time);
00433 
00434     return GE_TRUE;
00435     }
00436 
00437 
00438 //=====================================================================================
00439 //      Bot_TargetTest
00440 //=====================================================================================
00441 geBoolean Bot_TargetTest(GenVSI *VSI, void *PlayerData, float Time)
00442         {
00443         GPlayer                 *Player,*NewTgtPlayer;
00444         Bot_Var                 *DBot;
00445 
00446         Player = (GPlayer*)PlayerData;
00447         assert(Player);
00448         DBot = (Bot_Var*)Player->userData;
00449         assert(DBot);
00450 
00451         // time to check for new target
00452         if (GenVSI_GetTime(VSI) >= DBot->PickTimeout || DBot->TgtPlayer == NULL)
00453                 {
00454                 NewTgtPlayer = Bot_PickTgtPlayer(VSI, PlayerData, GE_FALSE);
00455 
00456                 // setup timout again
00457                 if (GenVSI_IsClientBot(VSI, NewTgtPlayer->ClientHandle))
00458                         {
00459                         DBot->BotTgtPicked++;
00460                         DBot->PickTimeout = GenVSI_GetTime(VSI) + 3.0f;
00461                         }
00462                 else
00463                         {
00464                         DBot->BotTgtPicked = 0;
00465                         DBot->PickTimeout = GenVSI_GetTime(VSI) + 10.0f;
00466                         }
00467 
00468                 if (++DBot->BotTgtPicked > 2)
00469                         {
00470                         // Bot was picked too many times - force human player
00471                         DBot->BotTgtPicked = 0;
00472                         NewTgtPlayer = Bot_PickTgtPlayer(VSI, PlayerData, GE_TRUE);
00473                         DBot->PickTimeout = GenVSI_GetTime(VSI) + 12.0f;
00474                         }
00475 
00476                 // changed targets - reset vars
00477                 if (NewTgtPlayer != DBot->TgtPlayer)    //changed targets
00478                         {
00479                         DBot->TgtPlayer = NewTgtPlayer;
00480                         DBot->TimeNotSeen = 0.0f;
00481                         DBot->TimeSeen = 0.0f;
00482                         }
00483                 }
00484 
00485         return GE_TRUE;
00486 }
00487 
00488 //=====================================================================================
00489 //      Bot_SuicideTest
00490 //=====================================================================================
00491 geBoolean Bot_SuicideTest(GenVSI *VSI, void *PlayerData, float Time)
00492         {
00493         GPlayer                 *Player;
00494         Bot_Var                 *DBot;
00495         geBoolean DammagePlayer(GenVSI *VSI, void *PlayerData, void *TargetData, int32 Amount, float Power, float Time);
00496         geBoolean KillPlayer(GenVSI *VSI, void *PlayerData, void *TargetData, float Time);
00497 
00498         Player = (GPlayer*)PlayerData;
00499         assert(Player);
00500         DBot = (Bot_Var*)Player->userData;
00501         assert(DBot);
00502 
00503         if (Track_OnTrack(&DBot->TrackInfo))
00504                 DBot->TimeSinceTrack = 0.0f;
00505         else
00506         if (DBot->TimeSinceTrack >= 20.0f)
00507                 {
00508                 GPlayer *SaveOwner;
00509 
00510                 Player->Health = 0;
00511                 SaveOwner = Player->Owner;
00512                 Player->Owner = Player;
00513                 KillPlayer(VSI, Player, Player, Time);
00514                 Player->Owner = SaveOwner;
00515 /*
00516                 DammagePlayer(VSI, PlayerData, TargetData, 300, 0, Time);
00517                 // suicide after no tracks for a while
00518                 if (!PlayerDead(Player)) Bot_Suicide(VSI, Player, Time);
00519                 if (!PlayerDead(Player)) Bot_Suicide(VSI, Player, Time);
00520                 if (!PlayerDead(Player)) Bot_Suicide(VSI, Player, Time);
00521                 if (!PlayerDead(Player)) Bot_Suicide(VSI, Player, Time);
00522                 if (!PlayerDead(Player)) Bot_Suicide(VSI, Player, Time);
00523                 if (!PlayerDead(Player)) Bot_Suicide(VSI, Player, Time);
00524                 if (!PlayerDead(Player)) Bot_Suicide(VSI, Player, Time);
00525                 if (!PlayerDead(Player)) Bot_Suicide(VSI, Player, Time);
00526                 if (!PlayerDead(Player)) Bot_Suicide(VSI, Player, Time);
00527 */
00528                 return GE_TRUE;
00529                 }
00530 
00531         return GE_FALSE;
00532         }
00533 
00534 //=====================================================================================
00535 //=====================================================================================
00536 //
00537 //      Bot Mode Routines
00538 //
00539 //=====================================================================================
00540 //=====================================================================================
00541 
00542 //=====================================================================================
00543 //      Bot_ModeThink - Run through the mode code
00544 //=====================================================================================
00545 geBoolean Bot_ModeThink(GenVSI *VSI, void *PlayerData, float Time)
00546 {
00547         GPlayer                         *Player;
00548         Bot_Var                         *DBot;
00549 
00550         Player = (GPlayer*)PlayerData;
00551         DBot = Player->userData;
00552 
00553         //if (BotDebugPrint) GenVSI_ConsoleHeaderPrintf(VSI, DBot->TgtPlayer->ClientHandle, GE_TRUE, "Bot Think Mode %s", ModeText[DBot->Mode]);
00554 
00555         Bot_ModeThinkFunc[DBot->Mode](VSI, PlayerData, Time);
00556 
00557     return GE_TRUE;
00558 }
00559 
00560 //=====================================================================================
00561 //      Bot_ModeThinkLedge
00562 //=====================================================================================
00563 geBoolean Bot_ModeThinkLedge(GenVSI *VSI, void *PlayerData, float Time)
00564 {
00565         GPlayer                         *Player;
00566         Bot_Var                         *DBot;
00567         int32 dir;
00568 
00569         Player = (GPlayer*)PlayerData;
00570         DBot = Player->userData;
00571 
00572     // Sometimes when making jumps the bot may land on a ledge
00573     // This attempts to see if we are in the middle of a track - not the first point
00574         // Also allows running off of ledges
00575     if (Track_OnTrack(&DBot->TrackInfo))
00576         {
00577                 #if 1
00578         TrackPt *pt,*fpt;
00579         pt = Track_GetPoint(&DBot->TrackInfo);
00580         fpt = Track_GetFirstPoint(&DBot->TrackInfo);
00581         if (pt != fpt)
00582             return GE_FALSE;  // do notdetect a ledge
00583                 #else
00584                 if (DBot->PastFirstTrackPoint)
00585                         return GE_FALSE;
00586                 #endif
00587 
00588                 Player->XForm.Translation = Player->LastGoodPos;
00589                 geVec3d_Clear(&Player->Velocity);
00590 
00591                 if (!Bot_InitTrackToGoal(VSI, Player, Time))
00592                         {
00593                         dir = RandomRange(3) - 1; //-1 to 1
00594                         Bot_Reposition(VSI, Player, &DBot->GoalPos, dir); //Try the opposite direction
00595                         }
00596         }
00597         else
00598                 {
00599                         Player->XForm.Translation = Player->LastGoodPos;
00600                         geVec3d_Clear(&Player->Velocity);
00601                     dir = RandomRange(3) - 1; //-1 to 1
00602                     Bot_Reposition(VSI, Player, &DBot->GoalPos, dir); //Try the opposite direction
00603                 }
00604 
00605 
00606     return GE_TRUE;
00607 }
00608 
00609 void Bot_SetMode(void *PlayerData, int32 NewMode)
00610 {
00611         GPlayer                         *Player;
00612         Bot_Var                         *DBot;
00613 
00614         Player = (GPlayer*)PlayerData;
00615         DBot = Player->userData;
00616 
00617         switch (NewMode)
00618                 {
00619                 case MODE_RETREAT:
00620                 case MODE_RETREAT_ON_TRACK:
00621                         DBot->HealthCheck = Player->Health;
00622                         DBot->FaceTgtPlayerOnRetreat = GE_FALSE;
00623                         break;
00624                 }
00625 
00626         DBot->Mode = NewMode;
00627 }
00628 
00629 
00630 //=====================================================================================
00631 //      Bot_ModeChange - This is the only place allowed to set modes
00632 //=====================================================================================
00633 geBoolean Bot_ModeChange(GenVSI *VSI, void *PlayerData, int32 NewMode, geBoolean Think, float Time)
00634 {
00635         GPlayer                         *Player;
00636         Bot_Var                         *DBot;
00637         int32                           *iptr;
00638         int32                           Rank,RNdx,SNdx;
00639 
00640         Player = (GPlayer*)PlayerData;
00641         DBot = Player->userData;
00642 
00643         // Reset Mode specific timers & counters
00644         DBot->ModeTimeSeen = 0.0f;
00645         DBot->ModeTimeNotSeen = 0.0f;
00646         DBot->ModeTimeOut = 0.0f;
00647 
00648         // get ranking info
00649         RNdx = Bot_GetRangeIndex(VSI, Player);
00650         SNdx = Bot_GetStrengthIndex(VSI, Player);
00651         Rank = RankTable[RNdx][SNdx];
00652 
00653     Bot_WeaponSetFromArray(VSI, Player, WeaponSetRange[RNdx]);
00654 
00655         // Set specific mode
00656         if (NewMode != MODE_NULL)
00657                 {
00658                 Bot_SetMode(Player, NewMode);
00659                 if (Think)
00660                         Bot_ModeThink(VSI, Player, Time);
00661                 return GE_TRUE;
00662                 }
00663 
00664         // CAN NOT SEE
00665         if (DBot->TimeNotSeen > 10.0f)
00666                 {
00667         #ifdef NEW_WANDER
00668                 if (RandomRange(1000) < 500)
00669                         Bot_SetMode(Player, MODE_FIND_PLAYER_QUICK);
00670                 else
00671                         Bot_SetMode(Player, MODE_WANDER);
00672         #else
00673                 Bot_SetMode(Player, MODE_FIND_PLAYER_QUICK);
00674         #endif
00675                 if (Think)
00676                         Bot_ModeThink(VSI, Player, Time);
00677                 return GE_TRUE;
00678                 }
00679 
00680         if (DBot->TimeNotSeen > 5.0f)
00681                 {
00682                 DECISION *dptr;
00683 
00684                 static DECISION d[] =
00685                         {
00686 #ifdef WANDER_TEST
00687                         {1000, &ModeTable[MODE_WANDER]},
00688 #else
00689         #ifdef NEW_WANDER
00690                         {200,  &ModeTable[MODE_FIND_PLAYER]},
00691                         {500,  &ModeTable[MODE_FIND_PLAYER_QUICK]},
00692                         {1000, &ModeTable[MODE_WANDER]},
00693         #else
00694                         {600,  &ModeTable[MODE_FIND_PLAYER]},
00695                         {1000,  &ModeTable[MODE_FIND_PLAYER_QUICK]},
00696         #endif
00697 #endif
00698                         };
00699 
00700                 static DECISION d2[] =
00701                         {
00702 #ifdef WANDER_TEST
00703                         {1000, &ModeTable[MODE_WANDER]},
00704 #else
00705         #ifdef NEW_WANDER
00706                         {200,  &ModeTable[MODE_FIND_PLAYER]},
00707                         {900,  &ModeTable[MODE_FIND_PLAYER_QUICK]},
00708                         {1000, &ModeTable[MODE_WANDER]},
00709         #else
00710                         {400,  &ModeTable[MODE_FIND_PLAYER]},
00711                         {1000,  &ModeTable[MODE_FIND_PLAYER_QUICK]},
00712         #endif
00713 #endif
00714                         };
00715 
00716                 if (Rank >= 8)
00717                         dptr = d2;
00718                 else
00719                         dptr = d;
00720 
00721                 iptr = ChooseAction(dptr);
00722                 Bot_SetMode(Player, *iptr);
00723 
00724                 if (Think)
00725                         Bot_ModeThink(VSI, Player, Time);
00726                 return GE_TRUE;
00727                 }
00728 
00729         if (DBot->TimeNotSeen > 0.0f)
00730                 {
00731                 static DECISION d[] =
00732                         {
00733                         {600,  &ModeTable[MODE_FIND_PLAYER]},
00734                         {1000,  &ModeTable[MODE_FIND_PLAYER_QUICK]},
00735                         //{1000, &ModeTable[MODE_RETREAT]},
00736                         };
00737 
00738                 iptr = ChooseAction(d);
00739                 Bot_SetMode(Player, *iptr);
00740 
00741                 if (Think)
00742                         Bot_ModeThink(VSI, Player, Time);
00743                 return GE_TRUE;
00744                 }
00745 
00746         // CANSEE
00747         if (DBot->TimeSeen > 15.0f)
00748                 {
00749                 if (Rank <= 3)
00750                         Bot_SetMode(Player, MODE_RETREAT);
00751                 else
00752                         Bot_SetMode(Player, MODE_ATTACK);
00753 
00754                 if (Think)
00755                         Bot_ModeThink(VSI, Player, Time);
00756                 return GE_TRUE;
00757                 }
00758 
00759         if (DBot->TimeSeen > 5.0f)
00760                 {
00761                 if (Rank <= 2)
00762                         Bot_SetMode(Player, MODE_RETREAT);
00763                 else
00764                         Bot_SetMode(Player, MODE_ATTACK);
00765 
00766                 if (Think)
00767                         Bot_ModeThink(VSI, Player, Time);
00768                 return GE_TRUE;
00769                 }
00770 
00771         if (DBot->TimeSeen > 0.0f)
00772                 {
00773                 if (Rank <= 1)
00774                         Bot_SetMode(Player, MODE_RETREAT);
00775                 else
00776                         Bot_SetMode(Player, MODE_ATTACK);
00777 
00778                 if (Think)
00779                         Bot_ModeThink(VSI, Player, Time);
00780                 return GE_TRUE;
00781                 }
00782 
00783 return GE_FALSE;
00784 }
00785 
00786 
00787 //=====================================================================================
00788 //      Bot_ModeThinkRetreat
00789 //=====================================================================================
00790 geBoolean Bot_ModeThinkRetreat(GenVSI *VSI, void *PlayerData, float Time)
00791 {
00792         GPlayer                         *Player;
00793         Bot_Var                         *DBot;
00794         GPlayer *GoalPlayer;
00795 
00796         Player = (GPlayer*)PlayerData;
00797         DBot = Player->userData;
00798 
00799         DBot->HealthCheck = Player->Health;
00800 
00801         if (Bot_ActionGetHealth(VSI, Player, 500.0f, Time))
00802                 return GE_TRUE;
00803         if (Bot_ActionGetWeapon(VSI, Player, 500.0f, Time))
00804                 return GE_TRUE;
00805 
00806         // first try and find some item to run towards
00807         if (GoalPlayer = Bot_FindRandomItem(VSI, &Player->XForm.Translation, ItemHealthList))
00808                 {
00809                 if (Bot_InitFindMultiTrack(VSI, Player, &GoalPlayer->XForm.Translation, Time))
00810                         {
00811                         Bot_ModeChange(VSI, Player, MODE_RETREAT, GE_FALSE, Time);
00812                         return GE_TRUE;
00813                         }
00814                 }
00815 
00816         if (Bot_InitFindMultiTrackAway(VSI, Player, &DBot->TgtPlayer->XForm.Translation, Time))
00817                 {
00818                 Bot_ModeChange(VSI, Player, MODE_RETREAT_ON_TRACK, GE_FALSE, Time);
00819                 return GE_TRUE;
00820                 }
00821 
00822         // ModeTimeOut on this operation
00823         if (DBot->ModeTimeOut > 10.0f)
00824                 {
00825                 Bot_ModeChange(VSI, Player, MODE_NULL, GE_TRUE, Time);
00826         return GE_TRUE;
00827                 }
00828         // cant get away
00829         if (DBot->ModeTimeSeen > 5.0f)
00830                 {
00831                 Bot_ModeChange(VSI, Player, MODE_NULL, GE_TRUE, Time);
00832         return GE_TRUE;
00833                 }       
00834 
00835         if (DBot->ModeTimeNotSeen > 6.0f)
00836                 {
00837                 Bot_ModeChange(VSI, Player, MODE_NULL, GE_TRUE, Time);
00838                 return GE_TRUE;
00839                 }       
00840         if (DBot->ModeTimeNotSeen > 3.0f)
00841                 {
00842                 if (Bot_InitHide(VSI, Player, Time))
00843                         {
00844                         // this sets the Action
00845                         return GE_TRUE;
00846                         }
00847                 }       
00848 
00849         // this sets the Action
00850         Bot_InitRunAway(VSI, Player, Time);
00851 
00852         return GE_TRUE;
00853 }
00854 
00855 //=====================================================================================
00856 //      Bot_ModeActionRetreat
00857 //=====================================================================================
00858 geBoolean Bot_ModeActionRetreat(GenVSI *VSI, void *PlayerData, float Time)
00859 {
00860         GPlayer                         *Player;
00861         Bot_Var                         *DBot;
00862 
00863         Player = (GPlayer*)PlayerData;
00864         DBot = Player->userData;
00865 
00866         // if hit when retreating - stand and fight like a (wo)man
00867         if (DBot->HealthCheck < Player->Health - 20)
00868                 {
00869                 DBot->FaceTgtPlayerOnRetreat = GE_TRUE;
00870                 //Bot_ModeChange(VSI, Player, MODE_ATTACK, GE_FALSE, Time);
00871                 return GE_TRUE;
00872                 }
00873 
00874         return GE_TRUE;
00875 }
00876 
00877 
00878 //=====================================================================================
00879 //      Bot_ModeThinkFindPlayerQuick
00880 //=====================================================================================
00881 geBoolean Bot_ModeThinkFindPlayerQuick(GenVSI *VSI, void *PlayerData, float Time)
00882 {
00883         GPlayer                         *Player;
00884         Bot_Var                         *DBot;
00885 
00886         Player = (GPlayer*)PlayerData;
00887         DBot = Player->userData;
00888 
00889         if (DBot->ModeTimeOut > 20.0f)
00890                 {
00891                 Bot_ModeChange(VSI, Player, MODE_NULL, GE_TRUE, Time);
00892         return GE_TRUE;
00893                 }
00894 
00895         if (Bot_InitFindMultiTrack(VSI, PlayerData, &DBot->TgtPlayer->XForm.Translation, Time))
00896                 {
00897                 Bot_ModeChange(VSI, Player, MODE_ON_TRACK, GE_FALSE, Time);
00898                 return GE_TRUE;
00899                 }
00900         else
00901                 {
00902                 GPlayer *GoalPlayer;
00903 
00904                 if (GoalPlayer = Bot_FindRandomItem(VSI, &Player->XForm.Translation, ItemHealthList))
00905                         {
00906                         if (Bot_InitFindMultiTrack(VSI, Player, &GoalPlayer->XForm.Translation, Time))
00907                                 {
00908                                 Bot_ModeChange(VSI, Player, MODE_WANDER_ON_TRACK, GE_FALSE, Time);
00909                                 return GE_TRUE;
00910                                 }
00911                         }
00912                 }
00913 
00914         if (Bot_ActionGetHealth(VSI, Player, 400.0f, Time))
00915                 return GE_TRUE;
00916         if (Bot_ActionGetWeapon(VSI, Player, 400.0f, Time))
00917                 return GE_TRUE;
00918 
00919         if (Bot_InitHide(VSI, Player, Time))
00920                 return GE_TRUE;
00921 
00922         // Found Player
00923         if (DBot->ModeTimeSeen > 1.0f)
00924                 {
00925                 Bot_ModeChange(VSI, Player, MODE_NULL, GE_TRUE, Time);
00926                 return GE_TRUE;
00927                 }
00928         
00929         Bot_InitRunCloser(VSI, Player, Time);
00930 
00931         return GE_TRUE;
00932 }
00933 
00934 
00935 //=====================================================================================
00936 //      Bot_ModeThinkFindPlayer
00937 //=====================================================================================
00938 geBoolean Bot_ModeThinkFindPlayer(GenVSI *VSI, void *PlayerData, float Time)
00939 {
00940         GPlayer                         *Player;
00941         Bot_Var                         *DBot;
00942 
00943         Player = (GPlayer*)PlayerData;
00944         DBot = Player->userData;
00945 
00946         DBot->WeaponDiff = Bot_CompareWeapons(VSI, Player, DBot->TgtPlayer);
00947 
00948         // outgunned
00949         if (DBot->WeaponDiff < -40)
00950                 {
00951                 Bot_ModeChange(VSI, Player, MODE_WANDER, GE_FALSE, Time);
00952             return GE_TRUE;
00953                 }
00954 
00955         if (DBot->ModeTimeOut > 7.0f)
00956                 {
00957                 Bot_ModeChange(VSI, Player, MODE_FIND_PLAYER_QUICK, GE_TRUE, Time);
00958         return GE_TRUE;
00959                 }
00960 
00961         if (Bot_ActionGetHealth(VSI, Player, 600.0f, Time))
00962                 return GE_TRUE;
00963         if (Bot_ActionGetWeapon(VSI, Player, 600.0f, Time))
00964                 return GE_TRUE;
00965 
00966         // Found Player
00967         if (DBot->ModeTimeSeen > 0.0f)
00968                 {
00969                 Bot_ModeChange(VSI, Player, MODE_NULL, GE_TRUE, Time);
00970                 return GE_TRUE;
00971                 }
00972 
00973         if (DBot->ModeTimeNotSeen > 3.0f)
00974                 {
00975                 if (Bot_InitHide(VSI, Player, Time))
00976                         return GE_TRUE;
00977                 }
00978 
00979         Bot_InitRunCloser(VSI, Player, Time);
00980 
00981         return GE_TRUE;
00982 }
00983 
00984 //=====================================================================================
00985 //      Bot_ModeThinkWander
00986 //=====================================================================================
00987 geBoolean Bot_ModeThinkWander(GenVSI *VSI, void *PlayerData, float Time)
00988 {
00989         GPlayer                         *Player;
00990         GPlayer                         *GoalPlayer;
00991         Bot_Var                         *DBot;
00992         Track                           *GoalTrack;
00993 
00994         Player = (GPlayer*)PlayerData;
00995         DBot = Player->userData;
00996 
00997         if (GoalTrack = Bot_FindRandomTrack(VSI, &Player->XForm.Translation, HideTrackList))
00998                 {
00999                 if (Bot_InitFindMultiTrack(VSI, Player, GoalTrack->PointList[0].Pos, Time))
01000                         {
01001                         Bot_ModeChange(VSI, Player, MODE_ON_TRACK, GE_FALSE, Time);
01002                         return GE_TRUE;
01003                         }
01004                 }
01005 
01006         // InitWanderGoal
01007         if (GoalPlayer = Bot_FindRandomItem(VSI, &Player->XForm.Translation, ItemHealthList))
01008                 {
01009                 if (Bot_InitFindMultiTrack(VSI, Player, &GoalPlayer->XForm.Translation, Time))
01010                         {
01011                         Bot_ModeChange(VSI, Player, MODE_WANDER_ON_TRACK, GE_FALSE, Time);
01012                         return GE_TRUE;
01013                         }
01014                 }
01015 
01016         if (Bot_ActionGetHealth(VSI, Player, 1200.0f, Time))
01017                 return GE_TRUE;
01018         if (Bot_ActionGetWeapon(VSI, Player, 1200.0f, Time))
01019                 return GE_TRUE;
01020 
01021         Bot_ModeChange(VSI, Player, MODE_FIND_PLAYER, GE_FALSE, Time);
01022 
01023         return GE_TRUE;
01024 }
01025 
01026 //=====================================================================================
01027 //      Bot_ModeThinkWanderGoal
01028 //=====================================================================================
01029 geBoolean Bot_ModeThinkWanderGoal(GenVSI *VSI, void *PlayerData, float Time)
01030 {
01031         GPlayer                         *Player;
01032         Bot_Var                         *DBot;
01033 
01034         Player = (GPlayer*)PlayerData;
01035         DBot = Player->userData;
01036 
01037         if (!Track_OnTrack(&DBot->TrackInfo))
01038                 {
01039                         // Try and find an item
01040                 if (Bot_ActionGetHealth(VSI, Player, 500.0f, Time))
01041                         return GE_TRUE;
01042                 if (Bot_ActionGetWeapon(VSI, Player, 500.0f, Time))
01043                         return GE_TRUE;
01044 
01045                 Bot_ModeChange(VSI, Player, MODE_FIND_PLAYER, GE_FALSE, Time);
01046                 }
01047         else
01048         // IF HERE THEN HIT SOMETHING!!!!! - if didn't hit then check logic!
01049         if (Track_OnTrack(&DBot->TrackInfo))
01050                 {
01051                 // This MAY push a track on the stack
01052                 Bot_InitRunCloser(VSI, Player, Time);
01053                 DBot->GoalPos = *Track_GetPoint(&DBot->TrackInfo)->Pos;
01054                 return GE_TRUE;
01055                 }
01056 
01057         Bot_InitRunCloser(VSI, Player, Time);
01058 
01059         return GE_TRUE;
01060 }
01061 
01062 
01063 //=====================================================================================
01064 //      Bot_ModeThinkAttack
01065 //=====================================================================================
01066 geBoolean Bot_ModeThinkAttack(GenVSI *VSI, void *PlayerData, float Time)
01067 {
01068         GPlayer                         *Player;
01069         Bot_Var                         *DBot;
01070         geVec3d                         Pos,TgtPlayerPos;
01071         float                           Dist;
01072 
01073         Player = (GPlayer*)PlayerData;
01074         DBot = Player->userData;
01075 
01076     Pos = Player->XForm.Translation;
01077     TgtPlayerPos = DBot->TgtPlayer->XForm.Translation;
01078 
01079         DBot->WeaponDiff = Bot_CompareWeapons(VSI, Player, DBot->TgtPlayer);
01080 
01081         // outgunned
01082         if (DBot->WeaponDiff < -40)
01083                 {
01084                 Bot_ModeChange(VSI, Player, MODE_RETREAT, GE_FALSE, Time);
01085             return GE_TRUE;
01086                 }
01087 
01088         if (DBot->ModeTimeNotSeen > 1.5f)
01089                 {
01090                 Bot_ModeChange(VSI, Player, MODE_FIND_PLAYER, GE_TRUE, Time);
01091         return GE_TRUE;
01092                 }
01093 
01094     if (PlayerDead(DBot->TgtPlayer))
01095         {
01096             if (Bot_InitFindMultiTrackAway(VSI, Player, &DBot->TgtPlayer->XForm.Translation, Time))
01097                     {
01098                     Bot_ModeChange(VSI, Player, MODE_RETREAT_ON_TRACK, GE_FALSE, Time);
01099                     return GE_TRUE;
01100             }
01101         else
01102             {
01103                     Bot_ModeChange(VSI, Player, MODE_RETREAT, GE_TRUE, Time);
01104                     return GE_TRUE;
01105             }
01106         }
01107 
01108     if (RandomRange(1000) < 300 &&
01109         Bot_GetRank(VSI, Player) >= 4)
01110                 {
01111                 Bot_ModeChange(VSI, Player, MODE_CROWD_PLAYER, GE_TRUE, Time);
01112         return GE_TRUE;
01113                 }
01114 
01115         if (DBot->ModeTimeOut > 12.0f || DBot->ModeTimeSeen > 7.0f)
01116                 {
01117                 Bot_ModeChange(VSI, Player, MODE_NULL, GE_TRUE, Time);
01118         return GE_TRUE;
01119                 }
01120 
01121         if (Bot_ActionGetHealth(VSI, Player, 600.0f, Time))
01122                 return GE_TRUE;
01123         if (Bot_ActionGetWeapon(VSI, Player, 600.0f, Time))
01124                 return GE_TRUE;
01125 
01126         // keep a medium range distance
01127     Dist = geVec3d_DistanceBetween(&Pos, &TgtPlayerPos);
01128     if (Dist <= CLOSE_RANGE_DIST)
01129                 {
01130                 Bot_InitMoveAway(VSI, Player, Time);
01131                 return GE_TRUE;
01132                 }
01133         else
01134     if (Dist <= MED_RANGE_DIST)
01135                 {
01136         if (RandomRange(1000) < 200)
01137                     Bot_InitRunCloser(VSI, Player, Time);
01138         else
01139             Bot_InitMaintain(VSI, Player, Time);
01140                 return GE_TRUE;
01141                 }
01142         else
01143                 {
01144                 Bot_InitRunCloser(VSI, Player, Time);
01145                 return GE_TRUE;
01146                 }
01147 
01148         // health assessment
01149     DBot->HealthDiff = Player->Health - DBot->TgtPlayer->Health;
01150         DBot->WeaponDiff = Bot_CompareWeapons(VSI, Player, DBot->TgtPlayer);
01151 
01152         return GE_TRUE;
01153 }
01154 
01155 //=====================================================================================
01156 //      Bot_ModeThinkCrowdPlayer
01157 //=====================================================================================
01158 geBoolean Bot_ModeThinkCrowdPlayer(GenVSI *VSI, void *PlayerData, float Time)
01159 {
01160         GPlayer                         *Player;
01161         Bot_Var                         *DBot;
01162 
01163         Player = (GPlayer*)PlayerData;
01164         DBot = Player->userData;
01165 
01166         DBot->WeaponDiff = Bot_CompareWeapons(VSI, Player, DBot->TgtPlayer);
01167 
01168         // outgunned
01169         if (DBot->WeaponDiff < -40)
01170                 {
01171                 Bot_ModeChange(VSI, Player, MODE_RETREAT, GE_FALSE, Time);
01172             return GE_TRUE;
01173                 }
01174 
01175     if (PlayerDead(DBot->TgtPlayer))
01176         {
01177             if (Bot_InitFindMultiTrackAway(VSI, Player, &DBot->TgtPlayer->XForm.Translation, Time))
01178                     {
01179                     Bot_ModeChange(VSI, Player, MODE_RETREAT_ON_TRACK, GE_FALSE, Time);
01180                     return GE_TRUE;
01181             }
01182         else
01183             {
01184                     Bot_ModeChange(VSI, Player, MODE_RETREAT, GE_TRUE, Time);
01185                     return GE_TRUE;
01186             }
01187         }
01188 
01189         if (DBot->ModeTimeOut > 6.0f || 
01190                 DBot->ModeTimeNotSeen > 6.0f)
01191                 {
01192                 Bot_ModeChange(VSI, Player, MODE_NULL, GE_TRUE, Time);
01193         return GE_TRUE;
01194                 }
01195 
01196         if (Bot_ActionGetHealth(VSI, Player, 400.0f, Time))
01197                 return GE_TRUE;
01198         if (Bot_ActionGetWeapon(VSI, Player, 400.0f, Time))
01199                 return GE_TRUE;
01200 
01201     if (Bot_GetRank(VSI, Player) <= 3)
01202                 {
01203                 Bot_ModeChange(VSI, Player, MODE_NULL, GE_TRUE, Time);
01204         return GE_TRUE;
01205                 }
01206 
01207     // crowd the player at all times
01208         Bot_InitRunCloser(VSI, Player, Time);
01209 
01210         return GE_TRUE;
01211 }
01212 
01213 //=====================================================================================
01214 //      Bot_ModeThinkGoalPoint
01215 //=====================================================================================
01216 geBoolean Bot_ModeThinkGoalPoint(GenVSI *VSI, void *PlayerData, float Time)
01217 {
01218         GPlayer                         *Player;
01219         Bot_Var                         *DBot;
01220 
01221         Player = (GPlayer*)PlayerData;
01222         DBot = Player->userData;
01223 
01224         // either hit something or made it to the point
01225 
01226         Bot_ModeChange(VSI, Player, MODE_NULL, GE_TRUE, Time);
01227 
01228         return GE_TRUE;
01229 }
01230 
01231 
01232 //=====================================================================================
01233 //      Bot_ModeThinkOnTrack
01234 //=====================================================================================
01235 geBoolean Bot_ModeThinkOnTrack(GenVSI *VSI, void *PlayerData, float Time)
01236 {
01237         GPlayer                         *Player;
01238         Bot_Var                         *DBot;
01239 
01240         Player = (GPlayer*)PlayerData;
01241         DBot = Player->userData;
01242 
01243 
01244         // left the track?
01245         if (!Track_OnTrack(&DBot->TrackInfo))
01246                 {
01247                 Bot_ModeChange(VSI, Player, MODE_NULL, GE_TRUE, Time);
01248                 return GE_TRUE;
01249                 }
01250 
01251         // IF HERE THEN HIT SOMETHING!!!!! - if didn't hit then check logic!
01252         if (Track_OnTrack(&DBot->TrackInfo))
01253                 {
01254                 // This MAY push a track on the stack
01255                 Bot_InitRunCloser(VSI, Player, Time);
01256                 DBot->GoalPos = *Track_GetPoint(&DBot->TrackInfo)->Pos;
01257                 return GE_TRUE;
01258                 }
01259 
01260 
01261         return GE_TRUE;
01262 }
01263 
01264 //=====================================================================================
01265 //      Bot_ModeThinkUnstick
01266 //=====================================================================================
01267 geBoolean Bot_ModeThinkUnstick(GenVSI *VSI, void *PlayerData, float Time)
01268 {
01269         GPlayer                         *Player;
01270         Bot_Var                         *DBot;
01271         int32                           dir;
01272 
01273         Player = (GPlayer*)PlayerData;
01274         DBot = Player->userData;
01275 
01276         if (DBot->ModeTimeOut > 3.0f)
01277                 {
01278                 Bot_ModeChange(VSI, Player, MODE_NULL, GE_TRUE, Time);
01279                 return GE_TRUE;
01280                 }
01281 
01282         dir = RandomRange(3) - 1;
01283         Bot_Reposition(VSI, Player, &DBot->TgtPlayer->XForm.Translation, dir);
01284         Bot_InitMoveFree(VSI, Player, &DBot->TgtPos);
01285 
01286         return GE_TRUE;
01287 }
01288 
01289 
01290 //=====================================================================================
01291 //      Bot_Destroy
01292 //=====================================================================================
01293 geBoolean Bot_Destroy(GenVSI *VSI, void *PlayerData, void *ClassData)
01294 {
01295         GPlayer                 *Player,*Hit;
01296         Bot_Var                 *DBot,*HBot;
01297         geWorld                 *World;
01298 
01299         Player = (GPlayer*)PlayerData;
01300         DBot = (Bot_Var*)Player->userData;
01301 
01302         World = GenVSI_GetWorld(VSI);
01303 
01304         // run through players setting resetting any targets pointing to this player
01305         // being killed 
01306 
01307         Hit = NULL;
01308         while (1)
01309         {
01310                 Hit = GenVSI_GetNextPlayer(VSI, Hit, NULL);
01311 
01312                 if (!Hit)
01313                         break;
01314 
01315                 if (Hit == Player)
01316                         break;
01317 
01318                 if (Hit->ClientHandle == CLIENT_NULL_HANDLE) // Will not find ACTORS!
01319                         continue;
01320 
01321                 if (GenVSI_IsClientBot(VSI, Hit->ClientHandle))
01322                         {
01323                         HBot = Hit->userData;
01324                         if (HBot)
01325                                 {
01326                                         //assert(HBot);
01327 
01328                                         if (HBot->TgtPlayer == Player)
01329                                                 {
01330                                                 HBot->TgtPlayer = NULL;
01331                                                 }
01332                                 }
01333                         }
01334         }
01335 
01336         Player = (GPlayer*)PlayerData;
01337     DBot = Player->userData;
01338         assert(DBot);
01339 
01340     assert(DBot->TrackStack.Data);
01341     geRam_Free(DBot->TrackStack.Data);
01342 
01343         geRam_Free(Player->userData);
01344         Player->userData = NULL;
01345 
01346         return GE_TRUE;
01347 }
01348 
01349 
01350 //=====================================================================================
01351 //      ChooseAction
01352 //=====================================================================================
01353 void *ChooseAction(DECISION decision[])
01354     {
01355     int32 i, random_value;
01356     
01357     random_value = RandomRange(1000);
01358 
01359     for (i = 0; TRUE; i++)
01360         {
01361         if (random_value <= decision[i].range)
01362             {
01363             return (decision[i].action);
01364             }
01365         }
01366     }
01367 
01368 
01369 //=====================================================================================
01370 //      Bot_Reposition
01371 //=====================================================================================
01372 geBoolean Bot_Reposition(GenVSI *VSI, void *PlayerData, geVec3d *TgtPos, int32 Dir)
01373 {
01374         GPlayer                 *Player;
01375         Bot_Var                 *DBot;
01376         
01377         geVec3d                 Vec2Player;
01378 
01379         Player = (GPlayer*)PlayerData;
01380         assert(Player);
01381         DBot = (Bot_Var*)Player->userData;
01382 
01383         //geVec3d_Subtract(TgtPos, &Player->XForm.Translation, &Vec2Player);
01384         geVec3d_Subtract(TgtPos, &DBot->GoalPos, &Vec2Player);
01385 
01386         // TgtPos is where we want to move to
01387         if (!Bot_FindNewMoveVec(VSI, Player, TgtPos, Dir, 300.0f, &DBot->MoveVec))
01388         {
01389                 // Couldn't find a dir to move
01390                 if (!Bot_FindNewMoveVec(VSI, Player, TgtPos, -Dir, 250.0f, &DBot->MoveVec))
01391                 {
01392                         // Couldn't find a dir to move - again
01393                         // Getting stuck
01394 
01395         return GE_FALSE;
01396                 }       
01397         }
01398 
01399     return GE_TRUE;
01400 }
01401 
01402 
01403 //=====================================================================================
01404 //      Bot_InitFindMultiTrack
01405 //=====================================================================================
01406 geBoolean Bot_InitFindMultiTrack(GenVSI *VSI, void *PlayerData, geVec3d *DestPos, float Time)
01407 {
01408         Bot_Var                 *DBot;
01409         GPlayer                 *Player;
01410         TrackCB                 CB;
01411 
01412         Player = (GPlayer*)PlayerData;
01413         assert(Player);
01414         DBot = (Bot_Var*)Player->userData;
01415         assert(DBot);
01416 
01417         if (!StackIsEmpty(&DBot->TrackStack))
01418                 return GE_FALSE;
01419 
01420         CB.Data = PlayerData;
01421         CB.CB = Bot_ValidateMultiTrackPoints;
01422 
01423         if (Track_FindMultiTrack (VSI, 
01424                                                 &Player->XForm.Translation,
01425                                                 DestPos,
01426                         BOT_DIR_TOWARD,
01427                                                 &CB,
01428                         &DBot->TrackStack))
01429                 {
01430                 DBot->Dir = BOT_DIR_TOWARD;
01431 
01432                 Track_NextMultiTrack(VSI, &Player->XForm.Translation, StackTop(&DBot->TrackStack), &DBot->TrackInfo);
01433                 DBot->PastFirstTrackPoint = GE_FALSE;
01434                 DBot->GoalPos = *Track_GetPoint(&DBot->TrackInfo)->Pos;
01435                 Bot_InitMoveToPoint(VSI, Player, &DBot->GoalPos);
01436 
01437                 return GE_TRUE;
01438                 }
01439 
01440         return GE_FALSE;
01441 }
01442 
01443 //=====================================================================================
01444 //      Bot_InitFindMultiTrackAway
01445 //=====================================================================================
01446 geBoolean Bot_InitFindMultiTrackAway(GenVSI *VSI, void *PlayerData, geVec3d *DestPos, float Time)
01447 {
01448         Bot_Var                 *DBot;
01449         GPlayer                 *Player;
01450         TrackCB                 CB;
01451 
01452         Player = (GPlayer*)PlayerData;
01453         assert(Player);
01454         DBot = (Bot_Var*)Player->userData;
01455         assert(DBot);
01456 
01457         if (!StackIsEmpty(&DBot->TrackStack))
01458                 return GE_FALSE;
01459 
01460         CB.Data = PlayerData;
01461         CB.CB = Bot_ValidateMultiTrackPoints;
01462 
01463         if (Track_FindMultiTrack(VSI, 
01464                                                 &Player->XForm.Translation,
01465                                                 DestPos,
01466                         BOT_DIR_AWAY,
01467                                                 &CB,
01468                                                 &DBot->TrackStack))
01469                 {
01470                 DBot->Dir = BOT_DIR_AWAY;
01471 
01472                 Track_NextMultiTrack(VSI, &Player->XForm.Translation, StackTop(&DBot->TrackStack), &DBot->TrackInfo);
01473                 DBot->PastFirstTrackPoint = GE_FALSE;
01474                 DBot->GoalPos = *Track_GetPoint(&DBot->TrackInfo)->Pos;
01475                 Bot_InitMoveToPoint(VSI, Player, &DBot->GoalPos);
01476                 return GE_TRUE;
01477                 }
01478 
01479         return GE_FALSE;
01480 }
01481 
01482 
01483 //=====================================================================================
01484 //      Bot_InitMoveToPoint
01485 //=====================================================================================
01486 geBoolean Bot_InitMoveToPoint(GenVSI *VSI, void *PlayerData, geVec3d *Pos)
01487 {
01488         GPlayer *Player;
01489         Bot_Var                 *DBot;
01490 
01491         Player = (GPlayer*)PlayerData;
01492         DBot = (Bot_Var*)Player->userData;
01493 
01494         DBot->TgtPos = *Pos;
01495 
01496         geVec3d_Subtract(&DBot->TgtPos, &Player->XForm.Translation, &DBot->MoveVec);
01497     DBot->MoveVec.Y = 0.0f;
01498         geVec3d_Normalize(&DBot->MoveVec);
01499 
01500         DBot->Action = Bot_MoveToPoint;
01501 
01502         return GE_TRUE;
01503 }
01504 
01505 //=====================================================================================
01506 //      Bot_InitMoveFree
01507 //=====================================================================================
01508 geBoolean Bot_InitMoveFree(GenVSI *VSI, void *PlayerData, geVec3d *Pos)
01509 {
01510         GPlayer *Player;
01511         Bot_Var                 *DBot;
01512 
01513         Player = (GPlayer*)PlayerData;
01514         DBot = (Bot_Var*)Player->userData;
01515 
01516         DBot->TgtPos = *Pos;
01517 
01518         geVec3d_Subtract(&DBot->TgtPos, &Player->XForm.Translation, &DBot->MoveVec);
01519     DBot->MoveVec.Y = 0.0f;
01520         geVec3d_Normalize(&DBot->MoveVec);
01521 
01522         DBot->Action = Bot_MoveFree;
01523 
01524         return GE_TRUE;
01525 }
01526 
01527 
01528 //=====================================================================================
01529 //      Bot_InitGenericMove
01530 //=====================================================================================
01531 geBoolean Bot_InitGenericMove(GenVSI *VSI, void *PlayerData, float Time)
01532 {
01533         GPlayer                 *Player;
01534         Bot_Var                 *DBot;
01535         
01536         Player = (GPlayer*)PlayerData;
01537         assert(Player);
01538         DBot = (Bot_Var*)Player->userData;
01539 
01540     // if still on a track
01541         if (Track_OnTrack(&DBot->TrackInfo))
01542         {
01543         // continue on the track
01544                 DBot->Action = Bot_MoveToPoint;
01545         return GE_TRUE;
01546         }
01547         
01548     Bot_Reposition(VSI, Player, &DBot->GoalPos, DBot->Dir);
01549     DBot->Action = Bot_MoveToPoint;
01550 
01551     return GE_TRUE;
01552 }
01553 
01554 //=====================================================================================
01555 //      Bot_InitMoveCloser
01556 //=====================================================================================
01557 geBoolean Bot_InitMoveCloser(GenVSI *VSI, void *PlayerData, float Time)
01558     {
01559         GPlayer                 *Player;
01560         Bot_Var                 *DBot;
01561         
01562         Player = (GPlayer*)PlayerData;
01563         assert(Player);
01564         DBot = (Bot_Var*)Player->userData;
01565 
01566     DBot->Dir = BOT_DIR_TOWARD;
01567 
01568         Bot_Reposition(VSI, Player, &DBot->GoalPos, DBot->Dir);
01569     DBot->Action = Bot_MoveToPoint;
01570 
01571     return GE_TRUE;
01572     }
01573 
01574 //=====================================================================================
01575 //      Bot_InitRunCloser
01576 //=====================================================================================
01577 geBoolean Bot_InitRunCloser(GenVSI *VSI, void *PlayerData, float Time)
01578     {
01579         GPlayer                 *Player;
01580         Bot_Var                 *DBot;
01581         
01582         Player = (GPlayer*)PlayerData;
01583         assert(Player);
01584         DBot = (Bot_Var*)Player->userData;
01585 
01586     DBot->Dir = BOT_DIR_TOWARD;
01587 
01588     if (Bot_InitTrackToGoal(VSI, PlayerData, Time))
01589         return GE_TRUE;
01590         
01591         Bot_Reposition(VSI, Player, &DBot->GoalPos, DBot->Dir);
01592     DBot->Action = Bot_MoveToPoint;
01593 
01594     return GE_TRUE;
01595     }
01596 
01597 //=====================================================================================
01598 //      Bot_InitTrackToGoal
01599 //=====================================================================================
01600 geBoolean Bot_InitTrackToGoal(GenVSI *VSI, void *PlayerData, float Time)
01601     {
01602         GPlayer                 *Player;
01603         Bot_Var                 *DBot;
01604         
01605         Player = (GPlayer*)PlayerData;
01606         assert(Player);
01607         DBot = (Bot_Var*)Player->userData;
01608 
01609     DBot->Dir = BOT_DIR_TOWARD;
01610 
01611     if (Bot_FindTrackToGoal(VSI, PlayerData, Time))
01612         {
01613         DBot->GoalPos = *Track_GetPoint(&DBot->TrackInfo)->Pos;
01614         Bot_InitMoveToPoint(VSI, PlayerData, &DBot->GoalPos);
01615         return GE_TRUE;
01616         }
01617         
01618     return GE_FALSE;
01619     }
01620 
01621 //=====================================================================================
01622 //      Bot_InitTrackAwayGoal
01623 //=====================================================================================
01624 geBoolean Bot_InitTrackAwayGoal(GenVSI *VSI, void *PlayerData, float Time)
01625     {
01626         GPlayer                 *Player;
01627         Bot_Var                 *DBot;
01628         
01629         Player = (GPlayer*)PlayerData;
01630         assert(Player);
01631         DBot = (Bot_Var*)Player->userData;
01632 
01633     DBot->Dir = BOT_DIR_AWAY;
01634 
01635     if (Bot_FindTrackToGoal(VSI, PlayerData, Time))
01636         {
01637         DBot->GoalPos = *Track_GetPoint(&DBot->TrackInfo)->Pos;
01638         Bot_InitMoveToPoint(VSI, PlayerData, &DBot->GoalPos);
01639         return GE_TRUE;
01640         }
01641         
01642     return GE_FALSE;
01643     }
01644 
01645 
01646 //=====================================================================================
01647 //      Bot_InitHide
01648 //=====================================================================================
01649 geBoolean Bot_InitHide(GenVSI *VSI, void *PlayerData, float Time)
01650     {
01651         GPlayer *Player;
01652         Bot_Var *DBot;
01653 
01654         Player = PlayerData;
01655         DBot = Player->userData;
01656 
01657         DBot->Dir = BOT_DIR_NONE;
01658 
01659     if (Bot_FindTrack(VSI, Player, HideTrackList))
01660         {
01661         DBot->GoalPos = *Track_GetPoint(&DBot->TrackInfo)->Pos;
01662         Bot_InitMoveToPoint(VSI, PlayerData, &DBot->GoalPos);
01663         Bot_InitMoveToPoint(VSI, Player, Track_GetPoint(&DBot->TrackInfo)->Pos);
01664         return GE_TRUE;
01665         }
01666 
01667     return GE_FALSE;
01668     }
01669 
01670 
01671 //=====================================================================================
01672 //      Bot_InitMoveAway
01673 //=====================================================================================
01674 geBoolean Bot_InitMoveAway(GenVSI *VSI, void *PlayerData, float Time)
01675     {
01676         GPlayer                 *Player;
01677         Bot_Var                 *DBot;
01678         
01679         Player = (GPlayer*)PlayerData;
01680         assert(Player);
01681         DBot = (Bot_Var*)Player->userData;
01682 
01683     DBot->Dir = BOT_DIR_AWAY;
01684 
01685     Bot_Reposition(VSI, PlayerData, &DBot->GoalPos, DBot->Dir);
01686     DBot->Action = Bot_MoveToPoint;
01687 
01688     return GE_TRUE;
01689     }
01690 
01691 
01692 //=====================================================================================
01693 //      Bot_InitRunAway
01694 //=====================================================================================
01695 geBoolean Bot_InitRunAway(GenVSI *VSI, void *PlayerData, float Time)
01696     {
01697         GPlayer                 *Player;
01698         Bot_Var                 *DBot;
01699         
01700         Player = (GPlayer*)PlayerData;
01701         assert(Player);
01702         DBot = (Bot_Var*)Player->userData;
01703 
01704     DBot->Dir = BOT_DIR_AWAY;
01705 
01706     if (Bot_InitTrackAwayGoal(VSI, PlayerData, Time))
01707         return GE_TRUE;
01708         
01709     Bot_Reposition(VSI, PlayerData, &DBot->GoalPos, DBot->Dir);
01710     DBot->Action = Bot_MoveToPoint;
01711 
01712     return GE_TRUE;
01713     }
01714 
01715 //=====================================================================================
01716 //      Bot_InitMaintain
01717 //=====================================================================================
01718 geBoolean Bot_InitMaintain(GenVSI *VSI, void *PlayerData, float Time)
01719     {
01720         GPlayer                 *Player;
01721         Bot_Var                 *DBot;
01722         
01723         Player = (GPlayer*)PlayerData;
01724         assert(Player);
01725         DBot = (Bot_Var*)Player->userData;
01726 
01727     DBot->Dir = BOT_DIR_NONE;
01728 
01729     Bot_Reposition(VSI, PlayerData, &DBot->GoalPos, DBot->Dir);
01730     DBot->Action = Bot_MoveToPoint;
01731 
01732     return GE_TRUE;
01733     }
01734 
01735 
01736 //=====================================================================================
01737 //      Bot_InitWaitForPlayer
01738 //=====================================================================================
01739 geBoolean Bot_InitWaitForPlayer(GenVSI *VSI, void *PlayerData, float Time)
01740 {
01741         GPlayer                 *Player;
01742         Bot_Var                 *DBot;
01743 
01744         Player = (GPlayer*)PlayerData;
01745         assert(Player);
01746         DBot = (Bot_Var*)Player->userData;
01747 
01748         Bot_SetupXForm(VSI, Player, &DBot->MoveVec);
01749 
01750         // Stop here
01751         geVec3d_Clear(&Player->Velocity);
01752 
01753         DBot->Action = Bot_WaitForPlayer;
01754         
01755         return GE_TRUE;
01756 }
01757 
01758 //=====================================================================================
01759 //      Bot_WaitForPlayer
01760 //=====================================================================================
01761 geBoolean Bot_WaitForPlayer(GenVSI *VSI, void *PlayerData, float Time)
01762 {
01763         GPlayer *Player;
01764         Bot_Var                 *DBot;
01765         geWorld                 *World;
01766 
01767         World = GenVSI_GetWorld(VSI);
01768 
01769         assert(World);
01770         
01771         Player = (GPlayer*)PlayerData;
01772         assert(Player);
01773         DBot = (Bot_Var*)Player->userData;
01774 
01775         Bot_GetContents(VSI, Player, Time);
01776         Bot_Animate(VSI, Player, Time);
01777 
01778         if (GenVSI_GetTime(VSI) >= DBot->TimeOut)
01779         {
01780         Bot_ClearTrack(VSI, Player);
01781                 Bot_InitGenericMove(VSI, Player, Time);
01782                 return GE_TRUE;
01783         }
01784 
01785         if (Bot_CanSeePlayerToPlayer(World, &Player->XForm.Translation, &DBot->TgtPlayer->XForm.Translation))
01786         {
01787                 Bot_InitGenericMove(VSI, Player, Time);
01788                 return GE_TRUE;
01789         }
01790 
01791         return GE_TRUE;
01792 }
01793 
01794 //=====================================================================================
01795 //      Bot_InitWaitForEntityVisible
01796 //=====================================================================================
01797 geBoolean Bot_InitWaitForEntityVisible(GenVSI *VSI, void *PlayerData, float Time)
01798 {
01799         GPlayer                 *Player;
01800         Bot_Var                 *DBot;
01801 
01802         Player = (GPlayer*)PlayerData;
01803         assert(Player);
01804         DBot = (Bot_Var*)Player->userData;
01805 
01806         Bot_SetupXForm(VSI, Player, &DBot->MoveVec);
01807 
01808         geVec3d_Clear(&Player->Velocity);       // Stop moving
01809 
01810         DBot->HealthCheck = Player->Health; // save health
01811         DBot->Action = Bot_WaitForEntityVisible;
01812         
01813         return GE_TRUE;
01814 }
01815 
01816 //=====================================================================================
01817 //      Bot_WaitForEntityVisible
01818 //=====================================================================================
01819 geBoolean Bot_WaitForEntityVisible(GenVSI *VSI, void *PlayerData, float Time)
01820 {
01821         GPlayer                 *Player;
01822         Bot_Var                 *DBot;
01823         geWorld                 *World;
01824     TrackPt         *Tp;
01825         geBoolean               CanSee;
01826         geVec3d                 Vec2Player;
01827 
01828         World = GenVSI_GetWorld(VSI);
01829 
01830         assert(World);
01831 
01832         Player = (GPlayer*)PlayerData;
01833         assert(Player);
01834         DBot = (Bot_Var*)Player->userData;
01835 
01836         PlayerPhysics(VSI, Player, PLAYER_GROUND_FRICTION, PLAYER_AIR_FRICTION, PLAYER_LIQUID_FRICTION, PLAYER_GRAVITY, 1.0f, GE_FALSE, Time);
01837 
01838         // vec2player
01839         //geVec3d_Subtract(&Player->XForm.Translation, &DBot->TgtPlayer->XForm.Translation, &Vec2Player);
01840         geVec3d_Subtract(&DBot->TgtPlayer->XForm.Translation, &Player->XForm.Translation, &Vec2Player);
01841         Bot_SetupXForm(VSI, PlayerData, &Vec2Player);       //Face Player
01842 
01843         // shooting
01844         if (!PlayerDead(DBot->TgtPlayer) && DBot->TimeSeen > 0.0f)
01845         {
01846         Bot_Shoot(VSI, Player, &DBot->TgtPlayer->XForm.Translation, Time);
01847         }
01848 
01849         Bot_GetContents(VSI, Player, Time);
01850         Bot_Animate(VSI, Player, Time);
01851 
01852     Tp = Track_GetPoint(&DBot->TrackInfoPrev);
01853     assert(Tp->WatchPos);
01854 
01855         if (Track_GetTrack(&DBot->TrackInfoPrev)->Type == TRACK_TYPE_TRAVERSE_DOOR)
01856                 CanSee = Bot_CanSeePointToPoint(World, &Player->XForm.Translation, Tp->WatchPos);
01857         else
01858                 CanSee = Bot_CanSeePlayerToPoint(World, &Player->XForm.Translation, Tp->WatchPos);
01859 
01860         if (CanSee)
01861         {
01862                 if (Track_OnTrack(&DBot->TrackInfo))
01863                         DBot->Action = Bot_MoveToPoint;
01864                 else
01865                         Bot_InitMoveToPoint(VSI, Player, &DBot->TgtPos);
01866                 return GE_TRUE;
01867         }
01868 
01869         // could not see point
01870         if (GenVSI_GetTime(VSI) >= DBot->TimeOut || DBot->HealthCheck < Player->Health)
01871                 {
01872         Bot_ClearTrack(VSI, Player);//&DBot->TrackInfo);
01873                 Bot_InitGenericMove(VSI, Player, Time);
01874                 return GE_TRUE;
01875                 }
01876 
01877         return GE_TRUE;
01878 }
01879 
01880 //=====================================================================================
01881 //      Bot_InitWaitForEntityDist
01882 //=====================================================================================
01883 geBoolean Bot_InitWaitForEntityDist(GenVSI *VSI, void *PlayerData, float Time)
01884 {
01885         GPlayer                 *Player;
01886         Bot_Var                 *DBot;
01887 
01888         Player = (GPlayer*)PlayerData;
01889         assert(Player);
01890         DBot = (Bot_Var*)Player->userData;
01891 
01892         Bot_SetupXForm(VSI, Player, &DBot->MoveVec);
01893 
01894         // Stop
01895         geVec3d_Clear(&Player->Velocity);
01896 
01897         DBot->HealthCheck = Player->Health; // save health
01898         DBot->Action = Bot_WaitForEntityDist;
01899         
01900         return GE_TRUE;
01901 }
01902 
01903 //=====================================================================================
01904 //      Bot_WaitForEntityDist
01905 //=====================================================================================
01906 geBoolean Bot_WaitForEntityDist(GenVSI *VSI, void *PlayerData, float Time)
01907 {
01908         GPlayer                 *Player;
01909         Bot_Var                 *DBot;
01910         geWorld                 *World;
01911     TrackPt         *Tp;
01912 
01913         World = GenVSI_GetWorld(VSI);
01914 
01915         assert(World);
01916 
01917         Player = (GPlayer*)PlayerData;
01918         assert(Player);
01919         DBot = (Bot_Var*)Player->userData;
01920 
01921         PlayerPhysics(VSI, Player, PLAYER_GROUND_FRICTION, PLAYER_AIR_FRICTION, PLAYER_LIQUID_FRICTION, PLAYER_GRAVITY, 1.0f, GE_FALSE, Time);
01922         Bot_GetContents(VSI, Player, Time);
01923         Bot_Animate(VSI, Player, Time);
01924 
01925     Tp = Track_GetPoint(&DBot->TrackInfoPrev);
01926     assert(Tp->WatchPos);
01927 
01928         if (geVec3d_DistanceBetween(&Player->XForm.Translation, Tp->WatchPos))
01929                 {
01930                 if (Track_OnTrack(&DBot->TrackInfo))
01931                         DBot->Action = Bot_MoveToPoint;
01932                 else
01933                         Bot_InitMoveToPoint(VSI, Player, &DBot->TgtPos);
01934                 return GE_TRUE;
01935                 }
01936 
01937         // timed out
01938         if (GenVSI_GetTime(VSI) >= DBot->TimeOut || DBot->HealthCheck < Player->Health)
01939         {
01940         Bot_ClearTrack(VSI, Player);
01941                 Bot_InitGenericMove(VSI, Player, Time);
01942                 return GE_TRUE;
01943         }
01944 
01945         return GE_TRUE;
01946 }
01947 
01948 
01949 //=====================================================================================
01950 //      Bot_WeaponJump
01951 //=====================================================================================
01952 geBoolean Bot_WeaponJump(GenVSI *VSI, void *PlayerData, float Time)
01953 {
01954         geVec3d                 Pos;
01955         float                   MoveSpeed;
01956         GPlayer                 *Player;
01957         Bot_Var                 *DBot;
01958         
01959         Player = (GPlayer*)PlayerData;
01960         assert(Player);
01961         DBot = (Bot_Var*)Player->userData;
01962 
01963         // Face Player
01964         //Bot_SetupXForm(VSI, PlayerData, &Vec2Player);
01965         // Face Running direction
01966         Bot_SetupXForm(VSI, PlayerData, &DBot->MoveVec);
01967 
01968         MoveSpeed = Time;
01969 
01970         if (Player->State == PSTATE_InAir)
01971                 MoveSpeed *= 0.15f;
01972         
01973         geVec3d_AddScaled(&Player->Velocity, &DBot->MoveVec, DBot->RunSpeed*MoveSpeed, &Player->Velocity);
01974 
01975         // save off the position
01976     Pos = Player->XForm.Translation;
01977 
01978         PlayerPhysics(VSI, Player, PLAYER_GROUND_FRICTION, PLAYER_AIR_FRICTION, PLAYER_LIQUID_FRICTION, PLAYER_GRAVITY, 1.0f, GE_FALSE, Time);
01979 
01980         Bot_GetContents(VSI, Player, Time);
01981 
01982         Bot_Animate(VSI, Player, Time);
01983 
01984         //??bot
01985         Player->VPos = Player->XForm.Translation;
01986 
01987     if (Player->State == PSTATE_Normal)
01988         {
01989                 DBot->RunSpeed = BOT_RUN_SPEED;
01990         Bot_InitGenericMove(VSI, Player, Time);
01991         return GE_TRUE;
01992         }
01993 
01994         return GE_TRUE;
01995 }
01996 
01997 //=====================================================================================
01998 //      Bot_Jump
01999 //=====================================================================================
02000 geBoolean Bot_Jump(GenVSI *VSI, void *PlayerData, float Time)
02001 {
02002         geVec3d                 Pos;
02003         float                   MoveSpeed;
02004         GPlayer                 *Player;
02005         Bot_Var                 *DBot;
02006         
02007         Player = (GPlayer*)PlayerData;
02008         assert(Player);
02009         DBot = (Bot_Var*)Player->userData;
02010 
02011         Bot_SetupXForm(VSI, PlayerData, &DBot->MoveVec);
02012 
02013         MoveSpeed = Time;
02014 
02015         if (Player->State == PSTATE_InAir)
02016                 MoveSpeed *= 0.15f;
02017         
02018         geVec3d_AddScaled(&Player->Velocity, &DBot->MoveVec, DBot->RunSpeed*MoveSpeed, &Player->Velocity);
02019 
02020         // save off the position
02021     Pos = Player->XForm.Translation;
02022 
02023         PlayerPhysics(VSI, Player, PLAYER_GROUND_FRICTION, PLAYER_AIR_FRICTION, PLAYER_LIQUID_FRICTION, PLAYER_GRAVITY, 1.0f, GE_FALSE, Time);
02024 
02025         Bot_GetContents(VSI, Player, Time);
02026 
02027         Bot_Animate(VSI, Player, Time);
02028 
02029         Player->VPos = Player->XForm.Translation;
02030 
02031     if (Player->State == PSTATE_Normal)
02032         {
02033                 DBot->RunSpeed = BOT_RUN_SPEED;
02034                 Bot_InitGenericMove(VSI, Player, Time);
02035         return GE_TRUE;
02036         }
02037 
02038         return GE_TRUE;
02039 }
02040 
02041 
02042 //=====================================================================================
02043 //      Bot_InitShootPoint
02044 //=====================================================================================
02045 geBoolean Bot_InitShootPoint(GenVSI *VSI, void *PlayerData, float Time)
02046 {
02047         GPlayer                 *Player;
02048         Bot_Var                 *DBot;
02049 
02050         Player = (GPlayer*)PlayerData;
02051         assert(Player);
02052         DBot = (Bot_Var*)Player->userData;
02053 
02054         //Bot_SetupXForm(VSI, Player, &DBot->MoveVec);
02055 
02056         // Stop
02057         geVec3d_Clear(&Player->Velocity);
02058 
02059         DBot->Action = Bot_ShootPoint;
02060         
02061         return GE_TRUE;
02062 }
02063 
02064 
02065 //=====================================================================================
02066 //      Bot_ShootPoint
02067 //=====================================================================================
02068 geBoolean Bot_ShootPoint(GenVSI *VSI, void *PlayerData, float Time)
02069 {
02070         GPlayer                 *Player;
02071         Bot_Var                 *DBot;
02072         geWorld                 *World;
02073     TrackPt         *Tp;
02074 
02075         World = GenVSI_GetWorld(VSI);
02076 
02077         assert(World);
02078 
02079         Player = (GPlayer*)PlayerData;
02080         assert(Player);
02081         DBot = (Bot_Var*)Player->userData;
02082 
02083         PlayerPhysics(VSI, Player, PLAYER_GROUND_FRICTION, PLAYER_AIR_FRICTION, PLAYER_LIQUID_FRICTION, PLAYER_GRAVITY, 1.0f, GE_FALSE, Time);
02084         Bot_GetContents(VSI, Player, Time);
02085         Bot_Animate(VSI, Player, Time);
02086 
02087         if (GenVSI_GetTime(VSI) >= Player->NextWeaponTime)
02088         {
02089                 geVec3d ShootPos, Vec2Point;
02090                 geXForm3d XFormSave;
02091 
02092                 Tp = Track_GetPoint(&DBot->TrackInfoPrev);
02093                 assert(Tp->WatchPos);
02094 
02095                 ShootPos = *Tp->WatchPos;
02096 
02097                 // adjust Y for Gun offset - shoot lower so it will be correct when 
02098                 // the vector is moved up
02099                 ShootPos.Y -= Player->GunOffset.Y;
02100                 geVec3d_Subtract(&ShootPos, &Player->XForm.Translation, &Vec2Point);
02101 
02102                 XFormSave = Player->XForm;
02103                 Bot_SetupShootXForm(VSI, PlayerData, &Vec2Point);
02104                 Bot_FireWeapon(VSI, PlayerData, Time);
02105                 Player->XForm = XFormSave;
02106 
02107                 DBot->ShootCount++;
02108                 if (DBot->ShootCount >= Tp->ShootTimes)
02109                         {
02110                         DBot->ShootCount = 0;
02111                         if (Track_OnTrack(&DBot->TrackInfo))
02112                                 DBot->Action = Bot_MoveToPoint;
02113                         else
02114                                 Bot_InitMoveToPoint(VSI, Player, &DBot->TgtPos);
02115                         return GE_TRUE;
02116                         }
02117 
02118         }
02119 
02120         // time out
02121         if (GenVSI_GetTime(VSI) >= DBot->TimeOut)
02122         {
02123         Bot_ClearTrack(VSI, Player);
02124                 Bot_InitGenericMove(VSI, Player, Time);
02125                 return GE_TRUE;
02126         }
02127 
02128         return GE_TRUE;
02129 }
02130 
02131 
02132 //=====================================================================================
02133 //      Bot_SetupXForm
02134 //=====================================================================================
02135 geBoolean Bot_SetupXForm(GenVSI *VSI, void *PlayerData, geVec3d *OrientVec)
02136 {
02137         GPlayer                 *Player;
02138         Bot_Var                 *DBot;
02139         geVec3d                 InVect;
02140         geVec3d                 LVect, UpVect = {0.0f,1.0f,0.0f}, Pos;
02141 
02142         Player = (GPlayer*)PlayerData;
02143         assert(Player);
02144         DBot = (Bot_Var*)Player->userData;
02145 
02146         Pos = Player->XForm.Translation;
02147 
02148         InVect = *OrientVec;
02149 
02150         InVect.Y = 0.0f; // Make it a 2D vector 
02151 
02152     if (geVec3d_Length(&InVect) == 0.0f)
02153         {
02154                 // This is hardly ever going to happen - but need to test for it
02155                 geXForm3d_SetIdentity(&Player->XForm);
02156         }
02157     else
02158         {
02159                 geVec3d_Normalize(&InVect);
02160                 geVec3d_CrossProduct(&UpVect, &InVect, &LVect);
02161                 geVec3d_Normalize(&LVect);
02162                 geVec3d_CrossProduct(&InVect, &LVect, &UpVect);
02163                 geXForm3d_SetFromLeftUpIn(&Player->XForm, &LVect, &UpVect, &InVect);
02164                 }
02165 
02166         // set the position back before moving
02167     Player->XForm.Translation = Pos;
02168 
02169         return GE_TRUE;
02170 }
02171 
02172 
02173 //=====================================================================================
02174 //      Bot_SetupShootXForm
02175 //=====================================================================================
02176 geBoolean Bot_SetupShootXForm(GenVSI *VSI, void *PlayerData, geVec3d *TargetVec)
02177 {
02178         GPlayer                 *Player;
02179         Bot_Var                 *DBot;
02180         geVec3d                 InVect;
02181         geVec3d                 LVect = {1.0f,0.0f,0.0f}, UpVect = {0.0f,1.0f,0.0f}, Pos;
02182 
02183         Player = (GPlayer*)PlayerData;
02184         assert(Player);
02185         DBot = (Bot_Var*)Player->userData;
02186 
02187         Pos = Player->XForm.Translation;
02188 
02189         InVect = *TargetVec;
02190 
02191     if (geVec3d_Length(&InVect) == 0.0f)
02192         {
02193                 // This is hardly ever going to happen - but need to test for it
02194                 geXForm3d_SetIdentity(&Player->XForm);
02195         }
02196     else
02197                 {
02198                 geVec3d_Normalize(&InVect);
02199                 if ((1.0f - fabs(geVec3d_DotProduct(&InVect, &UpVect))) < 0.01f)
02200                         {
02201                         // if co-linear
02202                         geVec3d_CrossProduct(&LVect, &InVect, &UpVect);
02203                         geVec3d_Normalize(&UpVect);
02204                         geVec3d_CrossProduct(&UpVect, &InVect, &LVect);
02205                         geXForm3d_SetFromLeftUpIn(&Player->XForm, &LVect, &UpVect, &InVect);
02206                         }
02207                 else
02208                         {
02209                         geVec3d_CrossProduct(&UpVect, &InVect, &LVect);
02210                         geVec3d_Normalize(&LVect);
02211                         geVec3d_CrossProduct(&InVect, &LVect, &UpVect);
02212                         geXForm3d_SetFromLeftUpIn(&Player->XForm, &LVect, &UpVect, &InVect);
02213                         }
02214                 }
02215 
02216         // set the position back before moving
02217     Player->XForm.Translation = Pos;
02218 
02219         return GE_TRUE;
02220 }
02221 
02222 //=====================================================================================
02223 //      Bot_ComparePlayers
02224 //=====================================================================================
02225 int16 Bot_ComparePlayers(GenVSI *VSI, void *PlayerData1, void *PlayerData2)
02226 {
02227         GPlayer                 *Player1;
02228         GPlayer                 *Player2;
02229         int32                   diff;
02230 
02231         // this func should be extended and to make better decision
02232 
02233         Player1 = (GPlayer*)PlayerData1;
02234         Player2 = (GPlayer*)PlayerData2;
02235 
02236         diff = Player1->Health - Player2->Health;
02237 
02238         if (diff > 30)
02239         {
02240                 return(1);
02241         }
02242         else
02243         if (diff < -30)
02244         {
02245                 return(-1);
02246         }
02247         else
02248                 return(1);
02249 }
02250 
02251 
02252 //=====================================================================================
02253 //      Bot_FireWeapon
02254 //=====================================================================================
02255 geBoolean Bot_FireWeapon(GenVSI *VSI, void *PlayerData, float Time)
02256 {
02257         GPlayer                 *Player;
02258 
02259         assert(PlayerData);
02260 
02261         Player = (GPlayer*)PlayerData;
02262 
02263         if (GenVSI_GetTime(VSI) < Player->NextWeaponTime)
02264                 return GE_FALSE;
02265         
02266         ValidateWeapon(VSI, PlayerData);
02267 
02268         switch (Player->CurrentWeapon)
02269         {
02270                 case 0:
02271                         FireBlaster(VSI, Player, Time);
02272                         Player->NextWeaponTime += 0.4f;
02273                         break;
02274                 case 1:
02275                         FireGrenade(VSI, Player, Time);
02276                         Player->NextWeaponTime += 0.4f;
02277                         break;
02278                 case 2:
02279                         FireRocket(VSI, Player, Time);
02280                         Player->NextWeaponTime += 0.4f;
02281                         break;
02282                 case 3:
02283                         FireShredder(VSI, Player, Time);
02284                         Player->NextWeaponTime += 0.1f;
02285                         break;
02286         }
02287 
02288         return GE_TRUE;
02289 }
02290 
02291 
02292 //=====================================================================================
02293 //      Bot_Shoot
02294 //=====================================================================================
02295 geBoolean Bot_Shoot(GenVSI *VSI, void *PlayerData, geVec3d *ShootPosition, float Time)
02296 {
02297         GPlayer                 *Player;
02298         Bot_Var                 *DBot;
02299         static uint32   Delay=0;
02300         geVec3d Vec2Player;
02301         geXForm3d XFormSave;
02302         #define TARGET_FEET_ADJUST_Y 130.0f
02303         #define TARGET_FEET_ADJUST_Y2 100.0f
02304 
02305         Player = (GPlayer*)PlayerData;
02306         assert(Player);
02307         DBot = (Bot_Var*)Player->userData;
02308 
02309         if (ShootPosition)
02310                 {
02311                 geVec3d ShootPos = *ShootPosition;
02312 
02313                 switch (Player->CurrentWeapon)
02314                         {
02315                         case ITEM_BLASTER:
02316                                 if (ShootPos.Y <= Player->XForm.Translation.Y || 
02317                                  fabs(ShootPos.Y - Player->XForm.Translation.Y) < TARGET_FEET_ADJUST_Y/2)
02318                                         {
02319                                         // aim dead on and at feet
02320                                         ShootPos.Y -= TARGET_FEET_ADJUST_Y;
02321                                         }
02322                                 break;
02323 
02324                         case ITEM_ROCKETS:
02325                                 if (ShootPos.Y <= Player->XForm.Translation.Y || 
02326                                         fabs(ShootPos.Y - Player->XForm.Translation.Y) < TARGET_FEET_ADJUST_Y/2
02327                                         )
02328                                         {
02329                                         // aim dead on and at feet
02330                                         ShootPos.X += (float)(RandomRange(100) - 50);
02331                                         ShootPos.Y -= TARGET_FEET_ADJUST_Y2;
02332                                         ShootPos.Y += (float)(RandomRange(100) - 50);
02333                                         ShootPos.Z += (float)(RandomRange(100) - 50);
02334                                         }
02335                                 break;
02336 
02337                         default:
02338                                 ShootPos.X += (float)(RandomRange(100) - 50);
02339                                 ShootPos.Y += (float)(RandomRange(100) - 50);
02340                                 ShootPos.Z += (float)(RandomRange(100) - 50);
02341                                 break;
02342                         }
02343 
02344                 geVec3d_Subtract(&ShootPos, &Player->XForm.Translation, &Vec2Player);
02345 
02346                 // save off the current XForm
02347                 XFormSave = Player->XForm;
02348                 Bot_SetupShootXForm(VSI, PlayerData, &Vec2Player);
02349                 Bot_FireWeapon(VSI, PlayerData, Time);
02350                 // restore the current XForm
02351                 Player->XForm = XFormSave;
02352                 }
02353         else
02354                 {
02355                 Bot_FireWeapon(VSI, PlayerData, Time);
02356                 }
02357 
02358         return GE_TRUE;
02359 }
02360 
02361 
02362 //=====================================================================================
02363 //      Bot_Animate
02364 //=====================================================================================
02365 geBoolean Bot_Animate(GenVSI *VSI, void *PlayerData, float Time)
02366 {
02367         GPlayer                 *Player;
02368         Bot_Var                 *DBot;
02369         float                   Speed;
02370         geBoolean               DoWalk = GE_FALSE;
02371 
02372         Player = (GPlayer*)PlayerData;
02373         assert(Player);
02374         DBot = (Bot_Var*)Player->userData;
02375 
02376         Speed = geVec3d_Length(&Player->Velocity);
02377 
02378         if (Speed > 0.1f)
02379         {
02380                 if (Player->MotionIndex != ACTOR_MOTION_PLAYER_RUN)
02381                         Player->FrameTime = 0.0f;
02382 
02383                 Player->MotionIndex = ACTOR_MOTION_PLAYER_RUN;
02384                 DoWalk = GE_TRUE;
02385         }
02386 
02387         if (Speed > 0.1f && DoWalk)
02388         {
02389                 if (Player->MotionIndex == ACTOR_MOTION_PLAYER_RUN)
02390                 {
02391                         Speed*=0.004f;
02392 
02393                         //if (Move->ForwardSpeed<0)
02394                         //      Speed *= -1.0f;
02395                 }
02396                 else
02397                         Speed = 1.0f;
02398                 
02399                 if (AnimatePlayer(VSI, Player, Player->MotionIndex, Time*Speed, GE_TRUE))
02400                 {
02401                         if (Player->MotionIndex != ACTOR_MOTION_PLAYER_RUN)
02402                                 Player->FrameTime = 0.0f;
02403 
02404                         Player->MotionIndex = ACTOR_MOTION_PLAYER_RUN;
02405                 }
02406         }
02407         else
02408         {
02409                 if (Player->MotionIndex != ACTOR_MOTION_PLAYER_IDLE)
02410                 {
02411                         Player->MotionIndex = ACTOR_MOTION_PLAYER_IDLE;
02412                         Player->FrameTime = 0.0f;
02413                 }
02414 
02415                 AnimatePlayer(VSI, Player, Player->MotionIndex, Time, GE_TRUE);
02416         }
02417 
02418         return GE_TRUE;
02419 }
02420 
02421 //=====================================================================================
02422 //      Bot_GetContents
02423 //=====================================================================================
02424 geBoolean Bot_GetContents(GenVSI *VSI, void *PlayerData, float Time)
02425 {
02426         GE_Contents             Contents;
02427         geVec3d                 CMins, CMaxs;
02428         GPlayer                 *Player;
02429         Bot_Var                 *DBot;
02430         uint32                  ColFlags;
02431         geWorld                 *World;
02432         CData                   Data;
02433         geBoolean SelfCollisionCB(geWorld_Model *Model, geActor *Actor, void *Context);
02434 
02435         World = GenVSI_GetWorld(VSI);
02436 
02437         #define ALL_BUT_SELF    (0xffffffff & ~(1<<0))
02438 
02439         assert(World);
02440 
02441         Player = (GPlayer*)PlayerData;
02442         DBot = (Bot_Var*)Player->userData;
02443 
02444         ColFlags = GE_COLLIDE_MODELS;
02445 
02446         if (VSI->Mode == MODE_Server)           // Only do this stuff when we are in server mode...
02447         {
02448                 if (!PlayerDead(Player) && Player->Roll > 0.0f)
02449                         Player->Roll -= Time;
02450 
02451                 if (geWorld_GetContents(World, &Player->XForm.Translation, &Player->Mins, &Player->Maxs, GE_COLLIDE_MODELS, 0, NULL, NULL, &Contents))
02452                 {
02453                         // Check to see if player is in lava...
02454                         if (Contents.Contents & CONTENTS_WATER)
02455                         {
02456                                 Player->State = PSTATE_InWater;
02457                         }
02458 
02459                         if (Contents.Contents & CONTENTS_LAVA)
02460                         {
02461                                 if (Player->Roll <= 0.0f)
02462                                 {
02463                                         DammagePlayer(VSI, NULL, Player, 20, 0.0f, Time);
02464                                         Player->Roll = 0.5f;
02465                                 }
02466 
02467                                 Player->State = PSTATE_InLava;
02468                         }
02469                 }
02470                 else if (PlayerLiquid(Player))
02471                                 Player->State = PSTATE_Normal;
02472 
02473                 // Get a box a little bigger than the player for doors, etc...
02474                 CMins = Player->Mins;
02475                 CMaxs = Player->Maxs;
02476         
02477                 CMins.X -= 100;
02478                 CMins.Y -= 10;
02479                 CMins.Z -= 100;
02480                 CMaxs.X += 100;
02481                 CMaxs.Y += 10;
02482                 CMaxs.Z += 100;
02483 
02484                 if (geWorld_GetContents(World, &Player->XForm.Translation, &CMins, &CMaxs, GE_COLLIDE_MODELS, 0,  NULL, NULL, &Contents))
02485                 {
02486                         if (Contents.Model)
02487                         {
02488                                 GPlayer *TPlayer;
02489 
02490                                 TPlayer = (GPlayer*)geWorld_ModelGetUserData(Contents.Model);
02491 
02492                                 if (TPlayer && TPlayer->Trigger && TPlayer->ViewFlags & VIEW_TYPE_TOUCH)
02493                                 {
02494                                         TPlayer->Trigger(VSI, TPlayer, Player, NULL);
02495                                 }
02496                         }
02497                 }
02498 
02499 
02500                 Data.VSI = VSI;
02501                 Data.Player = Player;
02502 
02503                 if (geWorld_GetContents(World, &Player->XForm.Translation, &CMins, &CMaxs, GE_COLLIDE_ACTORS, 0xffffffff, SelfCollisionCB, &Data, &Contents))
02504                 {
02505                         
02506                         if (Contents.Actor)
02507                         {
02508                                 GPlayer *TPlayer;
02509                                 static  int32   HackV;
02510 
02511                                 TPlayer = (GPlayer*)GenVSI_ActorToPlayer(VSI, Contents.Actor);
02512 
02513                                 if (TPlayer && TPlayer->Trigger)
02514                                 {
02515                                         TPlayer->Trigger(VSI, TPlayer, Player, NULL);
02516                                 }
02517                         }
02518                 }
02519 
02520         }
02521 
02522 
02523 
02524         return GE_TRUE;
02525 }
02526 
02527 //=====================================================================================
02528 //      Bot_CanSeePointToPoint
02529 //=====================================================================================
02530 geBoolean Bot_CanSeePointToPoint(geWorld *World, geVec3d *Pos1, geVec3d *Pos2)
02531 {
02532         GE_Collision Collision;
02533     int32 Leaf1, Leaf2;
02534 
02535         assert (World);
02536 
02537         geWorld_GetLeaf(World, Pos1, &Leaf1);
02538         geWorld_GetLeaf(World, Pos2, &Leaf2);
02539                         
02540         if (geWorld_LeafMightSeeLeaf(World, Leaf1, Leaf2, 0))
02541                 return !geWorld_Collision(World, &RayMins, &RayMaxs, Pos1, Pos2, GE_CONTENTS_CANNOT_OCCUPY, GE_COLLIDE_MODELS, 0, NULL, NULL, &Collision);
02542 
02543         return(GE_FALSE);
02544 }
02545 
02546 //=====================================================================================
02547 //      Bot_CanSeePlayerToPoint
02548 //      Adjust FIRST point for player height
02549 //=====================================================================================
02550 geBoolean Bot_CanSeePlayerToPoint(geWorld *World, geVec3d *Pos1, geVec3d *Pos2)
02551 {
02552         GE_Collision Collision;
02553         geVec3d PosAdj1,PosAdj2;
02554     int32 Leaf1, Leaf2;
02555 
02556         assert (World);
02557 
02558         PosAdj1 = *Pos1;
02559         PosAdj2 = *Pos2;
02560 
02561         PosAdj1.Y += 30.0f;
02562 
02563         geWorld_GetLeaf(World, &PosAdj1, &Leaf1);
02564         geWorld_GetLeaf(World, &PosAdj2, &Leaf2);
02565                         
02566         if (geWorld_LeafMightSeeLeaf(World, Leaf1, Leaf2, 0))
02567                 return !geWorld_Collision(World, &RayMins, &RayMaxs, &PosAdj1, &PosAdj2, GE_CONTENTS_CANNOT_OCCUPY, GE_COLLIDE_MODELS, 0, NULL, NULL, &Collision);
02568 
02569         return(GE_FALSE);
02570 }
02571 
02572 //=====================================================================================
02573 //      Bot_CanSeePlayerToPlayer
02574 //      Adjust BOTH points for player height
02575 //=====================================================================================
02576 geBoolean Bot_CanSeePlayerToPlayer(geWorld *World, geVec3d *Pos1, geVec3d *Pos2)
02577 {
02578         GE_Collision Collision;
02579         geVec3d PosAdj1,PosAdj2;
02580     int32 Leaf1, Leaf2;
02581 
02582         assert (World);
02583 
02584         PosAdj1 = *Pos1;
02585         PosAdj2 = *Pos2;
02586 
02587         PosAdj1.Y += 140.0f;
02588         PosAdj2.Y += 140.0f;
02589 
02590         geWorld_GetLeaf(World, &PosAdj1, &Leaf1);
02591         geWorld_GetLeaf(World, &PosAdj2, &Leaf2);
02592                         
02593         if (geWorld_LeafMightSeeLeaf(World, Leaf1, Leaf2, 0))
02594                 return !geWorld_Collision(World, &RayMins, &RayMaxs, &PosAdj1, &PosAdj2, GE_CONTENTS_CANNOT_OCCUPY, GE_COLLIDE_MODELS, 0, NULL, NULL, &Collision);
02595 
02596         return(GE_FALSE);
02597 }
02598 
02599 
02600 //=====================================================================================
02601 //      Bot_PickTgtPlayer
02602 //=====================================================================================
02603 GPlayer *Bot_PickTgtPlayer(GenVSI *VSI, void *PlayerData, geBoolean ForcePick)
02604 {
02605         GPlayer                 *Hit;
02606         geVec3d                 Pos, Pos2, Delta;
02607         float                   Dist, BotNearDist = 999999.0f;
02608         float                   PlayerNearDist = 999999.0f;
02609         GPlayer                 *Player;
02610         Bot_Var                 *DBot;
02611         geWorld                 *World;
02612         GPlayer         *FoundPlayerNearDist, *FoundPlayerCanSee, *FoundPlayerCanSeeNearDist;
02613         GPlayer                 *FoundBotNearDist, *FoundBotCanSee, *FoundBotCanSeeNearDist;
02614         GPlayer                 *LastChance = NULL;
02615         GPlayer                 *BestBot, *BestPlayer;
02616         GPlayer                 *BestBotWeapons, *BestPlayerWeapons;
02617         int32                   BestBotScore, BestPlayerScore;
02618         int32                   WRank, BestBotWRank=0, BestPlayerWRank=0;
02619 
02620         Player = (GPlayer*)PlayerData;
02621         DBot = (Bot_Var*)Player->userData;
02622 
02623         if (VSI->Mode != MODE_Server)
02624                 return NULL;
02625         
02626         Pos = Player->XForm.Translation;
02627 
02628         Hit = NULL;
02629     FoundPlayerNearDist = FoundPlayerCanSee = FoundPlayerCanSeeNearDist = NULL;
02630     FoundBotNearDist = FoundBotCanSee = FoundBotCanSeeNearDist = NULL;
02631         BestBot = BestPlayer = NULL;
02632         BestBotScore = BestPlayerScore = -1;
02633 
02634         World = GenVSI_GetWorld(VSI);
02635 
02636         while (1)
02637         {
02638                 Hit = GenVSI_GetNextPlayer(VSI, Hit, NULL);
02639 
02640                 if (!Hit)
02641                         break;
02642 
02643                 if (Hit->ClientHandle == CLIENT_NULL_HANDLE) // Will not find ACTORS!
02644                         continue;
02645 
02646                 if (GenVSI_IsClientBot(VSI, Hit->ClientHandle))
02647                         {
02648 
02649                         WRank = Bot_RankWeapons(VSI, Hit);
02650 
02651                         if (WRank > BestBotWRank)
02652                                 {
02653                                 BestBotWRank = WRank;
02654                                 BestBotWeapons = Hit;
02655                                 }
02656 
02657                         if (Hit->Score > BestBotScore)
02658                                 {
02659                                 BestBotScore = Hit->Score;
02660                                 BestBot = Hit;
02661                                 }
02662                         }
02663                 else
02664                         {
02665                         DBot->ClientPlayer = Hit;
02666                         WRank = Bot_RankWeapons(VSI, Hit);
02667 
02668                         if (WRank > BestPlayerWRank)
02669                                 {
02670                                 BestPlayerWRank = WRank;
02671                                 BestPlayerWeapons = Hit;
02672                                 }
02673 
02674                         if (Hit->Score > BestPlayerScore)
02675                                 {
02676                                 BestPlayerScore = Hit->Score;
02677                                 BestPlayer = Hit;
02678                                 }
02679                         }
02680 
02681 
02682                 // don't look at yourself
02683                 if (Hit == Player)
02684                         continue;
02685 
02686                 // SOMEbody other than yourself - even if dead
02687                 LastChance = Hit; // just in case everyone but you is dead
02688 
02689                 // skip dead players/bots
02690                 if (PlayerDead(Hit))
02691                         continue;
02692 
02693                 Pos2 = Hit->XForm.Translation;
02694 
02695                 geVec3d_Subtract(&Pos, &Pos2, &Delta);
02696                 Dist = geVec3d_Length(&Delta);
02697 
02698                 if (GenVSI_IsClientBot(VSI, Hit->ClientHandle))
02699                         {
02700                         // force human player to be picked
02701                         if (ForcePick)
02702                                 continue;
02703 
02704                         if (Dist < BotNearDist)
02705                                 {
02706                                 BotNearDist = Dist;
02707                                 FoundBotNearDist = Hit;
02708 
02709                                 if (Bot_CanSeePlayerToPlayer(World, &Pos, &Pos2))
02710                                         FoundBotCanSeeNearDist = Hit;
02711                                 }
02712                         else
02713                                 {
02714                                 if (Bot_CanSeePlayerToPlayer(World, &Pos, &Pos2))
02715                                         FoundBotCanSee = Hit;
02716                                 }
02717                         }
02718                 else
02719                         {
02720                         if (Dist < PlayerNearDist)
02721                                 {
02722                                 PlayerNearDist = Dist;
02723                                 FoundPlayerNearDist = Hit;
02724 
02725                                 if (Bot_CanSeePlayerToPlayer(World, &Pos, &Pos2))
02726                                         FoundPlayerCanSeeNearDist = Hit;
02727                                 }
02728                         else
02729                                 {
02730                                 if (Bot_CanSeePlayerToPlayer(World, &Pos, &Pos2))
02731                                         FoundPlayerCanSee = Hit;
02732                                 }
02733                         }
02734 
02735         }
02736 
02737         // if player gets ahead - let ALL bots go for player as first choice
02738         if (BestBot && BestPlayer) 
02739                 if (BestPlayerScore > BestBotScore && (BestPlayerScore - BestBotScore) > 10)
02740                         {
02741                         return BestPlayer;
02742                         }
02743 
02744         /*
02745         // if YOU aren't the bot best armed &&
02746                 // if player and bot are visible AND best bot is heavily armed - then go for him
02747         if (BestBotWeapons != NULL && BestBotWeapons != Player)
02748                 if (FoundPlayerCanSee && FoundBotCanSee && (FoundBotCanSee == BestBotWeapons))
02749                         if (BestBotWRank > BestPlayerWRank && (BestBotWRank - BestPlayerWRank) > 30)
02750                                 {
02751                                 return BestBotWeapons;
02752                                 }
02753         */
02754 
02755         if (FoundPlayerCanSeeNearDist)  return  FoundPlayerCanSeeNearDist;
02756         if (FoundBotCanSeeNearDist)             return  FoundBotCanSeeNearDist;
02757         if (FoundPlayerCanSee)                  return  FoundPlayerCanSee;
02758         if (FoundBotCanSee)                             return  FoundBotCanSee;
02759         if (FoundPlayerNearDist)                return  FoundPlayerNearDist;
02760         if (FoundBotNearDist)                   return  FoundBotNearDist;
02761 
02762         return (LastChance);
02763 }
02764 
02765 
02766 //=====================================================================================
02767 //      Bot_FindItem
02768 //=====================================================================================
02769 GPlayer *Bot_FindItem(GenVSI *VSI, geVec3d *Pos, char *ClassList[], float YDiff, float Range)
02770 {
02771         GPlayer                 *Hit;
02772         geVec3d                 Pos2;
02773         float                   Dist, NearDist = 999999.0f;
02774         geWorld                 *World;
02775     int             i;
02776         GPlayer         *FoundPlayerCanSeeNearDist;
02777 
02778         if (VSI->Mode != MODE_Server)
02779                 return NULL;
02780         
02781     FoundPlayerCanSeeNearDist = NULL;
02782 
02783         World = GenVSI_GetWorld(VSI);
02784 
02785         Hit = NULL;
02786         while (1)
02787         {
02788                 Hit = GenVSI_GetNextPlayer(VSI, Hit, NULL);
02789 
02790                 if (!Hit)
02791                         break;
02792 
02793         if (Hit->ViewIndex == 0xffff)
02794             continue;
02795 
02796         if (fabs(Pos->Y - Hit->Pos.Y) > YDiff)
02797             continue;
02798 
02799         for (i=0; ClassList[i]; i++)
02800         {
02801             if (strcmp(ClassList[i], Hit->ClassName) == 0)   
02802                 break;
02803         }
02804 
02805         if (!ClassList[i])
02806             continue;
02807 
02808                 Pos2 = Hit->XForm.Translation;
02809 
02810                 Dist = geVec3d_DistanceBetween(Pos, &Pos2);
02811 
02812                 if (Dist > Range)
02813                         continue;
02814 
02815                 if (Dist < NearDist)
02816                 {
02817                         if (Bot_CanSeePointToPoint(World, Pos, &Pos2))
02818                         {
02819                                 FoundPlayerCanSeeNearDist = Hit;
02820                         }       
02821                 }
02822         }
02823 
02824         if (FoundPlayerCanSeeNearDist)
02825                 return  FoundPlayerCanSeeNearDist;
02826 
02827         return NULL;
02828 }
02829 
02830 
02831 //=====================================================================================
02832 //      Bot_FindRandomItem
02833 //=====================================================================================
02834 GPlayer *Bot_FindRandomItem(GenVSI *VSI, geVec3d *Pos, char *ClassList[])
02835 {
02836         GPlayer                 *Hit;
02837         geVec3d                 Pos2;
02838         float                   Dist, NearDist = 999999.0f;
02839         geWorld                 *World;
02840     int             i,GoalCount;
02841         GPlayer         *FoundPlayerCanSeeNearDist;
02842         static GPlayer          *GoalList[300];
02843 
02844         if (VSI->Mode != MODE_Server)
02845                 return NULL;
02846         
02847     FoundPlayerCanSeeNearDist = NULL;
02848 
02849         World = GenVSI_GetWorld(VSI);
02850 
02851         GoalCount = 0;
02852         Hit = NULL;
02853         while (1)
02854         {
02855                 Hit = GenVSI_GetNextPlayer(VSI, Hit, NULL);
02856 
02857                 if (!Hit)
02858                         break;
02859 
02860         if (Hit->ViewIndex == 0xffff)
02861             continue;
02862 
02863         for (i=0; ClassList[i]; i++)
02864         {
02865             if (strcmp(ClassList[i], Hit->ClassName) == 0)   
02866                 break;
02867         }
02868 
02869         if (!ClassList[i])
02870             continue;
02871 
02872                 Pos2 = Hit->XForm.Translation;
02873                 Dist = geVec3d_DistanceBetween(Pos, &Pos2);
02874 
02875                 if (Dist < 2000)
02876                         continue;
02877 
02878                 GoalList[GoalCount++] = Hit;
02879                 if ( GoalCount >= sizeof(GoalList)/sizeof(GoalList[0]) )
02880                         break;
02881 
02882         }
02883 
02884         if (!GoalCount)
02885                 return NULL;
02886 
02887         return(GoalList[RandomRange(GoalCount)]);
02888 }
02889 
02890 
02891 //=====================================================================================
02892 //      Bot_FindRandomTrack
02893 //=====================================================================================
02894 Track *Bot_FindRandomTrack(GenVSI *VSI, geVec3d *Pos, int32 *TrackTypeList)
02895 {
02896         int             i,GoalCount;
02897         static Track    *GoalList[300];
02898         Track *t;
02899 
02900         GoalCount = 0;
02901         t = NULL;
02902         while (1)
02903         {
02904                 t = Track_GetNextTrack(t);
02905 
02906                 if (!t)
02907                         break;
02908 
02909         for (i=0; TrackTypeList[i] >= 0; i++)
02910         {
02911                         if (t->Type == TrackTypeList[i])
02912                 break;
02913         }
02914 
02915         if (TrackTypeList[i] <= -1)
02916             continue;
02917 
02918                 GoalList[GoalCount++] = t;
02919                 if ( GoalCount >= sizeof(GoalList)/sizeof(GoalList[0]) )
02920                         break;
02921 
02922         }
02923 
02924         if (!GoalCount)
02925                 return NULL;
02926 
02927         return(GoalList[RandomRange(GoalCount)]);
02928 }
02929 
02930 
02931 //=====================================================================================
02932 //      Bot_Dying
02933 //=====================================================================================
02934 geBoolean Bot_Dying(GenVSI *VSI, void *PlayerData, float Time)
02935 {
02936         GPlayer                 *Player;
02937         Bot_Var                 *DBot;
02938         static float WaitTime = 0.0f;
02939 
02940         Player = (GPlayer*)PlayerData;
02941         DBot = (Bot_Var*)Player->userData;
02942 
02943         Player->MotionIndex = ACTOR_MOTION_PLAYER_DIE;
02944         AnimatePlayer(VSI, Player, Player->MotionIndex, Time, GE_FALSE);
02945 
02946         Player->Roll -= 2.0f*Time;
02947 
02948         if (Player->Roll < -(3.14159f/2.0f))
02949         {
02950                 Player->Roll = -(3.14159f/2.0f);
02951 
02952                 WaitTime += Time;
02953 
02954                 if (WaitTime > 3.0f)
02955                 {
02956                         GPlayer *DMStart;
02957                         
02958                         DMStart = (GPlayer*)GetBotMatchSpawn(VSI);
02959 
02960                         Player->Roll = 0.0f;            // Make him stand right side up again
02961                         Player->Control = Bot_Control;
02962                         Player->ViewIndex = 0;
02963                         Player->MotionIndex = ACTOR_MOTION_PLAYER_RUN;
02964                         Player->FrameTime = 0.0f;
02965                         geVec3d_Clear(&Player->Velocity);
02966             geVec3d_Clear(&DBot->TgtPos);
02967             Bot_ClearTrack(VSI, Player);
02968             StackReset(&DBot->TrackStack);
02969             DBot->Action = Bot_InitGenericMove;
02970                         DBot->PickTimeout = 0.0f;
02971                         DBot->TimeSinceTrack = 0.0f;
02972                         DBot->BotTgtPicked = 0;
02973             Bot_ModeChange(VSI, Player, MODE_WANDER, GE_TRUE, Time);
02974                         DBot->RunSpeed = BOT_RUN_SPEED;
02975                         Player->State = PSTATE_Normal;          // Back to normal now...
02976 
02977                         Player->ViewFlags &= ~VIEW_TYPE_FORCE_XFORM;
02978 
02979                         Player->XForm = DMStart->XForm;
02980                         GenVSI_SpawnFx(VSI, FX_EXPLODE2, &Player->XForm.Translation, SOUND_INDEX_PLAYER_SPAWN);
02981 
02982                         return GE_TRUE;
02983                 }
02984         }
02985         else
02986         {
02987         WaitTime = 0.0f;        
02988         }
02989 
02990         SetupPlayerXForm(VSI, Player, Time);
02991 
02992         PlayerPhysics(VSI, Player, PLAYER_GROUND_FRICTION, PLAYER_AIR_FRICTION, PLAYER_LIQUID_FRICTION, PLAYER_GRAVITY, 1.0f, GE_FALSE, Time);
02993 
02994         return GE_TRUE;
02995 }
02996 
02997 
02998 //=====================================================================================
02999 //      Bot_ActorDying
03000 //=====================================================================================
03001 geBoolean Bot_ActorDying(GenVSI *VSI, void *PlayerData, float Time)
03002 {
03003         GPlayer                 *Player;
03004         Bot_Var                 *DBot;
03005         static float WaitTime = 0.0f;
03006 
03007         Player = (GPlayer*)PlayerData;
03008         DBot = (Bot_Var*)Player->userData;
03009 
03010         Player->MotionIndex = ACTOR_MOTION_PLAYER_DIE;
03011         AnimatePlayer(VSI, Player, Player->MotionIndex, Time, GE_FALSE);
03012 
03013         Player->Roll -= 2.0f*Time;
03014 
03015         if (Player->Roll < -(3.14159f/2.0f))
03016         {
03017                 Player->Roll = -(3.14159f/2.0f);
03018 
03019                 WaitTime += Time;
03020 
03021                 //if (Move->ButtonBits & HOST_BUTTON_FIRE)
03022                 if (WaitTime > 3.0f)
03023                 {
03024                         BotActorStart *Bs;
03025                         
03026                         Bs = Bot_GetActorStart(VSI, Player);
03027 
03028                         assert(Bs);
03029 
03030                         if (!Bs->Respawn)
03031                                 {
03032                                 GenVSI_DestroyPlayer(VSI, Player);
03033                                 return GE_TRUE;;
03034                                 }
03035 
03036                         Player->Roll = 0.0f;            // Make him stand right side up again
03037                         Player->Control = Bot_Control;
03038                         Player->ViewIndex = 0;
03039                         Player->MotionIndex = ACTOR_MOTION_PLAYER_RUN;
03040                         Player->FrameTime = 0.0f;
03041                         geVec3d_Clear(&Player->Velocity);
03042             geVec3d_Clear(&DBot->TgtPos);
03043             Bot_ClearTrack(VSI, Player);
03044                         DBot->PickTimeout = 0.0f;
03045                         DBot->BotTgtPicked = 0;
03046                         DBot->TimeSinceTrack = 0.0f;
03047             StackReset(&DBot->TrackStack);
03048             Bot_ModeChange(VSI, Player, MODE_WANDER, GE_TRUE, Time);
03049             DBot->Action = Bot_InitGenericMove;
03050                         DBot->RunSpeed = BOT_RUN_SPEED;
03051                         Player->State = PSTATE_Normal;          // Back to normal now...
03052 
03053                         Player->ViewFlags &= ~VIEW_TYPE_FORCE_XFORM;
03054 
03055                         geXForm3d_SetIdentity(&Player->XForm);
03056                         Player->XForm.Translation = Bs->origin;
03057                         GenVSI_SpawnFx(VSI, FX_EXPLODE2, &Player->XForm.Translation, SOUND_INDEX_PLAYER_SPAWN);
03058 
03059                         return GE_TRUE;
03060                 }
03061         }
03062         else
03063         {
03064         WaitTime = 0.0f;        
03065         }
03066 
03067         Bot_SetupXForm(VSI, Player, &DBot->MoveVec);
03068 
03069         PlayerPhysics(VSI, Player, PLAYER_GROUND_FRICTION, PLAYER_AIR_FRICTION, PLAYER_LIQUID_FRICTION, PLAYER_GRAVITY, 1.0f, GE_FALSE, Time);
03070 
03071         return GE_TRUE;
03072 }
03073 
03074 
03075 geBoolean Bot_NudgePlayer(GenVSI *VSI, void *PlayerData, geVec3d *TgtPos, float Time)
03076         {
03077         GPlayer                 *Player;
03078         Bot_Var                 *DBot;
03079         GE_Collision    Collision;
03080         uint32                  ColFlags;
03081         geVec3d                 NewPos, Pos;
03082         geWorld                 *World;
03083 
03084         Player = (GPlayer*)PlayerData;
03085         DBot = (Bot_Var*)Player->userData;
03086         World = GenVSI_GetWorld(VSI);
03087         assert(World);
03088 
03089         ColFlags = GE_COLLIDE_MODELS;
03090 
03091         NewPos = *TgtPos;
03092         Pos = Player->XForm.Translation;
03093 
03094         NewPos.Y += 40;
03095         // likely pushes you up in the air a bit
03096         if (!geWorld_Collision(World, &Player->Mins, &Player->Maxs, &Pos, &NewPos, GE_CONTENTS_CANNOT_OCCUPY, ColFlags, 0xffffffff, NULL, NULL, &Collision))
03097                 {
03098                 Pos = NewPos;
03099                 // back on the ground
03100                 NewPos.Y -= 200.0f;
03101                 assert (geWorld_Collision(World, &Player->Mins, &Player->Maxs, &Pos, &NewPos, GE_CONTENTS_CANNOT_OCCUPY, ColFlags, 0xffffffff, NULL, NULL, &Collision));
03102                 geVec3d_Copy(&Collision.Impact, &Player->XForm.Translation);
03103                 return GE_TRUE;
03104                 }
03105                 
03106         return GE_FALSE;
03107         }
03108 
03109 #define MAX_CLIP_PLANES         5
03110 //=====================================================================================
03111 //      Bot_CheckVelocity
03112 //      Adjust players Velocity. based on what it's doing in the world
03113 //=====================================================================================
03114 geBoolean Bot_CheckVelocity(GenVSI *VSI, void *PlayerData, float Time)
03115 {
03116         int32                   NumHits, NumPlanes;
03117         GE_Collision    Collision;
03118         int32                   HitCount, i, j;
03119         geVec3d                 Mins, Maxs;
03120         geVec3d                 Planes[MAX_CLIP_PLANES];
03121         geVec3d                 Pos, NewPos, OriginalVelocity, PrimalVelocity;
03122         geVec3d                 NewVelocity, Dir;
03123         float                   TimeLeft, Dist;
03124         GE_Contents             Contents;
03125         GPlayer                 *Player;
03126         geWorld                 *World;
03127         uint32                  ColFlags;
03128 
03129         Player = (GPlayer*)PlayerData;
03130 
03131         World = GenVSI_GetWorld(VSI);
03132 
03133         assert(World);
03134 
03135         Mins = Player->Mins;
03136         Maxs = Player->Maxs;
03137 
03138         geVec3d_Copy(&Player->Velocity, &OriginalVelocity);
03139         geVec3d_Copy(&Player->Velocity, &PrimalVelocity);
03140 
03141         TimeLeft = Time;
03142         
03143         NumHits = 4;
03144         //NumHits = 1;
03145         NumPlanes = 0;
03146 
03147         Player->State = PSTATE_InAir;
03148 
03149         ColFlags = GE_COLLIDE_MODELS;
03150 
03151         for (HitCount=0 ; HitCount<NumHits ; HitCount++)
03152         {
03153                 float   Fd, Bd;
03154                 //Server_Player *UPlayer;
03155 
03156                 Pos = Player->XForm.Translation;
03157 
03158                 geVec3d_AddScaled(&Pos, &Player->Velocity, TimeLeft, &NewPos);
03159                 
03160                 if (geWorld_GetContents(World, &Pos, &Mins, &Maxs, ColFlags, 1,  NULL, NULL, &Contents))
03161                 {
03162                         if (Contents.Contents & GE_CONTENTS_SOLID)
03163                         {
03164                                 if (geWorld_GetContents(World, &NewPos, &Mins, &Maxs, ColFlags, 0xffffffff,  NULL, NULL, &Contents))
03165                                 {
03166                                         if (Contents.Contents & GE_CONTENTS_SOLID)
03167                                         {
03168                                                 geVec3d_Copy(&Player->LastGoodPos, &Player->XForm.Translation);
03169                                                 geVec3d_Clear(&Player->Velocity);
03170                                                 return GE_TRUE;
03171                                         }
03172                                 }
03173                         }
03174                 }
03175                 
03176                 if (!geWorld_Collision(World, &Mins, &Maxs, &Pos, &NewPos, GE_CONTENTS_CANNOT_OCCUPY, ColFlags, 0xffffffff, NULL, NULL, &Collision))
03177                         return GE_TRUE;         // Covered the entire distance...
03178 
03179                 if (Collision.Plane.Normal.Y > 0.7f)
03180                 {
03181                         if (Player->State == PSTATE_InAir)
03182                                 Player->State = PSTATE_Normal;                  // Put the player on the ground if in air
03183                         else if (Player->State == PSTATE_Dead)
03184                                 Player->State = PSTATE_DeadOnGround;    // Put the player on the ground if in air
03185 
03186                         if (Collision.Model)
03187                         {
03188                                 GPlayer         *Target;
03189                                 Target = (GPlayer*)geWorld_ModelGetUserData(Collision.Model);
03190                                 if (Target && Target->Trigger && Target->ViewFlags & VIEW_TYPE_STANDON)
03191                                         Target->Trigger(VSI, Target, Player, NULL);
03192                         }
03193                 }
03194 
03195 
03196                 if (Collision.Model)
03197                 {
03198                         GPlayer         *Target;
03199                         Target = (GPlayer*)geWorld_ModelGetUserData(Collision.Model);
03200                         if (Target && Target->Trigger && Target->ViewFlags & VIEW_TYPE_PHYSOB)
03201                                 Target->Trigger(VSI, Target, Player, (void*)&Collision);
03202                 }
03203                 
03204                 if (Collision.Actor)            // Just stop at actors for now...
03205                 {
03206                         geVec3d_Copy(&Player->LastGoodPos, &Player->XForm.Translation);
03207                         geVec3d_Clear(&Player->Velocity);
03208                         return GE_TRUE;
03209                 }
03210 
03211                 // FIXME:  Save this ratio in the impact function...
03212                 Fd = geVec3d_DotProduct(&Pos, &Collision.Plane.Normal) - Collision.Plane.Dist;
03213                 Bd = geVec3d_DotProduct(&NewPos, &Collision.Plane.Normal) - Collision.Plane.Dist;
03214 
03215                 Collision.Ratio = Fd / (Fd - Bd);
03216                 
03217                 if (Collision.Ratio > 0.00f)    // Actually covered some distance
03218                 {       
03219                         // Set the players pos to the impact point
03220                         geVec3d_Copy(&Collision.Impact, &Player->XForm.Translation);
03221                         // Restore Velocity
03222                         geVec3d_Copy(&Player->Velocity, &OriginalVelocity);
03223                         NumPlanes = 0;
03224                 }
03225                 
03226                 if (!Collision.Plane.Normal.Y)
03227                 {
03228                         if (MovePlayerUpStep(VSI, Player, &Collision))
03229                         {
03230                                 continue;
03231                         }
03232                 }
03233 
03234         // This is the main change 
03235                 if (Collision.Plane.Normal.Y < 0.2f)
03236                 {
03237                         //geVec3d_Copy(&Collision.Impact, &Player->XForm.Translation);
03238                         geVec3d_Clear(&Player->Velocity);
03239                         return GE_FALSE;
03240                 }
03241 
03242                 //TimeLeft -= TimeLeft * Collision.Ratio;
03243                 
03244                 // Clipped to another plane
03245                 if (NumPlanes >= MAX_CLIP_PLANES)
03246                 {       
03247                         GenVSI_ConsolePrintf(VSI, "MAX_CLIP_PLANES!!!\n");
03248                         geVec3d_Clear(&Player->Velocity);
03249                         return GE_TRUE;
03250                 }
03251 
03252                 // Add the plane hit, to the plane list
03253                 geVec3d_Copy (&Collision.Plane.Normal, &Planes[NumPlanes]);
03254                 NumPlanes++;
03255 
03256                 //
03257                 // Modify original_velocity so it parallels all of the clip planes
03258                 //
03259                 for (i=0 ; i<NumPlanes ; i++)
03260                 {
03261                         ReflectVelocity(&OriginalVelocity, &Planes[i], &NewVelocity, 1.0f);
03262 
03263                         for (j=0 ; j<NumPlanes ; j++)
03264                         {
03265                                 if (j != i)
03266                                 {
03267                                         if (geVec3d_DotProduct(&NewVelocity, &Planes[j]) < 0.0f)
03268                                                 break;  // not ok
03269                                 }
03270                         }
03271                         if (j == NumPlanes)
03272                                 break;
03273                 }
03274                 
03275                 if (i != NumPlanes)
03276                 {       // Go along this plane
03277                         geVec3d_Copy(&NewVelocity, &Player->Velocity);
03278                 }
03279                 else
03280                 {       // Go along the crease
03281                         if (NumPlanes != 2)
03282                         {
03283                                 geVec3d_Clear(&Player->Velocity);
03284                                 return GE_FALSE;
03285                         }
03286                         
03287                         geVec3d_CrossProduct(&Planes[0], &Planes[1], &Dir);
03288                         Dist = geVec3d_DotProduct(&Dir, &Player->Velocity);
03289                         geVec3d_Scale(&Dir, Dist, &Player->Velocity);
03290                 }
03291 
03292                 //
03293                 // If original velocity is against the original velocity, stop dead
03294                 // to avoid tiny occilations in sloping corners
03295                 //
03296                 if (geVec3d_DotProduct (&Player->Velocity, &PrimalVelocity) <= 0.0f)
03297                 {
03298                         geVec3d_Clear(&Player->Velocity);
03299                         return GE_FALSE;
03300                 }
03301                 //
03302 
03303         }
03304         return GE_TRUE;                                                                 
03305 }
03306 
03307 
03308 //=====================================================================================
03309 //      Bot_ScanCheckVelocity
03310 //=====================================================================================
03311 geBoolean Bot_ScanCheckVelocity(GenVSI *VSI, void *PlayerData, float Time)
03312 {
03313         int32                   NumHits, NumPlanes;
03314         GE_Collision    Collision;
03315         int32                   HitCount, i, j;
03316         geVec3d                 Mins, Maxs;
03317         geVec3d                 Planes[MAX_CLIP_PLANES];
03318         geVec3d                 Pos, NewPos, OriginalVelocity, PrimalVelocity;
03319         geVec3d                 NewVelocity, Dir;
03320         float                   TimeLeft, Dist;
03321         GE_Contents             Contents;
03322         GPlayer                 *Player;
03323         Bot_Var                 *DBot;
03324         geWorld                 *World;
03325         uint32                  ColFlags;
03326 
03327         Player = (GPlayer*)PlayerData;
03328         DBot = (Bot_Var*)Player->userData;
03329 
03330         World = GenVSI_GetWorld(VSI);
03331 
03332         assert(World);
03333 
03334         Mins = Player->Mins;
03335         Maxs = Player->Maxs;
03336 
03337         geVec3d_Copy(&Player->Velocity, &OriginalVelocity);
03338         geVec3d_Copy(&Player->Velocity, &PrimalVelocity);
03339 
03340         TimeLeft = Time;
03341         
03342         NumHits = 4;
03343         //NumHits = 1;
03344         NumPlanes = 0;
03345 
03346         Player->State = PSTATE_InAir;
03347 
03348         ColFlags = GE_COLLIDE_ALL;
03349 
03350         for (HitCount=0 ; HitCount<NumHits ; HitCount++)
03351         {
03352                 float   Fd, Bd;
03353 
03354                 Pos = Player->XForm.Translation;
03355 
03356                 geVec3d_AddScaled(&Pos, &Player->Velocity, TimeLeft, &NewPos);
03357                 
03358                 if (geWorld_GetContents(World, &Pos, &Mins, &Maxs, ColFlags, 1,  NULL, NULL, &Contents))
03359                 {
03360                         if (Contents.Contents & GE_CONTENTS_SOLID)
03361                         {
03362                                 if (geWorld_GetContents(World, &NewPos, &Mins, &Maxs, ColFlags, 0xffffffff,  NULL, NULL, &Contents))
03363                                 {
03364                                         if (Contents.Contents & GE_CONTENTS_SOLID)
03365                                         {
03366                                                 geVec3d_Copy(&Player->LastGoodPos, &Player->XForm.Translation);
03367                                                 geVec3d_Clear(&Player->Velocity);
03368                                                 return GE_TRUE;
03369                                         }
03370                                 }
03371                         }
03372                 }
03373                 
03374                 if (!geWorld_Collision(World, &Mins, &Maxs, &Pos, &NewPos, GE_CONTENTS_CANNOT_OCCUPY, ColFlags, 0xffffffff, NULL, NULL, &Collision))
03375                         return GE_TRUE;         // Covered the entire distance...
03376 
03377                 
03378                 if (Collision.Actor)            // Just stop at actors for now...
03379                 {
03380                         //geVec3d_Copy(&Player->LastGoodPos, &Player->XForm.Translation);
03381                         geVec3d_Copy(&Collision.Impact, &Player->XForm.Translation);
03382                         geVec3d_Clear(&Player->Velocity);
03383                         return GE_FALSE;
03384                 }
03385 
03386                 // FIXME:  Save this ratio in the impact function...
03387                 Fd = geVec3d_DotProduct(&Pos, &Collision.Plane.Normal) - Collision.Plane.Dist;
03388                 Bd = geVec3d_DotProduct(&NewPos, &Collision.Plane.Normal) - Collision.Plane.Dist;
03389 
03390                 Collision.Ratio = Fd / (Fd - Bd);
03391                 
03392                 if (Collision.Ratio > 0.00f)    // Actually covered some distance
03393                 {       
03394                         // Set the players pos to the impact point
03395                         geVec3d_Copy(&Collision.Impact, &Player->XForm.Translation);
03396                         // Restore Velocity
03397                         geVec3d_Copy(&Player->Velocity, &OriginalVelocity);
03398                         NumPlanes = 0;
03399                 }
03400                 
03401                 if (!Collision.Plane.Normal.Y)
03402                 {
03403                         if (MovePlayerUpStep(VSI, Player, &Collision))
03404                         {
03405                                 continue;
03406                         }
03407                 }
03408 
03409         // This is the main change - other than optimizations
03410                 if (Collision.Plane.Normal.Y < 0.2f)
03411                 {
03412                         geVec3d_Copy(&Collision.Impact, &Player->XForm.Translation);
03413                         geVec3d_Clear(&Player->Velocity);
03414                         return GE_FALSE;
03415                 }
03416                 
03417                 //TimeLeft -= TimeLeft * Collision.Ratio;
03418                 
03419                 // Clipped to another plane
03420                 if (NumPlanes >= MAX_CLIP_PLANES)
03421                 {       
03422                         GenVSI_ConsolePrintf(VSI, "MAX_CLIP_PLANES!!!\n");
03423                         geVec3d_Clear(&Player->Velocity);
03424                         return GE_TRUE;
03425                 }
03426 
03427                 // Add the plane hit, to the plane list
03428                 geVec3d_Copy (&Collision.Plane.Normal, &Planes[NumPlanes]);
03429                 NumPlanes++;
03430 
03431                 //
03432                 // Modify original_velocity so it parallels all of the clip planes
03433                 //
03434                 for (i=0 ; i<NumPlanes ; i++)
03435                 {
03436                         ReflectVelocity(&OriginalVelocity, &Planes[i], &NewVelocity, 1.0f);
03437 
03438                         for (j=0 ; j<NumPlanes ; j++)
03439                         {
03440                                 if (j != i)
03441                                 {
03442                                         if (geVec3d_DotProduct(&NewVelocity, &Planes[j]) < 0.0f)
03443                                                 break;  // not ok
03444                                 }
03445                         }
03446                         if (j == NumPlanes)
03447                                 break;
03448                 }
03449                 
03450                 if (i != NumPlanes)
03451                 {       // Go along this plane
03452                         geVec3d_Copy(&NewVelocity, &Player->Velocity);
03453                 }
03454                 else
03455                 {       // Go along the crease
03456                         if (NumPlanes != 2)
03457                         {
03458                                 //Console_Printf(Server->Host->Console, "Clip velocity, numplanes == %i\n",NumPlanes);
03459                                 geVec3d_Clear(&Player->Velocity);
03460                                 return GE_TRUE;
03461                         }
03462                         
03463                         //Console_Printf(Server->Host->Console, "Cross product\n",NumPlanes);
03464                         geVec3d_CrossProduct(&Planes[0], &Planes[1], &Dir);
03465                         Dist = geVec3d_DotProduct(&Dir, &Player->Velocity);
03466                         geVec3d_Scale(&Dir, Dist, &Player->Velocity);
03467                 }
03468 
03469                 //
03470                 // If original velocity is against the original velocity, stop dead
03471                 // to avoid tiny occilations in sloping corners
03472                 //
03473                 if (geVec3d_DotProduct (&Player->Velocity, &PrimalVelocity) <= 0.0f)
03474                 {
03475                         geVec3d_Clear(&Player->Velocity);
03476                         return GE_TRUE;
03477                 }
03478                 //
03479 
03480         }
03481         return GE_TRUE;                                                                 
03482 }
03483 
03484 
03485 //=====================================================================================
03486 //      Bot_Physics
03487 //=====================================================================================
03488 geBoolean Bot_Physics(GenVSI *VSI, void *PlayerData, float Time)
03489 {
03490         float   Speed;
03491         GPlayer *Player;
03492         Bot_Var                 *DBot;
03493     geBoolean ClearMove = GE_TRUE;
03494 
03495         Player = (GPlayer*)PlayerData;
03496         DBot = (Bot_Var*)Player->userData;
03497 
03498         // Walk
03499         Player->LastGoodPos = Player->XForm.Translation;
03500 
03501         // Add gravity
03502         // Add gravity
03503         switch (Player->State)
03504         {
03505                 case PSTATE_InLava:
03506                 case PSTATE_InWater:
03507                         Player->Velocity.Y -= BOT_GRAVITY*Time*0.05f;
03508                         break;
03509 
03510                 default:
03511                         Player->Velocity.Y -= BOT_GRAVITY*Time;
03512                         break;
03513         }
03514 
03515         ClearMove = Bot_CheckVelocity(VSI, Player, Time);
03516 
03517         SqueezeVector(&Player->Velocity, 0.2f);
03518         geVec3d_AddScaled(&Player->XForm.Translation, &Player->Velocity, Time, &Player->XForm.Translation);
03519 
03520         if (Bot_CheckPosition(VSI, Player))
03521         {
03522                 // think
03523                 geVec3d_Clear(&DBot->TgtPos);
03524         }
03525         
03526         Speed = geVec3d_Length(&Player->Velocity);
03527 
03528     // Note that this is changed from PlayerPhysics
03529     // Does the exact same thing - just simplified with algebra
03530         if (Speed > 0.001f)
03531         {
03532                 float   Scale;
03533 
03534                 if (Player->State == PSTATE_Normal || Player->State == PSTATE_DeadOnGround)
03535                         Scale = 1.0f-(Time*BOT_GROUND_FRICTION);
03536                 else if (Player->State == PSTATE_InAir || Player->State == PSTATE_Dead)
03537                         Scale = 1.0f-(Time*BOT_AIR_FRICTION);
03538                 else if (PlayerLiquid(Player))
03539                         Scale = 1.0f-(Time*BOT_LIQUID_FRICTION);
03540 
03541                 if (Scale < 0.0f)
03542                         Scale = 0.0f;
03543 
03544                 // Apply movement friction
03545                 geVec3d_Scale(&Player->Velocity, Scale, &Player->Velocity);
03546         }
03547 
03548         return ClearMove;
03549 }
03550 
03551 //=====================================================================================
03552 //      Bot_ScanPhysics
03553 //=====================================================================================
03554 geBoolean Bot_ScanPhysics(GenVSI *VSI, void *PlayerData, float Time)
03555 {
03556         GPlayer *Player;
03557         Bot_Var                 *DBot;
03558     geBoolean ClearMove = GE_TRUE;
03559 
03560         Player = (GPlayer*)PlayerData;
03561         DBot = (Bot_Var*)Player->userData;
03562 
03563         // Walk
03564         Player->LastGoodPos = Player->XForm.Translation;
03565 
03566         ClearMove = Bot_ScanCheckVelocity(VSI, Player, Time);
03567 
03568         SqueezeVector(&Player->Velocity, 0.2f);
03569         geVec3d_AddScaled(&Player->XForm.Translation, &Player->Velocity, Time, &Player->XForm.Translation);
03570 
03571         Bot_CheckPosition(VSI, Player);
03572         
03573         return ClearMove;
03574 }
03575 
03576 
03577 //=====================================================================================
03578 //      Bot_CheckPosition
03579 //=====================================================================================
03580 geBoolean Bot_CheckPosition(GenVSI *VSI, void *PlayerData)
03581 {
03582         geVec3d         Mins, Maxs, Pos;
03583         GE_Contents     Contents;
03584         GPlayer         *Player;
03585         Bot_Var                 *DBot;
03586         uint32          ColFlags;
03587 
03588         Player = (GPlayer*)PlayerData;
03589         DBot = (Bot_Var*)Player->userData;
03590 
03591         Mins = Player->Mins;
03592         Maxs = Player->Maxs;
03593 
03594         Pos = Player->XForm.Translation;
03595 
03596         ColFlags = GE_COLLIDE_MODELS;
03597 
03598         if (geWorld_GetContents(GenVSI_GetWorld(VSI), &Pos, &Mins, &Maxs, ColFlags, 0,  NULL, NULL, &Contents))
03599         {
03600                 if (Contents.Contents & GE_CONTENTS_SOLID)
03601                 {
03602                         Player->XForm.Translation = Player->LastGoodPos;
03603                         return GE_TRUE;
03604                 }
03605         }
03606 
03607         return GE_FALSE;
03608 }
03609 
03610 
03611 //=====================================================================================
03612 //      Bot_MoveScan
03613 //=====================================================================================
03614 geBoolean Bot_MoveScan(GenVSI *VSI, void *PlayerData, geVec3d *vec_dir, float dist, geVec3d *stop_pos)
03615 {
03616         GPlayer *Player;
03617         Bot_Var                 *DBot;
03618         geVec3d SaveVelocity, SaveGoodPos, Pos;
03619         geBoolean ret_val = GE_FALSE;
03620         int32 SaveState;
03621     float Time = 1.0f; // don't allow scaling by time
03622 
03623         Player = (GPlayer*)PlayerData;
03624         DBot = (Bot_Var*)Player->userData;
03625 
03626     // Save off values that will change
03627         Pos = Player->XForm.Translation;
03628     SaveVelocity = Player->Velocity;
03629     SaveGoodPos = Player->LastGoodPos;
03630     SaveState = Player->State;
03631 
03632     // New Velocity in this direction
03633     geVec3d_Scale(vec_dir, dist, &Player->Velocity);
03634 
03635     if (!Bot_ScanPhysics(VSI, Player, Time))
03636         {
03637         ret_val = GE_TRUE;
03638         }
03639 
03640     *stop_pos = Player->XForm.Translation;
03641 
03642     // Restore saved values
03643     Player->Velocity = SaveVelocity;
03644     Player->XForm.Translation = Pos;
03645     Player->LastGoodPos = SaveGoodPos;
03646     Player->State = SaveState;
03647 
03648         return ret_val;
03649 }
03650                 
03651 
03652 //=====================================================================================
03653 //      Bot_OverLedge
03654 //=====================================================================================
03655 geBoolean Bot_OverLedge(GenVSI *VSI, void *PlayerData, geVec3d *ScanPos)
03656 {
03657         GE_Collision Collision;
03658         geWorld                 *World;
03659         GPlayer *Player;
03660         Bot_Var                 *DBot;
03661         geVec3d Pos, Pos2;
03662         geBoolean ret_val;
03663         GE_Contents Contents;
03664         geVec3d Mins, Maxs;
03665 
03666         Player = (GPlayer*)PlayerData;
03667         DBot = (Bot_Var*)Player->userData;
03668 
03669         World = GenVSI_GetWorld(VSI);
03670 
03671         assert(World);
03672 
03673     if (Player->State == PSTATE_InAir)
03674         return GE_FALSE;
03675 
03676         Pos = *ScanPos;
03677         Pos2 = Pos;
03678 
03679         // Try and move down by this much
03680         Pos2.Y -= (100.0f - Player->Maxs.Y) + Player->Maxs.Y;
03681 
03682 #if 0
03683         Mins = RayMins;
03684         Maxs = RayMaxs;
03685         Mins.Y = Player->Mins.Y;
03686         Maxs.Y = Player->Maxs.Y;
03687 #else
03688         Mins = Player->Mins;
03689         Maxs = Player->Maxs;
03690         Mins.X /= 2.0f;
03691         Mins.Z /= 2.0f;
03692         Maxs.X /= 2.0f;
03693         Maxs.Z /= 2.0f;
03694 #endif
03695         
03696     // just use a ray with no size - not the player box
03697         ret_val = geWorld_Collision(World, &Mins, &Maxs,//&RayMins, &RayMaxs, 
03698                 &Pos, &Pos2, GE_CONTENTS_CANNOT_OCCUPY, GE_COLLIDE_MODELS, 0xffffffff, NULL, NULL, &Collision);
03699 
03700         World = GenVSI_GetWorld(VSI);
03701         if (geWorld_GetContents(World, &Collision.Impact, &Mins, &Maxs, GE_COLLIDE_MODELS, 0,  NULL, NULL, &Contents))
03702         {
03703                 if (Contents.Model)
03704                 {
03705                         GPlayer *TPlayer;
03706 
03707                         TPlayer = (GPlayer*)geWorld_ModelGetUserData(Contents.Model);
03708 
03709                         if (TPlayer && TPlayer->Trigger && TPlayer->ViewFlags & VIEW_TYPE_TOUCH)
03710                         {
03711                                 switch (TPlayer->Trigger(VSI, TPlayer, Player, NULL))
03712                                 {
03713 
03714                                         case 2:
03715                                                 return GE_TRUE;
03716                                         default:
03717                                                 break;
03718                                 }
03719                         }
03720                 }
03721         }
03722 
03723 
03724         if (!ret_val)
03725         {
03726                 return GE_TRUE;
03727         }       
03728 
03729         World = GenVSI_GetWorld(VSI);
03730         if (geWorld_GetContents(World, &Player->XForm.Translation, &Player->Mins, &Player->Maxs, GE_COLLIDE_MODELS, 0,  NULL, NULL, &Contents))
03731         {
03732                 if (Contents.Model)
03733                 {
03734                         GPlayer *TPlayer;
03735 
03736                         TPlayer = (GPlayer*)geWorld_ModelGetUserData(Contents.Model);
03737 
03738                         if (TPlayer && TPlayer->Trigger && TPlayer->ViewFlags & VIEW_TYPE_TOUCH)
03739                         {
03740                                 switch (TPlayer->Trigger(VSI, TPlayer, Player, NULL))
03741                                 {
03742                                         case 2:
03743                                                 return GE_TRUE;
03744                                         default:
03745                                                 break;
03746                                 }
03747                         }
03748                 }
03749         }
03750 
03751         return GE_FALSE;
03752 }
03753 
03754 
03755 //=====================================================================================
03756 //      Bot_OverLedgeScan
03757 //=====================================================================================
03758 geBoolean Bot_OverLedgeScan(GenVSI *VSI, void *PlayerData, const geVec3d *StartPos, const geVec3d *EndPos, geVec3d *StopPos)
03759 {
03760         GE_Collision Collision;
03761         geWorld                 *World;
03762         Bot_Var                 *DBot;
03763         geVec3d Pos, Pos2, Vec, LastGoodPos, Mins, Maxs;
03764         float len;
03765         int32 i;
03766         GPlayer *Player;
03767         geBoolean ret_val;
03768 
03769         Player = (GPlayer*)PlayerData;
03770         DBot = (Bot_Var*)Player->userData;
03771 
03772         World = GenVSI_GetWorld(VSI);
03773 
03774         assert(World);
03775 
03776     if (Player->State == PSTATE_InAir)
03777         return GE_FALSE;
03778 
03779         geVec3d_Subtract(EndPos, StartPos, &Vec);
03780         len = geVec3d_Length(&Vec);
03781         geVec3d_Normalize(&Vec);
03782         
03783         Mins = Player->Mins;
03784         Maxs = Player->Maxs;
03785         Mins.X /= 2.0f;
03786         Mins.Z /= 2.0f;
03787         Maxs.X /= 2.0f;
03788         Maxs.Z /= 2.0f;
03789 
03790         Pos = *StartPos;
03791 
03792         for (i = 4; i > 0; i--)
03793         {
03794                 LastGoodPos = Pos;
03795                 geVec3d_AddScaled(StartPos, &Vec, len/(i*2), &Pos);
03796         
03797                 Pos2 = Pos;
03798 
03799                 // Try and move down by this much
03800                 Pos2.Y -= 100.0f;
03801 
03802                 // just use a ray with no size - not the player box
03803                 ret_val = geWorld_Collision(World, &Mins, &Maxs, 
03804                         &Pos, &Pos2, GE_CONTENTS_CANNOT_OCCUPY, GE_COLLIDE_MODELS, 0xffffffff, NULL, NULL, &Collision);
03805 
03806                 if (!ret_val)
03807                         {
03808                         *StopPos = LastGoodPos;
03809                         return(GE_TRUE);
03810                         }
03811 
03812         }
03813 
03814         return GE_FALSE;
03815 }
03816     
03817 //=====================================================================================
03818 //      Bot_FindNewMoveVec
03819 //=====================================================================================
03820 geBoolean 
03821 Bot_FindNewMoveVec(GenVSI *VSI, void *PlayerData, const geVec3d *TargetPos, int32 dir, float DistToMove, geVec3d *save_vec)
03822     {
03823         GPlayer *Player;
03824         Bot_Var                 *DBot;
03825 
03826     static float toward_angle_delta[4][10] = 
03827         { 
03828         { -28.0f, -68.0f, 28.0f, 68.0f, -45.0f, 45.0f, -90.0f, 90.0f, -999.0f}, 
03829         //{ 0.0f, -28.0f, -68.0f, 28.0f, 68.0f, -45.0f, 45.0f, -90.0f, 90.0f, -999}.0f,  // This is pretty good for circle strafing
03830         { -18.0f, -28.0f, 18.0f, 28.0f, -45.0f, 45.0f, -90.0f, 90.0f, -999.0f}, 
03831         { 28.0f, 68.0f, -28.0f, -68.0f, 45.0f, -45.0f, 90.0f, -90.0f, -999.0f}, 
03832         { 18.0f, 28.0f, -18.0f, -28.0f, 45.0f, -45.0f, 90.0f, -90.0f, -999.0f}
03833         };
03834         
03835     static float away_angle_delta[4][10] = 
03836         { 
03837         //{ 180.0f, 135.0f, -112.0f, 112.0f, -157.0f, 157.0f, 180.0f, 45.0f, -45.0f, -999}.0f, 
03838         { -135.0f, 135.0f, -112.0f, 112.0f, -157.0f, 157.0f, 180.0f, -999.0f}, 
03839         { 135.0f, -135.0f, 112.0f, -112.0f, -157.0f, 157.0f, 180.0f, -999.0f}, 
03840         { 157.0f, -157.0f, -135.0f, 135.0f, -112.0f, 112.0f, 180.0f, -999.0f},
03841         { 157.0f, -157.0f, 135.0f, -135.0f, 112.0f, -112.0f, 180.0f, -999.0f}
03842         };
03843 
03844     static float evade_angle_delta[4][8] = 
03845         { 
03846         { 90.0f,  -90.0f, -112.0f, 112.0f, -68.0f, 68.0f,  45.0f,  -999.0f}, 
03847         { -90.0f,  90.0f,  68.0f, -68.0f, -112.0f, 112.0f, 135.0f, -999.0f}, 
03848         { 68.0f, -68.0f,  -112.0f, 112.0f, -90.0f, 90.0f,  45.0f,  -999.0f},
03849         { 68.0f,  90.0f,  -68.0f, -90.0f, 112.0f, -112.0f, 135.0f, -999.0f}
03850         };
03851         
03852     float *adp;
03853         
03854     geBoolean ret;
03855         geBoolean found = GE_FALSE;
03856         
03857     float dist;
03858     // start out with mininum distance that will be accepted as a move
03859     float save_dist = 25.0f;
03860 
03861         geVec3d Vec2Tgt;
03862         geVec3d Pos, TgtPos;
03863         geVec3d vec_dir, stop_pos, save_stop_pos;
03864         float Dist2TgtPos,NewDist2TgtPos;
03865 
03866         Player = (GPlayer*)PlayerData;
03867         DBot = (Bot_Var*)Player->userData;
03868 
03869         Pos = Player->XForm.Translation;
03870         TgtPos = *TargetPos;
03871         Dist2TgtPos = geVec3d_DistanceBetween(&TgtPos, &Pos);
03872 
03873         save_dist = Dist2TgtPos;
03874 
03875         // Find vector to the player
03876     geVec3d_Subtract(&TgtPos, &Pos, &Vec2Tgt);
03877         Vec2Tgt.Y = 0.0f;
03878     if (geVec3d_Length(&Vec2Tgt) == 0)
03879         Vec2Tgt.X = 1.0f;
03880 
03881         // choose a random angle array
03882         if (dir == BOT_DIR_TOWARD)
03883                 adp = &toward_angle_delta[RandomRange(4)][0];
03884         else
03885         if (dir == BOT_DIR_AWAY)
03886                 adp = &away_angle_delta[RandomRange(4)][0];
03887         else
03888         if (dir == BOT_DIR_NONE)
03889                 {
03890                 adp = &evade_angle_delta[RandomRange(4)][0];
03891                 save_dist = 20.0f;
03892                 }
03893 
03894         for (; *adp != -999; adp++)
03895                 {
03896                 Vec2Tgt.Y = 0.0f;
03897                 VectorRotateY(&Vec2Tgt, (*adp * (PI_2/360)), &vec_dir);
03898         vec_dir.Y = 0.0f;
03899                 geVec3d_Normalize(&vec_dir);
03900     
03901                 // check to see how far we can move
03902                 ret = Bot_MoveScan(VSI, Player, &vec_dir, DistToMove, &stop_pos);
03903 
03904                 NewDist2TgtPos = geVec3d_DistanceBetween(&TgtPos, &stop_pos);
03905 
03906                 dist = geVec3d_DistanceBetween(&Pos, &stop_pos);
03907 
03908                 // hit something really close
03909                 if (dist < 25.0f)
03910                         continue;
03911 
03912                 if (Bot_OverLedgeScan(VSI, Player, &Pos, &stop_pos, &stop_pos))
03913                         {
03914                         dist = geVec3d_DistanceBetween(&Pos, &stop_pos);
03915                         // hit something really close
03916                         if (dist < 25.0f)
03917                                 continue;
03918                         }
03919 
03920                 if (dir == BOT_DIR_TOWARD)
03921                         {
03922                         if (NewDist2TgtPos < save_dist)
03923                                 {
03924                                 save_stop_pos = stop_pos;
03925                                 *save_vec = vec_dir;
03926                                 save_dist = dist;
03927                                 found = GE_TRUE;
03928                                 }       
03929                         }
03930                 else
03931                 if (dir == BOT_DIR_AWAY)
03932                         {
03933                         if (NewDist2TgtPos > save_dist)
03934                                 {
03935                                 save_stop_pos = stop_pos;
03936                                 *save_vec = vec_dir;
03937                                 save_dist = dist;
03938                                 found = GE_TRUE;
03939                                 }       
03940                         }
03941                 else
03942                 if (dir == BOT_DIR_NONE)
03943                         {
03944                         if (dist > save_dist)
03945                                 {
03946                                 save_stop_pos = stop_pos;
03947                                 *save_vec = vec_dir;
03948                                 save_dist = dist;
03949                                 found = GE_TRUE;
03950                                 }       
03951                         }
03952 
03953                 if (ret == GE_FALSE)
03954                         {
03955                         // cleanly moved in new direction without hitting something
03956                         save_stop_pos = stop_pos;
03957                         found = GE_TRUE;
03958                         break;
03959                         }
03960                 }
03961 
03962         if (found)
03963         {
03964                 geVec3d Vec2Point;
03965                 
03966                 // gimme the actual vector to the stop point
03967                 geVec3d_Subtract(&save_stop_pos, &Pos, &Vec2Point);
03968                 Vec2Point.Y = 0.0f;
03969                 
03970                 // scale it so that its a little shorter and find new stop point
03971                 geVec3d_Scale(&Vec2Point, 0.8f, &Vec2Point);
03972                 geVec3d_Add(&Pos, &Vec2Point, &save_stop_pos);
03973                 
03974                 DBot->TgtPos = save_stop_pos;
03975         
03976                 return(GE_TRUE);
03977         }
03978 
03979     return(GE_FALSE);
03980     }
03981 
03982 
03983 //=====================================================================================
03984 //      Bot_PastPoint
03985 //=====================================================================================
03986 geBoolean Bot_PastPoint(geVec3d *Pos, geVec3d *MoveVector, geVec3d *TgtPos)
03987 {
03988         geVec3d Vec2Point, MoveVec = *MoveVector;
03989 
03990         // Temp hack
03991         if (geVec3d_Length(TgtPos) == 0.0f)
03992         {
03993         return GE_TRUE; 
03994         }
03995 
03996         // see if the bot went past the point
03997         geVec3d_Subtract(TgtPos, Pos, &Vec2Point);
03998 
03999         // make sure they are 2d for this test
04000     Vec2Point.Y = 0.0f;
04001         MoveVec.Y = 0.0f;
04002 
04003         geVec3d_Normalize(&Vec2Point);  
04004     geVec3d_Normalize(&MoveVec);        
04005 
04006         return (geVec3d_DotProduct(&Vec2Point, &MoveVec) < 0.0f);
04007 }       
04008 
04009 //=====================================================================================
04010 //      Bot_ShootFoot
04011 //=====================================================================================
04012 geBoolean Bot_ShootFoot(GenVSI *VSI, void *PlayerData, float Time)
04013 {
04014         GPlayer *Player = (GPlayer *)PlayerData;
04015         Bot_Var *DBot;
04016     geVec3d ShootPos, ShootVec;
04017         int16 wpn;
04018 
04019         DBot = (Bot_Var*)Player->userData;
04020 
04021         if (Player->Health < 100)
04022                 return GE_FALSE;
04023 
04024     // get the shooing position
04025     geVec3d_Scale(&DBot->MoveVec, 50.0f, &ShootVec);
04026     geVec3d_Add(&Player->XForm.Translation, &ShootVec, &ShootPos);
04027     ShootPos.Y = Player->XForm.Translation.Y - 50.0f;
04028 
04029     // force a shot here
04030         wpn = Player->CurrentWeapon;
04031         Bot_SetWeapon(VSI, Player, 0);
04032     Player->NextWeaponTime = GenVSI_GetTime(VSI) - 0.01f;
04033     Bot_Shoot(VSI, Player, &ShootPos, Time);
04034         Player->CurrentWeapon = wpn;
04035 
04036     return GE_TRUE;
04037 }
04038 
04039 //=====================================================================================
04040 //      Bot_Suicide
04041 //=====================================================================================
04042 geBoolean Bot_Suicide(GenVSI *VSI, void *PlayerData, float Time)
04043 {
04044         GPlayer *Player = (GPlayer *)PlayerData;
04045         Bot_Var *DBot;
04046     geVec3d ShootPos, ShootVec;
04047         int16 wpn;
04048 
04049         DBot = (Bot_Var*)Player->userData;
04050 
04051     // get the shooing position
04052     geVec3d_Scale(&DBot->MoveVec, 50.0f, &ShootVec);
04053     geVec3d_Add(&Player->XForm.Translation, &ShootVec, &ShootPos);
04054     ShootPos.Y = Player->XForm.Translation.Y - 50.0f;
04055 
04056     // force a shot here
04057         wpn = Player->CurrentWeapon;
04058         Bot_SetWeapon(VSI, Player, 0);
04059     Player->NextWeaponTime = GenVSI_GetTime(VSI) - 0.01f;
04060     Bot_Shoot(VSI, Player, &ShootPos, Time);
04061         Player->CurrentWeapon = wpn;
04062 
04063     return GE_TRUE;
04064 }
04065 
04066 
04067 //=====================================================================================
04068 //      Bot_MoveToPoint
04069 //=====================================================================================
04070 geBoolean Bot_MoveToPoint(GenVSI *VSI, void *PlayerData, float Time)
04071 {
04072         geVec3d                 Pos, TgtPlayerPos, Vec2Player;
04073         float                   MoveSpeed;
04074         GPlayer                 *Player;
04075         Bot_Var                 *DBot;
04076         geBoolean               ResetVelocity = GE_FALSE, BotShoot;
04077     TrackPt         *ThisPoint = NULL, *NextPoint = NULL;
04078     //int32                     DoAction;
04079         geWorld                 *World;
04080 
04081         World = GenVSI_GetWorld(VSI);
04082         assert(World);
04083 
04084         Player = (GPlayer*)PlayerData;
04085         assert(Player);
04086         DBot = (Bot_Var*)Player->userData;
04087     
04088 
04089         assert(DBot->TgtPlayer);
04090 
04091         // save off the position
04092     Pos = Player->XForm.Translation;
04093     TgtPlayerPos = DBot->TgtPlayer->XForm.Translation;
04094 
04095         geVec3d_Subtract(&TgtPlayerPos, &Pos, &Vec2Player);
04096 
04097         // decide whether to face player & shoot
04098         switch (DBot->Mode)
04099                 {
04100                 case MODE_UNSTICK:
04101                         BotShoot = FALSE;
04102                         Bot_SetupXForm(VSI, PlayerData, &Vec2Player);       //Face Player
04103                         break;
04104                 case MODE_RETREAT:
04105                 case MODE_RETREAT_ON_TRACK:
04106                         if (DBot->FaceTgtPlayerOnRetreat)
04107                                 {
04108                                 BotShoot = TRUE;
04109                                 Bot_SetupXForm(VSI, PlayerData, &Vec2Player);       //Face Player
04110                                 }
04111                         else
04112                                 {
04113                                 BotShoot = FALSE;
04114                                 Bot_SetupXForm(VSI, PlayerData, &DBot->MoveVec);     //Face run direction
04115                                 }
04116                         break;
04117                 case MODE_WANDER:
04118                 case MODE_WANDER_ON_TRACK:
04119                 //case MODE_GOAL_POINT:
04120                         BotShoot = FALSE;
04121                         Bot_SetupXForm(VSI, PlayerData, &DBot->MoveVec);     //Face run direction
04122                         break;
04123                 default:
04124                         BotShoot = TRUE;
04125                         Bot_SetupXForm(VSI, PlayerData, &Vec2Player);       //Face Player
04126                         break;
04127 
04128                 }
04129 
04130         MoveSpeed = Time;
04131 
04132         if (Player->State == PSTATE_InAir)
04133                 MoveSpeed *= 0.15f;
04134 
04135     #if 1
04136     //an attempt to counteract Velocity and zero in on the target position
04137         if (!Bot_PastPoint(&Player->XForm.Translation, &DBot->MoveVec, &DBot->TgtPos))
04138         {
04139         geVec3d save = DBot->MoveVec;
04140 
04141         // get a new MoveVec
04142             geVec3d_Subtract(&DBot->TgtPos, &Player->XForm.Translation, &DBot->MoveVec);
04143         DBot->MoveVec.Y = 0.0f;
04144             geVec3d_Normalize(&DBot->MoveVec);
04145 
04146         if (Bot_PastPoint(&Player->XForm.Translation, &DBot->MoveVec, &DBot->TgtPos))
04147             {
04148             DBot->MoveVec = save;
04149             }
04150         }
04151     #endif
04152 
04153         geVec3d_AddScaled(&Player->Velocity, &DBot->MoveVec, DBot->RunSpeed*MoveSpeed, &Player->Velocity);
04154         
04155     if (Track_OnTrack(&DBot->TrackInfo))
04156                 {
04157                 PlayerPhysics(VSI, Player, PLAYER_GROUND_FRICTION, PLAYER_AIR_FRICTION, PLAYER_LIQUID_FRICTION, PLAYER_GRAVITY, 1.0f, GE_FALSE, Time);
04158 
04159                 if (DBot->TrackInfoPrev.TrackNdx == DBot->TrackInfo.TrackNdx &&
04160                         Track_OnTrack(&DBot->TrackInfoPrev) && 
04161                         Track_GetPoint(&DBot->TrackInfoPrev)->Action != POINT_TYPE_WAIT_POINT_VISIBLE)
04162                         {
04163                         if (geVec3d_DistanceBetween(&Player->XForm.Translation, &Player->LastGoodPos) <= 5.0f)
04164                                 {
04165                                 // get off of track
04166                                 Bot_ClearTrack(VSI, Player);
04167                                 // pick another mode
04168                                 Bot_ModeChange(VSI, Player, MODE_NULL, GE_TRUE, Time);
04169                                 //if (Bot_ModeThink(VSI, Player, Time))  //If couldn't move try a new action
04170                                 return GE_TRUE;
04171                                 }
04172                         }
04173                 else
04174                         {
04175                         if (geVec3d_DistanceBetween(&Player->XForm.Translation, &Player->LastGoodPos) <= 0.5f)
04176                                 {
04177                                 // get off of track
04178                                 Bot_ClearTrack(VSI, Player);
04179                                 // pick another mode
04180                                 Bot_ModeChange(VSI, Player, MODE_NULL, GE_TRUE, Time);
04181                                 //if (Bot_ModeThink(VSI, Player, Time))  //If couldn't move try a new action
04182                                 return GE_TRUE;
04183                                 }
04184                         }
04185                 }
04186     else
04187         // Run physics code...
04188         if (!Bot_Physics(VSI, Player, Time))
04189         {
04190                 if (DBot->Bumps++ > 3)
04191                         {
04192                         DBot->Bumps = 0;
04193                         Bot_ModeChange(VSI, Player, MODE_UNSTICK, GE_TRUE, Time);
04194             return GE_TRUE;
04195                         }
04196 
04197         if (Bot_ModeThink(VSI, Player, Time))  //If couldn't move try a new action
04198             return GE_TRUE;
04199         }
04200         else
04201                 {
04202                 DBot->Bumps = 0;
04203                 }
04204 
04205         if (Player->State == PSTATE_Normal)
04206         {
04207             if (Bot_OverLedge(VSI, Player, &Player->XForm.Translation))
04208             {
04209                         if (DBot->LedgeBumps++ > 16)
04210                                 {
04211                                 DBot->LedgeBumps = 0;
04212                                 Bot_ModeChange(VSI, Player, MODE_UNSTICK, GE_TRUE, Time);
04213                                 return GE_TRUE;
04214                                 }
04215 
04216                         Bot_ModeThinkLedge(VSI, Player, Time);                                                                                                                                                                    
04217             }
04218                 else
04219                         DBot->LedgeBumps = 0;
04220             }
04221 
04222         Bot_GetContents(VSI, Player, Time);
04223 
04224         Bot_Animate(VSI, Player, Time);
04225 
04226         // shooting
04227         if (Player->State != PSTATE_InAir && 
04228         !PlayerDead(DBot->TgtPlayer) &&
04229                 BotShoot)
04230         //DBot->Dir != BOT_DIR_AWAY)
04231         {
04232         //if (Bot_CanSeePlayerToPlayer(World, &Player->XForm.Translation, &TgtPlayerPos))
04233         if (DBot->TimeSeen > 0.0f)
04234                 Bot_Shoot(VSI, Player, &TgtPlayerPos, Time);
04235         }
04236 
04237         //??bot
04238         Player->VPos = Player->XForm.Translation;
04239 
04240         // see about getting off of a path
04241         if (Bot_LeaveTrack(VSI, Player, Time))
04242         {
04243                 DBot->GoalPos = DBot->TgtPlayer->XForm.Translation;
04244                 Bot_ModeThink(VSI, PlayerData, Time);
04245                 return GE_TRUE;
04246             }
04247 
04248     // test current pos and MoveVec
04249     if (Bot_PastPoint(&Player->XForm.Translation, &DBot->MoveVec, &DBot->TgtPos))    
04250         {
04251             if (DBot->Mode == MODE_GOAL_POINT &&
04252             Bot_PastPoint(&Player->XForm.Translation, &DBot->MoveVec, &DBot->GoalPos))
04253             {
04254             // pick another mode
04255             Bot_ModeChange(VSI, Player, MODE_NULL, GE_TRUE, Time);
04256             return GE_TRUE;
04257             }
04258 
04259         if (!Track_OnTrack(&DBot->TrackInfo))
04260             {
04261                         // decide what to do next
04262             if (Bot_ModeThink(VSI, PlayerData, Time))
04263                 return GE_TRUE;
04264 
04265                         // last resort - just reposition
04266             Bot_Reposition(VSI, Player, &DBot->GoalPos, DBot->Dir);
04267             return GE_TRUE;
04268             }
04269 
04270                 // -=ON=- A TRACK PAST HERE
04271                 DBot->PastFirstTrackPoint = GE_TRUE;
04272 
04273             //if ((DBot->Mode == MODE_ON_TRACK || DBot->Mode == MODE_RETREAT_ON_TRACK) &&
04274             if (Track_OnTrack(&DBot->TrackInfo) &&
04275                         !Bot_PastPoint(&Player->XForm.Translation, &DBot->MoveVec, &DBot->GoalPos))
04276             {
04277             return GE_TRUE;
04278             }
04279     
04280         ThisPoint = Track_GetPoint(&DBot->TrackInfo);
04281 
04282                 DBot->TrackInfoPrev = DBot->TrackInfo;
04283         if (NextPoint = Track_NextPoint(&DBot->TrackInfo))
04284             {
04285             // if there is a next point - face that direction
04286             DBot->GoalPos = DBot->TgtPos = *NextPoint->Pos;
04287 
04288                     //geVec3d_Subtract(&DBot->TgtPos, &Player->XForm.Translation, &DBot->MoveVec);
04289                     geVec3d_Subtract(NextPoint->Pos, ThisPoint->Pos, &DBot->MoveVec);
04290             DBot->MoveVec.Y = 0.0f;
04291                     geVec3d_Normalize(&DBot->MoveVec);
04292             }
04293 
04294         if (Bot_TrackAction(VSI, Player, ThisPoint, NextPoint, Time))
04295             return GE_TRUE;
04296 
04297                 // Track was cleared?
04298                 if (!Track_OnTrack(&DBot->TrackInfo))
04299                         {
04300                         Bot_ModeChange(VSI, PlayerData, MODE_NULL, GE_FALSE, Time);
04301                         }
04302 
04303                 if (!NextPoint)
04304         {
04305                         // Finish Track will pop stack if necessary
04306             Bot_FinishTrack(VSI, Player);
04307                         // ONLY THINK IF YOU ARE DONE WITH THE STACK!
04308                         if (StackIsEmpty(&DBot->TrackStack))
04309                                 Bot_ModeThink(VSI, PlayerData, Time);
04310             return(GE_TRUE);
04311         }
04312 
04313         }
04314 
04315         return GE_TRUE;
04316 }
04317 
04318 //=====================================================================================
04319 //      Bot_MoveFree
04320 //=====================================================================================
04321 geBoolean Bot_MoveFree(GenVSI *VSI, void *PlayerData, float Time)
04322 {
04323         geVec3d                 Pos, TgtPlayerPos, Vec2Player;
04324         float                   MoveSpeed;
04325         GPlayer                 *Player;
04326         Bot_Var                 *DBot;
04327         geBoolean               ResetVelocity = GE_FALSE;
04328     TrackPt         *ThisPoint = NULL, *NextPoint = NULL;
04329         geWorld                 *World;
04330 
04331         World = GenVSI_GetWorld(VSI);
04332         assert(World);
04333 
04334         Player = (GPlayer*)PlayerData;
04335         assert(Player);
04336         DBot = (Bot_Var*)Player->userData;
04337 
04338         // save off the position
04339     Pos = Player->XForm.Translation;
04340     TgtPlayerPos = DBot->TgtPlayer->XForm.Translation;
04341 
04342         geVec3d_Subtract(&TgtPlayerPos, &Pos, &Vec2Player);
04343 
04344     Bot_SetupXForm(VSI, PlayerData, &DBot->MoveVec);     //Face run direction
04345 
04346         MoveSpeed = Time;
04347 
04348         if (Player->State == PSTATE_InAir)
04349                 MoveSpeed *= 0.15f;
04350         
04351         geVec3d_AddScaled(&Player->Velocity, &DBot->MoveVec, DBot->RunSpeed*MoveSpeed, &Player->Velocity);
04352         
04353         PlayerPhysics(VSI, Player, PLAYER_GROUND_FRICTION, PLAYER_AIR_FRICTION, PLAYER_LIQUID_FRICTION, PLAYER_GRAVITY, 1.0f, GE_FALSE, Time);
04354         if (geVec3d_DistanceBetween(&Player->XForm.Translation, &Player->LastGoodPos) <= 25.0f)
04355                 {
04356         // reposition again
04357         Bot_ModeThink(VSI, Player, Time);
04358                 return GE_TRUE;
04359                 }
04360 
04361         Bot_GetContents(VSI, Player, Time);
04362 
04363         Bot_Animate(VSI, Player, Time);
04364 
04365         //??bot
04366         Player->VPos = Player->XForm.Translation;
04367 
04368     // test current pos and MoveVec
04369     if (Bot_PastPoint(&Player->XForm.Translation, &DBot->MoveVec, &DBot->TgtPos))    
04370                 {
04371                 // decide what to do next
04372         if (Bot_ModeThink(VSI, PlayerData, Time))
04373             return GE_TRUE;
04374                 }
04375 
04376         return GE_TRUE;
04377 }
04378 
04379 
04380 //=====================================================================================
04381 //      Bot_ActionGetHealth
04382 //=====================================================================================
04383 geBoolean Bot_ActionGetHealth(GenVSI *VSI, void *PlayerData, float Range, float Time)
04384 {
04385     GPlayer *HealthItem;
04386         GPlayer         *Player;
04387         Bot_Var                 *DBot;
04388 
04389         Player = (GPlayer*)PlayerData;
04390         DBot = (Bot_Var*)Player->userData;
04391 
04392     if (HealthItem = Bot_FindItem(VSI, &Player->XForm.Translation, ItemHealthList, BOT_SEARCH_Y_RANGE, Range))
04393         {
04394                 DBot->GoalPos = HealthItem->Pos;
04395         Bot_InitMoveToPoint(VSI, Player, &DBot->GoalPos);
04396         Bot_ModeChange(VSI, Player, MODE_GOAL_POINT, GE_FALSE, Time);
04397                 Bot_ShootFoot(VSI, Player, Time);
04398         return GE_TRUE;
04399         }
04400 
04401 #if 0
04402         DBot->Dir = BOT_DIR_NONE;
04403 
04404     if (Bot_FindTrack(VSI, Player, HealthTrackList))
04405         {
04406                 DBot->GoalPos = Track_GetPoint(&DBot->TrackInfo)->Pos;
04407         Bot_InitMoveToPoint(VSI, Player, &DBot->GoalPos);
04408         return GE_TRUE;
04409         }
04410 #endif
04411 
04412     return GE_FALSE;
04413 }
04414 
04415 //=====================================================================================
04416 //      Bot_ActionGetWeapon
04417 //=====================================================================================
04418 geBoolean Bot_ActionGetWeapon(GenVSI *VSI, void *PlayerData, float Range, float Time)
04419 {
04420     GPlayer *WeaponItem;
04421         GPlayer         *Player;
04422         Bot_Var                 *DBot;
04423 
04424         Player = (GPlayer*)PlayerData;
04425         DBot = (Bot_Var*)Player->userData;
04426 
04427     if (WeaponItem = Bot_FindItem(VSI, &Player->XForm.Translation, ItemWeaponList, BOT_SEARCH_Y_RANGE, Range))
04428         {
04429                 DBot->GoalPos = WeaponItem->Pos;
04430         Bot_InitMoveToPoint(VSI, Player, &DBot->GoalPos);
04431         Bot_ModeChange(VSI, Player, MODE_GOAL_POINT, GE_FALSE, Time);
04432                 Bot_ShootFoot(VSI, Player, Time);
04433         return GE_TRUE;
04434         }
04435 
04436 #if 0
04437         DBot->Dir = BOT_DIR_NONE;
04438 
04439     if (Bot_FindTrack(VSI, Player, WeaponTrackList))
04440         {
04441                 DBot->GoalPos = Track_GetPoint(&DBot->TrackInfo)->Pos;
04442         Bot_InitMoveToPoint(VSI, Player, &DBot->GoalPos);
04443         return GE_TRUE;
04444         }
04445 #endif
04446 
04447     return GE_FALSE;
04448 }
04449 
04450 
04451 //=====================================================================================
04452 //      Bot_ChooseBestWeapon
04453 //=====================================================================================
04454 void Bot_ChooseBestWeapon(GenVSI *VSI, void *PlayerData)
04455 {
04456         int16                   i;
04457         GPlayer                 *Player;
04458         Bot_Var                 *DBot;
04459 
04460         Player = (GPlayer*)PlayerData;
04461         DBot = (Bot_Var*)Player->userData;
04462 
04463         for (i=3; i>=0; i--)
04464         {
04465         if (i == 0)
04466             {
04467             Player->CurrentWeapon = 0;
04468             break;
04469             }
04470 
04471                 if (Player->InventoryHas[i] && Player->Inventory[i] > 0)
04472             {
04473             Player->CurrentWeapon = i;
04474             break;
04475             }
04476         }
04477 
04478         assert(Player->CurrentWeapon >= 0 && Player->CurrentWeapon < 4);
04479 }
04480 
04481 //=====================================================================================
04482 //      Bot_SetWeapon
04483 //=====================================================================================
04484 geBoolean Bot_SetWeapon(GenVSI *VSI, void *PlayerData, int16 WeaponNum)
04485 {
04486         GPlayer                 *Player;
04487 
04488         Player = (GPlayer*)PlayerData;
04489 
04490         if (WeaponNum == 0)
04491                 {
04492                 Player->CurrentWeapon = WeaponNum;
04493                 return GE_TRUE;
04494                 }
04495 
04496         if (Player->CurrentWeapon < 0 || Player->CurrentWeapon > 3)
04497                 return GE_FALSE;
04498 
04499         if (Player->InventoryHas[WeaponNum] && Player->Inventory[WeaponNum] > 0)
04500         {
04501                 Player->CurrentWeapon = WeaponNum;
04502                 return GE_TRUE;
04503         }
04504 
04505         return GE_FALSE;
04506 }
04507 
04508 
04509 //=====================================================================================
04510 //      Bot_WeaponSetFromArray
04511 //=====================================================================================
04512 void Bot_WeaponSetFromArray(GenVSI *VSI, void *PlayerData, int32 *WeaponArr)
04513 {
04514         int32                   i;
04515         GPlayer                 *Player;
04516 
04517         Player = (GPlayer*)PlayerData;
04518 
04519         for (i=0; i < 4; i++)
04520         {
04521         if (WeaponArr[i] == 0)
04522             {
04523             Player->CurrentWeapon = 0;
04524             break;
04525             }
04526         
04527                 if (Player->InventoryHas[WeaponArr[i]] && Player->Inventory[WeaponArr[i]] > 0)
04528             {
04529             Player->CurrentWeapon = (int16)WeaponArr[i];
04530             break;
04531             }
04532         }
04533 
04534         assert(Player->CurrentWeapon >= 0 && Player->CurrentWeapon < 4);
04535 }
04536 
04537 
04538 //=====================================================================================
04539 //=====================================================================================
04540 //
04541 //      Bot Related Setup for the World and Game
04542 //
04543 //=====================================================================================
04544 //=====================================================================================
04545 
04546 
04547 
04548 //=====================================================================================
04549 //      Bot_Main
04550 //=====================================================================================
04551 geBoolean Bot_Main(GenVSI *VSI, const char *LevelName)
04552         {
04553 
04554         BotDeathMatchStart = NULL;
04555 
04556         GenVSI_SetClassSpawn(VSI, "BotMatchStart", Bot_MatchStart, NULL);
04557         GenVSI_SetClassSpawn(VSI, "BotActorStart", Bot_ActorStart, NULL);
04558         GenVSI_SetClassSpawn(VSI, "BlockActor", BlockActor_Spawn, NULL);
04559 
04560         return GE_TRUE;
04561         }
04562 
04563 
04564 //=====================================================================================
04565 //      BotMatch_Spawn
04566 //=====================================================================================
04567 geBoolean Bot_MatchStart(GenVSI *VSI, void *PlayerData, void *ClassData, char *EntityName)
04568 {
04569         BotMatchStart   *Ps;
04570         GPlayer                 *Player;
04571 
04572         Player = (GPlayer*)PlayerData;
04573 
04574         Player->Control = NULL;
04575         Player->Trigger = NULL;
04576         Player->Blocked = NULL;
04577         Player->Time = 0.0f;
04578 
04579         if (ClassData == NULL)
04580                 {
04581                         GenVS_Error("Bot_MatchStart: entity missing class data ('%s')\n",EntityName);
04582                 }
04583 
04584         Ps = (BotMatchStart*)ClassData;
04585 
04586         geXForm3d_SetIdentity(&Player->XForm);
04587         geXForm3d_SetTranslation(&Player->XForm, Ps->origin.X, Ps->origin.Y, Ps->origin.Z);
04588 
04589         Player->VPos = Player->XForm.Translation;
04590 
04591         return GE_TRUE;
04592 }
04593 
04594 
04595 //=====================================================================================
04596 //      GetBotMatchSpawn
04597 //=====================================================================================
04598 GPlayer *GetBotMatchSpawn(GenVSI *VSI)
04599 {
04600         extern int32    GMode;
04601 
04602         if (GMode == 0)
04603         {
04604                 BotDeathMatchStart = (GPlayer*)GenVSI_GetNextPlayer(VSI, BotDeathMatchStart, "BotMatchStart");
04605                            
04606                 if (!BotDeathMatchStart)
04607                         BotDeathMatchStart = (GPlayer*)GenVSI_GetNextPlayer(VSI, NULL, "BotMatchStart");
04608         }
04609         else
04610         {
04611                 BotDeathMatchStart = (GPlayer*)GenVSI_GetNextPlayer(VSI, BotDeathMatchStart, "BotDeathMatchStart");
04612                            
04613                 if (!BotDeathMatchStart)
04614                         BotDeathMatchStart = (GPlayer*)GenVSI_GetNextPlayer(VSI, NULL, "BotDeathMatchStart");
04615         }
04616 
04617         return BotDeathMatchStart;
04618 }
04619 
04620 //=====================================================================================
04621 //      Bot_Create
04622 //=====================================================================================
04623 void Bot_Create(GenVSI *VSI, void *PlayerData)
04624 {
04625         Bot_Var *DBot;
04626         GPlayer                 *Player;
04627 
04628         Player = (GPlayer*)PlayerData;
04629         assert(Player);
04630 
04631         Player->Control = Bot_Control;
04632         Player->DFunc = Bot_Destroy;
04633 
04634         if (!Player->userData)
04635         {
04636                 DBot = GE_RAM_ALLOCATE_STRUCT(Bot_Var);
04637                 assert(DBot);
04638                 Player->userData = (void *)DBot;
04639         }
04640                 
04641         memset(DBot, 0, sizeof(Bot_Var));
04642         DBot->RunSpeed = BOT_RUN_SPEED;
04643         DBot->Action = Bot_ModeThink;
04644     Bot_ClearTrack(VSI, Player);
04645         DBot->Dir = 1;
04646     StackInit(&DBot->TrackStack);
04647     //DBot->TOS = -1;
04648 }
04649 
04650 void Bot_SetLighting(GenVSI *VSI, void *PlayerData)
04651         {
04652         GPlayer                 *Player;
04653         geVec3d                 Normal = {0.0f, 1.0f, 0.0f};
04654 
04655         Player = (GPlayer*)PlayerData;
04656 
04657 /*
04658 GENESISAPI geBoolean GENESISCC geActor_SetLightingOptions(geActor *A,
04659                                                                         geBoolean UseFillLight,
04660                                                                         const geVec3d *FillLightNormal,
04661                                                                         geFloat FillLightRed,                           // 0 .. 255
04662                                                                         geFloat FillLightGreen,                         // 0 .. 255
04663                                                                         geFloat FillLightBlue,                          // 0 .. 255
04664                                                                         geFloat AmbientLightRed,                        // 0 .. 255
04665                                                                         geFloat AmbientLightGreen,                      // 0 .. 255
04666                                                                         geFloat AmbientLightBlue,                       // 0 .. 255
04667                                                                         geBoolean AmbientLightFromFloor,
04668                                                                         int MaximumDynamicLightsToUse,          // 0 for none
04669                                                                         const char *LightReferenceBoneName);
04670 */
04671         
04672         return;
04673 
04674         geActor_SetLightingOptions(Player->Actor, GE_TRUE, &Normal, 
04675                 155.0f, 155.0f, 155.0f, 
04676                 1.0f, 1.0f, 1.0f, 
04677                 GE_TRUE, 3, NULL, GE_FALSE);
04678         }
04679 
04680 
04681 //=====================================================================================
04682 //      Game_SpawnBot
04683 //=====================================================================================
04684 geBoolean Game_SpawnBot(GenVSI *VSI, geWorld *World, void *PlayerData, void *ClassData)
04685 {
04686         int32                   i;
04687         GPlayer                 *DMStart;
04688         GPlayer                 *Player;
04689         geVec3d                 Normal = {0.0f, 1.0f, 0.0f};
04690 
04691         Player = (GPlayer*)PlayerData;
04692 
04693         // Get a DM start
04694         DMStart = GetBotMatchSpawn(VSI);
04695         if (!DMStart)
04696                 {
04697                 //GenVSI_ConsoleHeaderPrintf(VSI, DBot->TgtPlayer->ClientHandle, GE_TRUE, "No Bot spawn positions exist.");
04698                 GenVSI_ClientDisconnect(VSI, Player->ClientHandle);
04699                 return GE_TRUE;
04700                 }
04701         
04702         Player->XForm = DMStart->XForm;
04703 
04704         Player->Time = 0.0f;
04705 
04706         Player->Scale = 2.7f;   
04707         
04708         Player->Mins.X = -30.0f;
04709         Player->Mins.Y = -10.0f;
04710         Player->Mins.Z = -30.0f;
04711         Player->Maxs.X =  30.0f;
04712         Player->Maxs.Y = 160.0f;
04713         Player->Maxs.Z =  30.0f;
04714 
04715         Player->GunOffset.X = 0.0f;
04716         Player->GunOffset.Y = 130.0f;
04717         Player->GunOffset.Z = 0.0f;
04718 
04719         // Set the view info
04720         Player->ViewFlags = VIEW_TYPE_ACTOR | VIEW_TYPE_YAW_ONLY | VIEW_TYPE_COLLIDEMODEL;
04721         Player->ViewIndex = ACTOR_INDEX_PLAYER;
04722         Player->MotionIndex = ACTOR_MOTION_PLAYER_RUN;
04723         Player->DammageFlags = DAMMAGE_TYPE_NORMAL | DAMMAGE_TYPE_RADIUS;       
04724 
04725 
04726         // Hook player up to client physics controller
04727         Player->ControlIndex = 0;
04728         Player->DFunc = (void*)Bot_Destroy;
04729 
04730         Bot_Create(VSI, Player);
04731 
04732         // Set the view player on this machine to the clients player
04733         // !Important! - don't set the player view to the bot
04734         //GenVSI_SetViewPlayer(VSI, ClientHandle, Player);
04735 
04736         // Players keep track of scoring, health, etc for now.
04737         // Server_SetClientScore/Health must be called to update a particular client
04738         // that is associated with a player...
04739 
04740         Player->Health = 100;
04741         Player->Score = 0;
04742 
04743 
04744         // FIXME:  Soon, Scores, Health, etc won't be so arbitrary.  Maybe somthing like
04745         // Quake2's Layouts will be used instead, making it easier to make games that don't
04746         // use this sort of scoring system...
04747         GenVSI_SetClientScore(VSI, Player->ClientHandle, Player->Score);
04748         GenVSI_SetClientHealth(VSI, Player->ClientHandle, Player->Health);
04749 
04750         for (i=0; i< MAX_PLAYER_ITEMS; i++)
04751         {
04752                 Player->Inventory[i] = 0;
04753                 Player->InventoryHas[i] = GE_FALSE;
04754         }
04755 
04756         Player->CurrentWeapon = 0;
04757         
04758         GenVSI_SetClientInventory(VSI, Player->ClientHandle, ITEM_GRENADES, 0, GE_FALSE);
04759         GenVSI_SetClientInventory(VSI, Player->ClientHandle, ITEM_ROCKETS, 0, GE_FALSE);
04760         GenVSI_SetClientInventory(VSI, Player->ClientHandle, ITEM_SHREDDER, 0, GE_FALSE);
04761 
04762         Player->NextWeaponTime = 0.0f;
04763 
04764         return GE_TRUE;
04765 }
04766 
04767 //=====================================================================================
04768 //      Bot_IsActorRespawn
04769 //=====================================================================================
04770 geBoolean Bot_IsActorRespawn(GenVSI *VSI, void *PlayerData)
04771 {
04772         geEntity_EntitySet      *ClassSet;
04773         geEntity                        *Entity;
04774         BotActorStart           *Bs;
04775         GPlayer                         *Player;
04776         geWorld                         *World;
04777         
04778         Player = (GPlayer*)PlayerData;
04779 
04780         World = GenVSI_GetWorld(VSI);
04781         assert(World);
04782 
04783         // Look for the class name in the world
04784         ClassSet = geWorld_GetEntitySet(World, "BotActorStart");
04785     if (!ClassSet)
04786         return GE_FALSE;
04787 
04788         Entity = NULL;
04789 
04790         while (1)
04791         {
04792                 Entity = geEntity_EntitySetGetNextEntity(ClassSet, Entity);
04793 
04794                 if (!Entity)
04795                         break;
04796 
04797                 Bs = (BotActorStart*)geEntity_GetUserData(Entity);
04798 
04799                 if ((GPlayer*)Bs->Ptr == Player)
04800                 {
04801                         return(Bs->Respawn);
04802                 }
04803         }
04804 
04805         return(GE_FALSE);
04806 
04807 }
04808 
04809 //=====================================================================================
04810 //      Bot_GetActorStart
04811 //=====================================================================================
04812 BotActorStart *Bot_GetActorStart(GenVSI *VSI, void *PlayerData)
04813 {
04814         geEntity_EntitySet      *ClassSet;
04815         geEntity                        *Entity;
04816         BotActorStart           *Bs;
04817         GPlayer                         *Player;
04818         geWorld                         *World;
04819         
04820         Player = (GPlayer*)PlayerData;
04821 
04822         World = GenVSI_GetWorld(VSI);
04823         assert(World);
04824 
04825         // Look for the class name in the world
04826         ClassSet = geWorld_GetEntitySet(World, "BotActorStart");
04827     if (!ClassSet)
04828         return GE_FALSE;
04829 
04830         Entity = NULL;
04831 
04832         while (1)
04833         {
04834                 Entity = geEntity_EntitySetGetNextEntity(ClassSet, Entity);
04835 
04836                 if (!Entity)
04837                         break;
04838 
04839                 Bs = (BotActorStart*)geEntity_GetUserData(Entity);
04840 
04841                 if ((GPlayer*)Bs->Ptr == Player)
04842                 {
04843                         return(Bs);
04844                 }
04845         }
04846 
04847         return(NULL);
04848 
04849 }
04850 
04851 
04852 //=====================================================================================
04853 //      Bot_ActorStart
04854 //=====================================================================================
04855 geBoolean Bot_ActorStart(GenVSI *VSI, void *PlayerData, void *ClassData, char *EntityName)
04856 {
04857         int32                   i;
04858         GPlayer                 *Player;
04859         BotActorStart   *Start;
04860         Bot_Var                 *DBot;
04861 
04862         if (ClassData == NULL)
04863                 {
04864                         GenVS_Error("Bot_ActorStart: entity missing class data ('%s')\n",EntityName);
04865                 }
04866 
04867         Start = (BotActorStart*)ClassData;
04868 
04869         Player = (GPlayer*)GenVSI_SpawnPlayer(VSI, "Bot_Actor");
04870 
04871         Start->Ptr = (char*)(Player); //link to entity - sort of hacky
04872 
04873         //Player->XForm = Start->XForm;
04874         geXForm3d_SetIdentity(&Player->XForm);
04875         geXForm3d_SetTranslation(&Player->XForm, Start->origin.X, Start->origin.Y, Start->origin.Z);
04876 
04877         Player->Time = 0.0f;
04878 
04879         Player->Scale = 2.7f;   
04880 
04881         Player->Mins.X = -30.0f;
04882         Player->Mins.Y = -10.0f;
04883         Player->Mins.Z = -30.0f;
04884         Player->Maxs.X =  30.0f;
04885         Player->Maxs.Y = 160.0f;
04886         Player->Maxs.Z =  30.0f;
04887 
04888         Player->GunOffset.X = 0.0f;
04889         Player->GunOffset.Y = 130.0f;
04890         Player->GunOffset.Z = 0.0f;
04891 
04892         // Set the view info
04893         Player->ViewFlags = VIEW_TYPE_ACTOR | VIEW_TYPE_YAW_ONLY | VIEW_TYPE_COLLIDEMODEL;
04894         Player->ViewIndex = ACTOR_INDEX_PLAYER;
04895         Player->MotionIndex = ACTOR_MOTION_PLAYER_RUN;
04896         Player->DammageFlags = DAMMAGE_TYPE_NORMAL | DAMMAGE_TYPE_RADIUS;       
04897 
04898         // Hook player up to client physics controller
04899         Player->ControlIndex = 0;
04900         Player->DFunc = (void*)Bot_Destroy;
04901 
04902         Bot_Create(VSI, Player);
04903         //Player->Control = Bot_MoveToPoint;
04904         Player->Control = Bot_Control;
04905         DBot = (Bot_Var*)Player->userData;
04906 
04907         DBot->BotType = 1;
04908 
04909         Player->Health = 100;
04910         Player->Score = 0;
04911 
04912         // FIXME:  Soon, Scores, Health, etc won't be so arbitrary.  Maybe somthing like
04913         // Quake2's Layouts will be used instead, making it easier to make games that don't
04914         // use this sort of scoring system...
04915         //GenVSI_SetClientScore(VSI, Player->ClientHandle, Player->Score);
04916         //GenVSI_SetClientHealth(VSI, Player->ClientHandle, Player->Health);
04917 
04918         for (i=0; i< MAX_PLAYER_ITEMS; i++)
04919         {
04920                 Player->Inventory[i] = 0;
04921                 Player->InventoryHas[i] = GE_FALSE;
04922         }
04923 
04924         Player->CurrentWeapon = 0;
04925         
04926         //GenVSI_SetClientInventory(VSI, Player->ClientHandle, ITEM_GRENADES, 0, GE_FALSE);
04927         //GenVSI_SetClientInventory(VSI, Player->ClientHandle, ITEM_ROCKETS, 0, GE_FALSE);
04928         //GenVSI_SetClientInventory(VSI, Player->ClientHandle, ITEM_SHREDDER, 0, GE_FALSE);
04929 
04930         Player->NextWeaponTime = 0.0f;
04931 
04932         return GE_TRUE;
04933 }
04934 
04935 
04936 //=====================================================================================
04937 //      BlockActor_Trigger
04938 //=====================================================================================
04939 geBoolean BlockActor_Trigger(GenVSI *VSI, void *PlayerData, void *TargetData, void *Data)
04940 {
04941         GPlayer *Player = (GPlayer*)PlayerData;
04942 
04943         //if (strcmp(Player->ClassName,"Bot_Actor") == 0)
04944                 return(2);
04945 
04946         return GE_FALSE;
04947 }
04948 
04949 
04950 //=====================================================================================
04951 //      BlockActor_Spawn
04952 //=====================================================================================
04953 geBoolean BlockActor_Spawn(GenVSI *VSI, void *PlayerData, void *ClassData, char *EntityName)
04954 {
04955         BlockActor              *Ba;
04956         GPlayer                 *Player;
04957 
04958         Player = (GPlayer*)PlayerData;
04959 
04960         Player->Control = NULL;
04961         Player->Trigger = BlockActor_Trigger;
04962         Player->Blocked = NULL;
04963         Player->Time = 0.0f;
04964         Player->ViewFlags = VIEW_TYPE_NONE | VIEW_TYPE_TOUCH;
04965 
04966         if (ClassData == NULL)
04967                 {
04968                         GenVS_Error("BlockActor_Spawn: entity missing class data ('%s')\n",EntityName);
04969                 }
04970 
04971         Ba = (BlockActor*)ClassData;
04972 
04973         geXForm3d_SetIdentity(&Player->XForm);
04974         geXForm3d_SetTranslation(&Player->XForm, Ba->Origin.X, Ba->Origin.Y, Ba->Origin.Z);
04975 
04976         Player->VPos = Player->XForm.Translation;
04977 
04978         GenVSI_RegisterPlayerModel(VSI, Player, Ba->Model);
04979 
04980         return GE_TRUE;
04981 }
04982 
04983 //=====================================================================================
04984 //=====================================================================================
04985 //
04986 //      Bot Health/Weapon/Dist comparisons
04987 //
04988 //=====================================================================================
04989 //=====================================================================================
04990 
04991 //=====================================================================================
04992 //      Bot_RankWeapons
04993 //=====================================================================================
04994 int32 Bot_RankWeapons(GenVSI *VSI, void *PlayerData)
04995 {
04996         GPlayer *Player;
04997         int32 Strength = 0;
04998         int32 amt;
04999 
05000         Player = PlayerData;
05001 
05002         if (Player->InventoryHas[ITEM_SHREDDER] && Player->Inventory[ITEM_SHREDDER] > 100)
05003                 {
05004                 amt = Player->Inventory[ITEM_SHREDDER];
05005                 amt = min(amt, 100);
05006                 Strength += (int32)(amt * (60.0f/100.0f));
05007                 }
05008 
05009         if (Player->InventoryHas[ITEM_GRENADES] && Player->Inventory[ITEM_GRENADES] > 3)
05010                 {
05011                 amt = Player->Inventory[ITEM_GRENADES];
05012                 amt = min(amt, 5);
05013                 Strength += (int32)(amt * (15.0f/5.0f));
05014                 }
05015 
05016         if (Player->InventoryHas[ITEM_ROCKETS] && Player->Inventory[ITEM_ROCKETS] > 4)
05017                 {
05018                 amt = Player->Inventory[ITEM_ROCKETS];
05019                 amt = min(amt, 10);
05020                 Strength += (int32)(amt * (35.0f/10.0f));
05021                 }
05022 
05023         return Strength;
05024 }
05025 
05026 //=====================================================================================
05027 //      Bot_CompareWeapons
05028 //=====================================================================================
05029 int32 Bot_CompareWeapons(GenVSI *VSI, void *PlayerData, void *TgtPlayerData)
05030         {
05031         int32 d1, d2;
05032 
05033         d1 = Bot_RankWeapons(VSI, PlayerData);
05034         d2 = Bot_RankWeapons(VSI, TgtPlayerData);
05035 
05036         return d1 - d2;
05037         }
05038 
05039 //=====================================================================================
05040 //      Bot_GetRangeIndex
05041 //=====================================================================================
05042 int32 Bot_GetRangeIndex(GenVSI *VSI, void *PlayerData)
05043         {
05044         int32 index;
05045         GPlayer                 *Player;
05046         Bot_Var                 *DBot;
05047         float                   Dist;
05048 
05049         Player = (GPlayer*)PlayerData;
05050         DBot = (Bot_Var*)Player->userData;
05051 
05052         Dist = geVec3d_DistanceBetween(&Player->XForm.Translation, &DBot->TgtPlayer->XForm.Translation);
05053 
05054         if (Dist <= CLOSE_RANGE_DIST)
05055                 index = CLOSE_RANGE;
05056         else
05057         if (Dist <= MED_RANGE_DIST)
05058                 index = MED_RANGE;
05059         else
05060                 index = LONG_RANGE;
05061 
05062         return index;
05063         }
05064 
05065 //=====================================================================================
05066 //      Bot_GetStrengthIndex
05067 //=====================================================================================
05068 int32 Bot_GetStrengthIndex(GenVSI *VSI, void *PlayerData)
05069         {
05070         int32 index;
05071         GPlayer                 *Player;
05072         Bot_Var                 *DBot;
05073 
05074         Player = (GPlayer*)PlayerData;
05075         DBot = (Bot_Var*)Player->userData;
05076 
05077         // health assessment
05078     DBot->HealthDiff = Player->Health - DBot->TgtPlayer->Health;
05079         // weapon assessment
05080         DBot->WeaponDiff = Bot_CompareWeapons(VSI, Player, DBot->TgtPlayer);
05081 
05082         if (BOT_STRENGTH_HIGH(DBot->HealthDiff, DBot->WeaponDiff))
05083                 index = 2;
05084         else
05085         if (BOT_STRENGTH_LOW(DBot->HealthDiff, DBot->WeaponDiff))
05086                 index = 0;
05087         else
05088                 index = 1;
05089 
05090         return index;
05091         }
05092 
05093 //=====================================================================================
05094 //      Bot_GetRank
05095 //=====================================================================================
05096 int32 Bot_GetRank(GenVSI *VSI, void *PlayerData)
05097     {
05098     int32 RNdx,SNdx,Rank;
05099         GPlayer                 *Player;
05100 
05101         Player = (GPlayer*)PlayerData;
05102 
05103         RNdx = Bot_GetRangeIndex(VSI, Player);
05104         SNdx = Bot_GetStrengthIndex(VSI, Player);
05105         Rank = RankTable[RNdx][SNdx];
05106 
05107     return Rank;
05108     }
05109 
05110 //=====================================================================================
05111 //=====================================================================================
05112 //
05113 //      Bot Track Related
05114 //
05115 //=====================================================================================
05116 //=====================================================================================
05117 
05118 //=====================================================================================
05119 //      Bot_FindTrackToGoal
05120 //=====================================================================================
05121 Track *Bot_FindTrackToGoal(GenVSI *VSI, void *PlayerData, float Time)
05122     {
05123     Track *track;
05124     int32 *type;
05125     float ydiff;
05126         TrackData TrackInfo;
05127 
05128         geVec3d                 Pos, TgtPos;
05129         GPlayer                 *Player;
05130         Bot_Var                 *DBot;
05131 
05132     static int32 Away[] =
05133         {
05134         TRACK_TYPE_UP,
05135         TRACK_TYPE_DOWN,
05136                 TRACK_TYPE_ELEVATOR_UP,
05137                 TRACK_TYPE_ELEVATOR_DOWN,
05138         TRACK_TYPE_TRAVERSE,
05139         TRACK_TYPE_TRAVERSE_ONEWAY,
05140         TRACK_TYPE_EXIT,
05141         TRACK_TYPE_TRAVERSE_DOOR,
05142                 -1
05143         };
05144 
05145     static int32 PlayerAbove[] =
05146         {
05147         TRACK_TYPE_UP,
05148                 TRACK_TYPE_ELEVATOR_UP,
05149         TRACK_TYPE_TRAVERSE,
05150         TRACK_TYPE_TRAVERSE_ONEWAY,
05151                 -1
05152         };
05153 
05154     static int32 PlayerBelow[] =
05155         {
05156         TRACK_TYPE_DOWN,
05157                 TRACK_TYPE_ELEVATOR_DOWN,
05158         TRACK_TYPE_TRAVERSE,
05159         TRACK_TYPE_TRAVERSE_ONEWAY,
05160                 -1
05161         };
05162 
05163     static int32 PlayerOnLevel[] =
05164         {
05165         TRACK_TYPE_TRAVERSE,
05166         TRACK_TYPE_TRAVERSE_ONEWAY,
05167         TRACK_TYPE_EXIT,
05168         TRACK_TYPE_TRAVERSE_DOOR,
05169                 -1
05170         };
05171 
05172     geWorld *World;
05173 
05174     World = GenVSI_GetWorld(VSI);
05175 
05176         Player = (GPlayer*)PlayerData;
05177         assert(Player);
05178         DBot = (Bot_Var*)Player->userData;
05179 
05180         Pos = Player->XForm.Translation;
05181         TgtPos = DBot->GoalPos;
05182 
05183     ydiff = TgtPos.Y - Pos.Y;
05184 
05185         if (DBot->Dir == BOT_DIR_TOWARD)
05186                 {
05187                 if (fabs(ydiff) <= BOT_SEARCH_Y_RANGE)
05188                         type = PlayerOnLevel;
05189                 else
05190                         {
05191                         if (ydiff < 0.0f)
05192                                 type = PlayerBelow;
05193                         else
05194                                 type = PlayerAbove;
05195                         }
05196                 }
05197         else
05198         if (DBot->Dir == BOT_DIR_AWAY)
05199                 {
05200                 type = Away;
05201                 }
05202         if (DBot->Dir == BOT_DIR_NONE)
05203                 {
05204                 type = Away;
05205                 }
05206 
05207         Track_ClearTrack(&TrackInfo);
05208         while (1)
05209         {
05210                 track = Track_FindTrack(VSI, &Pos, &TgtPos, DBot->Dir, type, &TrackInfo);
05211 
05212                 if (!track)
05213                         return NULL;
05214 
05215                 if (Bot_ValidateTrackPoints(VSI, Player, track))
05216                 {
05217                         // can't add the same track!
05218                         if (StackTop(&DBot->TrackStack) == TrackInfo.TrackNdx)
05219                                 continue;
05220 
05221                         DBot->TrackInfo = TrackInfo;
05222                         StackPush(&DBot->TrackStack, DBot->TrackInfo.TrackNdx);
05223                         DBot->PastFirstTrackPoint = GE_FALSE;
05224 
05225                         return (track);
05226                 }
05227         }
05228 
05229     return NULL;
05230     }
05231 
05232 //=====================================================================================
05233 //      Bot_ValidateTrackPoints
05234 //=====================================================================================
05235 geBoolean Bot_ValidateTrackPoints(GenVSI *VSI, void *PlayerData, Track* t)
05236 {
05237         GPlayer *Player;
05238         TrackPt *tp;
05239 
05240         Player = (GPlayer*)PlayerData;
05241 
05242     for (tp = t->PointList; tp < &t->PointList[t->PointCount]; tp++)
05243         {
05244                 switch (tp->Action)
05245                         {
05246                         case POINT_TYPE_WAIT_POINT_VISIBLE:
05247                                 break;
05248 
05249                         case POINT_TYPE_LOOK_FOR_ITEMS:
05250                                 {
05251                                 GPlayer *HealthItem;
05252                                 GPlayer *WeaponItem;
05253 
05254                                 if (!(HealthItem = Bot_FindItem(VSI, tp->Pos, ItemHealthList, BOT_SEARCH_Y_RANGE, 1000.0f)))
05255                                         return GE_FALSE;
05256 
05257                                 if (!(WeaponItem = Bot_FindItem(VSI, tp->Pos, ItemWeaponList, BOT_SEARCH_Y_RANGE, 1000.0f)))
05258                                         return GE_FALSE;
05259 
05260                                 break;
05261                                 }
05262 
05263                         case POINT_TYPE_ROCKET_JUMP:
05264 
05265                                 if (!Player->InventoryHas[ITEM_ROCKETS] || Player->Inventory[ITEM_ROCKETS] <= 0)
05266                                         return GE_FALSE;
05267 
05268                                 if (Player->Health < 35)
05269                                         return GE_FALSE;
05270 
05271                                 break;
05272 
05273 
05274                         #if 0
05275                         case POINT_TYPE_SHOOT_BLASTER:
05276                         case POINT_TYPE_SHOOT_GRENADE:
05277                         case POINT_TYPE_SHOOT_ROCKET:
05278                         case POINT_TYPE_SHOOT_SHREDDER:
05279                 {
05280                 geVec3d ShootPos;
05281                 geVec3d Pos;
05282                                 int32 wpn_num
05283                                 int32 NumShots = ThisPoint->ShootTimes;
05284 
05285                                 wpn_num = ThisPoint->ActionType - POINT_TYPE_SHOOT_BLASTER;
05286 
05287                                 if (wpn_num == POINT_TYPE_SHOOT_BLASTER) // unlimited ammo
05288                                         break;
05289 
05290                                 if (Player->Inventory[wpn_num] >= NumShots && Player->InventoryHas[wpn_num])
05291                                         break;
05292 
05293                                 return GE_FALSE;
05294                         #endif
05295                         }
05296         }
05297 
05298         return GE_TRUE;
05299 }
05300 
05301 //=====================================================================================
05302 //      Bot_ValidateMultiTrackPoints
05303 //=====================================================================================
05304 geBoolean Bot_ValidateMultiTrackPoints(GenVSI *VSI, void *PlayerData, Track* t)
05305 {
05306         GPlayer *Player;
05307         TrackPt *tp;
05308 
05309         Player = (GPlayer*)PlayerData;
05310 
05311     for (tp = t->PointList; tp < &t->PointList[t->PointCount]; tp++)
05312         {
05313                 switch (tp->Action)
05314                         {
05315                         case POINT_TYPE_WAIT_FOR_PLAYER: // no hiding on multi-tracks
05316                                 return GE_FALSE;
05317 
05318                         case POINT_TYPE_LOOK_FOR_ITEMS:
05319                                 return GE_FALSE;
05320 
05321                         case POINT_TYPE_ROCKET_JUMP:
05322 
05323                                 if (!Player->InventoryHas[ITEM_ROCKETS] || Player->Inventory[ITEM_ROCKETS] <= 0)
05324                                         return GE_FALSE;
05325         
05326                                 if (Player->Health < 35)
05327                                         return GE_FALSE;
05328 
05329                                 break;
05330 
05331                         }
05332         }
05333 
05334         return GE_TRUE;
05335 }
05336 
05337 
05338 //=====================================================================================
05339 //      Bot_FindTrack
05340 //=====================================================================================
05341 Track *Bot_FindTrack(GenVSI *VSI, void *PlayerData, int32 TrackArr[])
05342     {
05343     Track *track;
05344         TrackData TrackInfo;
05345     
05346         geVec3d                 Pos, TgtPos;
05347         GPlayer                 *Player;
05348         Bot_Var                 *DBot;
05349 
05350     geWorld *World;
05351 
05352     World = GenVSI_GetWorld(VSI);
05353 
05354         Player = (GPlayer*)PlayerData;
05355         assert(Player);
05356         DBot = (Bot_Var*)Player->userData;
05357 
05358         Pos = Player->XForm.Translation;
05359         TgtPos = DBot->GoalPos;
05360 
05361         Track_ClearTrack(&TrackInfo);
05362         while (1)
05363                 {
05364             track = Track_FindTrack(VSI, &Pos, &TgtPos, 0, TrackArr, &TrackInfo);
05365 
05366                 if (!track)
05367                         break;
05368 
05369                 if (Bot_ValidateTrackPoints(VSI, Player, track))
05370                         {
05371                         // can't add the same track!
05372                         if (StackTop(&DBot->TrackStack) == TrackInfo.TrackNdx)
05373                         continue;
05374 
05375                         DBot->TrackInfo = TrackInfo;
05376                         StackPush(&DBot->TrackStack, DBot->TrackInfo.TrackNdx);
05377                         DBot->PastFirstTrackPoint = GE_FALSE;
05378                         return (track);
05379                         }
05380                 }
05381 
05382     return (NULL);
05383     }
05384 
05385 geBoolean Bot_TrackAction(GenVSI *VSI, void *PlayerData, const TrackPt* ThisPoint, const TrackPt* NextPoint, float Time)
05386     {
05387         GPlayer                 *Player;
05388     Bot_Var         *DBot;
05389     int32           DoAction;
05390 
05391     Player = PlayerData;
05392     DBot = Player->userData;
05393 
05394     DoAction = ThisPoint->Action;
05395 
05396     // make sure your going the right direction
05397     if (ThisPoint->ActionDir != 0 && ThisPoint->ActionDir != Track_GetDir(&DBot->TrackInfo))
05398         DoAction = -1;
05399 
05400     switch (DoAction)
05401         {
05402         case POINT_TYPE_JUMP:
05403                     {
05404                     float sy;
05405                     float Scale;
05406 
05408 
05409             Player->Velocity.Y += BOT_JUMP_THRUST;
05410 
05411                     if (ThisPoint->VelocityScale > 0.0f)
05412                             Scale = ThisPoint->VelocityScale;
05413                     else
05414                             Scale = 0.7f;
05415 
05416                     DBot->RunSpeed *= Scale;
05417 
05418             sy = Player->Velocity.Y;
05419                     Player->Velocity = DBot->MoveVec;
05420                     geVec3d_Scale(&Player->Velocity, 600*Scale, &Player->Velocity);
05421                     Player->Velocity.Y = sy;
05422 
05423             DBot->Action = Bot_Jump;
05424 
05425 
05426                     return(GE_TRUE);
05427             //break;
05428                     }
05429 
05430         case POINT_TYPE_LOOK_FOR_ITEMS:
05431             {
05432             GPlayer *HealthItem;
05433             GPlayer *WeaponItem;
05434 
05435                     // if multi-tracks
05436             if (DBot->TrackStack.TOS >= 1)
05437                 break;
05438 
05440 
05441             if (HealthItem = Bot_FindItem(VSI, &Player->XForm.Translation, ItemHealthList, 40.0f, 500.0f))
05442                 {
05443                 // No longer on a track
05444                 Bot_ClearTrack(VSI, Player);
05445 
05446                             DBot->GoalPos = HealthItem->Pos;
05447                             Bot_InitMoveToPoint(VSI, Player, &DBot->GoalPos);
05448                             Bot_ModeChange(VSI, Player, MODE_GOAL_POINT, GE_FALSE, Time);
05449                             Bot_ShootFoot(VSI, Player, Time);
05450                 return GE_TRUE;
05451                 }
05452 
05453             if (WeaponItem = Bot_FindItem(VSI, &Player->XForm.Translation, ItemWeaponList, 40.0f, 500.0f))
05454                 {
05455                 Bot_ClearTrack(VSI, Player);
05456                             DBot->GoalPos = WeaponItem->Pos;
05457                             Bot_InitMoveToPoint(VSI, Player, &DBot->GoalPos);
05458                             Bot_ModeChange(VSI, Player, MODE_GOAL_POINT, GE_FALSE, Time);
05459                             Bot_ShootFoot(VSI, Player, Time);
05460                 return GE_TRUE;
05461                 }
05462 
05463             break;
05464             }
05465 
05466         case POINT_TYPE_ROCKET_JUMP:
05467 
05469 
05470                     if (!Bot_SetWeapon(VSI, Player, ITEM_ROCKETS))
05471                             {
05472                             Bot_ClearTrack(VSI, Player);
05473                             break;
05474                             }
05475 
05476             if (Player->State == PSTATE_Normal && NextPoint)
05477                 {
05478                 float sy,Scale;
05479                 geVec3d ShootPos, ShootVec;
05480 
05481                                 //Bot_NudgePlayer(VSI, Player, ThisPoint->Pos, Time);
05482                 //Player->XForm.Translation.X = Pos.X;
05483                 //Player->XForm.Translation.Z = Pos.Z;
05484 
05485                 Player->Velocity.Y += BOT_JUMP_THRUST;
05486 
05487                             if (ThisPoint->VelocityScale > 0.0f)
05488                                     Scale = ThisPoint->VelocityScale;
05489                             else
05490                                     Scale = 0.3f; //default
05491 
05492                             DBot->RunSpeed *= Scale;
05493 
05494                 // reset Velocity
05495                                 sy = Player->Velocity.Y;
05496                                 Player->Velocity = DBot->MoveVec;
05497                                 geVec3d_Scale(&Player->Velocity, 500.0f, &Player->Velocity);
05498                                 Player->Velocity.Y = sy;
05499 
05500                 // facing the next point
05501                 // get the shooing position in the opposite direction
05502                 geVec3d_Scale(&DBot->MoveVec, 60.0f, &ShootVec);
05503                 geVec3d_Add(&Player->XForm.Translation, &ShootVec, &ShootPos);
05504                 ShootPos.Y = Player->XForm.Translation.Y - 30.0f;
05505 
05506                 // force a shot here
05507                 Player->NextWeaponTime = GenVSI_GetTime(VSI) - 0.01f;
05508                 Bot_Shoot(VSI, Player, &ShootPos, Time);
05509                 //Bot_ClearTrack(VSI, Player);
05510                 //Bot_FinishTrack(VSI, Player);
05511 
05512                 DBot->Action = Bot_WeaponJump;
05513                 return GE_TRUE;
05514                 }
05515                     else
05516                             {
05517                             Bot_ClearTrack(VSI, Player);
05518                             }
05519 
05520             break;
05521 
05522         case POINT_TYPE_BLASTER_JUMP:
05523 
05525 
05526             if (Player->State == PSTATE_Normal && NextPoint)
05527                 {
05528                 float sy,Scale;
05529                 geVec3d ShootPos, ShootVec;
05530 
05531                 //Player->XForm.Translation.X = Pos.X;
05532                 //Player->XForm.Translation.Z = Pos.Z;
05533                                 //Bot_NudgePlayer(VSI, Player, ThisPoint->Pos, Time);
05534 
05535                 Player->Velocity.Y += BOT_JUMP_THRUST;
05536 
05537                             if (ThisPoint->VelocityScale > 0.0f)
05538                                     Scale = ThisPoint->VelocityScale;
05539                             else
05540                                     Scale = 0.6f;
05541 
05542                             DBot->RunSpeed *= Scale;
05543 
05544                 // reset Velocity
05545                                 sy = Player->Velocity.Y;
05546                                 Player->Velocity = DBot->MoveVec;
05547                                 geVec3d_Scale(&Player->Velocity, 500.0f, &Player->Velocity);
05548                                 Player->Velocity.Y = sy;
05549 
05550                 // facing the next point
05551                 geVec3d_Scale(&DBot->MoveVec, 60.0f, &ShootVec);
05552                 geVec3d_Add(&Player->XForm.Translation, &ShootVec, &ShootPos);
05553                 ShootPos.Y = Player->XForm.Translation.Y - 30.0f;
05554 
05555                 // force a shot here
05556                 Player->NextWeaponTime = GenVSI_GetTime(VSI) - 0.01f;
05557                             Bot_SetWeapon(VSI, Player, ITEM_BLASTER);
05558                 Bot_Shoot(VSI, Player, &ShootPos, Time);
05559                 //Bot_ClearTrack(VSI, Player);
05560                 //Bot_FinishTrack(VSI, Player);
05561 
05562                 DBot->Action = Bot_WeaponJump;
05563                 return GE_TRUE;
05564                 }
05565                     else
05566                             {
05567                             Bot_ClearTrack(VSI, Player);
05568                             }
05569 
05570             break;
05571 
05572             case POINT_TYPE_SHOOT_BLASTER:
05573             case POINT_TYPE_SHOOT_GRENADE:
05574             case POINT_TYPE_SHOOT_ROCKET:
05575             case POINT_TYPE_SHOOT_SHREDDER:
05576             {
05577                     int32 wpn_num;
05578                     //int32 NumShots = ThisPoint->ShootTimes;
05579 
05580                     //if (BotDebugPrint) GenVSI_ConsoleHeaderPrintf(VSI, DBot->TgtPlayer->ClientHandle, GE_TRUE, "Point: Shoot");
05581 
05582                     wpn_num = ThisPoint->Action - POINT_TYPE_SHOOT_BLASTER;
05583                     // track should be validated but test again for good measure
05584 
05585                     if (Player->Inventory[wpn_num] <= 0 || !Player->InventoryHas[wpn_num])
05586                     {
05587                             Bot_ClearTrack(VSI, Player);
05588                             return GE_TRUE;
05589                     }
05590 
05591                     assert(NextPoint);
05592 
05593                     Bot_InitShootPoint(VSI, Player, Time);
05594                     // still on track at this point
05595                     return GE_TRUE;
05596             }
05597 
05598         case POINT_TYPE_WAIT_FOR_PLAYER:
05599                     {
05600                     geWorld                     *World;
05601                     World = GenVSI_GetWorld(VSI);
05602 
05603                     //if (BotDebugPrint) GenVSI_ConsoleHeaderPrintf(VSI, DBot->TgtPlayer->ClientHandle, GE_TRUE, "Point: WaitForPlayer");
05604 
05605                     // if multi-tracks
05606             if (DBot->TrackStack.TOS >= 1)
05607                 break;
05608 
05609                     if (!Bot_CanSeePlayerToPlayer(World, &Player->XForm.Translation, &DBot->TgtPlayer->XForm.Translation))
05610                     {
05611                 geVec3d Pos = *ThisPoint->Pos;
05612 
05613                 Player->XForm.Translation.X = Pos.X;
05614                 Player->XForm.Translation.Z = Pos.Z;
05615 
05616                             // Set timeout
05617                             if (ThisPoint->Time > 0.0f)
05618                                     DBot->TimeOut = GenVSI_GetTime(VSI) + ThisPoint->Time;
05619                             else
05620                                     DBot->TimeOut = GenVSI_GetTime(VSI) + 20.0f;
05621                                     
05622                             Bot_InitWaitForPlayer(VSI, Player, Time);
05623                             // still on track at this point
05624                             return GE_TRUE;
05625                     }
05626 
05627                     break;
05628                     }
05629 
05630         case POINT_TYPE_WAIT_POINT_VISIBLE:
05631                     {
05632             geVec3d Pos = *ThisPoint->Pos;
05633 
05634                     //if (BotDebugPrint) GenVSI_ConsoleHeaderPrintf(VSI, DBot->TgtPlayer->ClientHandle, GE_TRUE, "Point: WaitPointVisible");
05635 
05636                         // nudge to point
05637                         geVec3d_Subtract(&Pos, &Player->XForm.Translation, &Player->Velocity);
05638                         Player->Velocity.Y = 0.0f;
05639                         PlayerPhysics(VSI, Player, PLAYER_GROUND_FRICTION, PLAYER_AIR_FRICTION, PLAYER_LIQUID_FRICTION, PLAYER_GRAVITY, 1.0f, GE_FALSE, Time);
05640             //Player->XForm.Translation.X = Pos.X;
05641             //Player->XForm.Translation.Z = Pos.Z;
05642                     // Set timeout
05643                         
05644                         if (ThisPoint->Time > 0.0f)
05645                             DBot->TimeOut = GenVSI_GetTime(VSI) + ThisPoint->Time;
05646                     else
05647                             DBot->TimeOut = GenVSI_GetTime(VSI) + 5.0f;
05648 
05649                     geVec3d_Clear(&Player->Velocity);
05650 
05651                     Bot_InitWaitForEntityVisible(VSI, Player, Time);
05652                     // still on track at this point
05653                     return GE_TRUE;
05654                     }
05655 
05656         case POINT_TYPE_WAIT_POINT_DIST:
05657                     {
05658                     //if (BotDebugPrint) GenVSI_ConsoleHeaderPrintf(VSI, DBot->TgtPlayer->ClientHandle, GE_TRUE, "Point: WaitPointDist");
05659 
05660                     // Set timeout
05661                     if (ThisPoint->Time > 0.0f)
05662                             DBot->TimeOut = GenVSI_GetTime(VSI) + ThisPoint->Time;
05663                     else
05664                             DBot->TimeOut = GenVSI_GetTime(VSI) + 5.0f;
05665 
05666                     Bot_InitWaitForEntityDist(VSI, Player, Time);
05667                     // still on track at this point
05668                     return GE_TRUE;
05669                     }
05670         }
05671 
05672     return GE_FALSE;
05673     }
05674 
05675 //=====================================================================================
05676 //      Bot_LeaveTrack
05677 //=====================================================================================
05678 geBoolean Bot_LeaveTrack(GenVSI *VSI, void *PlayerData, float Time)
05679 {
05680         Bot_Var                 *DBot;
05681         GPlayer                 *Player;
05682         float           dist;
05683 
05684         Player = (GPlayer*)PlayerData;
05685         assert(Player);
05686         DBot = (Bot_Var*)Player->userData;
05687         assert(DBot);
05688 
05689     // run by when retreating
05690         if (DBot->Mode == MODE_RETREAT_ON_TRACK || DBot->Mode == MODE_RETREAT)
05691                 return GE_FALSE;
05692 
05693     // don't leave the track when in the air
05694         if (Player->State == PSTATE_InAir)
05695                 return GE_FALSE;
05696 
05697     dist = geVec3d_DistanceBetween(&Player->XForm.Translation, &DBot->TgtPlayer->XForm.Translation);
05698 
05699         if ((DBot->Mode == MODE_FIND_PLAYER || DBot->Mode == MODE_FIND_PLAYER_QUICK) &&
05700         dist < 500.0f && DBot->TimeSeen > 0.0f)
05701                 {
05702         Bot_ClearTrack(VSI, Player);
05703                 return GE_TRUE;
05704                 }
05705 
05706         if (dist < 150.0f && DBot->TimeSeen > 0.0f)
05707                 {
05708         Bot_ClearTrack(VSI, Player);
05709                 return GE_TRUE;
05710                 }
05711 
05712         return GE_FALSE;
05713 }
05714 
05715 
05716 //=====================================================================================
05717 //      Bot_FinishTrack - finishing a track should allow movement to the next track
05718 //=====================================================================================
05719 geBoolean Bot_FinishTrack(GenVSI *VSI, void *PlayerData)
05720         {
05721         Bot_Var                 *DBot;
05722         GPlayer                 *Player;
05723         int32                   NewTrack;
05724 
05725         Player = (GPlayer*)PlayerData;
05726         assert(Player);
05727         DBot = (Bot_Var*)Player->userData;
05728         assert(DBot);
05729 
05730         Track_ClearTrack(&DBot->TrackInfo);
05731 
05732         StackPop(&DBot->TrackStack);
05733         if (!StackIsEmpty(&DBot->TrackStack))
05734                 {
05735                 NewTrack = StackTop(&DBot->TrackStack);
05736                 Track_NextMultiTrack(VSI, &Player->XForm.Translation, NewTrack, &DBot->TrackInfo);
05737                 DBot->PastFirstTrackPoint = GE_FALSE;
05738                 // now on track
05739                 // set goal to next point
05740                 DBot->GoalPos = *Track_GetPoint(&DBot->TrackInfo)->Pos;
05741                 Bot_InitMoveToPoint(VSI, Player, &DBot->GoalPos);
05742                 }
05743     else 
05744         {
05745         DBot->GoalPos = DBot->TgtPlayer->XForm.Translation;
05746         }
05747 
05748         return GE_TRUE;
05749         }
05750 
05751 //=====================================================================================
05752 //      Bot_ClearTrack - clearing a track should clear ALL including stack
05753 //=====================================================================================
05754 geBoolean Bot_ClearTrack(GenVSI *VSI, void *PlayerData)
05755         {
05756         Bot_Var                 *DBot;
05757         GPlayer                 *Player;
05758 
05759         Player = (GPlayer*)PlayerData;
05760         assert(Player);
05761         DBot = (Bot_Var*)Player->userData;
05762         assert(DBot);
05763 
05764         Track_ClearTrack(&DBot->TrackInfoPrev);
05765         Track_ClearTrack(&DBot->TrackInfo);
05766     StackReset(&DBot->TrackStack);
05767 
05768         return GE_TRUE;
05769         }
05770 
05771 
05772 
05773 //=====================================================================================
05774 //=====================================================================================
05775 //
05776 //      Misc Bot Junk
05777 //
05778 //=====================================================================================
05779 //=====================================================================================
05780 
05781 //=====================================================================================
05782 //      Bot_Keys - debug mostly
05783 //=====================================================================================
05784 geBoolean Bot_Keys(GenVSI *VSI, void *PlayerData, float Time)
05785         {
05786         GPlayer                 *Player;
05787         Bot_Var                 *DBot;
05788 
05789         Player = (GPlayer*)PlayerData;
05790         assert(Player);
05791         DBot = (Bot_Var*)Player->userData;
05792         assert(DBot);
05793 
05794         if (GetAsyncKeyState('O') & 0x8000)
05795                 {
05796                 static geBoolean Mode = GE_FALSE;
05797                 if (Mode)
05798                         GenVSI_SetViewPlayer(VSI, DBot->ClientPlayer->ClientHandle, Player);
05799                 else
05800                         GenVSI_SetViewPlayer(VSI, DBot->ClientPlayer->ClientHandle, DBot->TgtPlayer);
05801                 Mode = !Mode;
05802                 }
05803 
05804         if (GetAsyncKeyState('I') & 0x8000)
05805                 {
05806                 GodMode = !GodMode;
05807                 GenVSI_ConsoleHeaderPrintf(VSI, DBot->ClientPlayer->ClientHandle, GE_TRUE, "God Mode %d", GodMode);
05808                 }
05809 
05810         if (GetAsyncKeyState('P') & 0x8000)
05811                 {
05812                 PathLight = !PathLight;
05813                 GenVSI_ConsoleHeaderPrintf(VSI, DBot->ClientPlayer->ClientHandle, GE_TRUE, "Path Light %d", PathLight);
05814                 }
05815 
05816         if (GetAsyncKeyState('N') & 0x8000)
05817                 {
05818                 MultiPathLight = !MultiPathLight;
05819                 GenVSI_ConsoleHeaderPrintf(VSI, DBot->ClientPlayer->ClientHandle, GE_TRUE, "Multi-Path Light %d", MultiPathLight);
05820                 }
05821 
05822         if (GetAsyncKeyState('D') & 0x8000)
05823                 {
05824                 BotDebugPrint = !BotDebugPrint;
05825                 GenVSI_ConsoleHeaderPrintf(VSI, DBot->ClientPlayer->ClientHandle, GE_TRUE, "Debug Print %d", BotDebugPrint);
05826                 }
05827 
05828         return GE_TRUE;
05829         }
05830 

Generated on Tue Sep 30 12:35:21 2003 for GTestAndEngine by doxygen 1.3.2