2
// C++ Implementation: bot_ai
4
// Description: The AI part comes here(navigation, shooting etc)
7
// Author: <rickhelmus@gmail.com>
11
// Code of CBot - Start
16
extern weaponinfo_s WeaponInfoTable[MAX_WEAPONS];
18
vec CBot::GetEnemyPos(playerent *d)
20
// Aim offset idea by botman
22
float flDist = GetDistance(d->o), flScale;
24
if (WeaponInfoTable[m_pMyEnt->gunselect].eWeaponType == TYPE_ROCKET)
26
// Bot is using a rocket launcher, aim at enemy feet?
27
if (m_bShootAtFeet && !OUTBORD(d->o.x, d->o.y))
29
// Only do this when enemy is fairly close to the ground
33
TraceLine(o, end, NULL, false, &tr);
34
if ((o.z - tr.end.z) < 8.0f)
46
if (m_pBotSkill->bCanPredict)
48
// How higher the skill, how further the bot predicts
49
float flPredictTime = RandomFloat(1.25f, 1.7f) / (m_sSkillNr+1);
50
o = PredictPos(o, d->vel, flPredictTime);
55
if (m_pBotSkill->bCanPredict)
57
// How higher the skill, how 'more' the bot predicts
58
float flPredictTime = RandomFloat(0.8f, 1.2f) / (m_sSkillNr+1);
59
o = PredictPos(o, d->vel, flPredictTime);
65
else if (flDist > 6.0f)
66
flScale = flDist / 60.0f;
79
// GOOD, offset a little for x, y, and z
80
offset.x = RandomFloat(-3, 3) * flScale;
81
offset.y = RandomFloat(-3, 3) * flScale;
82
offset.z = RandomFloat(-6, 6) * flScale;
85
// FAIR, offset somewhat for x, y, and z
86
offset.x = RandomFloat(-8, 8) * flScale;
87
offset.y = RandomFloat(-8, 8) * flScale;
88
offset.z = RandomFloat(-12, 12) * flScale;
91
// POOR, offset for x, y, and z
92
offset.x = RandomFloat(-15, 15) * flScale;
93
offset.y = RandomFloat(-15, 15) * flScale;
94
offset.z = RandomFloat(-25, 25) * flScale;
97
// BAD, offset lots for x, y, and z
98
offset.x = RandomFloat(-20, 20) * flScale;
99
offset.y = RandomFloat(-20, 20) * flScale;
100
offset.z = RandomFloat(-35, 35) * flScale;
108
bool CBot::FindEnemy(void)
110
// UNDONE: Enemies are now only scored on their distance
112
if (m_pMyEnt->enemy) // Bot already has an enemy
114
// Check if the enemy is still in game
115
bool found = IsInGame(m_pMyEnt->enemy);
117
// Check if the enemy is still ingame, still alive, not joined my team and is visible
118
if (found && !isteam(m_pMyEnt->team, m_pMyEnt->enemy->team))
120
if ((m_pMyEnt->enemy->state == CS_ALIVE) && (IsVisible(m_pMyEnt->enemy)))
123
m_pPrevEnemy = m_pMyEnt->enemy;
126
m_pMyEnt->enemy = NULL;
129
if (m_iEnemySearchDelay > lastmillis) return (m_pMyEnt->enemy!=NULL);
131
m_pMyEnt->enemy = NULL;
133
// Add enemy searchy delay
134
float MinDelay = m_pBotSkill->flMinEnemySearchDelay;
135
float MaxDelay = m_pBotSkill->flMaxEnemySearchDelay;
136
m_iEnemySearchDelay = lastmillis + int(RandomFloat(MinDelay, MaxDelay) * 1000.0f);
138
playerent *pNewEnemy = NULL, *d = NULL;
139
float flDist, flNearestDist = 99999.9f;
140
short EnemyVal, BestEnemyVal = -100;
142
// First loop through all players
145
d = players[i]; // Handy shortcut
147
if (d == m_pMyEnt || !d || isteam(d->team, m_pMyEnt->team) || (d->state != CS_ALIVE))
150
// Check if the enemy is visible
151
if(!IsInFOV(d) || !IsVisible(d))
154
flDist = GetDistance(d->o);
157
if (flDist < flNearestDist)
160
flNearestDist = flDist;
163
if (EnemyVal > BestEnemyVal)
166
BestEnemyVal = EnemyVal;
170
// Then examine the local player
171
if (player1 && !isteam(player1->team, m_pMyEnt->team) &&
172
(player1->state == CS_ALIVE))
174
// Check if the enemy is visible
175
if(IsInFOV(player1) && IsVisible(player1))
177
flDist = GetDistance(player1->o);
180
if (flDist < flNearestDist)
183
flNearestDist = flDist;
186
if (EnemyVal > BestEnemyVal)
189
BestEnemyVal = EnemyVal;
197
if (!m_pMyEnt->enemy) // Add shoot delay if new enemy is found
199
float flMinShootDelay = m_pBotSkill->flMinAttackDelay;
200
float flMaxShootDelay = m_pBotSkill->flMaxAttackDelay;
202
m_iShootDelay = lastmillis + int(RandomFloat(flMinShootDelay,
203
flMaxShootDelay) * 1000.0f);
206
if ((m_pMyEnt->enemy != pNewEnemy) && m_pMyEnt->enemy)
207
m_pPrevEnemy = m_pMyEnt->enemy;
209
m_pMyEnt->enemy = pNewEnemy;
216
bool CBot::CheckHunt(void)
218
if (!BotManager.BotsShoot()) return false;
220
if (m_pHuntTarget) // Bot already has an enemy to hunt
222
// Check if the enemy is still in game
223
bool found = IsInGame(m_pHuntTarget);
225
// Check if the enemy is still ingame, still alive, not joined my team and is visible
226
if (found && !isteam(m_pMyEnt->team, m_pHuntTarget->team))
228
if ((m_pHuntTarget->state == CS_ALIVE) && IsReachable(m_vHuntLocation))
232
m_pHuntTarget = NULL;
235
if (m_iHuntDelay > lastmillis) return (m_pHuntTarget!=NULL);
237
if (m_vHuntLocation!=g_vecZero)
238
m_vPrevHuntLocation = m_vHuntLocation;
240
m_pHuntTarget = NULL;
241
m_vHuntLocation = g_vecZero;
243
// Add enemy hunt search delay
244
m_iHuntDelay = lastmillis + 1500;
246
playerent *pNewEnemy = NULL, *d = NULL;
247
float flDist, flNearestDist = 99999.9f, flNearestOldPosDistToEnemy = 99999.9f;
248
float flNearestOldPosDistToBot = 99999.9f;
249
short EnemyVal, BestEnemyVal = -100;
252
// First loop through all players
255
d = players[i]; // Handy shortcut
257
if (d == m_pMyEnt || !d || isteam(d->team, m_pMyEnt->team) || (d->state != CS_ALIVE))
260
flDist = GetDistance(d->o);
262
if (flDist > 250.0f) continue;
266
if (flDist < flNearestDist)
269
flNearestDist = flDist;
272
if (d == m_pPrevEnemy)
275
if (EnemyVal < BestEnemyVal) continue;
277
vec bestfromenemy = g_vecZero, bestfrombot = g_vecZero;
278
flNearestOldPosDistToEnemy = flNearestOldPosDistToBot = 9999.9f;
280
// Check previous locations of enemy
281
for (int j=0;j<d->history.size();j++)
283
const vec &v = d->history.getpos(j);
284
if (v==m_vPrevHuntLocation) continue;
286
flDist = GetDistance(d->o, v);
288
if ((flDist < flNearestOldPosDistToEnemy) && IsReachable(v))
290
flNearestOldPosDistToEnemy = flDist;
295
// Check previous locations of bot hisself
296
for (int j=0;j<m_pMyEnt->history.size();j++)
298
const vec &v = m_pMyEnt->history.getpos(j);
299
if (v==m_vPrevHuntLocation) continue;
301
flDist = GetDistance(v);
303
if ((flDist < flNearestOldPosDistToBot) && ::IsVisible(d->o, v) &&
306
flNearestOldPosDistToBot = flDist;
311
if (bestfromenemy!=g_vecZero)
314
BestEnemyVal = EnemyVal;
315
BestOldPos = bestfromenemy;
317
else if (bestfrombot!=g_vecZero)
320
BestEnemyVal = EnemyVal;
321
BestOldPos = bestfrombot;
324
// Then examine the local player
325
if (player1 && !isteam(player1->team, m_pMyEnt->team) &&
326
(player1->state == CS_ALIVE) && ((flDist = GetDistance(player1->o)) <= 250.0f))
331
if (flDist < flNearestDist)
334
flNearestDist = flDist;
337
if (d == m_pPrevEnemy)
340
if (EnemyVal >= BestEnemyVal)
342
BestEnemyVal = EnemyVal;
343
vec bestfromenemy = g_vecZero, bestfrombot = g_vecZero;
344
flNearestOldPosDistToEnemy = flNearestOldPosDistToBot = 9999.9f;
346
// Check previous locations of enemy
347
for (int j=0;j<d->history.size();j++)
349
const vec &v = d->history.getpos(j);
350
if (v==m_vPrevHuntLocation) continue;
352
flDist = GetDistance(d->o, v);
354
if ((flDist < flNearestOldPosDistToEnemy) && IsReachable(v))
356
flNearestOldPosDistToEnemy = flDist;
361
// Check previous locations of bot hisself
362
for (int j=0;j<m_pMyEnt->history.size();j++)
364
const vec &v = m_pMyEnt->history.getpos(j);
365
if (v==m_vPrevHuntLocation) continue;
367
flDist = GetDistance(v);
369
if ((flDist < flNearestOldPosDistToBot) && ::IsVisible(d->o, v) &&
372
flNearestOldPosDistToBot = flDist;
377
if (bestfromenemy!=g_vecZero)
380
BestEnemyVal = EnemyVal;
381
BestOldPos = bestfromenemy;
383
else if (bestfrombot!=g_vecZero)
386
BestEnemyVal = EnemyVal;
387
BestOldPos = bestfrombot;
395
if (!m_pHuntTarget) // Add shoot delay if new enemy is found
397
float flMinShootDelay = m_pBotSkill->flMinAttackDelay;
398
float flMaxShootDelay = m_pBotSkill->flMaxAttackDelay;
400
m_iShootDelay = lastmillis + int(RandomFloat(flMinShootDelay,
401
flMaxShootDelay) * 1000.0f);
404
if (m_vHuntLocation!=g_vecZero)
405
m_vPrevHuntLocation = m_vHuntLocation;
407
m_pHuntTarget = pNewEnemy;
408
m_vHuntLocation = BestOldPos;
409
m_fPrevHuntDist = 0.0f;
416
bool CBot::HuntEnemy(void)
418
if (m_iCombatNavTime > lastmillis)
420
SetMoveDir(m_iMoveDir, false);
424
m_iCombatNavTime = m_iMoveDir = 0;
426
bool bDone = false, bNew = false;
427
float flDist = GetDistance(m_vHuntLocation);
432
if ((m_fPrevHuntDist > 0.0) && (flDist > m_fPrevHuntDist))
435
m_fPrevHuntDist = flDist;
437
if ((m_iHuntPlayerUpdateTime < lastmillis) || bDone)
439
m_iHuntPlayerUpdateTime = lastmillis + 1250;
441
short BestPosIndexFromEnemy = -1, BestPosIndexFromBot = -1, j;
442
float NearestDistToEnemy = 9999.9f, NearestDistToBot = 9999.9f;
444
// Check previous locations of enemy
445
for (j=0;j<m_pHuntTarget->history.size();j++)
447
const vec &OldPos = m_pHuntTarget->history.getpos(j);
449
if (bDone && m_vHuntLocation==OldPos)
452
if (GetDistance(OldPos) > 250.0f)
455
flDist = GetDistance(m_pHuntTarget->o, OldPos);
457
if ((flDist < NearestDistToEnemy) && (IsReachable(OldPos)))
459
NearestDistToEnemy = flDist;
460
BestPosIndexFromEnemy = j;
465
// Check previous locations of bot
466
for (j=0;j<m_pMyEnt->history.size();j++)
468
const vec &OldPos = m_pMyEnt->history.getpos(j);
470
if (bDone && m_vHuntLocation==OldPos)
473
if (GetDistance(OldPos) > 25.0f)
476
flDist = GetDistance(OldPos);
478
if ((flDist < NearestDistToBot) && ::IsVisible(m_pHuntTarget->o, OldPos) &&
479
(IsReachable(OldPos)))
481
NearestDistToBot = flDist;
482
BestPosIndexFromBot = j;
487
if (BestPosIndexFromEnemy > -1)
489
m_vPrevHuntLocation = m_vHuntLocation;
490
m_vHuntLocation = m_pHuntTarget->history.getpos(BestPosIndexFromEnemy);
492
m_fPrevHuntDist = 0.0f;
494
else if (BestPosIndexFromBot > -1)
496
m_vPrevHuntLocation = m_vHuntLocation;
497
m_vHuntLocation = m_pMyEnt->history.getpos(BestPosIndexFromEnemy);
499
m_fPrevHuntDist = 0.0f;
503
if (!bNew) // Check if current location is still reachable
505
if (bDone || !IsReachable(m_vHuntLocation))
507
m_pHuntTarget = NULL;
508
m_vPrevHuntLocation = m_vHuntLocation;
509
m_vHuntLocation = g_vecZero;
510
m_fPrevHuntDist = 0.0f;
511
m_iHuntDelay = lastmillis + 3500;
516
condebug("New hunt pos");
519
//AimToVec(m_vHuntLocation);
521
int iMoveDir = GetDirection(GetViewAngles(), m_pMyEnt->o, m_vHuntLocation);
523
if (iMoveDir != DIR_NONE)
525
m_iMoveDir = iMoveDir;
526
m_iCombatNavTime = lastmillis + 125;
529
bool aimtopos = true;
531
if ((lastmillis - m_iSawEnemyTime) > 1500)
533
if (m_iLookAroundDelay < lastmillis)
535
if (m_iLookAroundTime > lastmillis)
537
if (m_iLookAroundUpdateTime < lastmillis)
540
if (m_bLookLeft) flAddAngle = RandomFloat(-110, -80);
541
else flAddAngle = RandomFloat(80, 110);
542
m_pMyEnt->targetyaw = WrapYZAngle(m_pMyEnt->targetyaw + flAddAngle);
543
m_iLookAroundUpdateTime = lastmillis + RandomLong(400, 800);
547
else if (m_iLookAroundTime > 0)
549
m_iLookAroundTime = 0;
550
m_iLookAroundDelay = lastmillis + RandomLong(750, 1000);
553
m_iLookAroundTime = lastmillis + RandomLong(2200, 3200);
558
AimToVec(m_vHuntLocation);
560
debugbeam(m_pMyEnt->o, m_vHuntLocation);
562
if (m_fYawToTurn <= 25.0f)
563
m_iHuntLastTurnLessTime = lastmillis;
565
// Bot had to turn much for a while?
566
if ((m_iHuntLastTurnLessTime > 0) && (m_iHuntLastTurnLessTime < (lastmillis - 1000)))
568
m_iHuntPauseTime = lastmillis + 200;
571
if (m_iHuntPauseTime >= lastmillis)
574
m_fPrevHuntDist = 0.0f;
578
// Check if bot has to jump over a wall...
580
m_pMyEnt->jumpnext = true;
581
else // Check if bot has to jump to reach this location
583
float flHeightDiff = m_vHuntLocation.z - m_pMyEnt->o.z;
584
bool bToHigh = false;
585
if (Get2DDistance(m_vHuntLocation) <= 2.0f)
587
if (flHeightDiff >= 1.5f)
589
if (flHeightDiff <= JUMP_HEIGHT)
591
#ifndef RELEASE_BUILD
593
sprintf(sz, "OldPos z diff: %f", m_vHuntLocation.z-m_pMyEnt->o.z);
596
// Jump if close to pos and the pos is high
597
m_pMyEnt->jumpnext = true;
606
m_pHuntTarget = NULL;
607
m_vPrevHuntLocation = m_vHuntLocation;
608
m_vHuntLocation = g_vecZero;
609
m_fPrevHuntDist = 0.0f;
610
m_iHuntDelay = lastmillis + 3500;
619
void CBot::ShootEnemy()
621
if(!m_pMyEnt->enemy) return;
623
m_iSawEnemyTime = lastmillis;
626
vec enemypos = GetEnemyPos(m_pMyEnt->enemy);
630
if (m_iShootDelay < lastmillis)
631
//if ((lastmillis-m_pMyEnt->lastaction) >= m_pMyEnt->gunwait)
633
if (m_pMyEnt->mag[m_pMyEnt->gunselect])
635
// If the bot is using a sniper only shoot if crosshair is near the enemy
636
if (WeaponInfoTable[m_pMyEnt->gunselect].eWeaponType == TYPE_SNIPER)
638
float yawtoturn = fabs(WrapYZAngle(m_pMyEnt->yaw - m_pMyEnt->targetyaw));
639
float pitchtoturn = fabs(WrapYZAngle(m_pMyEnt->pitch - m_pMyEnt->targetpitch));
641
if ((yawtoturn > 5) || (pitchtoturn > 15)) // UNDONE: Should be skill based
645
float flDist = GetDistance(enemypos);
647
// Check if bot is in fire range
648
if ((flDist < WeaponInfoTable[m_pMyEnt->gunselect].flMinFireDistance) ||
649
(flDist > WeaponInfoTable[m_pMyEnt->gunselect].flMaxFireDistance))
653
m_pMyEnt->attacking = true;
655
// Get the position the bot is aiming at
656
vec forward, right, up, dest;
659
AnglesToVectors(GetViewAngles(), forward, right, up);
665
TraceLine(m_pMyEnt->o, dest, m_pMyEnt, false, &tr);
666
debugbeam(m_pMyEnt->o, tr.end);
669
shoot(m_pMyEnt, tr.end);
672
m_iShootDelay = lastmillis + GetShootDelay();
674
ChoosePreferredWeapon();
676
#ifndef RELEASE_BUILD
680
sprintf(sz, "shootdelay: %d\n", (m_iShootDelay-lastmillis));
686
bool CBot::ChoosePreferredWeapon()
688
TMultiChoice<int> WeaponChoices;
690
float flDist = GetDistance(m_pMyEnt->enemy->o);
692
if ((m_iChangeWeaponDelay > lastmillis) && (m_pMyEnt->ammo[m_pMyEnt->gunselect]))
694
if ((WeaponInfoTable[m_pMyEnt->gunselect].eWeaponType != TYPE_MELEE) || (flDist <= 3.5f))
699
for(int i=0;i<MAX_WEAPONS;i++)
701
// If no ammo for this weapon, skip it
702
if (m_pMyEnt->ammo[i] == 0) continue;
704
sWeaponScore = 5; // Minimal score for a weapon
706
if ((flDist >= WeaponInfoTable[i].flMinDesiredDistance) &&
707
(flDist <= WeaponInfoTable[i].flMaxDesiredDistance))
709
// In desired range for this weapon
710
sWeaponScore += 5; // Increase score much
712
else if ((flDist < WeaponInfoTable[i].flMinFireDistance) ||
713
(flDist > WeaponInfoTable[i].flMaxFireDistance))
714
continue; // Wrong distance for this weapon
716
// The ideal distance would be between the Min and Max desired distance.
717
// Score on the difference of the avarage of the Min and Max desired distance.
718
float flAvarage = (WeaponInfoTable[i].flMinDesiredDistance +
719
WeaponInfoTable[i].flMaxDesiredDistance) / 2.0f;
720
float flIdealDiff = fabs(flDist - flAvarage);
722
if (flIdealDiff < 0.5f) // Close to ideal distance
724
else if (flIdealDiff <= 1.0f)
727
// Now rate the weapon on available ammo...
728
if (WeaponInfoTable[i].sMinDesiredAmmo > 0)
730
// Calculate how much percent of the min desired ammo the bot has
731
float flDesiredPercent = (float(m_pMyEnt->ammo[i]) /
732
float(WeaponInfoTable[i].sMinDesiredAmmo)) *
735
if (flDesiredPercent >= 400.0f)
737
else if (flDesiredPercent >= 200.0f)
739
else if (flDesiredPercent >= 100.0f)
743
WeaponChoices.Insert(i, sWeaponScore);
747
if (WeaponChoices.GetSelection(WeaponSelect))
749
m_iChangeWeaponDelay = lastmillis + RandomLong(2000, 8000);
750
m_bShootAtFeet = ((WeaponInfoTable[WeaponSelect].eWeaponType==TYPE_ROCKET) &&
751
(RandomLong(1, 100) <=
752
m_pBotSkill->sShootAtFeetWithRLPercent));
753
return SelectGun(WeaponSelect);
759
int CBot::GetShootDelay()
762
if ((WeaponInfoTable[m_pMyEnt->gunselect].eWeaponType == TYPE_MELEE) ||
763
(WeaponInfoTable[m_pMyEnt->gunselect].eWeaponType == TYPE_AUTO))
764
return m_pMyEnt->gunwait[m_pMyEnt->gunselect];
766
float flMinShootDelay = m_pBotSkill->flMinAttackDelay;
767
float flMaxShootDelay = m_pBotSkill->flMaxAttackDelay;
768
return max(m_pMyEnt->gunwait[m_pMyEnt->gunselect], int(RandomFloat(flMinShootDelay, flMaxShootDelay) * 1000.0f));
771
void CBot::CheckReload() // reload gun if no enemies are around
773
if(m_pMyEnt->enemy) return;
774
SelectGun(m_pMyEnt->primary);
781
// Default bots will run forward
784
// Default bots won't strafe
785
m_pMyEnt->strafe = 0;
787
if (!BotManager.BotsShoot() && m_pMyEnt->enemy)
788
m_pMyEnt->enemy = NULL; // Clear enemy when bots may not shoot
790
if (m_bGoToDebugGoal) // For debugging the waypoint navigation
798
AddDebugText("Heading to debug goal...");
800
if (BotManager.BotsShoot() && FindEnemy()) // Combat
802
AddDebugText("has enemy");
807
if (m_eCurrentBotState != STATE_ENEMY)
813
m_eCurrentBotState = STATE_ENEMY;
817
else if (CheckHunt() && HuntEnemy())
820
AddDebugText("Hunting to %s", m_pHuntTarget->name);
821
m_eCurrentBotState = STATE_HUNT;
823
// Heading to an interesting entity(ammo, armour etc)
824
else if (CheckItems())
827
AddDebugText("has ent");
828
m_eCurrentBotState = STATE_ENT;
830
else if (m_classicsp && DoSPStuff()) // Home to goal, find/follow friends etc.
833
AddDebugText("SP stuff");
834
m_eCurrentBotState = STATE_SP;
836
else // Normal navigation
839
if (m_eCurrentBotState != STATE_NORMAL)
845
m_eCurrentBotState = STATE_NORMAL;
846
bool bDoNormalNav = true;
848
AddDebugText("normal nav");
850
// Make sure the bot looks straight forward and not up or down
853
// if it is time to look for a waypoint AND if there are waypoints in this
855
if (WaypointClass.m_iWaypointCount >= 1)
857
// check if we need to find a waypoint...
858
if (CurrentWPIsValid() == false)
860
if (m_iLookForWaypointTime <= lastmillis)
862
// find the nearest reachable waypoint
863
waypoint_s *pWP = GetNearestWaypoint(10.0f);
865
if (pWP && (pWP != m_pCurrentWaypoint))
867
SetCurrentWaypoint(pWP);
868
condebug("New nav wp");
869
bDoNormalNav = !HeadToWaypoint();
876
m_iLookForWaypointTime = lastmillis + 250;
881
bDoNormalNav = !HeadToWaypoint();
884
AddDebugText("Using wps for nav");
888
// If nothing special, do regular (waypointless) navigation
891
// Is the bot underwater?
892
if (UnderWater(m_pMyEnt->o) && WaterNav())
894
// Bot is under water, navigation happens in WaterNav
896
// Time to check the environment?
897
else if (m_iCheckEnvDelay < lastmillis)
899
if (m_vWaterGoal!=g_vecZero) m_vWaterGoal = g_vecZero;
901
// Check for stuck and strafe
902
if (UnderWater(m_pMyEnt->o) || !CheckStuck())
904
// Only do this when the bot is underwater or when the bot isn't stuck
906
// Check field of view (FOV)
911
// Check if the bot has to strafe
919
void CBot::DoCombatNav()
921
if (m_iCombatNavTime > lastmillis)
923
// If bot has a lower skill and has to turn much, wait
924
if ((m_sSkillNr > 2) && (m_fYawToTurn > 90.0f))
930
SetMoveDir(m_iMoveDir, false);
937
m_pMyEnt->jumpnext = true;
938
m_bCombatJump = false;
939
m_iCombatJumpDelay = lastmillis + RandomLong(1500, 2800);
943
m_iMoveDir = DIR_NONE;
945
// Check if bot is on top of his enemy
946
float r = m_pMyEnt->radius+m_pMyEnt->enemy->radius;
947
if ((fabs(m_pMyEnt->enemy->o.x-m_pMyEnt->o.x)<r &&
948
fabs(m_pMyEnt->enemy->o.y-m_pMyEnt->o.y)<r) &&
949
((m_pMyEnt->enemy->o.z+m_pMyEnt->enemy->aboveeye) < (m_pMyEnt->o.z + m_pMyEnt->aboveeye)))
951
// Try to get off him!
952
condebug("On enemy!");
953
TMultiChoice<int> AwayDirChoices;
955
if (IsVisible(LEFT, 4.0f, false))
956
AwayDirChoices.Insert(LEFT);
957
if (IsVisible(RIGHT, 4.0f, false))
958
AwayDirChoices.Insert(RIGHT);
959
if (IsVisible(FORWARD, 4.0f, false))
960
AwayDirChoices.Insert(FORWARD);
961
if (IsVisible(BACKWARD, 4.0f, false))
962
AwayDirChoices.Insert(BACKWARD);
965
if (AwayDirChoices.GetSelection(iDir))
968
m_iCombatNavTime = lastmillis + 500;
972
float flDist = GetDistance(m_pMyEnt->enemy->o);
974
// Check for nearby items?
975
if (((m_iCheckEntsDelay < lastmillis) || m_pTargetEnt) &&
976
m_pBotSkill->bCanSearchItemsInCombat)
978
m_iCheckEntsDelay = lastmillis + 125;
979
bool bSearchItems = false;
983
// Bot has already found an entity, still valid?
984
vec v(m_pTargetEnt->x, m_pTargetEnt->y,
985
S(m_pTargetEnt->x, m_pTargetEnt->y)->floor+m_pMyEnt->eyeheight);
986
if ((GetDistance(v) > 25.0f) || !IsVisible(m_pTargetEnt))
990
if (!m_pTargetEnt && (m_iCheckEntsDelay <= lastmillis))
992
if (WeaponInfoTable[m_pMyEnt->gunselect].eWeaponType == TYPE_MELEE)
993
bSearchItems = (flDist >= 8.0f);
995
bSearchItems = (m_pMyEnt->ammo[m_pMyEnt->gunselect] <=
996
WeaponInfoTable[m_pMyEnt->gunselect].sMinDesiredAmmo);
999
m_pTargetEnt = SearchForEnts(false, 25.0f, 1.0f);
1004
condebug("Combat ent");
1005
vec v(m_pTargetEnt->x, m_pTargetEnt->y,
1006
S(m_pTargetEnt->x, m_pTargetEnt->y)->floor+m_pMyEnt->eyeheight);
1008
debugbeam(m_pMyEnt->o, v);
1010
float flHeightDiff = v.z - m_pMyEnt->o.z;
1011
bool bToHigh = false;
1013
// Check he height for this ent
1014
if (Get2DDistance(v) <= 2.0f)
1016
if (flHeightDiff >= 1.5f)
1018
if (flHeightDiff <= JUMP_HEIGHT)
1020
#ifndef RELEASE_BUILD
1022
sprintf(sz, "Ent z diff: %f", v.z-m_pMyEnt->o.z);
1025
m_pMyEnt->jumpnext = true; // Jump if close to ent and the ent is high
1034
int iMoveDir = GetDirection(GetViewAngles(), m_pMyEnt->o, v);
1036
if (iMoveDir != DIR_NONE)
1038
m_iMoveDir = iMoveDir;
1039
m_iCombatNavTime = lastmillis + RandomLong(125, 250);
1042
// Check if bot needs to jump over something
1043
vec from = m_pMyEnt->o;
1045
if (!IsVisible(from, iMoveDir, 3.0f, false))
1046
m_pMyEnt->jumpnext = true;
1053
// High skill and enemy is close?
1054
if ((m_sSkillNr <= 1) && (m_fYawToTurn < 80.0f) && (flDist <= 20.0f) &&
1055
(m_iCombatJumpDelay < lastmillis))
1057
// Randomly jump a bit, to avoid some basic firepower ;)
1059
// How lower the distance to the enemy, how higher the chance for a jump
1060
short sJumpPercent = (100 - ((short)flDist * 8));
1061
if (RandomLong(1, 100) <= sJumpPercent)
1063
// Choose a nice direction to jump to
1065
// Is the enemy close?
1066
if ((GetDistance(m_pMyEnt->enemy->o) <= 4.0f) ||
1067
(WeaponInfoTable[m_pMyEnt->gunselect].eWeaponType == TYPE_MELEE))
1069
m_iMoveDir = FORWARD; // Jump forward
1070
SetMoveDir(FORWARD, false);
1071
m_bCombatJump = true;
1073
else if (WeaponInfoTable[m_pMyEnt->gunselect].eWeaponType != TYPE_MELEE)// else jump to a random direction
1076
Directions to choose:
1087
TMultiChoice<int> JumpDirChoices;
1088
short sForwardScore = ((flDist > 8.0f) || (flDist < 4.0f)) ? 20 : 10;
1089
short sBackwardScore = (flDist <= 6.0f) ? 20 : 10;
1090
short sStrafeScore = (flDist < 6.0f) ? 20 : 10;
1092
if (IsVisible((FORWARD | LEFT), 4.0f, false))
1093
JumpDirChoices.Insert((FORWARD | LEFT), sForwardScore);
1094
if (IsVisible((FORWARD | RIGHT), 4.0f, false))
1095
JumpDirChoices.Insert((FORWARD | RIGHT), sForwardScore);
1096
if (IsVisible(BACKWARD, 4.0f, false))
1097
JumpDirChoices.Insert(BACKWARD, sBackwardScore);
1098
if (IsVisible((BACKWARD | LEFT), 4.0f, false))
1099
JumpDirChoices.Insert((BACKWARD | LEFT), sBackwardScore);
1100
if (IsVisible((BACKWARD | RIGHT), 4.0f, false))
1101
JumpDirChoices.Insert((BACKWARD | RIGHT), sBackwardScore);
1102
if (IsVisible(LEFT, 4.0f, false))
1103
JumpDirChoices.Insert(LEFT, sStrafeScore);
1104
if (IsVisible(RIGHT, 4.0f, false))
1105
JumpDirChoices.Insert(RIGHT, sStrafeScore);
1108
if (JumpDirChoices.GetSelection(JumpDir))
1110
m_iMoveDir = JumpDir;
1111
SetMoveDir(JumpDir, false);
1112
m_bCombatJump = true;
1118
m_iCombatNavTime = lastmillis + RandomLong(125, 250);
1124
if (WeaponInfoTable[m_pMyEnt->gunselect].eWeaponType == TYPE_MELEE)
1125
return; // Simply walk towards enemy if using a melee type
1127
flDist = Get2DDistance(m_pMyEnt->enemy->o);
1129
// Out of desired range for current weapon?
1130
if ((flDist <= WeaponInfoTable[m_pMyEnt->gunselect].flMinDesiredDistance) ||
1131
(flDist >= WeaponInfoTable[m_pMyEnt->gunselect].flMaxDesiredDistance))
1133
if (flDist >= WeaponInfoTable[m_pMyEnt->gunselect].flMaxDesiredDistance)
1135
m_iMoveDir = FORWARD;
1139
m_iMoveDir = BACKWARD;
1142
vec src, forward, right, up, dest, MyAngles = GetViewAngles(), o = m_pMyEnt->o;
1145
// Is it furthest or farthest? bleh
1146
float flFurthestDist = 0;
1147
int bestdir = -1, dir = 0;
1148
bool moveback = (m_pMyEnt->move == -1);
1150
for(int j=-45;j<=45;j+=45)
1153
src.y = WrapYZAngle(src.y + j);
1156
// If we're moving backwards, trace backwards
1158
src.y = WrapYZAngle(src.y + 180);
1160
AnglesToVectors(src, forward, right, up);
1166
TraceLine(o, dest, m_pMyEnt, false, &tr);
1168
//debugbeam(origin, end);
1169
flDist = GetDistance(tr.end);
1171
if (flFurthestDist < flDist)
1173
flFurthestDist = flDist;
1183
m_iMoveDir |= RIGHT; // Strafe right
1185
m_iMoveDir |= LEFT; // Strafe left
1189
m_iMoveDir |= LEFT; // Strafe left
1191
m_iMoveDir |= RIGHT; // Strafe right
1195
if (m_iMoveDir != DIR_NONE)
1197
SetMoveDir(m_iMoveDir, false);
1198
m_iCombatNavTime = lastmillis + 500;
1201
else if (m_pBotSkill->bCircleStrafe) // Circle strafe when in desired range...
1204
vec angles, end, forward, right, up;
1205
TMultiChoice<int> StrafeDirChoices;
1207
// Check the left side...
1208
angles = GetViewAngles();
1209
angles.y = WrapYZAngle(angles.y - 75.0f); // Not 90 degrees because the bot
1210
// doesn't strafe in a straight line
1211
// (aims still to enemy).
1213
AnglesToVectors(angles, forward, right, up);
1218
TraceLine(m_pMyEnt->o, end, m_pMyEnt, true, &tr);
1219
StrafeDirChoices.Insert(LEFT, (int)GetDistance(m_pMyEnt->o, tr.end));
1221
// Check the right side...
1222
angles = GetViewAngles();
1223
angles.y = WrapYZAngle(angles.y + 75.0f); // Not 90 degrees because the bot
1224
// doesn't strafe in a straight line
1225
// (aims still to enemy).
1227
AnglesToVectors(angles, forward, right, up);
1232
TraceLine(m_pMyEnt->o, end, m_pMyEnt, true, &tr);
1233
StrafeDirChoices.Insert(RIGHT, (int)GetDistance(m_pMyEnt->o, tr.end));
1236
if (StrafeDirChoices.GetSelection(StrafeDir))
1238
m_iMoveDir = StrafeDir;
1239
SetMoveDir(StrafeDir, false);
1240
m_iCombatNavTime = lastmillis + RandomLong(1500, 3000);
1243
else // Bot can't circle strafe(low skill), just stand still
1247
bool CBot::CheckStuck()
1249
if (m_iStuckCheckDelay >= lastmillis)
1252
if ((m_vGoal!=g_vecZero) && (GetDistance(m_vGoal) < 2.0f))
1255
bool IsStuck = false;
1257
vec CurPos = m_pMyEnt->o, PrevPos = m_vPrevOrigin;
1258
CurPos.z = PrevPos.z = 0;
1259
// Did the bot hardly move the last frame?
1260
if (GetDistance(CurPos, PrevPos) <= 0.1f)
1264
if (m_iStuckTime < lastmillis)
1270
m_iStuckTime = lastmillis + 1000;
1281
#ifndef RELEASE_BUILD
1283
sprintf(msg, "stuck (%f)", GetDistance(m_vPrevOrigin));
1290
// Crap bot is stuck, lets just try some random things
1292
// Check if the bot can turn around
1293
vec src = GetViewAngles();
1295
vec forward, right, up, dir, dest;
1298
AnglesToVectors(src, forward, right, up);
1300
// Check the left side...
1306
TraceLine(m_pMyEnt->o, dest, m_pMyEnt, false, &tr);
1307
//debugbeam(m_pMyEnt->o, end);
1311
// Bot can turn left, do so
1312
m_pMyEnt->targetyaw = WrapYZAngle(m_pMyEnt->yaw - 90);
1313
m_iStuckCheckDelay = m_iCheckEnvDelay = lastmillis + 500;
1317
// Check the right side...
1323
TraceLine(m_pMyEnt->o, dest, m_pMyEnt, true, &tr);
1324
//debugbeam(m_pMyEnt->o, end);
1328
// Bot can turn right, do so
1329
m_pMyEnt->targetyaw = WrapYZAngle(m_pMyEnt->yaw + 90);
1330
m_iStuckCheckDelay = m_iCheckEnvDelay = lastmillis + 500;
1334
// Check if bot can turn 180 degrees
1340
TraceLine(m_pMyEnt->o, dest, m_pMyEnt, true, &tr);
1341
//debugbeam(m_pMyEnt->o, end);
1345
// Bot can turn around, do so
1346
m_pMyEnt->targetyaw = WrapYZAngle(m_pMyEnt->yaw + 180);
1347
m_iStuckCheckDelay = m_iCheckEnvDelay = lastmillis + 500;
1351
// Bleh bot couldn't turn, lets just randomly jump :|
1353
condebug("Randomly avoiding stuck...");
1354
if (RandomLong(0, 2) == 0)
1355
m_pMyEnt->jumpnext = true;
1357
m_pMyEnt->targetyaw = WrapYZAngle(m_pMyEnt->yaw + RandomLong(60, 160));
1364
// Check if a near wall is blocking and we can jump over it
1365
bool CBot::CheckJump()
1367
bool bHasGoal = m_vGoal!=g_vecZero;
1368
float flGoalDist = (bHasGoal) ? GetDistance(m_vGoal) : 0.0f;
1370
// if ((bHasGoal) && (flGoalDist < 2.0f))
1371
// return false; UNDONE?
1373
vec start = m_pMyEnt->o;
1374
float flTraceDist = 3.0f;
1376
if (bHasGoal && (flGoalDist < flTraceDist))
1377
flTraceDist = flGoalDist;
1379
// Something blocks at eye hight?
1380
if (!IsVisible(start, FORWARD, flTraceDist, false))
1382
// Check if the bot can jump over it
1383
start.z += (JUMP_HEIGHT - 1.0f);
1384
if (IsVisible(start) && !IsVisible(start, FORWARD, flTraceDist, false))
1387
debugnav("High wall");
1388
m_pMyEnt->jumpnext = true;
1394
// Check if something is blocking at feet height, so the bot can jump over it
1397
// Trace was blocked?
1398
if (!IsVisible(start, FORWARD, flTraceDist, false))
1400
//debugbeam(start, end);
1403
debugnav("Low wall");
1404
m_pMyEnt->jumpnext = true;
1409
return false; // Bot didn't had to jump(or couldn't)
1412
bool CBot::CheckStrafe()
1414
if (m_iStrafeTime >= lastmillis)
1416
SetMoveDir(m_iMoveDir, true);
1420
if (m_iStrafeCheckDelay >= lastmillis)
1423
// Check for near walls
1425
vec from = m_pMyEnt->o, to, forward, right, up, dir;
1426
float flLeftDist = -1.0f, flRightDist = -1.0f;
1427
bool bStrafe = false;
1428
int iStrafeDir = DIR_NONE;
1430
AnglesToVectors(GetViewAngles(), forward, right, up);
1432
// Check for a near left wall
1437
TraceLine(from, to, m_pMyEnt, false, &tr);
1439
flLeftDist = GetDistance(from, tr.end);
1440
//debugbeam(m_pMyEnt->o, to);
1442
// Check for a near right wall
1447
TraceLine(from, to, m_pMyEnt, false, &tr);
1449
flRightDist = GetDistance(from, tr.end);
1450
//debugbeam(m_pMyEnt->o, to);
1452
if ((flLeftDist == -1.0f) && (flRightDist == -1.0f))
1455
dir.mul(m_pMyEnt->radius);
1460
if (IsVisible(from, FORWARD, 3.0f, false, &flLeftDist))
1466
if (IsVisible(from, FORWARD, 3.0f, false, &flRightDist))
1467
flRightDist = -1.0f;
1470
if ((flLeftDist != -1.0f) && (flRightDist != -1.0f))
1472
if (flLeftDist < flRightDist)
1478
else if (flRightDist < flLeftDist)
1486
// Randomly choose a strafe direction
1488
if (RandomLong(0, 1))
1494
else if (flLeftDist != -1.0f)
1500
else if (flRightDist != -1.0f)
1509
SetMoveDir(iStrafeDir, true);
1510
m_iMoveDir = iStrafeDir;
1511
m_iStrafeTime = lastmillis + RandomLong(75, 150);
1517
void CBot::CheckFOV()
1519
m_iCheckEnvDelay = lastmillis + RandomLong(125, 250);
1520
vec MyAngles = GetViewAngles();
1521
vec src, forward, right, up, dest, best(0, 0, 0);
1522
vec origin = m_pMyEnt->o;
1523
float flDist, flFurthestDist = 0;
1524
bool WallLeft = false;
1527
//origin.z -= 1.5; // Slightly under eye level
1529
// Scan 90 degrees FOV
1530
for(int angle=-45;angle<=45;angle+=5)
1533
src.y = WrapYZAngle(src.y + angle);
1535
AnglesToVectors(src, forward, right, up);
1541
TraceLine(origin, dest, m_pMyEnt, false, &tr);
1543
//debugbeam(origin, end);
1544
flDist = GetDistance(tr.end);
1546
if (flFurthestDist < flDist)
1548
flFurthestDist = flDist;
1553
if (best.x && best.y && best.z)
1556
// Update MyAngles, since their (going to be) change(d)
1557
MyAngles.x = m_pMyEnt->targetpitch;
1558
MyAngles.y = m_pMyEnt->targetyaw;
1561
float flNearestHitDist = GetDistance(best);
1563
if (!UnderWater(m_pMyEnt->o) && m_pMyEnt->onfloor)
1565
// Check if a near wall is blocking and we can jump over it
1566
if (flNearestHitDist < 4)
1568
// Check if the bot can jump over it
1572
AnglesToVectors(src, forward, right, up);
1580
TraceLine(start, dest, m_pMyEnt, false, &tr);
1581
//debugbeam(start, end);
1586
debugnav("High wall");
1587
m_pMyEnt->jumpnext = true;
1588
m_iStrafeCheckDelay = lastmillis + RandomLong(250, 500);
1594
// Check if something is blocking below us, so the bot can jump over it
1598
AnglesToVectors(src, forward, right, up);
1606
TraceLine(start, dest, m_pMyEnt, false, &tr);
1608
// Trace was blocked?
1611
//debugbeam(start, end);
1614
debugnav("Low wall");
1615
m_pMyEnt->jumpnext = true;
1616
m_iStrafeCheckDelay = lastmillis + RandomLong(250, 500);
1621
// Check if the bot is going to fall...
1624
AnglesToVectors(src, forward, right, up);
1630
TraceLine(origin, dest, m_pMyEnt, false, &tr);
1632
int cx = int(tr.end.x), cy = int(tr.end.y);
1633
short CubesInWater=0;
1634
for(int x=cx-1;x<=(cx+1);x++)
1636
for(int y=cy-1;y<=(cy+1);y++)
1638
if (OUTBORD(x, y)) continue;
1639
//sqr *s = S(fast_f2nat(x), fast_f2nat(y));
1642
vec from(x, y, m_pMyEnt->o.z);
1645
TraceLine(from, dest, m_pMyEnt, false, &tr);
1647
if (UnderWater(tr.end)) CubesInWater++;
1648
if (CubesInWater > 2) turn = true; // Always avoid water
1649
if (!tr.collided && RandomLong(0, 1))
1650
turn = true; // Randomly avoid a fall
1654
m_pMyEnt->targetyaw = WrapYZAngle(m_pMyEnt->yaw + 180);
1655
m_iCheckEnvDelay = m_iStrafeCheckDelay = lastmillis + RandomLong(750, 1500);
1656
debugnav("Water or a fall in front");
1664
// Is the bot about to head a corner?
1665
if (flNearestHitDist <= 4.0f)
1668
src.y = WrapYZAngle(src.y - 45.0f);
1669
AnglesToVectors(src, forward, right, up);
1675
TraceLine(origin, dest, m_pMyEnt, false, &tr);
1677
WallLeft = (tr.collided);
1680
src.y += WrapYZAngle(src.y + 45.0f);
1681
AnglesToVectors(src, forward, right, up);
1687
TraceLine(origin, dest, m_pMyEnt, false, &tr);
1689
if (WallLeft && tr.collided)
1691
// We're about to hit a corner, turn away
1693
m_pMyEnt->targetyaw = WrapYZAngle(m_pMyEnt->yaw + RandomFloat(160.0f, 200.0f));
1694
m_iCheckEnvDelay = m_iStrafeCheckDelay = lastmillis + RandomLong(750, 1500);
1700
// Called when bot is underwater
1701
bool CBot::WaterNav()
1703
const int iSearchRange = 4;
1705
if (m_vWaterGoal==g_vecZero)
1707
AddDebugText("WaterNav");
1708
// Find the nearest and reachable cube which isn't underwater
1710
int cx = int(m_pMyEnt->o.x);
1711
int cy = int(m_pMyEnt->o.y);
1712
float flNearestDist = 9999.0f, flDist;
1714
if (OUTBORD(cx, cy)) return false;
1716
// Check all cubes in range...
1717
for (int x=(cx-iSearchRange);x<=(cx+iSearchRange);x++)
1719
for (int y=(cy-iSearchRange);y<=(cy+iSearchRange);y++)
1723
if (SOLID(s)) continue;
1724
if ((x==cx) && (y==cy)) continue;
1726
vec v(x, y, GetCubeFloor(x, y));
1728
if (UnderWater(v)) continue; // Skip, cube is underwater
1730
if (hdr.waterlevel < (v.z - 2.0f)) continue; // Cube is too high
1732
// Check if the bot 'can fit' on the cube(no near obstacles)
1734
for (int a=(x-2);a<=(x+2);a++)
1737
for (int b=(y-2);b<=(y+2);b++)
1739
if ((x==a) && (y==b)) continue;
1740
vec v2(a, b, GetCubeFloor(a, b));
1741
if (v.z < (v2.z-1-JUMP_HEIGHT))
1747
if ((a >= (x-1)) && (a <= (x+1)) && (b >= (y-1)) && (b <= (y+1)))
1749
if ((v2.z) < (v.z-2.0f))
1757
TraceLine(v, v2, NULL, false, &tr);
1768
debugbeam(m_pMyEnt->o, v);
1772
// Okay, cube is valid.
1773
flDist = GetDistance(v);
1774
if (flDist < flNearestDist)
1776
flNearestDist = flDist;
1783
if (m_vWaterGoal!=g_vecZero)
1785
AddDebugText("WaterNav");
1786
//debugbeam(m_pMyEnt->o, m_vWaterGoal);
1787
vec aim = m_vWaterGoal;
1788
aim.z += 1.5f; // Aim a bit further up
1790
if ((RandomLong(1, 100) <= 15) && (Get2DDistance(m_vWaterGoal) <= 7.0f))
1791
m_pMyEnt->jumpnext = true;
1798
bool CBot::CheckItems()
1800
if (!m_pCurrentGoalWaypoint && !CheckJump() && CheckStuck())
1802
// Don't check for ents a while when stuck
1803
m_iCheckEntsDelay = lastmillis + RandomLong(1000, 2000);
1807
if (m_vGoal==g_vecZero)
1808
m_pTargetEnt = NULL;
1812
if (m_iCheckEntsDelay > lastmillis)
1816
m_pTargetEnt = SearchForEnts(!m_classicsp);
1817
m_iCheckEntsDelay = lastmillis + RandomLong(2500, 5000);
1823
if (HeadToTargetEnt())
1827
if (m_eCurrentBotState == STATE_ENT)
1829
ResetWaypointVars();
1830
m_vGoal = g_vecZero;
1831
m_pTargetEnt = NULL;
1837
bool CBot::InUnreachableList(entity *e)
1839
TLinkedList<unreachable_ent_s *>::node_s *p = m_UnreachableEnts.GetFirst();
1842
if (p->Entry->ent == e) return true;
1848
bool CBot::IsReachable(vec to, float flMaxHeight)
1850
vec from = m_pMyEnt->o;
1852
float curr_height, last_height;
1854
float distance = GetDistance(from, to);
1856
// is the destination close enough?
1857
//if (distance < REACHABLE_RANGE)
1861
// Look if bot can 'fit trough'
1862
vec src = from, forward, right, up;
1863
AnglesToVectors(GetViewAngles(), forward, right, up);
1865
// Trace from 1 cube to the left
1869
if (!::IsVisible(src, to)) return false;
1871
// Trace from 1 cube to the right
1873
if (!::IsVisible(src, to)) return false;
1875
if (UnderWater(from) && UnderWater(to))
1877
// No need to worry about heights in water
1881
if (to.z > (from.z + JUMP_HEIGHT))
1884
vec v_new_dest = to;
1886
v_new_dest.z = v_new_dest.z - (JUMP_HEIGHT + 1.0f);
1888
// check if we didn't hit anything, if so then it's in mid-air
1889
if (::IsVisible(v_new_src, v_new_dest, NULL))
1891
condebug("to is in midair");
1892
debugbeam(from, to);
1893
return false; // can't reach this one
1898
// check if distance to ground increases more than jump height
1899
// at points between from and to...
1903
vec v_direction = Normalize(v_temp); // 1 unit long
1907
v_down.z = v_down.z - 100.0f; // straight down
1909
TraceLine(v_check, v_down, NULL, false, &tr);
1911
// height from ground
1912
last_height = GetDistance(v_check, tr.end);
1914
distance = GetDistance(to, v_check); // distance from goal
1916
while (distance > 2.0f)
1918
// move 2 units closer to the goal
1919
v_temp = v_direction;
1921
v_check.add(v_temp);
1924
v_down.z = v_down.z - 100.0f;
1926
TraceLine(v_check, v_down, NULL, false, &tr);
1928
curr_height = GetDistance(v_check, tr.end);
1930
// is the difference in the last height and the current height
1931
// higher that the jump height?
1932
if ((last_height - curr_height) >= flMaxHeight)
1934
// can't get there from here...
1935
//condebug("traces failed to to");
1936
debugbeam(from, to);
1940
last_height = curr_height;
1942
distance = GetDistance(to, v_check); // distance from goal
1952
void CBot::HearSound(int n, vec *o)
1954
// Has the bot already an enemy?
1955
if (m_pMyEnt->enemy) return;
1959
// Is the sound not interesting?
1960
if(n == S_DIE1 || n == S_DIE2) return;
1962
int soundvol = m_pBotSkill->iMaxHearVolume -
1963
(int)(GetDistance(*o)*3*m_pBotSkill->iMaxHearVolume/255);
1965
if (soundvol == 0) return;
1967
// Look who made the sound(check for the nearest enemy)
1968
float flDist, flNearestDist = 3.0f; // Range of 3 units
1969
playerent *pNearest = NULL;
1971
// Check all players first
1974
playerent *d = players[i];
1976
if (d == m_pMyEnt || !d || (d->state != CS_ALIVE) ||
1977
isteam(m_pMyEnt->team, d->team))
1980
flDist = GetDistance(*o, d->o);
1981
if ((flDist < flNearestDist) && IsVisible(d))
1984
flNearestDist = flDist;
1988
// Check local player
1989
if (player1 && (player1->state == CS_ALIVE) &&
1990
!isteam(m_pMyEnt->team, player1->team))
1992
flDist = GetDistance(*o, player1->o);
1993
if ((flDist < flNearestDist) && IsVisible(player1))
1996
flNearestDist = flDist;
2002
if (m_pMyEnt->enemy != pNearest)
2003
m_iShootDelay = lastmillis + GetShootDelay(); // Add shoot delay when new enemy found
2005
m_pMyEnt->enemy = pNearest;
2009
bool CBot::IsInFOV(const vec &o)
2011
vec v2, forward, right, up;
2014
AnglesToVectors(GetViewAngles(), forward, right, up);
2017
v2.sub(m_pMyEnt->o);
2018
v2.z = 0.0f; // Make 2D
2020
forward.z = 0; // Make 2D
2022
flDot = v2.dot(forward);
2024
return(flDot >= 0.5f); // sin2(0.5) == 60 degrees FOV
2027
// Code of CBot - End