00001
00002
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
00019
00020 geBoolean Bot_TrackAction(GenVSI *VSI, void *PlayerData, const TrackPt* ThisPoint, const TrackPt* NextPoint, float Time);
00021
00022
00023
00024
00025
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
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
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
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
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
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
00182 -1
00183 };
00184
00185 int32 WeaponTrackList[] =
00186 {
00187
00188
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;
00208 CONTROLp Action;
00209 TrackData TrackInfo;
00210 TrackData TrackInfoPrev;
00211 int32 Dir;
00212 geVec3d TgtPos;
00213 GPlayer *TgtPlayer;
00214 geVec3d MoveVec;
00215 float TimeOut;
00216 float ModeTimeOut;
00217 int32 ShootCount;
00218 float TimeSeen;
00219 float TimeNotSeen;
00220 float ModeTimeSeen;
00221 float ModeTimeNotSeen;
00222 float ActiveTime;
00223 int32 Mode;
00224 int32 Bumps;
00225 int32 LedgeBumps;
00226 geVec3d GoalPos;
00227
00228 int8 BotType;
00229 geBoolean PastFirstTrackPoint;
00230 int32 WeaponDiff;
00231 int32 HealthDiff;
00232 Stack TrackStack;
00233 int32 HealthCheck;
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
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,
00302 Bot_ModeThinkUnstick,
00303 Bot_ModeThinkOnTrack,
00304 };
00305
00306 CONTROLp Bot_ModeAction[MODE_MAX] =
00307 {
00308 NULL,
00309 Bot_ModeActionRetreat,
00310 NULL,
00311 NULL,
00312 NULL,
00313 NULL,
00314 NULL,
00315 NULL,
00316 Bot_ModeActionRetreat,
00317 NULL,
00318 NULL,
00319 };
00320
00321
00322 RankTable[3][3] =
00323 {
00324 {0, 2, 4},
00325 {5, 6, 7},
00326 {6, 10, 9},
00327 };
00328
00329 #if 0
00330
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
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
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
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
00398 if (DBot->BotType == 1)
00399 {
00400 if (CanSee)
00401 {
00402
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
00417 if (!Track_OnTrack(&DBot->TrackInfo) && !(DBot->Mode == MODE_GOAL_POINT))
00418 DBot->GoalPos = DBot->TgtPlayer->XForm.Translation;
00419
00420
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
00430
00431 if (Bot_ModeAction[DBot->Mode])
00432 Bot_ModeAction[DBot->Mode](VSI, PlayerData, Time);
00433
00434 return GE_TRUE;
00435 }
00436
00437
00438
00439
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
00452 if (GenVSI_GetTime(VSI) >= DBot->PickTimeout || DBot->TgtPlayer == NULL)
00453 {
00454 NewTgtPlayer = Bot_PickTgtPlayer(VSI, PlayerData, GE_FALSE);
00455
00456
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
00471 DBot->BotTgtPicked = 0;
00472 NewTgtPlayer = Bot_PickTgtPlayer(VSI, PlayerData, GE_TRUE);
00473 DBot->PickTimeout = GenVSI_GetTime(VSI) + 12.0f;
00474 }
00475
00476
00477 if (NewTgtPlayer != DBot->TgtPlayer)
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
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
00517
00518
00519
00520
00521
00522
00523
00524
00525
00526
00527
00528 return GE_TRUE;
00529 }
00530
00531 return GE_FALSE;
00532 }
00533
00534
00535
00536
00537
00538
00539
00540
00541
00542
00543
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
00554
00555 Bot_ModeThinkFunc[DBot->Mode](VSI, PlayerData, Time);
00556
00557 return GE_TRUE;
00558 }
00559
00560
00561
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
00573
00574
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;
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;
00594 Bot_Reposition(VSI, Player, &DBot->GoalPos, dir);
00595 }
00596 }
00597 else
00598 {
00599 Player->XForm.Translation = Player->LastGoodPos;
00600 geVec3d_Clear(&Player->Velocity);
00601 dir = RandomRange(3) - 1;
00602 Bot_Reposition(VSI, Player, &DBot->GoalPos, dir);
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
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
00644 DBot->ModeTimeSeen = 0.0f;
00645 DBot->ModeTimeNotSeen = 0.0f;
00646 DBot->ModeTimeOut = 0.0f;
00647
00648
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
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
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
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
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
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
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
00823 if (DBot->ModeTimeOut > 10.0f)
00824 {
00825 Bot_ModeChange(VSI, Player, MODE_NULL, GE_TRUE, Time);
00826 return GE_TRUE;
00827 }
00828
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
00845 return GE_TRUE;
00846 }
00847 }
00848
00849
00850 Bot_InitRunAway(VSI, Player, Time);
00851
00852 return GE_TRUE;
00853 }
00854
00855
00856
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
00867 if (DBot->HealthCheck < Player->Health - 20)
00868 {
00869 DBot->FaceTgtPlayerOnRetreat = GE_TRUE;
00870
00871 return GE_TRUE;
00872 }
00873
00874 return GE_TRUE;
00875 }
00876
00877
00878
00879
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
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
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
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
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
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
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
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
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
01049 if (Track_OnTrack(&DBot->TrackInfo))
01050 {
01051
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
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
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
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
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
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
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
01208 Bot_InitRunCloser(VSI, Player, Time);
01209
01210 return GE_TRUE;
01211 }
01212
01213
01214
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
01225
01226 Bot_ModeChange(VSI, Player, MODE_NULL, GE_TRUE, Time);
01227
01228 return GE_TRUE;
01229 }
01230
01231
01232
01233
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
01245 if (!Track_OnTrack(&DBot->TrackInfo))
01246 {
01247 Bot_ModeChange(VSI, Player, MODE_NULL, GE_TRUE, Time);
01248 return GE_TRUE;
01249 }
01250
01251
01252 if (Track_OnTrack(&DBot->TrackInfo))
01253 {
01254
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
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
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
01305
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)
01319 continue;
01320
01321 if (GenVSI_IsClientBot(VSI, Hit->ClientHandle))
01322 {
01323 HBot = Hit->userData;
01324 if (HBot)
01325 {
01326
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
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
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
01384 geVec3d_Subtract(TgtPos, &DBot->GoalPos, &Vec2Player);
01385
01386
01387 if (!Bot_FindNewMoveVec(VSI, Player, TgtPos, Dir, 300.0f, &DBot->MoveVec))
01388 {
01389
01390 if (!Bot_FindNewMoveVec(VSI, Player, TgtPos, -Dir, 250.0f, &DBot->MoveVec))
01391 {
01392
01393
01394
01395 return GE_FALSE;
01396 }
01397 }
01398
01399 return GE_TRUE;
01400 }
01401
01402
01403
01404
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
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
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
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
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
01541 if (Track_OnTrack(&DBot->TrackInfo))
01542 {
01543
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
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
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
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
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
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
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
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
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
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
01751 geVec3d_Clear(&Player->Velocity);
01752
01753 DBot->Action = Bot_WaitForPlayer;
01754
01755 return GE_TRUE;
01756 }
01757
01758
01759
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
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);
01809
01810 DBot->HealthCheck = Player->Health;
01811 DBot->Action = Bot_WaitForEntityVisible;
01812
01813 return GE_TRUE;
01814 }
01815
01816
01817
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
01839
01840 geVec3d_Subtract(&DBot->TgtPlayer->XForm.Translation, &Player->XForm.Translation, &Vec2Player);
01841 Bot_SetupXForm(VSI, PlayerData, &Vec2Player);
01842
01843
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
01870 if (GenVSI_GetTime(VSI) >= DBot->TimeOut || DBot->HealthCheck < Player->Health)
01871 {
01872 Bot_ClearTrack(VSI, Player);
01873 Bot_InitGenericMove(VSI, Player, Time);
01874 return GE_TRUE;
01875 }
01876
01877 return GE_TRUE;
01878 }
01879
01880
01881
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
01895 geVec3d_Clear(&Player->Velocity);
01896
01897 DBot->HealthCheck = Player->Health;
01898 DBot->Action = Bot_WaitForEntityDist;
01899
01900 return GE_TRUE;
01901 }
01902
01903
01904
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
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
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
01964
01965
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
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
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
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
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
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
02055
02056
02057 geVec3d_Clear(&Player->Velocity);
02058
02059 DBot->Action = Bot_ShootPoint;
02060
02061 return GE_TRUE;
02062 }
02063
02064
02065
02066
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
02098
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
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
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;
02151
02152 if (geVec3d_Length(&InVect) == 0.0f)
02153 {
02154
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
02167 Player->XForm.Translation = Pos;
02168
02169 return GE_TRUE;
02170 }
02171
02172
02173
02174
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
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
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
02217 Player->XForm.Translation = Pos;
02218
02219 return GE_TRUE;
02220 }
02221
02222
02223
02224
02225 int16 Bot_ComparePlayers(GenVSI *VSI, void *PlayerData1, void *PlayerData2)
02226 {
02227 GPlayer *Player1;
02228 GPlayer *Player2;
02229 int32 diff;
02230
02231
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
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
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
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
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
02347 XFormSave = Player->XForm;
02348 Bot_SetupShootXForm(VSI, PlayerData, &Vec2Player);
02349 Bot_FireWeapon(VSI, PlayerData, Time);
02350
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
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
02394
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
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)
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
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
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
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
02548
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
02574
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
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)
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
02683 if (Hit == Player)
02684 continue;
02685
02686
02687 LastChance = Hit;
02688
02689
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
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
02738 if (BestBot && BestPlayer)
02739 if (BestPlayerScore > BestBotScore && (BestPlayerScore - BestBotScore) > 10)
02740 {
02741 return BestPlayer;
02742 }
02743
02744
02745
02746
02747
02748
02749
02750
02751
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
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
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
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
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;
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;
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
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
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;
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;
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
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
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
03112
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
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
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;
03178
03179 if (Collision.Plane.Normal.Y > 0.7f)
03180 {
03181 if (Player->State == PSTATE_InAir)
03182 Player->State = PSTATE_Normal;
03183 else if (Player->State == PSTATE_Dead)
03184 Player->State = PSTATE_DeadOnGround;
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)
03205 {
03206 geVec3d_Copy(&Player->LastGoodPos, &Player->XForm.Translation);
03207 geVec3d_Clear(&Player->Velocity);
03208 return GE_TRUE;
03209 }
03210
03211
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)
03218 {
03219
03220 geVec3d_Copy(&Collision.Impact, &Player->XForm.Translation);
03221
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
03235 if (Collision.Plane.Normal.Y < 0.2f)
03236 {
03237
03238 geVec3d_Clear(&Player->Velocity);
03239 return GE_FALSE;
03240 }
03241
03242
03243
03244
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
03253 geVec3d_Copy (&Collision.Plane.Normal, &Planes[NumPlanes]);
03254 NumPlanes++;
03255
03256
03257
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;
03269 }
03270 }
03271 if (j == NumPlanes)
03272 break;
03273 }
03274
03275 if (i != NumPlanes)
03276 {
03277 geVec3d_Copy(&NewVelocity, &Player->Velocity);
03278 }
03279 else
03280 {
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
03294
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
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
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;
03376
03377
03378 if (Collision.Actor)
03379 {
03380
03381 geVec3d_Copy(&Collision.Impact, &Player->XForm.Translation);
03382 geVec3d_Clear(&Player->Velocity);
03383 return GE_FALSE;
03384 }
03385
03386
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)
03393 {
03394
03395 geVec3d_Copy(&Collision.Impact, &Player->XForm.Translation);
03396
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
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
03418
03419
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
03428 geVec3d_Copy (&Collision.Plane.Normal, &Planes[NumPlanes]);
03429 NumPlanes++;
03430
03431
03432
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;
03444 }
03445 }
03446 if (j == NumPlanes)
03447 break;
03448 }
03449
03450 if (i != NumPlanes)
03451 {
03452 geVec3d_Copy(&NewVelocity, &Player->Velocity);
03453 }
03454 else
03455 {
03456 if (NumPlanes != 2)
03457 {
03458
03459 geVec3d_Clear(&Player->Velocity);
03460 return GE_TRUE;
03461 }
03462
03463
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
03471
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
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
03499 Player->LastGoodPos = Player->XForm.Translation;
03500
03501
03502
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
03523 geVec3d_Clear(&DBot->TgtPos);
03524 }
03525
03526 Speed = geVec3d_Length(&Player->Velocity);
03527
03528
03529
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
03545 geVec3d_Scale(&Player->Velocity, Scale, &Player->Velocity);
03546 }
03547
03548 return ClearMove;
03549 }
03550
03551
03552
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
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
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
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;
03622
03623 Player = (GPlayer*)PlayerData;
03624 DBot = (Bot_Var*)Player->userData;
03625
03626
03627 Pos = Player->XForm.Translation;
03628 SaveVelocity = Player->Velocity;
03629 SaveGoodPos = Player->LastGoodPos;
03630 SaveState = Player->State;
03631
03632
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
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
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
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
03697 ret_val = geWorld_Collision(World, &Mins, &Maxs,
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
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
03800 Pos2.Y -= 100.0f;
03801
03802
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
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
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
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
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
03876 geVec3d_Subtract(&TgtPos, &Pos, &Vec2Tgt);
03877 Vec2Tgt.Y = 0.0f;
03878 if (geVec3d_Length(&Vec2Tgt) == 0)
03879 Vec2Tgt.X = 1.0f;
03880
03881
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
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
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
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
03956 save_stop_pos = stop_pos;
03957 found = GE_TRUE;
03958 break;
03959 }
03960 }
03961
03962 if (found)
03963 {
03964 geVec3d Vec2Point;
03965
03966
03967 geVec3d_Subtract(&save_stop_pos, &Pos, &Vec2Point);
03968 Vec2Point.Y = 0.0f;
03969
03970
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
03985
03986 geBoolean Bot_PastPoint(geVec3d *Pos, geVec3d *MoveVector, geVec3d *TgtPos)
03987 {
03988 geVec3d Vec2Point, MoveVec = *MoveVector;
03989
03990
03991 if (geVec3d_Length(TgtPos) == 0.0f)
03992 {
03993 return GE_TRUE;
03994 }
03995
03996
03997 geVec3d_Subtract(TgtPos, Pos, &Vec2Point);
03998
03999
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
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
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
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
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
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
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
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
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
04092 Pos = Player->XForm.Translation;
04093 TgtPlayerPos = DBot->TgtPlayer->XForm.Translation;
04094
04095 geVec3d_Subtract(&TgtPlayerPos, &Pos, &Vec2Player);
04096
04097
04098 switch (DBot->Mode)
04099 {
04100 case MODE_UNSTICK:
04101 BotShoot = FALSE;
04102 Bot_SetupXForm(VSI, PlayerData, &Vec2Player);
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);
04110 }
04111 else
04112 {
04113 BotShoot = FALSE;
04114 Bot_SetupXForm(VSI, PlayerData, &DBot->MoveVec);
04115 }
04116 break;
04117 case MODE_WANDER:
04118 case MODE_WANDER_ON_TRACK:
04119
04120 BotShoot = FALSE;
04121 Bot_SetupXForm(VSI, PlayerData, &DBot->MoveVec);
04122 break;
04123 default:
04124 BotShoot = TRUE;
04125 Bot_SetupXForm(VSI, PlayerData, &Vec2Player);
04126 break;
04127
04128 }
04129
04130 MoveSpeed = Time;
04131
04132 if (Player->State == PSTATE_InAir)
04133 MoveSpeed *= 0.15f;
04134
04135 #if 1
04136
04137 if (!Bot_PastPoint(&Player->XForm.Translation, &DBot->MoveVec, &DBot->TgtPos))
04138 {
04139 geVec3d save = DBot->MoveVec;
04140
04141
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
04166 Bot_ClearTrack(VSI, Player);
04167
04168 Bot_ModeChange(VSI, Player, MODE_NULL, GE_TRUE, Time);
04169
04170 return GE_TRUE;
04171 }
04172 }
04173 else
04174 {
04175 if (geVec3d_DistanceBetween(&Player->XForm.Translation, &Player->LastGoodPos) <= 0.5f)
04176 {
04177
04178 Bot_ClearTrack(VSI, Player);
04179
04180 Bot_ModeChange(VSI, Player, MODE_NULL, GE_TRUE, Time);
04181
04182 return GE_TRUE;
04183 }
04184 }
04185 }
04186 else
04187
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))
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
04227 if (Player->State != PSTATE_InAir &&
04228 !PlayerDead(DBot->TgtPlayer) &&
04229 BotShoot)
04230
04231 {
04232
04233 if (DBot->TimeSeen > 0.0f)
04234 Bot_Shoot(VSI, Player, &TgtPlayerPos, Time);
04235 }
04236
04237
04238 Player->VPos = Player->XForm.Translation;
04239
04240
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
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
04255 Bot_ModeChange(VSI, Player, MODE_NULL, GE_TRUE, Time);
04256 return GE_TRUE;
04257 }
04258
04259 if (!Track_OnTrack(&DBot->TrackInfo))
04260 {
04261
04262 if (Bot_ModeThink(VSI, PlayerData, Time))
04263 return GE_TRUE;
04264
04265
04266 Bot_Reposition(VSI, Player, &DBot->GoalPos, DBot->Dir);
04267 return GE_TRUE;
04268 }
04269
04270
04271 DBot->PastFirstTrackPoint = GE_TRUE;
04272
04273
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
04286 DBot->GoalPos = DBot->TgtPos = *NextPoint->Pos;
04287
04288
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
04298 if (!Track_OnTrack(&DBot->TrackInfo))
04299 {
04300 Bot_ModeChange(VSI, PlayerData, MODE_NULL, GE_FALSE, Time);
04301 }
04302
04303 if (!NextPoint)
04304 {
04305
04306 Bot_FinishTrack(VSI, Player);
04307
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
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
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);
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
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
04366 Player->VPos = Player->XForm.Translation;
04367
04368
04369 if (Bot_PastPoint(&Player->XForm.Translation, &DBot->MoveVec, &DBot->TgtPos))
04370 {
04371
04372 if (Bot_ModeThink(VSI, PlayerData, Time))
04373 return GE_TRUE;
04374 }
04375
04376 return GE_TRUE;
04377 }
04378
04379
04380
04381
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
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
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
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
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
04542
04543
04544
04545
04546
04547
04548
04549
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
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
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
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
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
04659
04660
04661
04662
04663
04664
04665
04666
04667
04668
04669
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
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
04694 DMStart = GetBotMatchSpawn(VSI);
04695 if (!DMStart)
04696 {
04697
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
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
04727 Player->ControlIndex = 0;
04728 Player->DFunc = (void*)Bot_Destroy;
04729
04730 Bot_Create(VSI, Player);
04731
04732
04733
04734
04735
04736
04737
04738
04739
04740 Player->Health = 100;
04741 Player->Score = 0;
04742
04743
04744
04745
04746
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
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
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
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
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
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);
04872
04873
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
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
04899 Player->ControlIndex = 0;
04900 Player->DFunc = (void*)Bot_Destroy;
04901
04902 Bot_Create(VSI, Player);
04903
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
04913
04914
04915
04916
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
04927
04928
04929
04930 Player->NextWeaponTime = 0.0f;
04931
04932 return GE_TRUE;
04933 }
04934
04935
04936
04937
04938
04939 geBoolean BlockActor_Trigger(GenVSI *VSI, void *PlayerData, void *TargetData, void *Data)
04940 {
04941 GPlayer *Player = (GPlayer*)PlayerData;
04942
04943
04944 return(2);
04945
04946 return GE_FALSE;
04947 }
04948
04949
04950
04951
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
04987
04988
04989
04990
04991
04992
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
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
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
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
05078 DBot->HealthDiff = Player->Health - DBot->TgtPlayer->Health;
05079
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
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
05114
05115
05116
05117
05118
05119
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
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
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)
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
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:
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
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
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
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
05428 }
05429
05430 case POINT_TYPE_LOOK_FOR_ITEMS:
05431 {
05432 GPlayer *HealthItem;
05433 GPlayer *WeaponItem;
05434
05435
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
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
05482
05483
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;
05491
05492 DBot->RunSpeed *= Scale;
05493
05494
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
05501
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
05507 Player->NextWeaponTime = GenVSI_GetTime(VSI) - 0.01f;
05508 Bot_Shoot(VSI, Player, &ShootPos, Time);
05509
05510
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
05532
05533
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
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
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
05556 Player->NextWeaponTime = GenVSI_GetTime(VSI) - 0.01f;
05557 Bot_SetWeapon(VSI, Player, ITEM_BLASTER);
05558 Bot_Shoot(VSI, Player, &ShootPos, Time);
05559
05560
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
05579
05580
05581
05582 wpn_num = ThisPoint->Action - POINT_TYPE_SHOOT_BLASTER;
05583
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
05595 return GE_TRUE;
05596 }
05597
05598 case POINT_TYPE_WAIT_FOR_PLAYER:
05599 {
05600 geWorld *World;
05601 World = GenVSI_GetWorld(VSI);
05602
05603
05604
05605
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
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
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
05635
05636
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
05641
05642
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
05653 return GE_TRUE;
05654 }
05655
05656 case POINT_TYPE_WAIT_POINT_DIST:
05657 {
05658
05659
05660
05661 if (ThisPoint->Time > 0.0f)
05662 DBot->TimeOut = GenVSI_GetTime(VSI) + ThisPoint->