diff --git a/README.md b/README.md
index 136beceb..82b032e7 100644
--- a/README.md
+++ b/README.md
@@ -28,7 +28,7 @@ Archive's bin directory contains 2 subdirectories, 'bugfixed' and 'pure'
## Current status
- Counter-Strike 1.6 - 100%
-- Counter-Strike: Condition Zero - 63%
+- Counter-Strike: Condition Zero - 90%
## Build instructions
diff --git a/regamedll/build.gradle b/regamedll/build.gradle
index a91135f1..28f9497c 100644
--- a/regamedll/build.gradle
+++ b/regamedll/build.gradle
@@ -170,7 +170,7 @@ void setupToolchain(NativeBinarySpec b)
'_vsnprintf': 'vsnprintf',
'_write' : 'write',
'_close' : 'close',
- '_vsnwprintf' : 'vsnwprintf'
+ '_vsnwprintf' : 'vswprintf'
])
cfg.linkerOptions.args '-no-opt-class-analysis'
diff --git a/regamedll/common/mathlib.h b/regamedll/common/mathlib.h
index 3fb018d9..4c2250b3 100644
--- a/regamedll/common/mathlib.h
+++ b/regamedll/common/mathlib.h
@@ -32,17 +32,17 @@
#pragma once
#endif
-#ifdef PLAY_GAMEDLL
-
-// probably gamedll compiled with flag /fpmath:fasted,
-// so we need to use type double, otherwise will be the test failed
-
-typedef double float_precision;
-
-#else // HOOK_GAMEDLL
-
-typedef float float_precision;
-
+#ifdef PLAY_GAMEDLL
+
+// probably gamedll compiled with flag /fpmath:fasted,
+// so we need to use type double, otherwise will be the test failed
+
+typedef double float_precision;
+
+#else // PLAY_GAMEDLL
+
+typedef float float_precision;
+
#endif // PLAY_GAMEDLL
/* <42b7f> ../common/mathlib.h:3 */
@@ -76,6 +76,22 @@ T Q_max(T a, T b) { return (a > b) ? a : b; }
template
T clamp(T a, T min, T max) { return (a > max) ? max : (a < min) ? min : a; }
+// bitwise operators templates
+template::type>
+inline T operator~ (T a) { return (T)~(type)a; }
+template::type>
+inline T operator| (T a, T b) { return (T)((type)a | (type)b); }
+template::type>
+inline T operator& (T a, T b) { return (T)((type)a & (type)b); }
+template::type>
+inline T operator^ (T a, T b) { return (T)((type)a ^ (type)b); }
+template::type>
+inline T& operator|= (T& a, T b){ return (T&)((type&)a |= (type)b); }
+template::type>
+inline T& operator&= (T& a, T b){ return (T&)((type&)a &= (type)b); }
+template::type>
+inline T& operator^= (T& a, T b){ return (T&)((type&)a ^= (type)b); }
+
#define VectorSubtract(a,b,c) {(c)[0]=(a)[0]-(b)[0];(c)[1]=(a)[1]-(b)[1];(c)[2]=(a)[2]-(b)[2];}
#define VectorAdd(a,b,c) {(c)[0]=(a)[0]+(b)[0];(c)[1]=(a)[1]+(b)[1];(c)[2]=(a)[2]+(b)[2];}
#define VectorCopy(a,b) {(b)[0]=(a)[0];(b)[1]=(a)[1];(b)[2]=(a)[2];}
diff --git a/regamedll/dlls/activity.h b/regamedll/dlls/activity.h
index 9941d7e2..e5df9293 100644
--- a/regamedll/dlls/activity.h
+++ b/regamedll/dlls/activity.h
@@ -32,12 +32,9 @@
#pragma once
#endif
-#define ACTIVITY_NOT_AVAILABLE -1
-
typedef enum
{
- //TODO: i think it need added (from hlbeta2)
- //ACT_INVALID = -1,
+ ACT_INVALID = -1,
ACT_RESET = 0, // Set m_Activity to this invalid value to force a reset to m_IdealActivity
ACT_IDLE,
diff --git a/regamedll/dlls/animation.cpp b/regamedll/dlls/animation.cpp
index 188003c6..f2a69404 100644
--- a/regamedll/dlls/animation.cpp
+++ b/regamedll/dlls/animation.cpp
@@ -119,7 +119,7 @@ int LookupActivity(void *pmodel, entvars_t *pev, int activity)
}
}
- return ACTIVITY_NOT_AVAILABLE;
+ return ACT_INVALID;
}
/* <1539a> ../cstrike/dlls/animation.cpp:149 */
@@ -134,7 +134,7 @@ int LookupActivityHeaviest(void *pmodel, entvars_t *pev, int activity)
mstudioseqdesc_t *pseqdesc = (mstudioseqdesc_t *)((byte *)pstudiohdr + pstudiohdr->seqindex);
int weight = 0;
- int seq = ACTIVITY_NOT_AVAILABLE;
+ int seq = ACT_INVALID;
for (int i = 0; i < pstudiohdr->numseq; i++)
{
@@ -179,13 +179,16 @@ int LookupSequence(void *pmodel, const char *label)
return 0;
}
+ // Look up by sequence name.
mstudioseqdesc_t *pseqdesc = (mstudioseqdesc_t *)((byte *)pstudiohdr + pstudiohdr->seqindex);
for (int i = 0; i < pstudiohdr->numseq; i++)
{
if (!Q_stricmp(pseqdesc[i].label, label))
return i;
}
- return -1;
+
+ // Not found
+ return ACT_INVALID;
}
/* <1518c> ../cstrike/dlls/animation.cpp:215 */
diff --git a/regamedll/dlls/bot/cs_bot.cpp b/regamedll/dlls/bot/cs_bot.cpp
index 5bc54caa..afc12061 100644
--- a/regamedll/dlls/bot/cs_bot.cpp
+++ b/regamedll/dlls/bot/cs_bot.cpp
@@ -1,110 +1,299 @@
#include "precompiled.h"
+// Return the number of bots following the given player
+
/* <2e85c8> ../cstrike/dlls/bot/cs_bot.cpp:24 */
-NOBODY int GetBotFollowCount(CBasePlayer *leader)
+int GetBotFollowCount(CBasePlayer *leader)
{
-// {
-// int count; // 26
-// {
-// int i; // 28
-// {
-// class CBaseEntity *entity; // 30
-// class CBasePlayer *player; // 41
-// class CCSBot *bot; // 49
-// FNullEnt(entvars_t *pev); // 35
-// GetFollowLeader(CCSBot *const this); // 50
-// }
-// }
-// }
+ int count = 0;
+
+ for (int i = 1; i <= gpGlobals->maxClients; ++i)
+ {
+ CBaseEntity *entity = UTIL_PlayerByIndex(i);
+
+ if (entity == NULL)
+ continue;
+
+ if (FNullEnt(entity->pev))
+ continue;
+
+ if (FStrEq(STRING(entity->pev->netname), ""))
+ continue;
+
+ CBasePlayer *player = static_cast(entity);
+
+ if (!player->IsBot())
+ continue;
+
+ if (!player->IsAlive())
+ continue;
+
+ CCSBot *bot = dynamic_cast(player);
+ if (bot && bot->GetFollowLeader() == leader)
+ ++count;
+ }
+
+ return count;
}
+// Change movement speed to walking
+
/* <2e86df> ../cstrike/dlls/bot/cs_bot.cpp:62 */
-NOBODY void CCSBot::__MAKE_VHOOK(Walk)(void)
+void CCSBot::__MAKE_VHOOK(Walk)(void)
{
-// IsElapsed(const class CountdownTimer *const this); // 64
-// Walk(CBot *const this); // 66
+ if (m_mustRunTimer.IsElapsed())
+ {
+ CBot::Walk();
+ return;
+ }
+
+ // must run
+ Run();
}
+// Return true if jump was started.
+// This is extended from the base jump to disallow jumping when in a crouch area.
+
/* <2e8732> ../cstrike/dlls/bot/cs_bot.cpp:80 */
-NOBODY bool CCSBot::__MAKE_VHOOK(Jump)(bool mustJump)
+bool CCSBot::__MAKE_VHOOK(Jump)(bool mustJump)
{
+ // prevent jumping if we're crouched, unless we're in a crouchjump area - jump wins
+ bool inCrouchJumpArea = (m_lastKnownArea &&
+ (m_lastKnownArea->GetAttributes() & NAV_CROUCH) &&
+ !(m_lastKnownArea->GetAttributes() & NAV_JUMP));
+
+ if (inCrouchJumpArea)
+ {
+ return false;
+ }
+
+ return CBot::Jump(mustJump);
}
+// Invoked when injured by something
+// NOTE: We dont want to directly call Attack() here, or the bots will have super-human reaction times when injured
+
/* <2e8e39> ../cstrike/dlls/bot/cs_bot.cpp:97 */
-NOBODY int CCSBot::__MAKE_VHOOK(TakeDamage)(entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType)
+int CCSBot::__MAKE_VHOOK(TakeDamage)(entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType)
{
-// {
-// class CBaseEntity *attacker; // 99
-// GetClassPtr(CBaseEntity *a); // 99
-// {
-// class CBasePlayer *player; // 104
-// }
-// {
-// class CBasePlayer *lastAttacker; // 113
-// float lastAttackedTimestamp; // 114
-// AdjustSafeTime(CCSBot *const this); // 121
-// IsSurprised(const class CCSBot *const this); // 124
-// {
-// class CBasePlayer *enemy; // 126
-// bool panic; // 127
-// {
-// float invSkill; // 148
-// float panicChance; // 149
-// }
-// }
-// }
-// }
+ CBaseEntity *attacker = GetClassPtr((CBaseEntity *)pevInflictor);
+
+ // if we were attacked by a teammate, rebuke
+ if (attacker->IsPlayer())
+ {
+ CBasePlayer *player = static_cast(attacker);
+
+ if (player->m_iTeam == m_iTeam && !player->IsBot())
+ {
+ GetChatter()->FriendlyFire();
+ }
+ }
+
+ if (attacker->IsPlayer() && IsEnemy(attacker))
+ {
+ // Track previous attacker so we don't try to panic multiple times for a shotgun blast
+ CBasePlayer *lastAttacker = m_attacker;
+ float lastAttackedTimestamp = m_attackedTimestamp;
+
+ // keep track of our last attacker
+ m_attacker = reinterpret_cast(attacker);
+ m_attackedTimestamp = gpGlobals->time;
+
+ // no longer safe
+ AdjustSafeTime();
+
+ if (!IsSurprised() && (m_attacker != lastAttacker || m_attackedTimestamp != lastAttackedTimestamp))
+ {
+ CBasePlayer *enemy = static_cast(attacker);
+
+ // being hurt by an enemy we can't see causes panic
+ if (!IsVisible(enemy, CHECK_FOV))
+ {
+ bool panic = false;
+
+ // if not attacking anything, look around to try to find attacker
+ if (!IsAttacking())
+ {
+ panic = true;
+ }
+ else
+ {
+ // we are attacking
+ if (!IsEnemyVisible())
+ {
+ // can't see our current enemy, panic to acquire new attacker
+ panic = true;
+ }
+ }
+
+ if (!panic)
+ {
+ float invSkill = 1.0f - GetProfile()->GetSkill();
+ float panicChance = invSkill * invSkill * 50.0f;
+
+ if (panicChance > RANDOM_FLOAT(0, 100))
+ {
+ panic = true;
+ }
+ }
+
+ if (panic != false)
+ {
+ // can't see our current enemy, panic to acquire new attacker
+ Panic(m_attacker);
+ }
+ }
+ }
+ }
+
+ // extend
+ return CBasePlayer::TakeDamage(pevInflictor, pevAttacker, flDamage, bitsDamageType);
}
+// Invoked when killed
+
/* <2e8769> ../cstrike/dlls/bot/cs_bot.cpp:171 */
-NOBODY void CCSBot::__MAKE_VHOOK(Killed)(entvars_t *pevAttacker, int iGib)
+void CCSBot::__MAKE_VHOOK(Killed)(entvars_t *pevAttacker, int iGib)
{
-// {
-// float const deathDanger; // 178
-// float const deathDangerRadius; // 179
-// }
+ PrintIfWatched("Killed( attacker = %s )\n", STRING(pevAttacker->netname));
+
+ GetChatter()->OnDeath();
+
+ // increase the danger where we died
+ const float deathDanger = 1.0f;
+ const float deathDangerRadius = 500.0f;
+ IncreaseDangerNearby(m_iTeam - 1, deathDanger, m_lastKnownArea, &pev->origin, deathDangerRadius);
+
+ // end voice feedback
+ EndVoiceFeedback();
+
+ // extend
+ CBasePlayer::Killed(pevAttacker, iGib);
}
+// Return true if line segment intersects rectagular volume
+
/* <2e7c11> ../cstrike/dlls/bot/cs_bot.cpp:200 */
-NOBODY inline bool IsIntersectingBox(const Vector *start, const Vector *end, const Vector *boxMin, const Vector *boxMax)
+bool IsIntersectingBox(const Vector *start, const Vector *end, const Vector *boxMin, const Vector *boxMax)
{
-// {
-// unsigned char startFlags; // 202
-// unsigned char endFlags; // 203
-// }
+ unsigned char startFlags = 0;
+ unsigned char endFlags = 0;
+
+ // classify start point
+ if (start->x < boxMin->x)
+ startFlags |= LO_X;
+ if (start->x > boxMax->x)
+ startFlags |= HI_X;
+
+ if (start->y < boxMin->y)
+ startFlags |= LO_Y;
+ if (start->y > boxMax->y)
+ startFlags |= HI_Y;
+
+ if (start->z < boxMin->z)
+ startFlags |= LO_Z;
+ if (start->z > boxMax->z)
+ startFlags |= HI_Z;
+
+ // classify end point
+ if (end->x < boxMin->x)
+ endFlags |= LO_X;
+ if (end->x > boxMax->x)
+ endFlags |= HI_X;
+
+ if (end->y < boxMin->y)
+ endFlags |= LO_Y;
+ if (end->y > boxMax->y)
+ endFlags |= HI_Y;
+
+ if (end->z < boxMin->z)
+ endFlags |= LO_Z;
+ if (end->z > boxMax->z)
+ endFlags |= HI_Z;
+
+ // trivial reject
+ if (startFlags & endFlags)
+ return false;
+
+ // TODO: Do exact line/box intersection check
+ return true;
}
+// When bot is touched by another entity.
+
/* <2e87d9> ../cstrike/dlls/bot/cs_bot.cpp:253 */
-NOBODY void CCSBot::BotTouch(CBaseEntity *other)
+void CCSBot::BotTouch(CBaseEntity *other)
{
-// FStrEq(const char *sz1,
-// const char *sz2); // 297
-// {
-// Vector center; // 299
-// class Extent extent; // 301
-// bool breakIt; // 307
-// operator+(const Vector *const this,
-// const Vector &v); // 299
-// {
-// Vector goal; // 312
-// Vector(Vector *const this,
-// const Vector &v); // 312
-// IsIntersectingBox(const Vector *start,
-// const Vector *end,
-// const Vector *boxMin,
-// const Vector *boxMax); // 314
-// }
-// operator/(const Vector *const this,
-// float fl); // 299
-// }
-// {
-// class CBasePlayer *player; // 269
-// unsigned int otherPri; // 272
-// unsigned int myPri; // 275
-// {
-// unsigned int avoidPri; // 284
-// }
-// }
+ // if we have touched a higher-priority player, make way
+ // TODO: Need to account for reaction time, etc.
+ if (other->IsPlayer())
+ {
+ // if we are defusing a bomb, don't move
+ if (IsDefusingBomb())
+ return;
+
+ CBasePlayer *player = static_cast(other);
+
+ // get priority of other player
+ unsigned int otherPri = TheCSBots()->GetPlayerPriority(player);
+
+ // get our priority
+ unsigned int myPri = TheCSBots()->GetPlayerPriority(this);
+
+ // if our priority is better, don't budge
+ if (myPri < otherPri)
+ return;
+
+ // they are higher priority - make way, unless we're already making way for someone more important
+ if (m_avoid != NULL)
+ {
+ unsigned int avoidPri = TheCSBots()->GetPlayerPriority(static_cast(static_cast(m_avoid)));
+ if (avoidPri < otherPri)
+ {
+ // ignore 'other' because we're already avoiding someone better
+ return;
+ }
+ }
+
+ m_avoid = other;
+ m_avoidTimestamp = gpGlobals->time;
+
+ return;
+ }
+
+ // If we won't be able to break it, don't try
+ if (other->pev->takedamage != DAMAGE_YES)
+ return;
+
+ if (IsAttacking())
+ return;
+
+ // See if it's breakable
+ if (FClassnameIs(other->pev, "func_breakable"))
+ {
+ Vector center = (other->pev->absmax + other->pev->absmin) / 2.0f;
+ bool breakIt = true;
+
+ if (m_pathLength)
+ {
+ Vector goal = m_goalPosition + Vector(0, 0, HalfHumanHeight);
+ breakIt = IsIntersectingBox(&pev->origin, &goal, &other->pev->absmin, &other->pev->absmax);
+ }
+
+ if (breakIt)
+ {
+ // it's breakable - try to shoot it.
+ SetLookAt("Breakable", ¢er, PRIORITY_HIGH, 0.2, 0, 5.0);
+
+ if (IsUsingGrenade())
+ {
+ EquipBestWeapon(0);
+ return;
+ }
+
+ PrimaryAttack();
+ }
+ }
}
/* <2e89e3> ../cstrike/dlls/bot/cs_bot.cpp:335 */
@@ -124,22 +313,34 @@ bool CCSBot::IsBusy(void) const
}
/* <2e8a0c> ../cstrike/dlls/bot/cs_bot.cpp:351 */
-NOBODY void CCSBot::BotDeathThink(void)
+void CCSBot::BotDeathThink(void)
{
+ ;
}
/* <2e8a34> ../cstrike/dlls/bot/cs_bot.cpp:358 */
-NOBODY CBasePlayer *CCSBot::FindNearbyPlayer(void)
+CBasePlayer *CCSBot::FindNearbyPlayer(void)
{
-// {
-// class CBaseEntity *pEntity; // 360
-// Vector vecSrc; // 361
-// float flRadius; // 362
-// Vector(Vector *const this,
-// const Vector &v); // 361
-// }
+ CBaseEntity *pEntity = NULL;
+ Vector vecSrc = pev->origin;
+ const float flRadius = 800.0f;
+
+ while ((pEntity = UTIL_FindEntityInSphere(pEntity, vecSrc, flRadius)) != NULL)
+ {
+ if (!pEntity->IsPlayer())
+ continue;
+
+ if (!(pEntity->pev->flags & FL_FAKECLIENT))
+ continue;
+
+ return static_cast(pEntity);
+ }
+
+ return NULL;
}
+// Assign given player as our current enemy to attack
+
/* <2e8abd> ../cstrike/dlls/bot/cs_bot.cpp:385 */
void CCSBot::SetEnemy(CBasePlayer *enemy)
{
@@ -150,180 +351,393 @@ void CCSBot::SetEnemy(CBasePlayer *enemy)
}
}
+// If we are not on the navigation mesh (m_currentArea == NULL),
+// move towards last known area.
+// Return false if off mesh.
+
/* <2e8af6> ../cstrike/dlls/bot/cs_bot.cpp:400 */
-NOBODY bool CCSBot::StayOnNavMesh(void)
+bool CCSBot::StayOnNavMesh(void)
{
-// {
-// class CNavArea *goalArea; // 408
-// {
-// Vector pos; // 422
-// Vector to; // 426
-// float const stepInDist; // 429
-// operator-(const Vector *const this,
-// const Vector &v); // 426
-// NormalizeInPlace(Vector *const this); // 427
-// operator*(float fl,
-// const Vector &v); // 430
-// operator+(const Vector *const this,
-// const Vector &v); // 430
-// }
-// }
+ if (m_currentArea != NULL)
+ return true;
+
+ // move back onto the area map
+
+ // if we have no lastKnownArea, we probably started off
+ // of the nav mesh - find the closest nav area and use it
+ CNavArea *goalArea;
+ if (!m_currentArea && !m_lastKnownArea)
+ {
+ goalArea = TheNavAreaGrid.GetNearestNavArea(&pev->origin);
+ PrintIfWatched("Started off the nav mesh - moving to closest nav area...\n");
+ }
+ else
+ {
+ goalArea = m_lastKnownArea;
+ PrintIfWatched("Getting out of NULL area...\n");
+ }
+
+ if (goalArea != NULL)
+ {
+ Vector pos;
+ goalArea->GetClosestPointOnArea(&pev->origin, &pos);
+
+ // move point into area
+ Vector to = pos - pev->origin;
+ to.NormalizeInPlace();
+
+ // how far to "step into" an area - must be less than min area size
+ const float stepInDist = 5.0f;
+ pos = pos + (stepInDist * to);
+
+ MoveTowardsPosition(&pos);
+ }
+
+ // if we're stuck, try to get un-stuck
+ // do stuck movements last, so they override normal movement
+ if (m_isStuck)
+ {
+ Wiggle();
+ }
+
+ return false;
}
/* <2e8c56> ../cstrike/dlls/bot/cs_bot.cpp:450 */
-NOBODY void CCSBot::Panic(CBasePlayer *enemy)
+void CCSBot::Panic(CBasePlayer *enemy)
{
-// {
-// class Vector2D dir; // 456
-// class Vector2D perp; // 457
-// Vector spot; // 459
-// IsSurprised(const class CCSBot *const this); // 453
-// {
-// class Vector2D toEnemy; // 473
-// float along; // 476
-// float c45; // 477
-// float size; // 478
-// float shift; // 479
-// NormalizeInPlace(Vector2D *const this); // 474
-// DotProduct(const class Vector2D &a,
-// const class Vector2D &b); // 476
-// {
-// float side; // 495
-// DotProduct(const class Vector2D &a,
-// const class Vector2D &b); // 495
-// }
-// }
-// {
-// float const offset; // 464
-// float side; // 465
-// }
-// }
+ if (IsSurprised())
+ return;
+
+ Vector2D dir(BotCOS(pev->v_angle.y), BotSIN(pev->v_angle.y));
+ Vector2D perp(-dir.y, dir.x);
+ Vector spot;
+
+ if (GetProfile()->GetSkill() >= 0.5f)
+ {
+ Vector2D toEnemy = (enemy->pev->origin - pev->origin).Make2D();
+ toEnemy.NormalizeInPlace();
+
+ float along = DotProduct(toEnemy, dir);
+
+ float c45 = 0.7071f;
+ float size = 100.0f;
+
+ float_precision shift = RANDOM_FLOAT(-75.0, 75.0);
+
+ if (along > c45)
+ {
+ spot.x = pev->origin.x + dir.x * size + perp.x * shift;
+ spot.y = pev->origin.y + dir.y * size + perp.y * shift;
+ }
+ else if (along < -c45)
+ {
+ spot.x = pev->origin.x - dir.x * size + perp.x * shift;
+ spot.y = pev->origin.y - dir.y * size + perp.y * shift;
+ }
+ else if (DotProduct(toEnemy, perp) > 0.0)
+ {
+ spot.x = pev->origin.x + perp.x * size + dir.x * shift;
+ spot.y = pev->origin.y + perp.y * size + dir.y * shift;
+ }
+ else
+ {
+ spot.x = pev->origin.x - perp.x * size + dir.x * shift;
+ spot.y = pev->origin.y - perp.y * size + dir.y * shift;
+ }
+ }
+ else
+ {
+ const float offset = 200.0f;
+ float_precision side = RANDOM_FLOAT(-offset, offset) * 2.0f;
+
+ spot.x = pev->origin.x - dir.x * offset + perp.x * side;
+ spot.y = pev->origin.y - dir.y * offset + perp.y * side;
+ }
+
+ spot.z = pev->origin.z + RANDOM_FLOAT(-50.0, 50.0);
+
+ // we are stunned for a moment
+ m_surpriseDelay = RANDOM_FLOAT(0.1, 0.2);
+ m_surpriseTimestamp = gpGlobals->time;
+
+ SetLookAt("Panic", &spot, PRIORITY_HIGH, 0, 0, 5.0);
+ PrintIfWatched("Aaaah!\n");
}
/* <2e9047> ../cstrike/dlls/bot/cs_bot.cpp:527 */
-NOBODY bool CCSBot::IsDoingScenario(void)
+bool CCSBot::IsDoingScenario(void) const
{
+ if (cv_bot_defer_to_human.value <= 0.0f)
+ return true;
+
+ return !UTIL_HumansOnTeam(m_iTeam, true);
}
+// Return true if we noticed the bomb on the ground or on the radar (for T's only)
+
/* <2e9070> ../cstrike/dlls/bot/cs_bot.cpp:544 */
-NOBODY bool CCSBot::NoticeLooseBomb(void) const
+bool CCSBot::NoticeLooseBomb(void) const
{
-// {
-// class CCSBotManager *ctrl; // 546
-// class CBaseEntity *bomb; // 551
-// GetLooseBomb(CCSBotManager *const this); // 551
-// }
+ CCSBotManager *ctrl = TheCSBots();
+
+ if (ctrl->GetScenario() != CCSBotManager::SCENARIO_DEFUSE_BOMB)
+ return false;
+
+ CBaseEntity *bomb = ctrl->GetLooseBomb();
+
+ if (bomb != NULL)
+ {
+ // T's can always see bomb on their radar
+ return true;
+ }
+
+ return false;
}
+// Return true if can see the bomb lying on the ground
+
/* <2e90d4> ../cstrike/dlls/bot/cs_bot.cpp:566 */
-NOBODY bool CCSBot::CanSeeLooseBomb(void) const
+bool CCSBot::CanSeeLooseBomb(void) const
{
-// {
-// class CCSBotManager *ctrl; // 568
-// class CBaseEntity *bomb; // 573
-// GetLooseBomb(CCSBotManager *const this); // 573
-// }
+ CCSBotManager *ctrl = TheCSBots();
+
+ if (ctrl->GetScenario() != CCSBotManager::SCENARIO_DEFUSE_BOMB)
+ return false;
+
+ CBaseEntity *bomb = ctrl->GetLooseBomb();
+
+ if (bomb != NULL)
+ {
+ if (IsVisible(&bomb->pev->origin, CHECK_FOV))
+ return true;
+ }
+
+ return false;
}
+// Return true if can see the planted bomb
+
/* <2e9140> ../cstrike/dlls/bot/cs_bot.cpp:588 */
-NOBODY bool CCSBot::CanSeePlantedBomb(void) const
+bool CCSBot::CanSeePlantedBomb(void) const
{
-// {
-// class CCSBotManager *ctrl; // 590
-// const Vector *bombPos; // 598
-// }
+ CCSBotManager *ctrl = TheCSBots();
+
+ if (ctrl->GetScenario() != CCSBotManager::SCENARIO_DEFUSE_BOMB)
+ return false;
+
+ if (!GetGameState()->IsBombPlanted())
+ return false;
+
+ const Vector *bombPos = GetGameState()->GetBombPosition();
+
+ if (bombPos != NULL && IsVisible(bombPos, CHECK_FOV))
+ return true;
+
+ return false;
}
+// Return last enemy that hurt us
+
/* <2e918e> ../cstrike/dlls/bot/cs_bot.cpp:610 */
-NOBODY CBasePlayer *CCSBot::GetAttacker(void)
+CBasePlayer *CCSBot::GetAttacker(void) const
{
+ if (m_attacker != NULL && m_attacker->IsAlive())
+ return m_attacker;
+
+ return NULL;
}
+// Immediately jump off of our ladder, if we're on one
+
/* <2e91b7> ../cstrike/dlls/bot/cs_bot.cpp:622 */
-NOBODY void CCSBot::GetOffLadder(void)
+void CCSBot::GetOffLadder(void)
{
-// DestroyPath(CCSBot *const this); // 627
+ if (IsUsingLadder())
+ {
+ Jump(MUST_JUMP);
+ DestroyPath();
+ }
}
+// Return time when given spot was last checked
+
/* <2e91f1> ../cstrike/dlls/bot/cs_bot.cpp:637 */
-NOBODY float CCSBot::GetHidingSpotCheckTimestamp(HidingSpot *spot)
+float CCSBot::GetHidingSpotCheckTimestamp(HidingSpot *spot) const
{
-// {
-// int i; // 639
-// }
+ for (int i = 0; i < m_checkedHidingSpotCount; ++i)
+ {
+ if (m_checkedHidingSpot[i].spot->GetID() == spot->GetID())
+ return m_checkedHidingSpot[i].timestamp;
+ }
+
+ return -999999.9f;
}
+// Set the timestamp of the given spot to now.
+// If the spot is not in the set, overwrite the least recently checked spot.
+
/* <2e9240> ../cstrike/dlls/bot/cs_bot.cpp:651 */
-NOBODY void CCSBot::SetHidingSpotCheckTimestamp(HidingSpot *spot)
+void CCSBot::SetHidingSpotCheckTimestamp(HidingSpot *spot)
{
-// {
-// int leastRecent; // 653
-// float leastRecentTime; // 654
-// {
-// int i; // 656
-// }
-// }
+ int leastRecent = 0;
+ float leastRecentTime = gpGlobals->time + 1.0f;
+
+ for (int i = 0; i < m_checkedHidingSpotCount; ++i)
+ {
+ // if spot is in the set, just update its timestamp
+ if (m_checkedHidingSpot[i].spot->GetID() == spot->GetID())
+ {
+ m_checkedHidingSpot[i].timestamp = gpGlobals->time;
+ return;
+ }
+
+ // keep track of least recent spot
+ if (m_checkedHidingSpot[i].timestamp < leastRecentTime)
+ {
+ leastRecentTime = m_checkedHidingSpot[i].timestamp;
+ leastRecent = i;
+ }
+ }
+
+ // if there is room for more spots, append this one
+ if (m_checkedHidingSpotCount < MAX_CHECKED_SPOTS)
+ {
+ m_checkedHidingSpot[ m_checkedHidingSpotCount ].spot = spot;
+ m_checkedHidingSpot[ m_checkedHidingSpotCount ].timestamp = gpGlobals->time;
+ ++m_checkedHidingSpotCount;
+ }
+ else
+ {
+ // replace the least recent spot
+ m_checkedHidingSpot[ leastRecent ].spot = spot;
+ m_checkedHidingSpot[ leastRecent ].timestamp = gpGlobals->time;
+ }
}
+// Periodic check of hostage count in case we lost some
+
/* <2e92b8> ../cstrike/dlls/bot/cs_bot.cpp:693 */
-NOBODY void CCSBot::UpdateHostageEscortCount(void)
+void CCSBot::UpdateHostageEscortCount(void)
{
-// {
-// float const updateInterval; // 695
-// {
-// class CHostage *hostage; // 704
-// IsValid(CHostage *const this); // 709
-// IsFollowing(CHostage *const this,
-// const class CBaseEntity *entity); // 713
-// edict(CBaseEntity *const this); // 705
-// FNullEnt(const edict_t *pent); // 705
-// }
-// }
+ const float updateInterval = 1.0f;
+ if (m_hostageEscortCount == 0 || gpGlobals->time - m_hostageEscortCountTimestamp < updateInterval)
+ return;
+
+ m_hostageEscortCountTimestamp = gpGlobals->time;
+
+ // recount the hostages in case we lost some
+ m_hostageEscortCount = 0;
+
+ CHostage *hostage = NULL;
+ while ((hostage = static_cast(UTIL_FindEntityByClassname(hostage, "hostage_entity"))) != NULL)
+ {
+ if (FNullEnt(hostage->edict()))
+ break;
+
+ // skip dead or rescued hostages
+ if (!hostage->IsValid())
+ continue;
+
+ // check if hostage has targeted us, and is following
+ if (hostage->IsFollowing(this))
+ ++m_hostageEscortCount;
+ }
}
+// Return true if we are outnumbered by enemies
+
/* <2e940d> ../cstrike/dlls/bot/cs_bot.cpp:722 */
-NOBODY bool CCSBot::IsOutnumbered(void)
+bool CCSBot::IsOutnumbered(void) const
{
-// GetNearbyFriendCount(const class CCSBot *const this); // 724
-// GetNearbyEnemyCount(const class CCSBot *const this); // 724
+ return (GetNearbyFriendCount() < GetNearbyEnemyCount() - 1) ? true : false;
}
+// Return number of enemies we are outnumbered by
+
/* <2e94a0> ../cstrike/dlls/bot/cs_bot.cpp:731 */
-NOBODY int CCSBot::OutnumberedCount(void)
+int CCSBot::OutnumberedCount(void) const
{
-// IsOutnumbered(const class CCSBot *const this); // 733
-// GetNearbyEnemyCount(const class CCSBot *const this); // 734
-// GetNearbyFriendCount(const class CCSBot *const this); // 734
+ if (IsOutnumbered())
+ {
+ return (GetNearbyEnemyCount() - 1) - GetNearbyFriendCount();
+ }
+
+ return 0;
}
+// Return the closest "important" enemy for the given scenario (bomb carrier, VIP, hostage escorter)
+
/* <2e95cb> ../cstrike/dlls/bot/cs_bot.cpp:744 */
-NOBODY CBasePlayer *CCSBot::GetImportantEnemy(bool checkVisibility)
+CBasePlayer *CCSBot::GetImportantEnemy(bool checkVisibility) const
{
-// {
-// class CCSBotManager *ctrl; // 746
-// class CBasePlayer *nearEnemy; // 747
-// float nearDist; // 748
-// {
-// int i; // 750
-// {
-// class CBaseEntity *entity; // 752
-// class CBasePlayer *player; // 767
-// Vector d; // 782
-// float distSq; // 783
-// FNullEnt(entvars_t *pev); // 757
-// operator-(const Vector *const this,
-// const Vector &v); // 782
-// }
-// }
-// }
+ CCSBotManager *ctrl = TheCSBots();
+ CBasePlayer *nearEnemy = NULL;
+ float nearDist = 999999999.9f;
+
+ for (int i = 1; i <= gpGlobals->maxClients; i++)
+ {
+ CBaseEntity *entity = UTIL_PlayerByIndex(i);
+
+ if (entity == NULL)
+ continue;
+
+ if (FNullEnt(entity->pev))
+ continue;
+
+ if (FStrEq(STRING(entity->pev->netname), ""))
+ continue;
+
+ // is it a player?
+ if (!entity->IsPlayer())
+ continue;
+
+ CBasePlayer *player = static_cast(entity);
+
+ // is it alive?
+ if (!player->IsAlive())
+ continue;
+
+ // skip friends
+ if (player->m_iTeam == m_iTeam)
+ continue;
+
+ // is it "important"
+ if (!ctrl->IsImportantPlayer(player))
+ continue;
+
+ // is it closest?
+ Vector d = pev->origin - player->pev->origin;
+
+ float distSq = d.x * d.x + d.y * d.y + d.z * d.z;
+ if (distSq < nearDist)
+ {
+ if (checkVisibility && !IsVisible(player, CHECK_FOV))
+ continue;
+
+ nearEnemy = player;
+ nearDist = distSq;
+ }
+ }
+
+ return nearEnemy;
}
+// Sets our current disposition
+
/* <2e9719> ../cstrike/dlls/bot/cs_bot.cpp:801 */
-NOBODY void CCSBot::SetDisposition(DispositionType disposition)
+void CCSBot::SetDisposition(DispositionType disposition)
{
-// Invalidate(CountdownTimer *const this); // 806
+ m_disposition = disposition;
+
+ if (m_disposition != IGNORE_ENEMIES)
+ {
+ m_ignoreEnemiesTimer.Invalidate();
+ }
}
+// Return our current disposition
+
/* <2e9762> ../cstrike/dlls/bot/cs_bot.cpp:814 */
CCSBot::DispositionType CCSBot::GetDisposition(void) const
{
@@ -333,18 +747,27 @@ CCSBot::DispositionType CCSBot::GetDisposition(void) const
return m_disposition;
}
+// Ignore enemies for a short durationy
+
/* <2e979b> ../cstrike/dlls/bot/cs_bot.cpp:826 */
-NOBODY void CCSBot::IgnoreEnemies(float duration)
+void CCSBot::IgnoreEnemies(float duration)
{
-// Start(CountdownTimer *const this,
-// float duration); // 828
+ m_ignoreEnemiesTimer.Start(duration);
}
+// Increase morale one step
+
/* <2e97fc> ../cstrike/dlls/bot/cs_bot.cpp:835 */
-NOBODY void CCSBot::IncreaseMorale(void)
+void CCSBot::IncreaseMorale(void)
{
+ if (m_morale < EXCELLENT)
+ {
+ m_morale = static_cast(m_morale + 1);
+ }
}
+// Decrease morale one step
+
/* <2e9824> ../cstrike/dlls/bot/cs_bot.cpp:845 */
void CCSBot::DecreaseMorale(void)
{
@@ -354,6 +777,9 @@ void CCSBot::DecreaseMorale(void)
}
}
+// Return true if we are acting like a rogue (not listening to teammates, not doing scenario goals)
+// TODO: Account for morale
+
/* <2e984c> ../cstrike/dlls/bot/cs_bot.cpp:857 */
bool CCSBot::IsRogue(void) const
{
@@ -376,48 +802,75 @@ bool CCSBot::IsRogue(void) const
return m_isRogue;
}
+// Return true if we are in a hurry
+
/* <2e98f1> ../cstrike/dlls/bot/cs_bot.cpp:882 */
-NOBODY bool CCSBot::IsHurrying(void) const
+bool CCSBot::IsHurrying(void) const
{
-// {
-// class CCSBotManager *ctrl; // 887
-// IsElapsed(const class CountdownTimer *const this); // 884
-// }
+ if (!m_hurryTimer.IsElapsed())
+ return true;
+
+ CCSBotManager *ctrl = TheCSBots();
+
+ // if the bomb has been planted, we are in a hurry, CT or T (they could be defusing it!)
+ if (ctrl->GetScenario() == CCSBotManager::SCENARIO_DEFUSE_BOMB && ctrl->IsBombPlanted())
+ return true;
+
+ // if we are a T and hostages are being rescued, we are in a hurry
+ if (ctrl->GetScenario() == CCSBotManager::SCENARIO_RESCUE_HOSTAGES
+ && m_iTeam == TERRORIST
+ && GetGameState()->AreAllHostagesBeingRescued())
+ return true;
+
+ return false;
}
+// Return true if it is the early, "safe", part of the round
+
/* <2e9942> ../cstrike/dlls/bot/cs_bot.cpp:906 */
-NOBODY bool CCSBot::IsSafe(void) const
+bool CCSBot::IsSafe(void) const
{
-// {
-// class CCSBotManager *ctrl; // 908
-// GetElapsedRoundTime(const class CCSBotManager *const this); // 910
-// }
+ CCSBotManager *ctrl = TheCSBots();
+
+ if (ctrl->GetElapsedRoundTime() < m_safeTime)
+ return true;
+
+ return false;
}
+// Return true if it is well past the early, "safe", part of the round
+
/* <2e9987> ../cstrike/dlls/bot/cs_bot.cpp:920 */
-NOBODY bool CCSBot::IsWellPastSafe(void) const
+bool CCSBot::IsWellPastSafe(void) const
{
-// {
-// class CCSBotManager *ctrl; // 922
-// GetElapsedRoundTime(const class CCSBotManager *const this); // 924
-// }
+ CCSBotManager *ctrl = TheCSBots();
+
+ if (ctrl->GetElapsedRoundTime() > 1.25f * m_safeTime)
+ return true;
+
+ return false;
}
+// Return true if we were in the safe time last update, but not now
+
/* <2e99d8> ../cstrike/dlls/bot/cs_bot.cpp:934 */
-NOBODY bool CCSBot::IsEndOfSafeTime(void) const
+bool CCSBot::IsEndOfSafeTime(void) const
{
-// IsSafe(const class CCSBot *const this); // 936
+ return m_wasSafe && !IsSafe();
}
+// Return the amount of "safe time" we have left
+
/* <2e9a3e> ../cstrike/dlls/bot/cs_bot.cpp:943 */
-NOBODY float CCSBot::GetSafeTimeRemaining(void) const
+float CCSBot::GetSafeTimeRemaining(void) const
{
-// {
-// class CCSBotManager *ctrl; // 945
-// GetElapsedRoundTime(const class CCSBotManager *const this); // 947
-// }
+ CCSBotManager *ctrl = TheCSBots();
+
+ return m_safeTime - ctrl->GetElapsedRoundTime();
}
+// Called when enemy seen to adjust safe time for this round
+
/* <2e9a8f> ../cstrike/dlls/bot/cs_bot.cpp:954 */
void CCSBot::AdjustSafeTime(void)
{
@@ -431,47 +884,68 @@ void CCSBot::AdjustSafeTime(void)
}
}
+// Return true if we haven't seen an enemy for "a long time"
+
/* <2e9ad0> ../cstrike/dlls/bot/cs_bot.cpp:970 */
-NOBODY bool CCSBot::HasNotSeenEnemyForLongTime(void) const
+bool CCSBot::HasNotSeenEnemyForLongTime(void) const
{
-// {
-// float const longTime; // 972
-// GetTimeSinceLastSawEnemy(const class CCSBot *const this); // 973
-// }
+ const float longTime = 30.0f;
+ return (GetTimeSinceLastSawEnemy() > longTime);
}
+// Pick a random zone and hide near it
+
/* <2e9b26> ../cstrike/dlls/bot/cs_bot.cpp:980 */
-NOBODY bool CCSBot::GuardRandomZone(float range)
+bool CCSBot::GuardRandomZone(float range)
{
-// {
-// class CCSBotManager *ctrl; // 982
-// const class Zone *zone; // 984
-// GetRandomZone(const class CCSBotManager *const this); // 984
-// {
-// class CNavArea *rescueArea; // 987
-// }
-// }
+ CCSBotManager *ctrl = TheCSBots();
+ const CCSBotManager::Zone *zone = ctrl->GetRandomZone();
+
+ if (zone != NULL)
+ {
+ CNavArea *rescueArea = ctrl->GetRandomAreaInZone(zone);
+ if (rescueArea != NULL)
+ {
+ Hide(rescueArea, -1.0f, range);
+ return true;
+ }
+ }
+
+ return false;
}
+// Do a breadth-first search to find a good retreat spot.
+// Don't pick a spot that a Player is currently occupying.
+
/* <2e9c1f> ../cstrike/dlls/bot/cs_bot.cpp:1066 */
-NOBODY const Vector *FindNearbyRetreatSpot(CCSBot *me, float maxRange)
+const Vector *FindNearbyRetreatSpot(CCSBot *me, float maxRange)
{
-// {
-// class CNavArea *area; // 1068
-// class CollectRetreatSpotsFunctor collector; // 1073
-// int which; // 1080
-// SearchSurroundingAreas(CNavArea *startArea,
-// const Vector *startPos,
-// class CollectRetreatSpotsFunctor &func,
-// float maxRange); // 1074
-// }
+ CNavArea *area = me->GetLastKnownArea();
+ if (area == NULL)
+ return NULL;
+
+ // collect spots that enemies cannot see
+ CollectRetreatSpotsFunctor collector(me, maxRange);
+ SearchSurroundingAreas(area, &me->pev->origin, collector, maxRange);
+
+ if (collector.m_count == 0)
+ return NULL;
+
+ // select a hiding spot at random
+ int which = RANDOM_LONG(0, collector.m_count - 1);
+ return collector.m_spot[ which ];
}
+// Return euclidean distance to farthest escorted hostage.
+// Return -1 if no hostage is following us.
+
/* <2eaa1d> ../cstrike/dlls/bot/cs_bot.cpp:1116 */
-float CCSBot::GetRangeToFarthestEscortedHostage(void)
+float CCSBot::GetRangeToFarthestEscortedHostage(void) const
{
FarthestHostage away(this);
+
g_pHostages->ForEachHostage(away);
+
return away.m_farRange;
}
@@ -481,6 +955,7 @@ void CCSBot::Walk(void)
{
Walk_();
}
+
bool CCSBot::Jump(bool mustJump)
{
return Jump_(mustJump);
@@ -490,6 +965,7 @@ int CCSBot::TakeDamage(entvars_t *pevInflictor, entvars_t *pevAttacker, float fl
{
return TakeDamage_(pevInflictor, pevAttacker, flDamage, bitsDamageType);
}
+
void CCSBot::Killed(entvars_t *pevAttacker, int iGib)
{
Killed_(pevAttacker, iGib);
diff --git a/regamedll/dlls/bot/cs_bot.h b/regamedll/dlls/bot/cs_bot.h
index 85e10697..7f7a2c95 100644
--- a/regamedll/dlls/bot/cs_bot.h
+++ b/regamedll/dlls/bot/cs_bot.h
@@ -43,6 +43,13 @@
#define FLAG_PROGRESS_START 0x1 // init status bar progress
#define FLAG_PROGRESS_HIDE 0x2 // hide status bar progress
+#define HI_X 0x01
+#define LO_X 0x02
+#define HI_Y 0x04
+#define LO_Y 0x08
+#define HI_Z 0x10
+#define LO_Z 0x20
+
#ifdef HOOK_GAMEDLL
#define _navAreaCount (*pnavAreaCount)
@@ -73,10 +80,14 @@ class IdleState: public BotState
public:
NOBODY virtual void OnEnter(CCSBot *me);
NOBODY virtual void OnUpdate(CCSBot *me);
- virtual const char *GetName(void) const
- {
- return "Idle";
- }
+ virtual const char *GetName(void) const { return "Idle"; }
+
+#ifdef HOOK_GAMEDLL
+
+ void OnEnter_(CCSBot *me);
+ void OnUpdate_(CCSBot *me);
+
+#endif // HOOK_GAMEDLL
};/* size: 4, cachelines: 1, members: 1 */
@@ -87,14 +98,17 @@ public:
NOBODY virtual void OnEnter(CCSBot *me);
NOBODY virtual void OnUpdate(CCSBot *me);
NOBODY virtual void OnExit(CCSBot *me);
- virtual const char *GetName(void) const
- {
- return "Hunt";
- }
- void ClearHuntArea(void)
- {
- m_huntArea = NULL;
- }
+ virtual const char *GetName(void) const { return "Hunt"; }
+
+#ifdef HOOK_GAMEDLL
+
+ void OnEnter_(CCSBot *me);
+ void OnUpdate_(CCSBot *me);
+ void OnExit_(CCSBot *me);
+
+#endif // HOOK_GAMEDLL
+
+ void ClearHuntArea(void) { m_huntArea = NULL; }
private:
CNavArea *m_huntArea;
@@ -107,15 +121,17 @@ public:
NOBODY virtual void OnEnter(CCSBot *me);
NOBODY virtual void OnUpdate(CCSBot *me);
NOBODY virtual void OnExit(CCSBot *me);
- virtual const char *GetName(void) const
- {
- return "Attack";
- }
+ virtual const char *GetName(void) const { return "Attack"; }
- void SetCrouchAndHold(bool crouch)
- {
- m_crouchAndHold = crouch;
- }
+#ifdef HOOK_GAMEDLL
+
+ void OnEnter_(CCSBot *me);
+ void OnUpdate_(CCSBot *me);
+ void OnExit_(CCSBot *me);
+
+#endif // HOOK_GAMEDLL
+
+ void SetCrouchAndHold(bool crouch) { m_crouchAndHold = crouch; }
void StopAttacking(CCSBot *me);
protected:
@@ -153,10 +169,16 @@ public:
NOBODY virtual void OnEnter(CCSBot *me);
NOBODY virtual void OnUpdate(CCSBot *me);
NOBODY virtual void OnExit(CCSBot *me);
- virtual const char *GetName(void) const
- {
- return "InvestigateNoise";
- }
+ virtual const char *GetName(void) const { return "InvestigateNoise"; }
+
+#ifdef HOOK_GAMEDLL
+
+ void OnEnter_(CCSBot *me);
+ void OnUpdate_(CCSBot *me);
+ void OnExit_(CCSBot *me);
+
+#endif // HOOK_GAMEDLL
+
private:
NOBODY void AttendCurrentNoise(CCSBot *me);
Vector m_checkNoisePosition;
@@ -170,10 +192,16 @@ public:
NOBODY virtual void OnEnter(CCSBot *me);
NOBODY virtual void OnUpdate(CCSBot *me);
NOBODY virtual void OnExit(CCSBot *me);
- virtual const char *GetName(void) const
- {
- return "Buy";
- }
+ virtual const char *GetName(void) const { return "Buy"; }
+
+#ifdef HOOK_GAMEDLL
+
+ void OnEnter_(CCSBot *me);
+ void OnUpdate_(CCSBot *me);
+ void OnExit_(CCSBot *me);
+
+#endif // HOOK_GAMEDLL
+
private:
bool m_isInitialDelay;
int m_prefRetries;
@@ -194,18 +222,19 @@ public:
NOBODY virtual void OnEnter(CCSBot *me);
NOBODY virtual void OnUpdate(CCSBot *me);
NOBODY virtual void OnExit(CCSBot *me);
- virtual const char *GetName(void) const
- {
- return "MoveTo";
- }
- void SetGoalPosition(const Vector &pos)
- {
- m_goalPosition = pos;
- }
- void SetRouteType(RouteType route)
- {
- m_routeType = route;
- }
+ virtual const char *GetName(void) const { return "MoveTo"; }
+
+#ifdef HOOK_GAMEDLL
+
+ void OnEnter_(CCSBot *me);
+ void OnUpdate_(CCSBot *me);
+ void OnExit_(CCSBot *me);
+
+#endif // HOOK_GAMEDLL
+
+ void SetGoalPosition(const Vector &pos) { m_goalPosition = pos; }
+ void SetRouteType(RouteType route) { m_routeType = route; }
+
private:
Vector m_goalPosition;
RouteType m_routeType;
@@ -218,12 +247,16 @@ private:
class FetchBombState: public BotState
{
public:
- NOBODY virtual void OnEnter(CCSBot *me);
- NOBODY virtual void OnUpdate(CCSBot *me);
- virtual const char *GetName(void) const
- {
- return "FetchBomb";
- }
+ virtual void OnEnter(CCSBot *me);
+ virtual void OnUpdate(CCSBot *me);
+ virtual const char *GetName(void) const { return "FetchBomb"; }
+
+#ifdef HOOK_GAMEDLL
+
+ void OnEnter_(CCSBot *me);
+ void OnUpdate_(CCSBot *me);
+
+#endif // HOOK_GAMEDLL
};/* size: 4, cachelines: 1, members: 1 */
@@ -231,16 +264,18 @@ public:
class PlantBombState: public BotState
{
public:
- NOBODY virtual void OnEnter(CCSBot *me);
- NOBODY virtual void OnUpdate(CCSBot *me);
- NOBODY virtual void OnExit(CCSBot *me);
- virtual const char *GetName(void) const
- {
- return "PlantBomb";
+ virtual void OnEnter(CCSBot *me);
+ virtual void OnUpdate(CCSBot *me);
+ virtual void OnExit(CCSBot *me);
+ virtual const char *GetName(void) const { return "PlantBomb"; }
- // TODO: ??
- //return &statement.m_next[3];
- }
+#ifdef HOOK_GAMEDLL
+
+ void OnEnter_(CCSBot *me);
+ void OnUpdate_(CCSBot *me);
+ void OnExit_(CCSBot *me);
+
+#endif // HOOK_GAMEDLL
};/* size: 4, cachelines: 1, members: 1 */
@@ -251,10 +286,15 @@ public:
NOBODY virtual void OnEnter(CCSBot *me);
NOBODY virtual void OnUpdate(CCSBot *me);
NOBODY virtual void OnExit(CCSBot *me);
- virtual const char *GetName(void) const
- {
- return "DefuseBomb";
- }
+ virtual const char *GetName(void) const { return "DefuseBomb"; }
+
+#ifdef HOOK_GAMEDLL
+
+ void OnEnter_(CCSBot *me);
+ void OnUpdate_(CCSBot *me);
+ void OnExit_(CCSBot *me);
+
+#endif // HOOK_GAMEDLL
};/* size: 4, cachelines: 1, members: 1 */
@@ -265,38 +305,28 @@ public:
NOBODY virtual void OnEnter(CCSBot *me);
NOBODY virtual void OnUpdate(CCSBot *me);
NOBODY virtual void OnExit(CCSBot *me);
- virtual const char *GetName(void) const
- {
- return "Hide";
- }
- void SetHidingSpot(const Vector &pos)
- {
- m_hidingSpot = pos;
- }
- const Vector &GetHidingSpot(void) const
- {
- return m_hidingSpot;
- }
- void SetSearchArea(CNavArea *area)
- {
- m_searchFromArea = area;
- }
- void SetSearchRange(float range)
- {
- m_range = range;
- }
- void SetDuration(float time)
- {
- m_duration = time;
- }
- void SetHoldPosition(bool hold)
- {
- m_isHoldingPosition = hold;
- }
- bool IsAtSpot(void) const
- {
- return m_isAtSpot;
- }
+ virtual const char *GetName(void) const { return "Hide"; }
+
+#ifdef HOOK_GAMEDLL
+
+ void OnEnter_(CCSBot *me);
+ void OnUpdate_(CCSBot *me);
+ void OnExit_(CCSBot *me);
+
+#endif // HOOK_GAMEDLL
+
+public:
+ void SetHidingSpot(const Vector &pos) { m_hidingSpot = pos; }
+ const Vector &GetHidingSpot(void) const { return m_hidingSpot; }
+
+ void SetSearchArea(CNavArea *area) { m_searchFromArea = area; }
+ void SetSearchRange(float range) { m_range = range; }
+
+ void SetDuration(float time) { m_duration = time; }
+ void SetHoldPosition(bool hold) { m_isHoldingPosition = hold; }
+
+ bool IsAtSpot(void) const { return m_isAtSpot; }
+
private:
CNavArea *m_searchFromArea;
float m_range;
@@ -321,10 +351,15 @@ public:
NOBODY virtual void OnEnter(CCSBot *me);
NOBODY virtual void OnUpdate(CCSBot *me);
NOBODY virtual void OnExit(CCSBot *me);
- virtual const char *GetName(void) const
- {
- return "EscapeFromBomb";
- }
+ virtual const char *GetName(void) const { return "EscapeFromBomb"; }
+
+#ifdef HOOK_GAMEDLL
+
+ void OnEnter_(CCSBot *me);
+ void OnUpdate_(CCSBot *me);
+ void OnExit_(CCSBot *me);
+
+#endif // HOOK_GAMEDLL
};/* size: 4, cachelines: 1, members: 1 */
@@ -335,17 +370,21 @@ public:
NOBODY virtual void OnEnter(CCSBot *me);
NOBODY virtual void OnUpdate(CCSBot *me);
NOBODY virtual void OnExit(CCSBot *me);
- virtual const char *GetName(void) const
- {
- return "Follow";
- }
- void SetLeader(CBaseEntity *leader)
- {
- m_leader = leader;
- }
+ virtual const char *GetName(void) const { return "Follow"; }
+
+#ifdef HOOK_GAMEDLL
+
+ void OnEnter_(CCSBot *me);
+ void OnUpdate_(CCSBot *me);
+ void OnExit_(CCSBot *me);
+
+#endif // HOOK_GAMEDLL
+
+ void SetLeader(CBaseEntity *leader) { m_leader = leader; }
+
private:
NOBODY void ComputeLeaderMotionState(float leaderSpeed);
-private:
+
EHANDLE m_leader;
Vector m_lastLeaderPos;
bool m_isStopped;
@@ -357,7 +396,9 @@ private:
STOPPED,
WALKING,
RUNNING
+
} m_leaderMotionState;
+
IntervalTimer m_leaderMotionStateTime;
bool m_isSneaking;
@@ -376,52 +417,57 @@ private:
class UseEntityState: public BotState
{
public:
- NOBODY virtual void OnEnter(CCSBot *me);
- NOBODY virtual void OnUpdate(CCSBot *me);
- NOBODY virtual void OnExit(CCSBot *me);
- virtual const char *GetName(void) const
- {
- return "UseEntity";
- }
- void SetEntity(CBaseEntity *entity)
- {
- m_entity = entity;
- }
+ virtual void OnEnter(CCSBot *me);
+ virtual void OnUpdate(CCSBot *me);
+ virtual void OnExit(CCSBot *me);
+ virtual const char *GetName(void) const { return "UseEntity"; }
+
+#ifdef HOOK_GAMEDLL
+
+ void OnEnter_(CCSBot *me);
+ void OnUpdate_(CCSBot *me);
+ void OnExit_(CCSBot *me);
+
+#endif // HOOK_GAMEDLL
+
+ void SetEntity(CBaseEntity *entity) { m_entity = entity; }
+
private:
EHANDLE m_entity;
};/* size: 12, cachelines: 1, members: 2 */
+// The Counter-strike Bot
+
/* <32b267> ../cstrike/dlls/bot/cs_bot.h:300 */
class CCSBot: public CBot
{
public:
- CCSBot(void)
- {
- };
+ CCSBot(void); // constructor initializes all values to zero
public:
- NOBODY virtual int TakeDamage(entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType);
- NOBODY virtual void Killed(entvars_t *pevAttacker, int iGib);
- NOBODY virtual void RoundRespawn(void);
- NOBODY virtual void Blind(float duration, float holdTime, float fadeTime, int alpha = 255);
- NOBODY virtual void OnTouchingWeapon(CWeaponBox *box);
- NOBODY virtual bool Initialize(const BotProfile *profile);
+ virtual int TakeDamage(entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType); // invoked when injured by something (EXTEND) - returns the amount of damage inflicted
+ virtual void Killed(entvars_t *pevAttacker, int iGib); // invoked when killed (EXTEND)
+ virtual void RoundRespawn(void);
+ virtual void Blind(float duration, float holdTime, float fadeTime, int alpha = 255); // player blinded by a flashbang
+ virtual void OnTouchingWeapon(CWeaponBox *box); // invoked when in contact with a CWeaponBox
- NOBODY virtual void SpawnBot(void);
- virtual void Upkeep(void);
+ virtual bool Initialize(const BotProfile *profile); // (EXTEND) prepare bot for action
+ virtual void SpawnBot(void); // (EXTEND) spawn the bot into the game
- NOBODY virtual void Update(void);
- NOBODY virtual void Walk(void);
- NOBODY virtual bool Jump(bool mustJump = false);
+ virtual void Upkeep(void); // lightweight maintenance, invoked frequently
+ NOBODY virtual void Update(void); // heavyweight algorithms, invoked less often
- NOBODY virtual void OnEvent(GameEventType event, CBaseEntity *entity = NULL, CBaseEntity *other = NULL);
+ virtual void Walk(void);
+ virtual bool Jump(bool mustJump = false); // returns true if jump was started
- // TODO: change both places?
- NOBODY virtual bool IsVisible(const Vector *pos, bool testFOV = false) const;
- NOBODY virtual bool IsVisible(CBasePlayer *player, bool testFOV = false, unsigned char *visParts = NULL) const;
+ NOBODY virtual void OnEvent(GameEventType event, CBaseEntity *entity = NULL, CBaseEntity *other = NULL); // invoked when event occurs in the game (some events have NULL entity)
- virtual bool IsEnemyPartVisible(VisiblePartType part) const;
+ #define CHECK_FOV true
+ virtual bool IsVisible(const Vector *pos, bool testFOV = false) const; // return true if we can see the point
+ virtual bool IsVisible(CBasePlayer *player, bool testFOV = false, unsigned char *visParts = NULL) const; // return true if we can see any part of the player
+
+ virtual bool IsEnemyPartVisible(VisiblePartType part) const; // if enemy is visible, return the part we see for our current enemy
#ifdef HOOK_GAMEDLL
@@ -445,137 +491,97 @@ public:
public:
void Disconnect(void);
- float GetCombatRange(void) const
- {
- return m_combatRange;
- }
- bool IsRogue(void)const;
- void SetRogue(bool rogue)
- {
- m_isRogue = rogue;
- }
- NOBODY bool IsHurrying(void) const;
- void Hurry(float duration)
- {
- m_hurryTimer.Start(duration);
- }
- NOBODY bool IsSafe(void) const;
- NOBODY bool IsWellPastSafe(void) const;
- NOBODY bool IsEndOfSafeTime(void) const;
- NOBODY float GetSafeTimeRemaining(void) const;
- float GetSafeTime(void) const
- {
- return m_safeTime;
- }
- NOBODY bool IsUnhealthy(void);
+ // behavior properties
+ float GetCombatRange(void) const;
+ bool IsRogue(void) const; // return true if we dont listen to teammates or pursue scenario goals
+ void SetRogue(bool rogue);
+ bool IsHurrying(void) const; // return true if we are in a hurry
+ void Hurry(float duration); // force bot to hurry
+ bool IsSafe(void) const; // return true if we are in a safe region
+ bool IsWellPastSafe(void) const; // return true if it is well past the early, "safe", part of the round
+ bool IsEndOfSafeTime(void) const; // return true if we were in the safe time last update, but not now
+ float GetSafeTimeRemaining(void) const; // return the amount of "safe time" we have left
+ float GetSafeTime(void) const; // return what we think the total "safe time" for this map is
+ NOXREF bool IsUnhealthy(void) const; // returns true if bot is low on health
+
+ // behaviors
void Idle(void);
+ void Hide(CNavArea *searchFromArea = NULL, float duration = -1.0f, float hideRange = 750.0f, bool holdPosition = false); // DEPRECATED: Use TryToHide() instead
+ #define USE_NEAREST true
+ bool TryToHide(CNavArea *searchFromArea = NULL, float duration = -1.0f, float hideRange = 750.0f, bool holdPosition = false, bool useNearest = false); // try to hide nearby, return false if cannot
- NOBODY void Hide(CNavArea *searchFromArea = NULL, float duration = -1.0f, float hideRange = 750.0f, bool holdPosition = false);
- NOBODY void Hide(const Vector *hidingSpot = NULL, float duration = -1.0f, bool holdPosition = false);
+ void Hide(const Vector *hidingSpot, float duration = -1.0f, bool holdPosition = false); // move to the given hiding place
+ bool IsHiding(void) const; // returns true if bot is currently hiding
+ bool IsAtHidingSpot(void) const; // return true if we are hiding and at our hiding spot
+ bool TryToRetreat(void); // retreat to a nearby hiding spot, away from enemies
- NOBODY bool TryToHide(CNavArea *searchFromArea = NULL, float duration = -1.0f, float hideRange = 750.0f, bool holdPosition = false, bool useNearest = false);
- NOBODY bool TryToRetreat(void);
+ void Hunt(void);
+ bool IsHunting(void) const; // returns true if bot is currently hunting
- bool IsHiding(void) const;
- bool IsAtHidingSpot(void) const;
- NOBODY void Hunt(void);
- NOBODY bool IsHunting(void) const;
- NOBODY void Attack(CBasePlayer *victim);
- NOBODY void FireWeaponAtEnemy(void);
+ void Attack(CBasePlayer *victim);
+ void FireWeaponAtEnemy(void); // fire our active weapon towards our current enemy
void StopAttacking(void);
- bool IsAttacking(void) const;
- NOBODY void MoveTo(const Vector *pos, RouteType route = SAFEST_ROUTE);
- NOBODY bool IsMovingTo(void) const;
- NOBODY void PlantBomb(void);
- NOBODY void FetchBomb(void);
- NOBODY bool NoticeLooseBomb(void) const;
- NOBODY bool CanSeeLooseBomb(void) const;
- bool IsCarryingBomb(void)
- {
- //TODO: unsure
- //return (m_bomber.Get() != NULL);
- return false;
- }
- NOBODY void DefuseBomb(void);
- bool IsDefusingBomb(void) const;
- NOBODY bool CanSeePlantedBomb(void) const;
- NOBODY void EscapeFromBomb(void);
- NOBODY bool IsEscapingFromBomb(void) const;
- NOBODY void RescueHostages(void);
- NOBODY void UseEntity(CBaseEntity *entity);
- bool IsBuying(void) const;
- NOBODY void Panic(CBasePlayer *enemy);
- NOBODY void Follow(CBasePlayer *player);
- NOBODY void ContinueFollowing(void);
- NOBODY void StopFollowing(void);
- bool IsFollowing(void) const
- {
- return m_isFollowing;
- }
- CBasePlayer *GetFollowLeader(void)
- {
- CBaseEntity *entity = (CBaseEntity *)m_leader;
- return (CBasePlayer *)entity;
- }
- float GetFollowDuration(void) const
- {
- return (gpGlobals->time - m_followTimestamp);
- }
- bool CanAutoFollow(void) const
- {
- return (gpGlobals->time > m_allowAutoFollowTime);
- }
- NOBODY bool IsNotMoving(void);
- void AimAtEnemy(void)
- {
- m_isAimingAtEnemy = true;
- }
- void StopAiming(void)
- {
- m_isAimingAtEnemy = false;
- }
- bool IsAimingAtEnemy(void) const
- {
- return m_isAimingAtEnemy;
- }
- bool IsSurprised(void) const
- {
- return (gpGlobals->time - this->m_surpriseTimestamp >= 5.0f);
- }
- float GetSurpriseDelay(void) const
- {
- return m_surpriseDelay;
- }
- void ClearSurpriseDelay(void)
- {
- m_surpriseDelay = 0.0f;
- }
- float GetStateTimestamp(void) const
- {
- return m_stateTimestamp;
- }
- NOBODY bool IsDoingScenario(void);
- CSGameState *GetGameState(void)
- {
- return &m_gameState;
- }
- const CSGameState *GetGameState(void) const
- {
- return &m_gameState;
- }
- bool IsAtBombsite(void) const
- {
- UNTESTED
- // TODO: return true if we are in a bomb planting zone
- return GetGameState()->IsAtPlantedBombsite();
- }
- NOBODY bool GuardRandomZone(float range = 500.0f);
- bool IsBusy(void) const;
+ bool IsAttacking(void) const; // returns true if bot is currently engaging a target
+ void MoveTo(const Vector *pos, RouteType route = SAFEST_ROUTE); // move to potentially distant position
+ bool IsMovingTo(void) const; // return true if we are in the MoveTo state
+
+ void PlantBomb(void);
+
+ void FetchBomb(void); // bomb has been dropped - go get it
+ bool NoticeLooseBomb(void) const; // return true if we noticed the bomb on the ground or on radar
+ bool CanSeeLooseBomb(void) const; // return true if we directly see the loose bomb
+ bool IsCarryingBomb(void) const;
+
+ void DefuseBomb(void);
+ bool IsDefusingBomb(void) const; // returns true if bot is currently defusing the bomb
+ bool CanSeePlantedBomb(void) const; // return true if we directly see the planted bomb
+
+ void EscapeFromBomb(void);
+ bool IsEscapingFromBomb(void) const; // return true if we are escaping from the bomb
+
+ void RescueHostages(void);
+ void UseEntity(CBaseEntity *entity); // use the entity
+
+ bool IsBuying(void) const;
+
+ void Panic(CBasePlayer *enemy); // look around in panic
+ void Follow(CBasePlayer *player); // begin following given Player
+ void ContinueFollowing(void); // continue following our leader after finishing what we were doing
+ void StopFollowing(void); // stop following
+ bool IsFollowing(void) const; // return true if we are following someone (not necessarily in the follow state)
+ CBasePlayer *GetFollowLeader(void); // return the leader we are following
+ float GetFollowDuration(void) const; // return how long we've been following our leader
+ bool CanAutoFollow(void) const; // return true if we can auto-follow
+
+ bool IsNotMoving(void) const; // return true if we are currently standing still
+
+ void AimAtEnemy(void); // point our weapon towards our enemy
+ void StopAiming(void); // stop aiming at enemy
+ bool IsAimingAtEnemy(void) const; // returns true if we are trying to aim at an enemy
+
+ bool IsSurprised(void) const; // return true if we are "surprised"
+ float GetSurpriseDelay(void) const;
+ void ClearSurpriseDelay(void);
+
+ float GetStateTimestamp(void) const; // get time current state was entered
+
+ bool IsDoingScenario(void) const; // return true if we will do scenario-related tasks
+
+ // scenario / gamestate
+ CSGameState *GetGameState(void); // return an interface to this bot's gamestate
+ const CSGameState *GetGameState(void) const; // return an interface to this bot's gamestate
+
+ bool IsAtBombsite(void); // return true if we are in a bomb planting zone
+ bool GuardRandomZone(float range = 500.0f); // pick a random zone and hide near it
+
+ bool IsBusy(void) const; // return true if we are busy doing something important
+
+ // high-level tasks
enum TaskType
{
- SEEK_AND_DESTROY = 0,
+ SEEK_AND_DESTROY,
PLANT_BOMB,
FIND_TICKING_BOMB,
DEFUSE_BOMB,
@@ -595,33 +601,29 @@ public:
MOVE_TO_LAST_KNOWN_ENEMY_POSITION,
MOVE_TO_SNIPER_SPOT,
SNIPING,
+
+ NUM_TASKS
};
- void SetTask(TaskType task, CBaseEntity *entity = NULL)
- {
- m_task = task;
- m_taskEntity = entity;
- }
- TaskType GetTask(void) const
- {
- return m_task;
- }
- CBaseEntity *GetTaskEntity(void)
- {
- return m_taskEntity;
- }
+ void SetTask(TaskType task, CBaseEntity *entity = NULL); // set our current "task"
+ TaskType GetTask(void) const;
+ CBaseEntity *GetTaskEntity(void);
+ // behavior modifiers
enum DispositionType
{
- ENGAGE_AND_INVESTIGATE,
- OPPORTUNITY_FIRE,
- SELF_DEFENSE,
- IGNORE_ENEMIES,
+ ENGAGE_AND_INVESTIGATE, // engage enemies on sight and investigate enemy noises
+ OPPORTUNITY_FIRE, // engage enemies on sight, but only look towards enemy noises, dont investigate
+ SELF_DEFENSE, // only engage if fired on, or very close to enemy
+ IGNORE_ENEMIES, // ignore all enemies - useful for ducking around corners, running away, etc
+
+ NUM_DISPOSITIONS
};
- NOBODY void SetDisposition(DispositionType disposition);
- DispositionType GetDisposition(void) const;
- NOBODY void IgnoreEnemies(float duration);
+ void SetDisposition(DispositionType disposition); // define how we react to enemies
+ DispositionType GetDisposition(void) const; // return enum describing current disposition
+
+ void IgnoreEnemies(float duration); // ignore enemies for a short duration
enum MoraleType
{
@@ -633,368 +635,227 @@ public:
GOOD = 2,
EXCELLENT = 3,
};
- MoraleType GetMorale(void) const
- {
- return m_morale;
- }
- NOBODY void IncreaseMorale(void);
+
+ MoraleType GetMorale(void) const; // return enum describing current morale
+ void IncreaseMorale(void);
void DecreaseMorale(void);
- bool IsNoiseHeard(void) const
- {
- if (m_noiseTimestamp <= 0.0f)
- return false;
- if (gpGlobals->time - m_noiseTimestamp >= GetProfile()->GetReactionTime())
- return true;
+ // listening for noises
+ bool IsNoiseHeard(void) const; // return true if we have heard a noise
+ bool ShouldInvestigateNoise(float *retNoiseDist);
+ void InvestigateNoise(void); // investigate recent enemy noise
+ const Vector *GetNoisePosition(void) const; // return position of last heard noise, or NULL if none heard
+ CNavArea *GetNoiseArea(void) const; // return area where noise was heard
+ void ForgetNoise(void); // clear the last heard noise
+ bool CanSeeNoisePosition(void) const; // return true if we directly see where we think the noise came from
+ NOXREF float GetNoiseRange(void) const; // return approximate distance to last noise heard
- return false;
- }
- NOBODY bool ShouldInvestigateNoise(float *retNoiseDist);
- NOBODY void InvestigateNoise(void);
- NOBODY const Vector *GetNoisePosition(void);
- CNavArea *GetNoiseArea(void) const
- {
- return m_noiseArea;
- }
- void ForgetNoise(void)
- {
- m_noiseTimestamp = 0;
- }
- NOBODY bool CanSeeNoisePosition(void);
- NOBODY float GetNoiseRange(void) const
- {
- return 0.0f;
- }
- NOBODY bool CanHearNearbyEnemyGunfire(float range = -1.0f);
- PriorityType GetNoisePriority(void) const
- {
- return m_noisePriority;
- }
- NOBODY void SendRadioMessage(GameEventType event);
- BotChatterInterface *GetChatter(void)
- {
- return &m_chatter;
- }
- NOBODY bool RespondToHelpRequest(CBasePlayer *them, Place place, float maxRange = -1.0f);
- NOBODY void StartVoiceFeedback(float duration);
- bool IsUsingVoice(void) const
- {
- return (m_voiceFeedbackEndTimestamp != 0.0f); //return (m_voiceFeedbackEndTimestamp > gpGlobals->time);
- }
- void SetEnemy(CBasePlayer *enemy);
- CBasePlayer *GetEnemy(void)
- {
- return GetClassPtr((CBasePlayer *)m_enemy->pev);
- }
- int GetNearbyEnemyCount(void) const
- {
- return Q_min(GetEnemiesRemaining(), m_nearbyEnemyCount);
- }
- unsigned int GetEnemyPlace(void) const
- {
- return m_enemyPlace;
- }
- NOBODY bool CanSeeBomber(void);
- CBasePlayer *GetBomber(void) const
- {
- return GetClassPtr((CBasePlayer *)m_bomber->pev);
- }
- int GetNearbyFriendCount(void) const
- {
- return Q_min(GetFriendsRemaining(), m_nearbyFriendCount);
- }
- CBasePlayer *GetClosestVisibleFriend(void) const
- {
- return GetClassPtr((CBasePlayer *)m_closestVisibleFriend->pev);
- }
- CBasePlayer *GetClosestVisibleHumanFriend(void) const
- {
- return GetClassPtr((CBasePlayer *)m_closestVisibleHumanFriend->pev);
- }
- NOBODY bool IsOutnumbered(void);
- NOBODY int OutnumberedCount(void);
- NOBODY CBasePlayer *GetImportantEnemy(bool checkVisibility);
- NOBODY void UpdateReactionQueue(void);
- CBasePlayer *GetRecognizedEnemy(void);
- NOBODY bool IsRecognizedEnemyReloading(void);
- NOBODY bool IsRecognizedEnemyProtectedByShield(void);
- NOBODY float GetRangeToNearestRecognizedEnemy(void);
- NOBODY CBasePlayer *GetAttacker(void);
- float GetTimeSinceAttacked(void) const
- {
- return gpGlobals->time - m_attackedTimestamp;
- }
- NOBODY float GetFirstSawEnemyTimestamp(void);
- float GetLastSawEnemyTimestamp(void) const
- {
- return m_lastSawEnemyTimestamp;
- }
- float GetTimeSinceLastSawEnemy(void) const
- {
- return gpGlobals->time - m_lastSawEnemyTimestamp;
- }
- float GetTimeSinceAcquiredCurrentEnemy(void) const
- {
- return (gpGlobals->time - m_currentEnemyAcquireTimestamp);
- }
- NOBODY bool HasNotSeenEnemyForLongTime(void) const;
- const Vector &GetLastKnownEnemyPosition(void) const
- {
- return m_lastEnemyPosition;
- }
- bool IsEnemyVisible(void) const
- {
- return m_isEnemyVisible;
- }
- float GetEnemyDeathTimestamp(void) const
- {
- return m_enemyDeathTimestamp;
- }
- NOBODY bool IsFriendInLineOfFire(void);
- NOBODY bool IsAwareOfEnemyDeath(void) const;
- int GetLastVictimID(void) const
- {
- return m_lastVictimID;
- }
- bool HasPath(void) const
- {
- return m_pathLength != 0;
- }
- void DestroyPath(void)
- {
- m_pathLength = 0;
- m_pathLadder = NULL;
- }
- float GetFeetZ(void) const
- {
- const Vector crouch = VEC_DUCK_HULL_MIN_Z;
- const Vector stand = VEC_HULL_MIN_Z;
+ bool CanHearNearbyEnemyGunfire(float range = -1.0f) const; // return true if we hear nearby threatening enemy gunfire within given range (-1 == infinite)
+ PriorityType GetNoisePriority(void) const; // return priority of last heard noise
- return (IsCrouching()) ? (pev->origin + crouch).z : (pev->origin + stand).z;
- }
+ // radio and chatter
+ void SendRadioMessage(GameEventType event); // send voice chatter
+ BotChatterInterface *GetChatter(void); // return an interface to this bot's chatter system
+ bool RespondToHelpRequest(CBasePlayer *them, Place place, float maxRange = -1.0f); // decide if we should move to help the player, return true if we will
+ void StartVoiceFeedback(float duration);
+ bool IsUsingVoice(void) const; // new-style "voice" chatter gets voice feedback
+
+ // enemies
+ // BOTPORT: GetEnemy() collides with GetEnemy() in CBaseEntity - need to use different nomenclature
+
+ void SetEnemy(CBasePlayer *enemy); // set given player as our current enemy
+ CBasePlayer *GetEnemy(void);
+ int GetNearbyEnemyCount(void) const; // return max number of nearby enemies we've seen recently
+ unsigned int GetEnemyPlace(void) const; // return location where we see the majority of our enemies
+ bool CanSeeBomber(void) const; // return true if we can see the bomb carrier
+ CBasePlayer *GetBomber(void) const;
+
+ int GetNearbyFriendCount(void) const; // return number of nearby teammates
+ CBasePlayer *GetClosestVisibleFriend(void) const; // return the closest friend that we can see
+ CBasePlayer *GetClosestVisibleHumanFriend(void) const; // return the closest human friend that we can see
+
+ bool IsOutnumbered(void) const; // return true if we are outnumbered by enemies
+ int OutnumberedCount(void) const; // return number of enemies we are outnumbered by
+
+ #define ONLY_VISIBLE_ENEMIES true
+ CBasePlayer *GetImportantEnemy(bool checkVisibility = false) const; // return the closest "important" enemy for the given scenario (bomb carrier, VIP, hostage escorter)
+
+ void UpdateReactionQueue(void); // update our reaction time queue
+ CBasePlayer *GetRecognizedEnemy(void); // return the most dangerous threat we are "conscious" of
+ bool IsRecognizedEnemyReloading(void); // return true if the enemy we are "conscious" of is reloading
+ bool IsRecognizedEnemyProtectedByShield(void); // return true if the enemy we are "conscious" of is hiding behind a shield
+ float GetRangeToNearestRecognizedEnemy(void); // return distance to closest enemy we are "conscious" of
+
+ CBasePlayer *GetAttacker(void) const; // return last enemy that hurt us
+ float GetTimeSinceAttacked(void) const; // return duration since we were last injured by an attacker
+ float GetFirstSawEnemyTimestamp(void) const; // time since we saw any enemies
+ float GetLastSawEnemyTimestamp(void) const;
+ float GetTimeSinceLastSawEnemy(void) const;
+ float GetTimeSinceAcquiredCurrentEnemy(void) const;
+ bool HasNotSeenEnemyForLongTime(void) const; // return true if we haven't seen an enemy for "a long time"
+ const Vector &GetLastKnownEnemyPosition(void) const;
+ bool IsEnemyVisible(void) const; // is our current enemy visible
+ float GetEnemyDeathTimestamp(void) const;
+ bool IsFriendInLineOfFire(void); // return true if a friend is in our weapon's way
+ bool IsAwareOfEnemyDeath(void) const; // return true if we *noticed* that our enemy died
+ int GetLastVictimID(void) const; // return the ID (entindex) of the last victim we killed, or zero
+
+ // navigation
+ bool HasPath(void) const;
+ void DestroyPath(void);
+
+ float GetFeetZ(void) const; // return Z of bottom of feet
enum PathResult
{
- PROGRESSING,
- END_OF_PATH,
- PATH_FAILURE,
+ PROGRESSING, // we are moving along the path
+ END_OF_PATH, // we reached the end of the path
+ PATH_FAILURE, // we failed to reach the end of the path
};
- NOBODY PathResult UpdatePathMovement(bool allowSpeedChange);
- //bool AStarSearch(CNavArea *startArea); // NOXREF Not implemented
- NOBODY bool ComputePath(CNavArea *goalArea, const Vector *goal, RouteType route);
- NOBODY bool StayOnNavMesh(void);
- CNavArea *GetLastKnownArea(void) const
- {
- return m_lastKnownArea;
- }
- const Vector &GetPathEndpoint(void) const
- {
- return m_path[ m_pathLength - 1 ].pos;
- }
- NOBODY float GetPathDistanceRemaining(void);
- NOBODY void ResetStuckMonitor(void);
- //bool IsAreaVisible(CNavArea *area); // NOXREF Not implemented
- const Vector &GetPathPosition(int numpath) const
- {
- return m_path[ numpath ].pos;
- }
- NOBODY bool GetSimpleGroundHeightWithFloor(const Vector *pos, float *height, Vector *normal);
- NOBODY Place GetPlace(void);
- bool IsUsingLadder(void) const
- {
- return (m_pathLadder != NULL);
- }
- NOBODY void GetOffLadder(void);
- void SetGoalEntity(CBaseEntity *entity)
- {
- m_goalEntity = entity;
- }
- CBaseEntity *GetGoalEntity(void)
- {
- return m_goalEntity;
- }
- NOBODY bool IsNearJump(void);
- NOBODY float GetApproximateFallDamage(float height);
- void ForceRun(float duration)
- {
- Run();
- m_mustRunTimer.Start(duration);
- }
- NOBODY void Wiggle(void);
- NOBODY bool IsFriendInTheWay(Vector *goalPos);
- NOBODY void FeelerReflexAdjustment(Vector *goalPosition);
- void SetLookAngles(float yaw, float pitch)
- {
- m_lookYaw = yaw;
- m_lookPitch = pitch;
- }
- void UpdateLookAngles(void);
+ #define NO_SPEED_CHANGE false
+ PathResult UpdatePathMovement(bool allowSpeedChange = true); // move along our computed path - if allowSpeedChange is true, bot will walk when near goal to ensure accuracy
- NOBODY void UpdateLookAround(bool updateNow);
- NOBODY void InhibitLookAround(float duration);
- void SetForwardAngle(float angle)
- {
- m_forwardAngle = angle;
- }
- void SetLookAheadAngle(float angle)
- {
- m_lookAheadAngle = angle;
- }
+ NOXREF bool AStarSearch(CNavArea *startArea, CNavArea *goalArea); // find shortest path from startArea to goalArea - don't actually buid the path
+ bool ComputePath(CNavArea *goalArea, const Vector *goal, RouteType route); // compute path to goal position
+ bool StayOnNavMesh(void);
+ CNavArea *GetLastKnownArea(void) const; // return the last area we know we were inside of
+ const Vector &GetPathEndpoint(void) const; // return final position of our current path
+ float GetPathDistanceRemaining(void) const; // eturn estimated distance left to travel along path
+ void ResetStuckMonitor(void);
+ NOXREF bool IsAreaVisible(CNavArea *area) const; // is any portion of the area visible to this bot
+ const Vector &GetPathPosition(int numpath) const;
+ bool GetSimpleGroundHeightWithFloor(const Vector *pos, float *height, Vector *normal = NULL); // find "simple" ground height, treating current nav area as part of the floor
+
+ Place GetPlace(void) const; // get our current radio chatter place
+
+ bool IsUsingLadder(void) const; // returns true if we are in the process of negotiating a ladder
+ void GetOffLadder(void);
+
+ void SetGoalEntity(CBaseEntity *entity);
+ CBaseEntity *GetGoalEntity(void);
+
+ bool IsNearJump(void) const; // return true if nearing a jump in the path
+ float GetApproximateFallDamage(float height) const; // return how much damage will will take from the given fall height
+
+ void ForceRun(float duration); // force the bot to run if it moves for the given duration
+ void Wiggle(void); // random movement, for getting un-stuck
+
+ bool IsFriendInTheWay(const Vector *goalPos) const; // return true if a friend is between us and the given position
+ void FeelerReflexAdjustment(Vector *goalPosition); // do reflex avoidance movements if our "feelers" are touched
+
+ // looking around
+ void SetLookAngles(float yaw, float pitch); // set our desired look angles
+ void UpdateLookAngles(void); // move actual view angles towards desired ones
+ void UpdateLookAround(bool updateNow = false); // update "looking around" mechanism
+ void InhibitLookAround(float duration); // block all "look at" and "looking around" behavior for given duration - just look ahead
+
+ // TODO: Clean up notion of "forward angle" and "look ahead angle"
+ void SetForwardAngle(float angle); // define our forward facing
+ void SetLookAheadAngle(float angle); // define default look ahead angle
+
+ // look at the given point in space for the given duration (-1 means forever)
void SetLookAt(const char *desc, const Vector *pos, PriorityType pri, float duration = -1.0f, bool clearIfClose = false, float angleTolerance = 5.0f);
+ void ClearLookAt(void); // stop looking at a point in space and just look ahead
+ bool IsLookingAtSpot(PriorityType pri = PRIORITY_LOW) const; // return true if we are looking at spot with equal or higher priority
+ bool IsViewMoving(float angleVelThreshold = 1.0f) const; // returns true if bot's view angles are rotating (not still)
- void ClearLookAt(void)
+ const Vector &GetEyePosition(void) const
{
- m_lookAtSpotState = NOT_LOOKING_AT_SPOT;
- m_lookAtDesc = NULL;
+ m_eyePos = pev->origin + pev->view_ofs;
+ return m_eyePos;
}
- bool IsLookingAtSpot(PriorityType pri) const
- {
- if (m_lookAtSpotState != NOT_LOOKING_AT_SPOT && m_lookAtSpotPriority >= pri)
- return true;
+ float ComputeWeaponSightRange(void); // return line-of-sight distance to obstacle along weapon fire ray
- return false;
- }
- bool IsViewMoving(float angleVelThreshold) const
- {
- if (m_lookYawVel < angleVelThreshold && m_lookYawVel > -angleVelThreshold &&
- m_lookPitchVel < angleVelThreshold && m_lookPitchVel > -angleVelThreshold)
- {
- return false;
- }
- return true;
- }
- NOBODY const Vector *GetEyePosition(void) const;
- NOBODY float ComputeWeaponSightRange(void);
- NOBODY void ComputeApproachPoints(void);
- NOBODY void UpdateApproachPoints(void);
- void ClearApproachPoints(void)
- {
- m_approachPointCount = 0;
- }
- NOBODY void DrawApproachPoints(void);
- NOBODY float GetHidingSpotCheckTimestamp(HidingSpot *spot);
- NOBODY void SetHidingSpotCheckTimestamp(HidingSpot *spot);
- NOBODY void EquipBestWeapon(bool mustEquip);
- NOBODY void EquipPistol(void);
- NOBODY void EquipKnife(void);
- NOBODY bool EquipGrenade(bool noSmoke);
- bool IsUsingKnife(void);
- bool IsUsingPistol(void);
- bool IsUsingGrenade(void);
- bool IsUsingSniperRifle(void);
- bool IsUsingAWP(void);
- NOBODY bool IsSniper(void);
- bool IsSniping(void) const;
- bool IsUsingShotgun(void);
- bool IsUsingMachinegun(void);
- void ThrowGrenade(const Vector *target);
- bool IsThrowingGrenade(void) const
- {
- return m_isWaitingToTossGrenade;
- }
- NOBODY bool HasGrenade(void);
- NOBODY bool DoesActiveWeaponHaveSilencer(void);
- NOBODY bool IsUsingHEGrenade(void);
- NOBODY void StartRapidFire(void);
- NOBODY void StopRapidFire(void);
- NOBODY bool IsRapidFiring(void);
+ // approach points
+ void ComputeApproachPoints(void); // determine the set of "approach points" representing where the enemy can enter this region
+ NOXREF void UpdateApproachPoints(void); // recompute the approach point set if we have moved far enough to invalidate the current ones
+ void ClearApproachPoints(void);
+ void DrawApproachPoints(void); // for debugging
+ float GetHidingSpotCheckTimestamp(HidingSpot *spot) const; // return time when given spot was last checked
+ void SetHidingSpotCheckTimestamp(HidingSpot *spot); // set the timestamp of the given spot to now
- enum ZoomType
- {
- NO_ZOOM = 0,
- LOW_ZOOM,
- HIGH_ZOOM,
- };
- ZoomType GetZoomLevel(void)
- {
- if (m_iFOV > 60.0f)
- return NO_ZOOM;
+ // weapon query and equip
+ #define MUST_EQUIP true
+ void EquipBestWeapon(bool mustEquip = false); // equip the best weapon we are carrying that has ammo
+ void EquipPistol(void); // equip our pistol
+ void EquipKnife(void); // equip our knife
- if (m_iFOV > 25.0f)
- return LOW_ZOOM;
+ #define DONT_USE_SMOKE_GRENADE true
+ bool EquipGrenade(bool noSmoke = false); // equip a grenade, return false if we cant
- return HIGH_ZOOM;
- }
- NOBODY bool AdjustZoom(float range);
- NOBODY bool IsPrimaryWeaponEmpty(void);
- NOBODY bool IsPistolEmpty(void);
- NOBODY int GetHostageEscortCount(void);
- NOBODY void IncreaseHostageEscortCount(void);
- NOBODY float GetRangeToFarthestEscortedHostage(void);
- NOBODY void ResetWaitForHostagePatience(void);
- NOBODY void ResetValues(void);
- NOBODY void BotDeathThink(void);
- NOBODY CBasePlayer *FindNearbyPlayer(void);
- void AdjustSafeTime(void);
- void SetState(BotState *state);
- NOBODY void MoveTowardsPosition(const Vector *pos);
- NOBODY void MoveAwayFromPosition(const Vector *pos);
- NOBODY void StrafeAwayFromPosition(const Vector *pos);
- NOBODY void StuckCheck(void);
- NOBODY void BuildTrivialPath(const Vector *goal);
- NOBODY bool ComputePathPositions(void);
- NOBODY void SetupLadderMovement(void);
- NOBODY void SetPathIndex(int newIndex);
- NOBODY void DrawPath(void);
- NOBODY int FindOurPositionOnPath(Vector *close, bool local);
- NOBODY int FindPathPoint(float aheadRange, Vector *point, int *prevIndex);
- NOBODY bool FindClosestPointOnPath(Vector *worldPos, int startIndex, int endIndex, Vector *close);
- NOBODY bool IsStraightLinePathWalkable(Vector *goal);
- NOBODY bool DiscontinuityJump(float ground, bool onlyJumpDown, bool mustJump);
- NOBODY bool UpdateLadderMovement(void);
- NOBODY void ComputeLadderEndpoint(bool isAscending);
- NOBODY void UpdateHostageEscortCount(void);
- NOBODY bool UpdateLookAtNoise(void);
- void UpdateLookAt(void);
- NOBODY void UpdatePeripheralVision(void);
- NOBODY bool BendLineOfSight(Vector *eye, const Vector *point, Vector *bend);
- NOBODY bool FindApproachPointNearestPath(const Vector *pos);
- NOBODY bool FindGrenadeTossPathTarget(const Vector *pos);
- void SetAimOffset(float accuracy);
- void UpdateAimOffset(void);
- NOBODY bool DoEquip(CBasePlayerWeapon *gun);
- NOBODY void ReloadCheck(void);
- NOBODY void SilencerCheck(void);
- NOBODY CBasePlayer *FindMostDangerousThreat(void);
- NOBODY void RespondToRadioCommands(void);
- NOBODY bool IsRadioCommand(GameEventType event);
- void EndVoiceFeedback(bool force = true);
- NOBODY CNavNode *AddNode(const Vector *destPos, const Vector *normal, NavDirType dir, CNavNode *source);
- NOBODY void StartLearnProcess(void);
- NOBODY void UpdateLearnProcess(void);
- NOBODY bool LearnStep(void);
- NOBODY void StartAnalyzeAlphaProcess(void);
- NOBODY void UpdateAnalyzeAlphaProcess(void);
- NOBODY bool AnalyzeAlphaStep(void);
- NOBODY void StartAnalyzeBetaProcess(void);
- NOBODY void UpdateAnalyzeBetaProcess(void);
- NOBODY bool AnalyzeBetaStep(void);
- NOBODY void StartSaveProcess(void);
- NOBODY void UpdateSaveProcess(void);
- void StartNormalProcess(void);
- NOBODY void BotTouch(CBaseEntity *other);
+ bool IsUsingKnife(void) const; // returns true if we have knife equipped
+ bool IsUsingPistol(void) const; // returns true if we have pistol equipped
+ bool IsUsingGrenade(void) const; // returns true if we have grenade equipped
+ bool IsUsingSniperRifle(void) const; // returns true if using a "sniper" rifle
+ bool IsUsingAWP(void) const; // returns true if we have AWP equipped
+
+ bool IsSniper(void) const; // return true if we have a sniper rifle in our inventory
+ bool IsSniping(void) const; // return true if we are actively sniping (moving to sniper spot or settled in)
+ bool IsUsingShotgun(void) const; // returns true if using a shotgun
+ bool IsUsingMachinegun(void) const; // returns true if using the big 'ol machinegun
+ void ThrowGrenade(const Vector *target); // begin the process of throwing the grenade
+ bool IsThrowingGrenade(void) const; // return true if we are in the process of throwing a grenade
+ bool HasGrenade(void) const; // return true if we have a grenade in our inventory
+
+ bool DoesActiveWeaponHaveSilencer(void) const;
+ bool IsUsingHEGrenade(void) const;
+ void StartRapidFire(void);
+ void StopRapidFire(void);
+ bool IsRapidFiring(void) const;
+
+ enum ZoomType { NO_ZOOM, LOW_ZOOM, HIGH_ZOOM };
+ ZoomType GetZoomLevel(void) const; // return the current zoom level of our weapon
+
+ bool AdjustZoom(float range); // change our zoom level to be appropriate for the given range
+
+ bool IsPrimaryWeaponEmpty(void) const; // return true if primary weapon doesn't exist or is totally out of ammo
+ bool IsPistolEmpty(void) const; // return true if secondary weapon doesn't exist or is totally out of ammo
+
+ int GetHostageEscortCount(void) const;
+ void IncreaseHostageEscortCount(void);
+ float GetRangeToFarthestEscortedHostage(void) const;
+ void ResetWaitForHostagePatience(void);
+ void ResetValues(void); // reset internal data to initial state
+ void BotDeathThink(void);
+ CBasePlayer *FindNearbyPlayer(void);
+ void AdjustSafeTime(void); // called when enemy seen to adjust safe time for this round
+ void EXPORT BotTouch(CBaseEntity *other);
+ bool HasAnyAmmo(CBasePlayerWeapon *weapon) const;
+
+#ifndef HOOK_GAMEDLL
private:
+#endif // HOOK_GAMEDLL
friend class CCSBotManager;
+
+ // TODO: Get rid of these
friend class AttackState;
friend class BuyState;
- char m_name[64];
- float m_combatRange;
- mutable bool m_isRogue;
+ char m_name[64]; // copied from STRING(pev->netname) for debugging
+
+ // behavior properties
+ float m_combatRange; // desired distance between us and them during gunplay
+ mutable bool m_isRogue; // if true, the bot is a "rogue" and listens to no-one
mutable CountdownTimer m_rogueTimer;
- MoraleType m_morale;
- bool m_diedLastRound;
- float m_safeTime;
- bool m_wasSafe;
- NavRelativeDirType m_blindMoveDir;
- bool m_blindFire;
- float m_surpriseDelay;
+ MoraleType m_morale; // our current morale, based on our win/loss history
+ bool m_diedLastRound; // true if we died last round
+ float m_safeTime; // duration at the beginning of the round where we feel "safe"
+ bool m_wasSafe; // true if we were in the safe time last update
+ NavRelativeDirType m_blindMoveDir; // which way to move when we're blind
+ bool m_blindFire; // if true, fire weapon while blinded
+
+ // TODO: implement through CountdownTimer
+ float m_surpriseDelay; // when we were surprised
float m_surpriseTimestamp;
- bool m_isFollowing;
- EHANDLE m_leader;
- float m_followTimestamp;
- float m_allowAutoFollowTime;
- CountdownTimer m_hurryTimer;
+
+ bool m_isFollowing; // true if we are following someone
+ EHANDLE m_leader; // the ID of who we are following
+ float m_followTimestamp; // when we started following
+ float m_allowAutoFollowTime; // time when we can auto follow
+
+ CountdownTimer m_hurryTimer; // if valid, bot is in a hurry
+
+ // instances of each possible behavior state, to avoid dynamic memory allocation during runtime
IdleState m_idleState;
HuntState m_huntState;
AttackState m_attackState;
@@ -1008,202 +869,272 @@ private:
EscapeFromBombState m_escapeFromBombState;
FollowState m_followState;
UseEntityState m_useEntityState;
- BotState *m_state;
- float m_stateTimestamp;
- bool m_isAttacking;
- TaskType m_task;
- EHANDLE m_taskEntity;
+
+ // TODO: Allow multiple simultaneous state machines (look around, etc)
+ void SetState(BotState *state); // set the current behavior state
+ BotState *m_state; // current behavior state
+ float m_stateTimestamp; // time state was entered
+ bool m_isAttacking; // if true, special Attack state is overriding the state machine
+
+ TaskType m_task; // our current task
+ EHANDLE m_taskEntity; // an entity used for our task
+
+ // navigation
Vector m_goalPosition;
EHANDLE m_goalEntity;
- CNavArea *m_currentArea;
- CNavArea *m_lastKnownArea;
- EHANDLE m_avoid;
+ void MoveTowardsPosition(const Vector *pos); // move towards position, independant of view angle
+ NOXREF void MoveAwayFromPosition(const Vector *pos); // move away from position, independant of view angle
+ void StrafeAwayFromPosition(const Vector *pos); // strafe (sidestep) away from position, independant of view angle
+ void StuckCheck(void); // check if we have become stuck
+
+ CNavArea *m_currentArea; // the nav area we are standing on
+ CNavArea *m_lastKnownArea; // the last area we were in
+ EHANDLE m_avoid; // higher priority player we need to make way for
float m_avoidTimestamp;
bool m_isJumpCrouching;
bool m_isJumpCrouched;
float m_jumpCrouchTimestamp;
+ // path navigation data
enum { MAX_PATH_LENGTH = 256 };
-
struct ConnectInfo
{
- CNavArea *area;
- NavTraverseType how;
- Vector pos;
- const CNavLadder *ladder;
- } m_path[MAX_PATH_LENGTH];
- /* size: 24, cachelines: 1, members: 4 */
-
+ CNavArea *area; // the area along the path
+ NavTraverseType how; // how to enter this area from the previous one
+ Vector pos; // our movement goal position at this point in the path
+ const CNavLadder *ladder; // if "how" refers to a ladder, this is it
+ }
+ m_path[ MAX_PATH_LENGTH ];
int m_pathLength;
int m_pathIndex;
float m_areaEnteredTimestamp;
- CountdownTimer m_repathTimer;
- mutable CountdownTimer m_avoidFriendTimer;
- mutable bool m_isFriendInTheWay;
- CountdownTimer m_politeTimer;
- bool m_isWaitingBehindFriend;
+ void BuildTrivialPath(const Vector *goal); // build trivial path to goal, assuming we are already in the same area
+ bool FindGrenadeTossPathTarget(Vector *pos);
+
+ CountdownTimer m_repathTimer; // must have elapsed before bot can pathfind again
+
+ bool ComputePathPositions(void); // determine actual path positions bot will move between along the path
+ void SetupLadderMovement(void);
+ void SetPathIndex(int newIndex); // set the current index along the path
+ void DrawPath(void);
+ int FindOurPositionOnPath(Vector *close, bool local = false) const; // compute the closest point to our current position on our path
+ int FindPathPoint(float aheadRange, Vector *point, int *prevIndex = NULL); // compute a point a fixed distance ahead along our path.
+ bool FindClosestPointOnPath(const Vector *worldPos, int startIndex, int endIndex, Vector *close) const; // compute closest point on path to given point
+ bool IsStraightLinePathWalkable(const Vector *goal) const; // test for un-jumpable height change, or unrecoverable fall
+
+ mutable CountdownTimer m_avoidFriendTimer; // used to throttle how often we check for friends in our path
+ mutable bool m_isFriendInTheWay; // true if a friend is blocking our path
+ CountdownTimer m_politeTimer; // we'll wait for friend to move until this runs out
+ bool m_isWaitingBehindFriend; // true if we are waiting for a friend to move
+
+ #define ONLY_JUMP_DOWN true
+ bool DiscontinuityJump(float ground, bool onlyJumpDown = false, bool mustJump = false); // check if we need to jump due to height change
enum LadderNavState
{
- APPROACH_ASCENDING_LADDER,
- APPROACH_DESCENDING_LADDER,
+ APPROACH_ASCENDING_LADDER, // prepare to scale a ladder
+ APPROACH_DESCENDING_LADDER, // prepare to go down ladder
FACE_ASCENDING_LADDER,
FACE_DESCENDING_LADDER,
- MOUNT_ASCENDING_LADDER,
- MOUNT_DESCENDING_LADDER,
- ASCEND_LADDER,
- DESCEND_LADDER,
- DISMOUNT_ASCENDING_LADDER,
- DISMOUNT_DESCENDING_LADDER,
- MOVE_TO_DESTINATION,
+ MOUNT_ASCENDING_LADDER, // move toward ladder until "on" it
+ MOUNT_DESCENDING_LADDER, // move toward ladder until "on" it
+ ASCEND_LADDER, // go up the ladder
+ DESCEND_LADDER, // go down the ladder
+ DISMOUNT_ASCENDING_LADDER, // get off of the ladder
+ DISMOUNT_DESCENDING_LADDER, // get off of the ladder
+ MOVE_TO_DESTINATION, // dismount ladder and move to destination area
}
m_pathLadderState;
- bool m_pathLadderFaceIn;
- CNavLadder *m_pathLadder; // 9260
- NavRelativeDirType m_pathLadderDismountDir;
- float m_pathLadderDismountTimestamp;
- float m_pathLadderEnd;
- float m_pathLadderTimestamp;
- class CountdownTimer m_mustRunTimer;
+ bool m_pathLadderFaceIn; // if true, face towards ladder, otherwise face away
+ const CNavLadder *m_pathLadder; // the ladder we need to use to reach the next area
+ bool UpdateLadderMovement(void); // called by UpdatePathMovement()
+ NavRelativeDirType m_pathLadderDismountDir; // which way to dismount
+ float m_pathLadderDismountTimestamp; // time when dismount started
+ float m_pathLadderEnd; // if ascending, z of top, if descending z of bottom
+ void ComputeLadderEndpoint(bool isAscending);
+ float m_pathLadderTimestamp; // time when we started using ladder - for timeout check
+
+ CountdownTimer m_mustRunTimer; // if nonzero, bot cannot walk
+
+ // game scenario mechanisms
CSGameState m_gameState;
+
+ // hostages mechanism
byte m_hostageEscortCount;
+ void UpdateHostageEscortCount(void);
float m_hostageEscortCountTimestamp;
bool m_isWaitingForHostage;
CountdownTimer m_inhibitWaitingForHostageTimer;
CountdownTimer m_waitForHostageTimer;
- Vector m_noisePosition;
- float m_noiseTimestamp;
- CNavArea *m_noiseArea;
+
+ // listening mechanism
+ Vector m_noisePosition; // position we last heard non-friendly noise
+ float m_noiseTimestamp; // when we heard it (can get zeroed)
+ CNavArea *m_noiseArea; // the nav area containing the noise
float m_noiseCheckTimestamp;
- PriorityType m_noisePriority;
+ PriorityType m_noisePriority; // priority of currently heard noise
+ bool UpdateLookAtNoise(void); // return true if we decided to look towards the most recent noise source
bool m_isNoiseTravelRangeChecked;
- float m_lookAroundStateTimestamp;
- float m_lookAheadAngle;
- float m_forwardAngle;
- float m_inhibitLookAroundTimestamp;
+
+ // "looking around" mechanism
+ float m_lookAroundStateTimestamp; // time of next state change
+ float m_lookAheadAngle; // our desired forward look angle
+ float m_forwardAngle; // our current forward facing direction
+ float m_inhibitLookAroundTimestamp; // time when we can look around again
enum LookAtSpotState
{
- NOT_LOOKING_AT_SPOT = 0,
- LOOK_TOWARDS_SPOT,
- LOOK_AT_SPOT,
- NUM_LOOK_AT_SPOT_STATES,
+ NOT_LOOKING_AT_SPOT, // not currently looking at a point in space
+ LOOK_TOWARDS_SPOT, // in the process of aiming at m_lookAtSpot
+ LOOK_AT_SPOT, // looking at m_lookAtSpot
+ NUM_LOOK_AT_SPOT_STATES
}
m_lookAtSpotState;
- Vector m_lookAtSpot;
-
+ Vector m_lookAtSpot; // the spot we're currently looking at
PriorityType m_lookAtSpotPriority;
- float m_lookAtSpotDuration;
- float m_lookAtSpotTimestamp;
- float m_lookAtSpotAngleTolerance;
- bool m_lookAtSpotClearIfClose;
- const char *m_lookAtDesc;
+ float m_lookAtSpotDuration; // how long we need to look at the spot
+ float m_lookAtSpotTimestamp; // when we actually began looking at the spot
+ float m_lookAtSpotAngleTolerance; // how exactly we must look at the spot
+ bool m_lookAtSpotClearIfClose; // if true, the look at spot is cleared if it gets close to us
+ const char *m_lookAtDesc; // for debugging
+ void UpdateLookAt(void);
+ void UpdatePeripheralVision(void); // update enounter spot timestamps, etc
float m_peripheralTimestamp;
enum { MAX_APPROACH_POINTS = 16 };
- Vector m_approachPoint[MAX_APPROACH_POINTS];
+ Vector m_approachPoint[ MAX_APPROACH_POINTS ];
unsigned char m_approachPointCount;
- Vector m_approachPointViewPosition;
+ Vector m_approachPointViewPosition; // the position used when computing current approachPoint set
- bool m_isWaitingToTossGrenade;
- CountdownTimer m_tossGrenadeTimer;
- SpotEncounter *m_spotEncounter;
- float m_spotCheckTimestamp;
+ bool BendLineOfSight(const Vector *eye, const Vector *point, Vector *bend) const; // "bend" our line of sight until we can see the target point. Return bend point, false if cant bend.
+ NOXREF bool FindApproachPointNearestPath(Vector *pos); // find the approach point that is nearest to our current path, ahead of us
+ bool m_isWaitingToTossGrenade; // lining up throw
+ CountdownTimer m_tossGrenadeTimer; // timeout timer for grenade tossing
+
+ SpotEncounter *m_spotEncounter; // the spots we will encounter as we move thru our current area
+ float m_spotCheckTimestamp; // when to check next encounter spot
+
+ // TODO: Add timestamp for each possible client to hiding spots
enum { MAX_CHECKED_SPOTS = 64 };
struct HidingSpotCheckInfo
{
HidingSpot *spot;
float timestamp;
- }/* size: 8, cachelines: 1, members: 2 */
- m_checkedHidingSpot[MAX_CHECKED_SPOTS];
+ }
+ m_checkedHidingSpot[ MAX_CHECKED_SPOTS ];
int m_checkedHidingSpotCount;
- float m_lookPitch; // 10500
+ // view angle mechanism
+ float m_lookPitch; // our desired look pitch angle
float m_lookPitchVel;
- float m_lookYaw;
+ float m_lookYaw; // our desired look yaw angle
float m_lookYawVel;
- Vector m_eyePos;
- Vector m_aimOffset;
- Vector m_aimOffsetGoal;
- float m_aimOffsetTimestamp;
- float m_aimSpreadTimestamp;
- Vector m_aimSpot;
- DispositionType m_disposition;
- CountdownTimer m_ignoreEnemiesTimer;
- mutable EHANDLE m_enemy;
- bool m_isEnemyVisible;
- unsigned char m_visibleEnemyParts;
- Vector m_lastEnemyPosition;
+
+ // aim angle mechanism
+ mutable Vector m_eyePos;
+ Vector m_aimOffset; // current error added to victim's position to get actual aim spot
+ Vector m_aimOffsetGoal; // desired aim offset
+ float m_aimOffsetTimestamp; // time of next offset adjustment
+ float m_aimSpreadTimestamp; // time used to determine max spread as it begins to tighten up
+ void SetAimOffset(float accuracy); // set the current aim offset
+ void UpdateAimOffset(void); // wiggle aim error based on m_accuracy
+ Vector m_aimSpot; // the spot we are currently aiming to fire at
+
+ // attack state data
+ DispositionType m_disposition; // how we will react to enemies
+ CountdownTimer m_ignoreEnemiesTimer; // how long will we ignore enemies
+ mutable EHANDLE m_enemy; // our current enemy
+ bool m_isEnemyVisible; // result of last visibility test on enemy
+ unsigned char m_visibleEnemyParts; // which parts of the visible enemy do we see
+ Vector m_lastEnemyPosition; // last place we saw the enemy
float m_lastSawEnemyTimestamp;
float m_firstSawEnemyTimestamp;
float m_currentEnemyAcquireTimestamp;
- float m_enemyDeathTimestamp;
- bool m_isLastEnemyDead;
- int m_nearbyEnemyCount;
- unsigned int m_enemyPlace;
+ float m_enemyDeathTimestamp; // if m_enemy is dead, this is when he died
+ bool m_isLastEnemyDead; // true if we killed or saw our last enemy die
+ int m_nearbyEnemyCount; // max number of enemies we've seen recently
+ unsigned int m_enemyPlace; // the location where we saw most of our enemies
struct WatchInfo
{
float timestamp;
bool isEnemy;
- }/* size: 8, cachelines: 1, members: 2 */
- m_watchInfo[32];
+ }
+ m_watchInfo[ MAX_CLIENTS ];
+ mutable EHANDLE m_bomber; // points to bomber if we can see him
+
+ int m_nearbyFriendCount; // number of nearby teammates
+ mutable EHANDLE m_closestVisibleFriend; // the closest friend we can see
+ mutable EHANDLE m_closestVisibleHumanFriend; // the closest human friend we can see
+
+ CBasePlayer *m_attacker; // last enemy that hurt us (may not be same as m_enemy)
+ float m_attackedTimestamp; // when we were hurt by the m_attacker
+
+ int m_lastVictimID; // the entindex of the last victim we killed, or zero
+ bool m_isAimingAtEnemy; // if true, we are trying to aim at our enemy
+ bool m_isRapidFiring; // if true, RunUpkeep() will toggle our primary attack as fast as it can
+ IntervalTimer m_equipTimer; // how long have we had our current weapon equipped
+ bool DoEquip(CBasePlayerWeapon *gun); // equip the given item
+
+ void ReloadCheck(void); // reload our weapon if we must
+ void SilencerCheck(void); // use silencer
- mutable EHANDLE m_bomber;
- int m_nearbyFriendCount;
- mutable EHANDLE m_closestVisibleFriend;
- mutable EHANDLE m_closestVisibleHumanFriend;
- CBasePlayer *m_attacker;
- float m_attackedTimestamp;
- int m_lastVictimID;
- bool m_isAimingAtEnemy;
- bool m_isRapidFiring;
- IntervalTimer m_equipTimer;
float m_fireWeaponTimestamp;
+ // reaction time system
enum { MAX_ENEMY_QUEUE = 20 };
struct ReactionState
{
+ // NOTE: player position & orientation is not currently stored separately
EHANDLE player;
bool isReloading;
bool isProtectedByShield;
- } m_enemyQueue[MAX_ENEMY_QUEUE];
- /* size: 12, cachelines: 1, members: 3 */
+ }
+ m_enemyQueue[ MAX_ENEMY_QUEUE ]; // round-robin queue for simulating reaction times
byte m_enemyQueueIndex;
byte m_enemyQueueCount;
- byte m_enemyQueueAttendIndex;
+ byte m_enemyQueueAttendIndex; // index of the timeframe we are "conscious" of
+
+ CBasePlayer *FindMostDangerousThreat(void); // return most dangerous threat in my field of view (feeds into reaction time queue)
+
+ // stuck detection
bool m_isStuck;
- float m_stuckTimestamp;
- Vector m_stuckSpot;
+ float m_stuckTimestamp; // time when we got stuck
+ Vector m_stuckSpot; // the location where we became stuck
NavRelativeDirType m_wiggleDirection;
float m_wiggleTimestamp;
- float m_stuckJumpTimestamp;
+ float m_stuckJumpTimestamp; // time for next jump when stuck
enum { MAX_VEL_SAMPLES = 5 };
-
- float m_avgVel[MAX_VEL_SAMPLES];
+ float m_avgVel[ MAX_VEL_SAMPLES ];
int m_avgVelIndex;
int m_avgVelCount;
Vector m_lastOrigin;
- GameEventType m_lastRadioCommand;
- float m_lastRadioRecievedTimestamp;
- float m_lastRadioSentTimestamp;
- EHANDLE m_radioSubject;
- Vector m_radioPosition;
+ // chatter mechanism
+ GameEventType m_lastRadioCommand; // last radio command we recieved
+ void RespondToRadioCommands(void);
+ bool IsRadioCommand(GameEventType event) const; // returns true if the radio message is an order to do something
+ void EndVoiceFeedback(bool force = true);
+ float m_lastRadioRecievedTimestamp; // time we recieved a radio message
+ float m_lastRadioSentTimestamp; // time when we send a radio message
+ EHANDLE m_radioSubject; // who issued the radio message
+ Vector m_radioPosition; // position referred to in radio message
float m_voiceFeedbackStartTimestamp;
- float m_voiceFeedbackEndTimestamp;
+ float m_voiceFeedbackEndTimestamp; // new-style "voice" chatter gets voice feedback
BotChatterInterface m_chatter;
- CNavNode *m_navNodeList;
+
+ // learn map mechanism
+ const CNavNode *m_navNodeList;
CNavNode *m_currentNode;
NavDirType m_generationDir;
- NavAreaList::iterator m_analyzeIter; // TODO: //iterator m_analyzeIter;
-
+ NavAreaList::iterator m_analyzeIter;
+
enum ProcessType
{
- PROCESS_NORMAL = 0,
+ PROCESS_NORMAL,
PROCESS_LEARN,
PROCESS_ANALYZE_ALPHA,
PROCESS_ANALYZE_BETA,
@@ -1214,8 +1145,519 @@ private:
CountdownTimer m_booTimer;
CountdownTimer m_relocateTimer;
+ CNavNode *AddNode(const Vector *destPos, const Vector *normal, NavDirType dir, CNavNode *source);
+ void StartLearnProcess(void);
+ void UpdateLearnProcess(void);
+ bool LearnStep(void);
+ void StartAnalyzeAlphaProcess(void);
+ void UpdateAnalyzeAlphaProcess(void);
+ bool AnalyzeAlphaStep(void);
+ void StartAnalyzeBetaProcess(void);
+ void UpdateAnalyzeBetaProcess(void);
+ bool AnalyzeBetaStep(void);
+ void StartSaveProcess(void);
+ void UpdateSaveProcess(void);
+ void StartNormalProcess(void);
+
};/* size: 11424, cachelines: 179, members: 161 */
+// Inlines
+
+/* <51934c> ../cstrike/dlls/bot/cs_bot.h:316 */
+inline float CCSBot::GetCombatRange(void) const
+{
+ return m_combatRange;
+}
+
+/* <58de9b> ../cstrike/dlls/bot/cs_bot.h:318 */
+inline void CCSBot::SetRogue(bool rogue)
+{
+ m_isRogue = rogue;
+}
+
+/* <519617> ../cstrike/dlls/bot/cs_bot.h:320 */
+inline void CCSBot::Hurry(float duration)
+{
+ m_hurryTimer.Start(duration);
+}
+
+/* <5a0773> ../cstrike/dlls/bot/cs_bot.h:326 */
+inline float CCSBot::GetSafeTime(void) const
+{
+ return m_safeTime;
+}
+
+/* <5c4b10> ../cstrike/dlls/bot/cs_bot.h:355 */
+inline bool CCSBot::IsCarryingBomb(void) const
+{
+ return m_bHasC4;
+}
+
+/* <5a07aa> ../cstrike/dlls/bot/cs_bot.h:369 */
+inline bool CCSBot::IsFollowing(void) const
+{
+ return m_isFollowing;
+}
+
+/* <57bf57> ../cstrike/dlls/bot/cs_bot.h:370 */
+inline CBasePlayer *CCSBot::GetFollowLeader(void)
+{
+ return m_leader;
+}
+
+/* <3c5a20> ../cstrike/dlls/bot/cs_bot.h:375 */
+inline float CCSBot::GetFollowDuration(void) const
+{
+ return gpGlobals->time - m_followTimestamp;
+}
+
+/* <3c5a39> ../cstrike/dlls/bot/cs_bot.h:376 */
+inline bool CCSBot::CanAutoFollow(void) const
+{
+ return (gpGlobals->time > m_allowAutoFollowTime);
+}
+
+/* <3c5a52> ../cstrike/dlls/bot/cs_bot.h:381 */
+inline void CCSBot::AimAtEnemy(void)
+{
+ m_isAimingAtEnemy = true;
+}
+
+/* <3c5a70> ../cstrike/dlls/bot/cs_bot.h:382 */
+inline void CCSBot::StopAiming(void)
+{
+ m_isAimingAtEnemy = false;
+}
+
+/* <3c5a89> ../cstrike/dlls/bot/cs_bot.h:383 */
+inline bool CCSBot::IsAimingAtEnemy(void) const
+{
+ return m_isAimingAtEnemy;
+}
+
+/* <3e9c5e> ../cstrike/dlls/bot/cs_bot.h:385 */
+inline bool CCSBot::IsSurprised(void) const
+{
+ return gpGlobals->time - m_surpriseTimestamp < 5.0f;
+}
+
+/* <3ea00d> ../cstrike/dlls/bot/cs_bot.h:386 */
+inline float CCSBot::GetSurpriseDelay(void) const
+{
+ return gpGlobals->time - IsSurprised() ? m_surpriseDelay : 0.0f;
+}
+
+/* <51938e> ../cstrike/dlls/bot/cs_bot.h:387 */
+inline void CCSBot::ClearSurpriseDelay(void)
+{
+ m_surpriseDelay = 0.0f;
+ m_surpriseTimestamp = 0.0f;
+}
+
+/* <5e2f12> ../cstrike/dlls/bot/cs_bot.h:389 */
+inline float CCSBot::GetStateTimestamp(void) const
+{
+ return m_stateTimestamp;
+}
+
+/* <5c4c60> ../cstrike/dlls/bot/cs_bot.h:394 */
+inline CSGameState *CCSBot::GetGameState(void)
+{
+ return &m_gameState;
+}
+
+/* <2e7d45> ../cstrike/dlls/bot/cs_bot.h:395 */
+inline const CSGameState *CCSBot::GetGameState(void) const
+{
+ return &m_gameState;
+}
+
+/* <5c4ce8> ../cstrike/dlls/bot/cs_bot.h:397 */
+inline bool CCSBot::IsAtBombsite(void)
+{
+ UNTESTED
+ return GetGameState()->IsAtPlantedBombsite();
+}
+
+/* <5a07c3> ../cstrike/dlls/bot/cs_bot.h:453 */
+inline CCSBot::MoraleType CCSBot::GetMorale(void) const
+{
+ return m_morale;
+}
+
+/* <5b2dba> ../cstrike/dlls/bot/cs_bot.h:459 */
+inline bool CCSBot::IsNoiseHeard(void) const
+{
+ if (m_noiseTimestamp <= 0.0f)
+ return false;
+
+ // primitive reaction time simulation - cannot "hear" noise until reaction time has elapsed
+ if (gpGlobals->time - m_noiseTimestamp >= GetProfile()->GetReactionTime())
+ return true;
+
+ return false;
+}
+
+/* <5d3f92> ../cstrike/dlls/bot/cs_bot.h:426 */
+inline void CCSBot::SetTask(TaskType task, CBaseEntity *entity)
+{
+ m_task = task;
+ m_taskEntity = entity;
+}
+
+/* <5e2f30> ../cstrike/dlls/bot/cs_bot.h:427 */
+inline CCSBot::TaskType CCSBot::GetTask(void) const
+{
+ return m_task;
+}
+
+/* <5c4c42> ../cstrike/dlls/bot/cs_bot.h:428 */
+inline CBaseEntity *CCSBot::GetTaskEntity(void)
+{
+ return m_taskEntity;
+}
+
+/* <5b2d33> ../cstrike/dlls/bot/cs_bot.h:474 */
+inline CNavArea *CCSBot::GetNoiseArea(void) const
+{
+ return m_noiseArea;
+}
+
+/* <5b2d51> ../cstrike/dlls/bot/cs_bot.h:475 */
+inline void CCSBot::ForgetNoise(void)
+{
+ m_noiseTimestamp = 0.0f;
+}
+
+/* <5b2d6f> ../cstrike/dlls/bot/cs_bot.h:487 */
+inline PriorityType CCSBot::GetNoisePriority(void) const
+{
+ return m_noisePriority;
+}
+
+/* <5c4ccf> ../cstrike/dlls/bot/cs_bot.h:491 */
+inline BotChatterInterface *CCSBot::GetChatter(void)
+{
+ return &m_chatter;
+}
+
+/* <111238> ../cstrike/dlls/bot/cs_bot.h:508 */
+inline bool CCSBot::IsUsingVoice(void) const
+{
+ UNTESTED
+ return (m_voiceFeedbackEndTimestamp != 0.0f); //return (m_voiceFeedbackEndTimestamp > gpGlobals->time);
+}
+
+/* <519493> ../cstrike/dlls/bot/cs_bot.h:513 */
+inline CBasePlayer *CCSBot::GetEnemy(void)
+{
+ return m_enemy;
+}
+
+/* <57bfbd> ../cstrike/dlls/bot/cs_bot.h:514 */
+inline int CCSBot::GetNearbyEnemyCount(void) const
+{
+ return Q_min(GetEnemiesRemaining(), m_nearbyEnemyCount);
+}
+
+/* <2fecad> ../cstrike/dlls/bot/cs_bot.h:515 */
+inline unsigned int CCSBot::GetEnemyPlace(void) const
+{
+ return m_enemyPlace;
+}
+
+/* <2eff13> ../cstrike/dlls/bot/cs_bot.h:516 */
+inline bool CCSBot::CanSeeBomber(void) const
+{
+ return (m_bomber == NULL) ? false : true;
+}
+
+/* <3c6110> ../cstrike/dlls/bot/cs_bot.h:517 */
+inline CBasePlayer *CCSBot::GetBomber(void) const
+{
+ return m_bomber;
+}
+
+/* <2fecc8> ../cstrike/dlls/bot/cs_bot.h:519 */
+inline int CCSBot::GetNearbyFriendCount(void) const
+{
+ return Q_min(GetFriendsRemaining(), m_nearbyFriendCount);
+}
+
+/* <3a138c> ../cstrike/dlls/bot/cs_bot.h:521 */
+inline CBasePlayer *CCSBot::GetClosestVisibleFriend(void) const
+{
+ return m_closestVisibleFriend;
+}
+
+/* <3c615b> ../cstrike/dlls/bot/cs_bot.h:521 */
+inline CBasePlayer *CCSBot::GetClosestVisibleHumanFriend(void) const
+{
+ return m_closestVisibleHumanFriend;
+}
+
+/* <57bfd6> ../cstrike/dlls/bot/cs_bot.h:536 */
+inline float CCSBot::GetTimeSinceAttacked(void) const
+{
+ return gpGlobals->time - m_attackedTimestamp;
+}
+
+/* <56ae2c> ../cstrike/dlls/bot/cs_bot.h:537 */
+inline float CCSBot::GetFirstSawEnemyTimestamp(void) const
+{
+ return m_firstSawEnemyTimestamp;
+}
+
+/* <58df07> ../cstrike/dlls/bot/cs_bot.h:538 */
+inline float CCSBot::GetLastSawEnemyTimestamp(void) const
+{
+ return m_lastSawEnemyTimestamp;
+}
+
+/* <3e9ccc> ../cstrike/dlls/bot/cs_bot.h:539 */
+inline float CCSBot::GetTimeSinceLastSawEnemy(void) const
+{
+ return gpGlobals->time - m_lastSawEnemyTimestamp;
+}
+
+/* <3e9ce5> ../cstrike/dlls/bot/cs_bot.h:540 */
+inline float CCSBot::GetTimeSinceAcquiredCurrentEnemy(void) const
+{
+ return gpGlobals->time - m_currentEnemyAcquireTimestamp;
+}
+
+/* <5196d7> ../cstrike/dlls/bot/cs_bot.h:542 */
+inline const Vector &CCSBot::GetLastKnownEnemyPosition(void) const
+{
+ return m_lastEnemyPosition;
+}
+
+/* <5e2f49> ../cstrike/dlls/bot/cs_bot.h:543 */
+inline bool CCSBot::IsEnemyVisible(void) const
+{
+ return m_isEnemyVisible;
+}
+
+/* <519429> ../cstrike/dlls/bot/cs_bot.h:544 */
+inline float CCSBot::GetEnemyDeathTimestamp(void) const
+{
+ return m_enemyDeathTimestamp;
+}
+
+/* <519442> ../cstrike/dlls/bot/cs_bot.h:547 */
+inline int CCSBot::GetLastVictimID(void) const
+{
+ return m_lastVictimID;
+}
+
+/* <5b2da1> ../cstrike/dlls/bot/cs_bot.h:550 */
+inline bool CCSBot::HasPath(void) const
+{
+ return m_pathLength != 0;
+}
+
+/* <5a07f5> ../cstrike/dlls/bot/cs_bot.h:551 */
+inline void CCSBot::DestroyPath(void)
+{
+ m_pathLength = 0;
+ m_pathLadder = NULL;
+}
+
+/* <5a0813> ../cstrike/dlls/bot/cs_bot.h:567 */
+inline CNavArea *CCSBot::GetLastKnownArea(void) const
+{
+ return m_lastKnownArea;
+}
+
+/* <51963c> ../cstrike/dlls/bot/cs_bot.h:568 */
+inline const Vector &CCSBot::GetPathEndpoint(void) const
+{
+ return m_path[ m_pathLength - 1 ].pos;
+}
+
+/* <5c1be3> ../cstrike/dlls/bot/cs_bot.h:571 */
+inline const Vector &CCSBot::GetPathPosition(int numpath) const
+{
+ return m_path[ numpath ].pos;
+}
+
+/* <5c4b79> ../cstrike/dlls/bot/cs_bot.h:577 */
+inline bool CCSBot::IsUsingLadder(void) const
+{
+ return m_pathLadder != NULL;
+}
+
+/* <5a0c27> ../cstrike/dlls/bot/cs_bot.h:580 */
+inline void CCSBot::SetGoalEntity(CBaseEntity *entity)
+{
+ m_goalEntity = entity;
+}
+
+/* <5c4d01> ../cstrike/dlls/bot/cs_bot.h:581 */
+inline CBaseEntity *CCSBot::GetGoalEntity(void)
+{
+ return m_goalEntity;
+}
+
+/* <5195f2> ../cstrike/dlls/bot/cs_bot.h:586 */
+inline void CCSBot::ForceRun(float duration)
+{
+ Run();
+ m_mustRunTimer.Start(duration);
+}
+
+/* <3d8238> ../cstrike/dlls/bot/cs_bot.h:598 */
+inline void CCSBot::SetLookAngles(float yaw, float pitch)
+{
+ m_lookYaw = yaw;
+ m_lookPitch = pitch;
+}
+
+inline void CCSBot::SetForwardAngle(float angle)
+{
+ m_forwardAngle = angle;
+}
+
+/* <57c008> ../cstrike/dlls/bot/cs_bot.h:609 */
+inline void CCSBot::SetLookAheadAngle(float angle)
+{
+ m_lookAheadAngle = angle;
+}
+
+/* <5e2f62> ../cstrike/dlls/bot/cs_bot.h:612 */
+inline void CCSBot::ClearLookAt(void)
+{
+ //PrintIfWatched("ClearLookAt()\n");
+ m_lookAtSpotState = NOT_LOOKING_AT_SPOT;
+ m_lookAtDesc = NULL;
+}
+
+/* <3d8287> ../cstrike/dlls/bot/cs_bot.h:618 */
+inline bool CCSBot::IsLookingAtSpot(PriorityType pri) const
+{
+ if (m_lookAtSpotState != NOT_LOOKING_AT_SPOT && m_lookAtSpotPriority >= pri)
+ return true;
+
+ return false;
+}
+
+/* <3e9d59> ../cstrike/dlls/bot/cs_bot.h:625 */
+inline bool CCSBot::IsViewMoving(float angleVelThreshold) const
+{
+ if (m_lookYawVel < angleVelThreshold && m_lookYawVel > -angleVelThreshold &&
+ m_lookPitchVel < angleVelThreshold && m_lookPitchVel > -angleVelThreshold)
+ {
+ return false;
+ }
+ return true;
+}
+
+/* <57c047> ../cstrike/dlls/bot/cs_bot.h:651 */
+inline void CCSBot::ClearApproachPoints(void)
+{
+ m_approachPointCount = 0;
+}
+
+/* <3e9d7e> ../cstrike/dlls/bot/cs_bot.h:674 */
+inline bool CCSBot::IsThrowingGrenade(void) const
+{
+ return m_isWaitingToTossGrenade;
+}
+
+/* <3e9d97> ../cstrike/dlls/bot/cs_bot.h:679 */
+inline void CCSBot::StartRapidFire(void)
+{
+ m_isRapidFiring = true;
+}
+
+/* <3e9db0> ../cstrike/dlls/bot/cs_bot.h:680 */
+inline void CCSBot::StopRapidFire(void)
+{
+ m_isRapidFiring = false;
+}
+
+/* <51954d> ../cstrike/dlls/bot/cs_bot.h:684 */
+inline CCSBot::ZoomType CCSBot::GetZoomLevel(void) const
+{
+ if (m_iFOV > 60.0f)
+ return NO_ZOOM;
+
+ if (m_iFOV > 25.0f)
+ return LOW_ZOOM;
+
+ return HIGH_ZOOM;
+}
+
+/* <5c4b92> ../cstrike/dlls/bot/cs_bot.h:698 */
+inline int CCSBot::GetHostageEscortCount(void) const
+{
+ return m_hostageEscortCount;
+}
+
+/* <5e2f80> ../cstrike/dlls/bot/cs_bot.h:699 */
+inline void CCSBot::IncreaseHostageEscortCount(void)
+{
+ ++m_hostageEscortCount;
+}
+
+/* <5a0c4d> ../cstrike/dlls/bot/cs_bot.h:701 */
+inline void CCSBot::ResetWaitForHostagePatience(void)
+{
+ m_isWaitingForHostage = false;
+ m_inhibitWaitingForHostageTimer.Invalidate();
+}
+
+/* <5d402a> ../cstrike/dlls/bot/cs_bot.h:1055 */
+inline float CCSBot::GetFeetZ(void) const
+{
+ if (IsCrouching())
+ {
+ const Vector crouch = Vector(0, 0, -StepHeight);
+ return (pev->origin + crouch).z;
+ }
+ else
+ {
+ const Vector stand = Vector(0, 0, -HalfHumanHeight);
+ return (pev->origin + stand).z;
+ }
+}
+
+/* <5b2dd3> ../cstrike/dlls/bot/cs_bot.h:1063 */
+inline const Vector *CCSBot::GetNoisePosition(void) const
+{
+ if (m_noiseTimestamp > 0.0f)
+ return &m_noisePosition;
+
+ return NULL;
+}
+
+/* <519655> ../cstrike/dlls/bot/cs_bot.h:1071 */
+inline bool CCSBot::IsAwareOfEnemyDeath(void) const
+{
+ if (GetEnemyDeathTimestamp() == 0.0f)
+ return false;
+
+ if (m_enemy == NULL)
+ return true;
+
+ if (!m_enemy->IsAlive() && gpGlobals->time - GetEnemyDeathTimestamp() > (1.0f - GetProfile()->GetSkill()))
+ return true;
+
+ return false;
+}
+
+/* <568b12> ../cstrike/dlls/bot/cs_bot.h:1085 */
+inline bool CCSBot::IsNotMoving(void) const
+{
+ const float stillSpeed = 10.0f;
+ return pev->velocity.IsLengthLessThan(stillSpeed);
+}
+
+inline bool CCSBot::HasAnyAmmo(CBasePlayerWeapon *weapon) const
+{
+ return (weapon->m_iClip != 0 || m_rgAmmo[weapon->m_iPrimaryAmmoType] > 0);
+}
+
/* <2e8465> ../cstrike/dlls/bot/cs_bot.cpp:1004 */
class CollectRetreatSpotsFunctor
{
@@ -1234,14 +1676,19 @@ public:
// collect all the hiding spots in this area
const HidingSpotList *list = area->GetHidingSpotList();
- for (HidingSpotList::const_iterator iter = list->begin(); iter != list->end() && m_count < MAX_SPOTS; ++iter)
+ for (HidingSpotList::const_iterator iter = list->begin(); iter != list->end(); ++iter)
{
- const HidingSpot *spot = *iter;
+ const HidingSpot *spot = (*iter);
+
+ if (m_count >= MAX_SPOTS)
+ break;
// make sure hiding spot is in range
if (m_range > 0.0f)
+ {
if ((*spot->GetPosition() - m_me->pev->origin).IsLengthGreaterThan(m_range))
continue;
+ }
// if a Player is using this hiding spot, don't consider it
if (IsSpotOccupied(m_me, spot->GetPosition()))
@@ -1252,12 +1699,12 @@ public:
}
// don't select spot if an enemy can see it
- if (UTIL_IsVisibleToTeam(*spot->GetPosition() + Vector(0, 0, HalfHumanHeight), OtherTeam(m_me->m_iTeam )))
+ if (UTIL_IsVisibleToTeam(*spot->GetPosition() + Vector(0, 0, HalfHumanHeight), OtherTeam(m_me->m_iTeam)))
continue;
// don't select spot if it is closest to an enemy
CBasePlayer *owner = UTIL_GetClosestPlayer(spot->GetPosition());
- if (owner && m_me->m_iTeam != owner->m_iTeam)
+ if (owner != NULL && m_me->m_iTeam != owner->m_iTeam)
continue;
m_spot[ m_count++ ] = spot->GetPosition();
@@ -1269,7 +1716,6 @@ public:
return true;
}
-private:
CCSBot *m_me;
float m_range;
@@ -1286,11 +1732,23 @@ public:
FarthestHostage(const CCSBot *me)
{
m_me = me;
- m_farRange = -1.0;
+ m_farRange = -1.0f;
}
bool operator()(CHostage *hostage)
{
- if (hostage->pev->takedamage != DAMAGE_YES)
+ if (hostage->IsFollowing(m_me))
+ {
+ float range = (hostage->Center() - m_me->pev->origin).Length();
+
+ if (range > m_farRange)
+ {
+ m_farRange = range;
+ }
+ }
+
+ return true;
+
+ /*if (hostage->pev->takedamage != DAMAGE_YES)
return true;
if (hostage->m_improv != NULL)
@@ -1308,7 +1766,7 @@ public:
m_farRange = range;
}
- return true;
+ return true;*/
}
const CCSBot *m_me;
@@ -1316,6 +1774,8 @@ public:
};/* size: 8, cachelines: 1, members: 2 */
+// Functor used with NavAreaBuildPath()
+
/* <5a0af3> ../cstrike/dlls/bot/cs_bot.h:1114 */
class PathCost
{
@@ -1327,90 +1787,129 @@ public:
}
float operator()(CNavArea *area, CNavArea *fromArea, const CNavLadder *ladder)
{
- /*#define NAV_MESH_JUMP 0x0002
+ const float baseDangerFactor = 100.0f;
- float baseDangerFactor = 100.0f;
+ // respond to the danger modulated by our aggression (even super-aggressives pay SOME attention to danger)
float dangerFactor = (1.0f - (0.95f * m_bot->GetProfile()->GetAggression())) * baseDangerFactor;
if (fromArea == NULL)
{
if (m_route == FASTEST_ROUTE)
return 0.0f;
- return dangerFactor * area->GetDanger(m_bot->m_iTeam);
+
+ // first area in path, cost is just danger
+ return dangerFactor * area->GetDanger(m_bot->m_iTeam - 1);
}
- else if ((fromArea->GetAttributes() & NAV_MESH_JUMP) && (area->GetAttributes() & NAV_MESH_JUMP))
+ else if ((fromArea->GetAttributes() & NAV_JUMP) && (area->GetAttributes() & NAV_JUMP))
{
+ // cannot actually walk in jump areas - disallow moving from jump area to jump area
return -1.0f;
}
else
{
+ // compute distance from previous area to this area
float dist;
if (ladder)
{
+ // ladders are slow to use
const float ladderPenalty = 1.0f;
dist = ladderPenalty * ladder->m_length;
+ // if we are currently escorting hostages, avoid ladders (hostages are confused by them)
//if (m_bot->GetHostageEscortCount())
// dist *= 100.0f;
}
else
{
- dist = (area->GetCenter() - fromArea->GetCenter()).Length();
+ dist = (*area->GetCenter() - *fromArea->GetCenter()).Length();
}
+
+ // compute distance travelled along path so far
float cost = dist + fromArea->GetCostSoFar();
- if (cv_bot_zombie.value)
+
+ // zombies ignore all path penalties
+ if (cv_bot_zombie.value > 0.0f)
return cost;
- if (!area->IsUnderwater() && area->IsConnected(fromArea, NUM_DIRECTIONS) == false)
+ // add cost of "jump down" pain unless we're jumping into water
+ if (!area->IsConnected(fromArea, NUM_DIRECTIONS))
{
+ // this is a "jump down" (one way drop) transition - estimate damage we will take to traverse it
float fallDistance = -fromArea->ComputeHeightChange(area);
- if (ladder && ladder->m_bottom.z < fromArea->GetCenter().z && ladder->m_bottom.z > area->GetCenter().z)
- {
- fallDistance = ladder->m_bottom.z - area->GetCenter().z;
- }
+
+ // if it's a drop-down ladder, estimate height from the bottom of the ladder to the lower area
+ //if (ladder && ladder->m_bottom.z < fromArea->GetCenter()->z && ladder->m_bottom.z > area->GetCenter()->z)
+ //{
+ // fallDistance = ladder->m_bottom.z - area->GetCenter()->z;
+ //}
+
float fallDamage = m_bot->GetApproximateFallDamage(fallDistance);
+
if (fallDamage > 0.0f)
{
+ // if the fall would kill us, don't use it
const float deathFallMargin = 10.0f;
if (fallDamage + deathFallMargin >= m_bot->pev->health)
return -1.0f;
+
+ // if we need to get there in a hurry, ignore minor pain
const float painTolerance = 15.0f * m_bot->GetProfile()->GetAggression() + 10.0f;
if (m_route != FASTEST_ROUTE || fallDamage > painTolerance)
{
+ // cost is proportional to how much it hurts when we fall
+ // 10 points - not a big deal, 50 points - ouch!
cost += 100.0f * fallDamage * fallDamage;
}
}
}
- if (area->GetAttributes() & (NAV_MESH_CROUCH | NAV_MESH_WALK))
+
+ // if this is a "crouch" area, add penalty
+ if (area->GetAttributes() & NAV_CROUCH)
{
- float penalty = (m_route == FASTEST_ROUTE) ? 20.0f : 5.0f;
- cost += penalty * dist;
+ // these areas are very slow to move through
+ float_precision crouchPenalty = (m_route == FASTEST_ROUTE) ? 20.0f : 5.0f;
+
+ // avoid crouch areas if we are rescuing hostages
+ if (m_bot->GetHostageEscortCount())
+ {
+ crouchPenalty *= 3.0f;
+ }
+
+ cost += crouchPenalty * dist;
}
- if (area->GetAttributes() & NAV_MESH_JUMP)
+
+ // if this is a "jump" area, add penalty
+ if (area->GetAttributes() & NAV_JUMP)
{
+ // jumping can slow you down
+ //const float jumpPenalty = (m_route == FASTEST_ROUTE) ? 100.0f : 0.5f;
const float jumpPenalty = 1.0f;
cost += jumpPenalty * dist;
}
- if (area->GetAttributes() & NAV_MESH_AVOID)
- {
- const float avoidPenalty = 20.0f;
- cost += avoidPenalty * dist;
- }
+
if (m_route == SAFEST_ROUTE)
{
- cost += dist * dangerFactor * area->GetDanger(m_bot->GetTeamNumber());
+ // add in the danger of this path - danger is per unit length travelled
+ cost += dist * dangerFactor * area->GetDanger(m_bot->m_iTeam - 1);
}
+
if (!m_bot->IsAttacking())
{
+ // add in cost of teammates in the way
+ // approximate density of teammates based on area
float size = (area->GetSizeX() + area->GetSizeY()) / 2.0f;
+
+ // degenerate check
if (size >= 1.0f)
{
+ // cost is proportional to the density of teammates in this area
const float costPerFriendPerUnit = 50000.0f;
- cost += costPerFriendPerUnit * (float)area->GetPlayerCount(m_bot->GetTeamNumber()) / size;
+ cost += costPerFriendPerUnit * (float)area->GetPlayerCount(m_bot->m_iTeam, m_bot) / size;
}
}
+
return cost;
- }*/
+ }
return 0.0f;
}
@@ -1499,34 +1998,35 @@ public:
#ifdef HOOK_GAMEDLL
-//typedef bool (CCSBot::*IS_VISIBLE_VECTOR)(Vector *, bool);
-//typedef bool (CCSBot::*IS_VISIBLE_CBASEPLAYER)(CBasePlayer *, bool, unsigned char *);
+typedef bool (CCSBot::*CS_IS_VISIBLE_VECTOR)(const Vector *, bool) const;
+typedef bool (CCSBot::*CS_IS_VISIBLE_CBASEPLAYER)(CBasePlayer *, bool, unsigned char *) const;
+typedef const Vector *(FIND_SPOT_CSSBOT)(CCSBot *, float);
typedef void (CCSBot::*HIDE_NAV_AREA)(CNavArea *, float, float, bool);
typedef void (CCSBot::*HIDE_VECTOR)(const Vector *, float, bool);
typedef const CSGameState *(CCSBot::*GETGAMESTATE_CONST)(void) const;
typedef CSGameState *(CCSBot::*GETGAMESTATE_NOTCONST)(void);
-#endif // HOOK_GAMEDLL
-
-NOBODY void InstallBotControl(void);
-void Bot_ServerCommand(void);
-void Bot_RegisterCvars(void);
-NOBODY int GetBotFollowCount(CBasePlayer *leader);
-NOBODY const Vector *FindNearbyRetreatSpot(CCSBot *me, float maxRange);
-
-NOXREF void drawProgressMeter(float progress, char *title);
-NOXREF void startProgressMeter(const char *title);
-NOXREF void hideProgressMeter(void);
-
-bool isSniperRifle(CBasePlayerItem *item);
-float StayOnLadderLine(CCSBot *me, const CNavLadder *ladder);
-
+bool NavAreaBuildPath__PathCost__wrapper(CNavArea *startArea, CNavArea *goalArea, const Vector *goalPos, PathCost &costFunc, CNavArea **closestArea = NULL);
// refs
extern void (*pCCSBot__UpdateLookAngles)(void);
extern void (*pCCSBot__Update)(void);
-extern void (*pCCSBot__ResetValues)(void);
+
+#endif // HOOK_GAMEDLL
+
+void InstallBotControl(void);
+void Bot_ServerCommand(void);
+void Bot_RegisterCvars(void);
+int GetBotFollowCount(CBasePlayer *leader);
+const Vector *FindNearbyRetreatSpot(CCSBot *me, float maxRange);
+
+void drawProgressMeter(float progress, char *title);
+void startProgressMeter(const char *title);
+void hideProgressMeter(void);
+
+bool isSniperRifle(CBasePlayerItem *item);
+float StayOnLadderLine(CCSBot *me, const CNavLadder *ladder);
#endif // CS_BOT_H
diff --git a/regamedll/dlls/bot/cs_bot_chatter.cpp b/regamedll/dlls/bot/cs_bot_chatter.cpp
index 013794e4..f0ae192b 100644
--- a/regamedll/dlls/bot/cs_bot_chatter.cpp
+++ b/regamedll/dlls/bot/cs_bot_chatter.cpp
@@ -1,4 +1,5 @@
#include "precompiled.h"
+#include
/*
* Globals initialization
@@ -7,12 +8,19 @@
BotPhraseManager *TheBotPhrases = NULL;
CBaseEntity *g_pSelectedZombieSpawn = NULL;
+CountdownTimer BotChatterInterface::m_encourageTimer;
+IntervalTimer BotChatterInterface::m_radioSilenceInterval[ 2 ];
#else // HOOK_GAMEDLL
BotPhraseManager *TheBotPhrases;
CBaseEntity *g_pSelectedZombieSpawn;
+CountdownTimer IMPL_CLASS(BotChatterInterface, m_encourageTimer);
+IntervalTimer IMPL_CLASS(BotChatterInterface, m_radioSilenceInterval)[ 2 ];
+
+void (*pBotPhrase__Randomize)(void);
+
#endif // HOOK_GAMEDLL
/* <303469> ../cstrike/dlls/bot/cs_bot_chatter.cpp:32 */
@@ -46,58 +54,118 @@ const Vector *GetRandomSpotAtPlace(Place place)
return NULL;
}
+// Transmit meme to other bots
+
/* <303541> ../cstrike/dlls/bot/cs_bot_chatter.cpp:62 */
-NOBODY void BotMeme::Transmit(CCSBot *sender) const
+void BotMeme::Transmit(CCSBot *sender) const
{
-// {
-// int i; // 64
-// {
-// class CBasePlayer *player; // 66
-// class CCSBot *bot; // 93
-// FNullEnt(entvars_t *pev); // 71
-// }
-// }
+ for (int i = 1; i <= gpGlobals->maxClients; ++i)
+ {
+ CBasePlayer *player = static_cast(UTIL_PlayerByIndex(i));
+
+ if (player == NULL)
+ continue;
+
+ if (FNullEnt(player->pev))
+ continue;
+
+ if (FStrEq(STRING(player->pev->netname), ""))
+ continue;
+
+ // skip self
+ if (sender == player)
+ continue;
+
+ // ignore dead humans
+ if (!player->IsBot() && !player->IsAlive())
+ continue;
+
+ // ignore enemies, since we can't hear them talk
+ if (sender->m_iTeam != player->m_iTeam)
+ continue;
+
+ // if not a bot, fail the test
+ if (!player->IsBot())
+ continue;
+
+ CCSBot *bot = dynamic_cast(player);
+
+ if (!bot)
+ continue;
+
+ // allow bot to interpret our meme
+ Interpret(sender, bot);
+ }
}
+// A teammate called for help - respond
+
/* <301f03> ../cstrike/dlls/bot/cs_bot_chatter.cpp:104 */
-NOBODY void BotHelpMeme::Interpret(CCSBot *sender, CCSBot *receiver) const
+void BotHelpMeme::__MAKE_VHOOK(Interpret)(CCSBot *sender, CCSBot *receiver) const
{
-// {
-// float const maxHelpRange; // 106
-// }
+ const float maxHelpRange = 3000.0f; // 2000
+ receiver->RespondToHelpRequest(sender, m_place, maxHelpRange);
}
+// A teammate reported information about a bombsite
+
/* <306b4f> ../cstrike/dlls/bot/cs_bot_chatter.cpp:114 */
-NOBODY void BotBombsiteStatusMeme::Interpret(CCSBot *sender, CCSBot *receiver) const
+void BotBombsiteStatusMeme::__MAKE_VHOOK(Interpret)(CCSBot *sender, CCSBot *receiver) const
{
-// Interpret(const class BotBombsiteStatusMeme *const this,
-// class CCSBot *sender,
-// class CCSBot *receiver); // 114
+ // remember this bombsite's status
+ if (m_status == CLEAR)
+ receiver->GetGameState()->ClearBombsite(m_zoneIndex);
+ else
+ receiver->GetGameState()->MarkBombsiteAsPlanted(m_zoneIndex);
+
+ // if we were heading to the just-cleared bombsite, pick another one to search
+ // if our target bombsite wasn't cleared, will will continue going to it,
+ // because GetNextBombsiteToSearch() will return the same zone (since its not cleared)
+ // if the bomb was planted, we will head to that bombsite
+ if (receiver->GetTask() == CCSBot::FIND_TICKING_BOMB)
+ {
+ receiver->Idle();
+ receiver->GetChatter()->Affirmative();
+ }
}
+// A teammate reported information about the bomb
/* <306ab6> ../cstrike/dlls/bot/cs_bot_chatter.cpp:137 */
-NOBODY void BotBombStatusMeme::Interpret(CCSBot *sender, CCSBot *receiver) const
+void BotBombStatusMeme::__MAKE_VHOOK(Interpret)(CCSBot *sender, CCSBot *receiver) const
{
-// Interpret(const class BotBombStatusMeme *const this,
-// class CCSBot *sender,
-// class CCSBot *receiver); // 137
+ // update our gamestate based on teammate's report
+ switch (m_state)
+ {
+ case CSGameState::MOVING:
+ {
+ receiver->GetGameState()->UpdateBomber(&m_pos);
+
+ // if we are hunting and see no enemies, respond
+ if (!receiver->IsRogue() && receiver->IsHunting() && receiver->GetNearbyEnemyCount() == 0)
+ receiver->RespondToHelpRequest(sender, TheNavAreaGrid.GetPlace(&m_pos));
+
+ break;
+ }
+ case CSGameState::LOOSE:
+ {
+ receiver->GetGameState()->UpdateLooseBomb(&m_pos);
+
+ if (receiver->GetTask() == CCSBot::GUARD_BOMB_ZONE)
+ {
+ receiver->Idle();
+ receiver->GetChatter()->Affirmative();
+ }
+ break;
+ }
+ }
}
// A teammate has asked that we follow him
/* <302c87> ../cstrike/dlls/bot/cs_bot_chatter.cpp:167 */
-NOBODY void BotFollowMeme::Interpret(CCSBot *sender, CCSBot *receiver) const
+void BotFollowMeme::__MAKE_VHOOK(Interpret)(CCSBot *sender, CCSBot *receiver) const
{
-// {
-// class PathCost pathCost; // 178
-// float travelDistance; // 179
-// float const tooFar; // 185
-// }
-// Interpret(const class BotFollowMeme *const this,
-// class CCSBot *sender,
-// class CCSBot *receiver); // 167
-
if (receiver->IsRogue())
return;
@@ -121,57 +189,96 @@ NOBODY void BotFollowMeme::Interpret(CCSBot *sender, CCSBot *receiver) const
receiver->GetChatter()->Say("CoveringFriend");
}
+// A teammate has asked us to defend a place
+
/* <302759> ../cstrike/dlls/bot/cs_bot_chatter.cpp:200 */
-NOBODY void BotDefendHereMeme::Interpret(CCSBot *sender, CCSBot *receiver) const
+void BotDefendHereMeme::__MAKE_VHOOK(Interpret)(CCSBot *sender, CCSBot *receiver) const
{
-// {
-// Place place; // 209
-// {
-// const Vector *spot; // 213
-// }
-// }
+ if (receiver->IsRogue())
+ return;
+
+ // if we're busy, ignore
+ if (receiver->IsBusy())
+ return;
+
+ Place place = TheNavAreaGrid.GetPlace(&m_pos);
+ if (place != UNDEFINED_PLACE)
+ {
+ // pick a random hiding spot in this place
+ const Vector *spot = FindRandomHidingSpot(receiver, place, receiver->IsSniper());
+ if (spot != NULL)
+ {
+ receiver->SetTask(CCSBot::HOLD_POSITION);
+ receiver->Hide(spot);
+ return;
+ }
+ }
+
+ // hide nearby
+ receiver->SetTask(CCSBot::HOLD_POSITION);
+ receiver->Hide(TheNavAreaGrid.GetNearestNavArea(&m_pos));
+
+ // acknowledge
+ receiver->GetChatter()->Say("Affirmative");
}
+// A teammate has asked where the bomb is planted
+
/* <3082a5> ../cstrike/dlls/bot/cs_bot_chatter.cpp:234 */
-NOBODY void BotWhereBombMeme::Interpret(CCSBot *sender, CCSBot *receiver) const
+void BotWhereBombMeme::__MAKE_VHOOK(Interpret)(CCSBot *sender, CCSBot *receiver) const
{
-// {
-// int zone; // 236
-// }
+ int zone = receiver->GetGameState()->GetPlantedBombsite();
+
+ if (zone != CSGameState::UNKNOWN)
+ receiver->GetChatter()->FoundPlantedBomb(zone);
}
+// A teammate has asked us to report in
+
/* <30a56e> ../cstrike/dlls/bot/cs_bot_chatter.cpp:246 */
-NOBODY void BotRequestReportMeme::Interpret(CCSBot *sender, CCSBot *receiver) const
+void BotRequestReportMeme::__MAKE_VHOOK(Interpret)(CCSBot *sender, CCSBot *receiver) const
{
+ receiver->GetChatter()->ReportingIn();
}
+// A teammate told us all the hostages are gone
+
/* <3025b5> ../cstrike/dlls/bot/cs_bot_chatter.cpp:256 */
-NOBODY void BotAllHostagesGoneMeme::Interpret(CCSBot *sender, CCSBot *receiver) const
+void BotAllHostagesGoneMeme::__MAKE_VHOOK(Interpret)(CCSBot *sender, CCSBot *receiver) const
{
-// Say(// const char *phraseName,
-// float lifetime,
-// float delay); // 261
+ receiver->GetGameState()->AllHostagesGone();
+
+ // acknowledge
+ receiver->GetChatter()->Say("Affirmative");
}
+// A teammate told us a CT is talking to a hostage
+
/* <3029a9> ../cstrike/dlls/bot/cs_bot_chatter.cpp:269 */
-NOBODY void BotHostageBeingTakenMeme::Interpret(CCSBot *sender, CCSBot *receiver) const
+void BotHostageBeingTakenMeme::__MAKE_VHOOK(Interpret)(CCSBot *sender, CCSBot *receiver) const
{
-// HostageWasTaken(CSGameState *const this); // 271
-// Interpret(const class BotHostageBeingTakenMeme *const this,
-// class CCSBot *sender,
-// class CCSBot *receiver); // 269
+ receiver->GetGameState()->HostageWasTaken();
+
+ // if we're busy, ignore
+ if (receiver->IsBusy())
+ return;
+
+ receiver->Idle();
+
+ // acknowledge
+ receiver->GetChatter()->Say("Affirmative");
}
/* <303609> ../cstrike/dlls/bot/cs_bot_chatter.cpp:285 */
-NOBODY BotSpeakable::BotSpeakable(void)
+BotSpeakable::BotSpeakable(void)
{
m_phrase = NULL;
}
/* <303655> ../cstrike/dlls/bot/cs_bot_chatter.cpp:291 */
-NOBODY BotSpeakable::~BotSpeakable(void)
+BotSpeakable::~BotSpeakable(void)
{
- if (m_phrase)
+ if (m_phrase != NULL)
{
delete[] m_phrase;
m_phrase = NULL;
@@ -179,57 +286,56 @@ NOBODY BotSpeakable::~BotSpeakable(void)
}
/* <30ba3b> ../cstrike/dlls/bot/cs_bot_chatter.cpp:303 */
-NOBODY BotPhrase::BotPhrase(unsigned int id, bool isPlace)
+BotPhrase::BotPhrase(unsigned int id, bool isPlace)
{
-// vector(vector>*, std::allocator> *const this); // 303
-// vector(vector> *const this); // 303
-// ClearCriteria(const class BotPhrase *const this); // 309
+ m_name = NULL;
+ m_id = id;
+ m_isPlace = isPlace;
+ m_radioEvent = EVENT_INVALID;
+ m_isImportant = false;
+
+ ClearCriteria();
+
+ m_numVoiceBanks = 0;
+ InitVoiceBank(0);
}
/* <3036c2> ../cstrike/dlls/bot/cs_bot_chatter.cpp:314 */
-NOBODY BotPhrase::~BotPhrase(void)
+BotPhrase::~BotPhrase(void)
{
-// {
-// int bank; // 316
-// size(const class vector>*, std::allocator>*, std::allocator> *const this); // 318
-// ~BotSpeakable(BotSpeakable *const this,
-// int const __in_chrg); // 320
-// }
-// ~vector(vector> *const this,
-// int const __in_chrg); // 322
-// }
-// ~vector(vector> *const this,
-// int const __in_chrg); // 314
-// ~vector(vector> *const this,
-// int const __in_chrg); // 314
-// ~vector(vector>*, std::allocatorsize(); ++speakable)
+ {
+ delete (*m_voiceBank[bank])[speakable];
+ }
+ delete m_voiceBank[bank];
+ }
+
+ if (m_name != NULL)
+ delete [] m_name;
}
/* <30b837> ../cstrike/dlls/bot/cs_bot_chatter.cpp:326 */
-NOBODY void BotPhrase::InitVoiceBank(int bankIndex)
+void BotPhrase::InitVoiceBank(int bankIndex)
{
-// push_back(vector> *const this,
-// const value_type &__x); // 330
-// push_back(vector> *const this,
-// const value_type &__x); // 331
-// vector(vector> *const this); // 332
-// push_back(vector>*, std::allocator ../cstrike/dlls/bot/cs_bot_chatter.cpp:340 */
char *BotPhrase::GetSpeakable(int bankIndex, float *duration) const
{
if (bankIndex < 0 || bankIndex >= m_numVoiceBanks || m_count[bankIndex] == 0)
{
- if (duration)
+ if (duration != NULL)
*duration = 0.0f;
return NULL;
@@ -269,7 +375,7 @@ char *BotPhrase::GetSpeakable(int bankIndex, float *duration) const
// check if we exhausted all speakables
if (m_index[bankIndex] == start)
{
- if (duration)
+ if (duration != NULL)
*duration = 0.0f;
return NULL;
@@ -279,57 +385,48 @@ char *BotPhrase::GetSpeakable(int bankIndex, float *duration) const
return NULL;
}
-void (*pBotPhrase__Randomize)(void);
+// Randomly shuffle the speakable order
/* <30395a> ../cstrike/dlls/bot/cs_bot_chatter.cpp:395 */
-NOBODY void __declspec(naked) BotPhrase::Randomize(void)
+#ifdef HOOK_GAMEDLL
+void __declspec(naked) BotPhrase::Randomize(void)
{
+ // you can not hook this function, because it uses the rand() function
+ // which does not allow us to carry out tests because different results at the output.
__asm
{
jmp pBotPhrase__Randomize
}
-
-// UNTESTED
-//
-// for (unsigned int i = 0; i < m_voiceBank.size(); i++)
-// {
-// BotSpeakableVector *speakables = m_voiceBank[i];
-//
-//#ifdef HOOK_GAMEDLL
-// // TODO: temporary fix of std::vector padding
-// *(byte *)&speakables += 4;
-//#endif // HOOK_GAMEDLL
-//
-// BotSpeakable *firstElem = speakables->front();
-// int nSize = speakables->size();
-//
-// for (unsigned int index = 1; index < nSize; index++)
-// {
-// // TODO: check it, need hook std rand
-// int randIndex = (rand() % nSize);
-//
-// BotSpeakable *speakable = (*speakables)[ randIndex ];
-//
-// (*speakables)[ randIndex ] = (*speakables)[ index ];
-// (*speakables)[ index ] = speakable;
-// }
-// }
}
+#else
+void BotPhrase::Randomize(void)
+{
+ for (uint32 i = 0; i < m_voiceBank.size(); i++)
+ {
+ std::random_shuffle(m_voiceBank[i]->begin(), m_voiceBank[i]->end());
+ }
+}
+#endif // HOOK_GAMEDLL
/* <303b3f> ../cstrike/dlls/bot/cs_bot_chatter.cpp:409 */
-NOBODY BotPhraseManager::BotPhraseManager(void)
+BotPhraseManager::BotPhraseManager(void)
{
-// list(list> *const this); // 409
-// list(list> *const this); // 409
-// PlaceTimeInfo(PlaceTimeInfo *const this); // 409
+ for (int i = 0; i < MAX_PLACES_PER_MAP; ++i)
+ m_placeStatementHistory[i].timer.Invalidate();
+
+ m_placeCount = 0;
}
+// Invoked when map changes
+
/* <303c45> ../cstrike/dlls/bot/cs_bot_chatter.cpp:417 */
-NOBODY void BotPhraseManager::OnMapChange(void)
+void BotPhraseManager::OnMapChange(void)
{
m_placeCount = 0;
}
+// Invoked when the round resets
+
/* <303c70> ../cstrike/dlls/bot/cs_bot_chatter.cpp:425 */
void BotPhraseManager::OnRoundRestart(void)
{
@@ -349,84 +446,282 @@ void BotPhraseManager::OnRoundRestart(void)
}
}
+// Initialize phrase system from database file
+
/* <30c1fc> ../cstrike/dlls/bot/cs_bot_chatter.cpp:443 */
-NOBODY bool BotPhraseManager::Initialize(const char *filename, int bankIndex)
+bool BotPhraseManager::Initialize(const char *filename, int bankIndex)
{
-// {
-// bool isDefault; // 445
-// int phraseDataLength; // 446
-// char *phraseDataFile; // 447
-// char *phraseData; // 448
-// unsigned int nextID; // 459
-// int const RadioPathLen; // 461
-// char baseDir; // 462
-// char compositeFilename; // 463
-// {
-// char *token; // 474
-// {
-// bool isPlace; // 492
-// class BotPhrase *phrase; // 495
-// PlaceCriteria placeCriteria; // 533
-// CountCriteria countCriteria; // 534
-// enum GameEventType radioEvent; // 535
-// bool isImportant; // 536
-// {
-// class BotSpeakable *speak; // 635
-// BotSpeakableVector *speakables; // 657
-// operator[](vector>*, std::allocator> *const this,
-// const value_type &__x); // 658
-// operator[](vector> *const this,
-// size_type __n); // 660
-// NameToID(const class BotPhraseManager *const this,
-// const char *name); // 572
-// atoi(const char *__nptr); // 593
-// CloneString(const char *str); // 643
-// }
-// GetPlace(const class BotPhraseManager *const this,
-// const char *name); // 517
-// GetPhrase(const class BotPhraseManager *const this,
-// const char *name); // 521
-// BotPhrase(BotPhrase *const this,
-// unsigned int id,
-// bool isPlace); // 498
-// CloneString(const char *str); // 511
-// push_back(list> *const this,
-// const value_type &__x); // 671
-// push_back(list> *const this,
-// const value_type &__x); // 673
-// }
-// {
-// char *token; // 486
-// }
-// }
-// }
+ bool isDefault = (bankIndex == 0);
+ int phraseDataLength;
+ char *phraseDataFile = (char *)LOAD_FILE_FOR_ME((char *)filename, &phraseDataLength);
+
+ if (phraseDataFile == NULL)
+ {
+ if (UTIL_IsGame("czero"))
+ {
+ CONSOLE_ECHO("WARNING: Cannot access bot phrase database '%s'\n", filename);
+ }
+
+ return false;
+ }
+
+ char *phraseData = phraseDataFile;
+ unsigned int nextID = 1;
+
+ // wav filenames need to be shorter than this to go over the net anyway.
+ const int RadioPathLen = 128;
+ char baseDir[RadioPathLen] = "";
+ char compositeFilename[RadioPathLen];
+
+ // Parse the BotChatter.db into BotPhrase collections
+ while (true)
+ {
+ phraseData = MP_COM_Parse(phraseData);
+ if (!phraseData)
+ break;
+
+ char *token = MP_COM_GetToken();
+
+ if (!Q_stricmp(token, "BaseDir"))
+ {
+ // get name of this output device
+ phraseData = MP_COM_Parse(phraseData);
+ if (!phraseData)
+ {
+ CONSOLE_ECHO("Error parsing '%s' - expected identifier\n", filename);
+ FREE_FILE(phraseDataFile);
+ return false;
+ }
+
+ char *token = MP_COM_GetToken();
+ Q_strncpy(baseDir, token, RadioPathLen);
+ baseDir[RadioPathLen - 1] = '\0';
+ }
+ else if (!Q_stricmp(token, "Place") || !Q_stricmp(token, "Chatter"))
+ {
+ bool isPlace = (Q_stricmp(token, "Place") == 0);
+
+ // encountered a new phrase collection
+ BotPhrase *phrase = NULL;
+ if (isDefault)
+ {
+ phrase = new BotPhrase(nextID++, isPlace);
+ }
+
+ // get name of this phrase
+ phraseData = MP_COM_Parse(phraseData);
+ if (!phraseData)
+ {
+ CONSOLE_ECHO("Error parsing '%s' - expected identifier\n", filename);
+ FREE_FILE(phraseDataFile);
+ return false;
+ }
+
+ if (isDefault)
+ {
+ phrase->m_name = CloneString(MP_COM_GetToken());
+ }
+ // look up the existing phrase
+ else
+ {
+ if (isPlace)
+ {
+ phrase = const_cast(GetPlace(MP_COM_GetToken()));
+ }
+ else
+ {
+ phrase = const_cast(GetPhrase(MP_COM_GetToken()));
+ }
+
+ if (!phrase)
+ {
+ CONSOLE_ECHO("Error parsing '%s' - phrase '%s' is invalid\n", filename, MP_COM_GetToken());
+ FREE_FILE(phraseDataFile);
+ return false;
+ }
+ }
+
+ phrase->InitVoiceBank(bankIndex);
+
+ PlaceCriteria placeCriteria = ANY_PLACE;
+ CountCriteria countCriteria = UNDEFINED_COUNT;
+ GameEventType radioEvent = EVENT_INVALID;
+ bool isImportant = false;
+
+ // read attributes of this phrase
+ while (true)
+ {
+ // get next token
+ phraseData = MP_COM_Parse(phraseData);
+ if (!phraseData)
+ {
+ CONSOLE_ECHO("Error parsing %s - expected 'End'\n", filename);
+ FREE_FILE(phraseDataFile);
+ return false;
+ }
+
+ token = MP_COM_GetToken();
+
+ // check for Place criteria
+ if (!Q_stricmp(token, "Place"))
+ {
+ phraseData = MP_COM_Parse(phraseData);
+ if (!phraseData)
+ {
+ CONSOLE_ECHO("Error parsing %s - expected Place name\n", filename);
+ FREE_FILE(phraseDataFile);
+ return false;
+ }
+
+ token = MP_COM_GetToken();
+
+ // update place criteria for subsequent speak lines
+ // NOTE: this assumes places must be first in the chatter database
+
+ // check for special identifiers
+ if (!Q_stricmp("ANY", token))
+ placeCriteria = ANY_PLACE;
+ else if (!Q_stricmp("UNDEFINED", token))
+ placeCriteria = UNDEFINED_PLACE;
+ else
+ placeCriteria = TheBotPhrases->NameToID(token);
+
+ continue;
+ }
+
+ // check for Count criteria
+ if (!Q_stricmp(token, "Count"))
+ {
+ phraseData = MP_COM_Parse(phraseData);
+ if (!phraseData)
+ {
+ CONSOLE_ECHO("Error parsing %s - expected Count value\n", filename);
+ FREE_FILE(phraseDataFile);
+ return false;
+ }
+
+ token = MP_COM_GetToken();
+
+ // update count criteria for subsequent speak lines
+ if (!Q_stricmp(token, "Many"))
+ countCriteria = COUNT_MANY;
+ else
+ countCriteria = Q_atoi(token);
+
+ continue;
+ }
+
+ // check for radio equivalent
+ if (!Q_stricmp(token, "Radio"))
+ {
+ phraseData = MP_COM_Parse(phraseData);
+ if (!phraseData)
+ {
+ CONSOLE_ECHO("Error parsing %s - expected radio event\n", filename);
+ FREE_FILE(phraseDataFile);
+ return false;
+ }
+ token = MP_COM_GetToken();
+
+ GameEventType event = NameToGameEvent(token);
+ if (event <= EVENT_START_RADIO_1 || event >= EVENT_END_RADIO)
+ {
+ CONSOLE_ECHO("Error parsing %s - invalid radio event '%s'\n", filename, token);
+ FREE_FILE(phraseDataFile);
+ return false;
+ }
+
+ radioEvent = event;
+
+ continue;
+ }
+
+ // check for "important" flag
+ if (!Q_stricmp(token, "Important"))
+ {
+ isImportant = true;
+ continue;
+ }
+
+ // check for End delimiter
+ if (!Q_stricmp(token, "End"))
+ break;
+
+ // found a phrase - add it to the collection
+ BotSpeakable *speak = new BotSpeakable;
+ if (baseDir[0])
+ {
+ Q_snprintf(compositeFilename, RadioPathLen, "%s%s", baseDir, token);
+ speak->m_phrase = CloneString(compositeFilename);
+ }
+ else
+ {
+ speak->m_phrase = CloneString(token);
+ }
+
+ speak->m_place = placeCriteria;
+ speak->m_count = countCriteria;
+
+ Q_snprintf(compositeFilename, RadioPathLen, "sound\\%s", speak->m_phrase);
+ speak->m_duration = (double)GET_APPROX_WAVE_PLAY_LEN(compositeFilename) / 1000.0f;
+
+ if (speak->m_duration <= 0.0f)
+ {
+ CONSOLE_ECHO("Warning: Couldn't get duration of phrase '%s'\n", compositeFilename);
+ speak->m_duration = 1.0f;
+ }
+
+ BotSpeakableVector *speakables = phrase->m_voiceBank[ bankIndex ];
+ speakables->push_back(speak);
+
+ ++phrase->m_count[ bankIndex ];
+ }
+
+ if (isDefault)
+ {
+ phrase->m_radioEvent = radioEvent;
+ phrase->m_isImportant = isImportant;
+ }
+
+ // add phrase collection to the appropriate master list
+ if (isPlace)
+ m_placeList.push_back(phrase);
+ else
+ m_list.push_back(phrase);
+ }
+ }
+
+ FREE_FILE(phraseDataFile);
+
+ return true;
}
/* <30409e> ../cstrike/dlls/bot/cs_bot_chatter.cpp:682 */
-NOBODY BotPhraseManager::~BotPhraseManager(void)
+BotPhraseManager::~BotPhraseManager(void)
{
-// ~list(list>::~BotPhraseManager(// int const __in_chrg); // 682
-// {
-// iterator iter; // 684
-// {
-// class BotPhrase *phrase; // 689
-// }
-// operator++(_List_iterator *const this); // 687
-// end(list> *const this); // 694
-// {
-// class BotPhrase *phrase; // 696
-// }
-// operator++(_List_iterator *const this); // 694
-// clear(list> *const this); // 701
-// clear(list> *const this); // 702
-// }
+ BotPhraseList::iterator iter;
+ for (iter = m_list.begin(); iter != m_list.end(); ++iter)
+ {
+ const BotPhrase *phrase = *iter;
+
+ if (phrase != NULL)
+ {
+ delete phrase;
+ }
+ }
+
+ for (iter = m_placeList.begin(); iter != m_placeList.end(); ++iter)
+ {
+ const BotPhrase *phrase = *iter;
+
+ if (phrase != NULL)
+ {
+ delete phrase;
+ }
+ }
+
+ m_list.clear();
+ m_placeList.clear();
}
/* <3043ec> ../cstrike/dlls/bot/cs_bot_chatter.cpp:708 */
@@ -473,8 +768,10 @@ const char *BotPhraseManager::IDToName(Place id) const
return NULL;
}
+// Given a name, return the associated phrase collection
+
/* <304597> ../cstrike/dlls/bot/cs_bot_chatter.cpp:758 */
-NOBODY const BotPhrase *BotPhraseManager::GetPhrase(const char *name) const
+const BotPhrase *BotPhraseManager::GetPhrase(const char *name) const
{
for (BotPhraseList::const_iterator iter = m_list.begin(); iter != m_list.end(); ++iter)
{
@@ -483,11 +780,34 @@ NOBODY const BotPhrase *BotPhraseManager::GetPhrase(const char *name) const
if (!Q_stricmp(phrase->m_name, name))
return phrase;
}
+
+ //CONSOLE_ECHO("GetPhrase: ERROR - Invalid phrase '%s'\n", name);
return NULL;
}
+// Given an id, return the associated phrase collection
+// TODO: Store phrases in a vector to make this fast
+
+/*
+const BotPhrase *BotPhraseManager::GetPhrase(unsigned int id) const
+{
+ for (BotPhraseList::const_iterator iter = m_list.begin(); iter != m_list.end(); ++iter)
+ {
+ const BotPhrase *phrase = *iter;
+
+ if (phrase->m_id == id)
+ return phrase;
+ }
+
+ CONSOLE_ECHO("GetPhrase: ERROR - Invalid phrase id #%d\n", id);
+ return NULL;
+}
+*/
+
+// Given a name, return the associated Place phrase collection
+
/* <304654> ../cstrike/dlls/bot/cs_bot_chatter.cpp:793 */
-NOBODY const BotPhrase *BotPhraseManager::GetPlace(const char *name) const
+const BotPhrase *BotPhraseManager::GetPlace(const char *name) const
{
if (name == NULL)
return NULL;
@@ -503,8 +823,10 @@ NOBODY const BotPhrase *BotPhraseManager::GetPlace(const char *name) const
return NULL;
}
+// Given a place, return the associated Place phrase collection
+
/* <3046eb> ../cstrike/dlls/bot/cs_bot_chatter.cpp:811 */
-NOBODY const BotPhrase *BotPhraseManager::GetPlace(PlaceCriteria place) const
+const BotPhrase *BotPhraseManager::GetPlace(PlaceCriteria place) const
{
if (place == UNDEFINED_PLACE)
return NULL;
@@ -521,1060 +843,1621 @@ NOBODY const BotPhrase *BotPhraseManager::GetPlace(PlaceCriteria place) const
}
/* <30477e> ../cstrike/dlls/bot/cs_bot_chatter.cpp:830 */
-NOBODY BotStatement::BotStatement(BotChatterInterface *chatter, BotStatementType type, float expireDuration)
+BotStatement::BotStatement(BotChatterInterface *chatter, BotStatementType type, float expireDuration)
{
+ m_chatter = chatter;
+
+ m_prev = m_next = NULL;
+ m_timestamp = gpGlobals->time;
+ m_speakTimestamp = 0.0f;
+
+ m_type = type;
+ m_subject = UNDEFINED_SUBJECT;
+ m_place = UNDEFINED_PLACE;
+ m_meme = NULL;
+
+ m_startTime = gpGlobals->time;
+ m_expireTime = gpGlobals->time + expireDuration;
+ m_isSpeaking = false;
+
+ m_nextTime = 0.0f;
+ m_index = -1;
+ m_count = 0;
+
+ m_conditionCount = 0;
}
/* <3047bd> ../cstrike/dlls/bot/cs_bot_chatter.cpp:855 */
-NOBODY BotStatement::~BotStatement(void)
+BotStatement::~BotStatement(void)
{
+ if (m_meme != NULL)
+ {
+ delete m_meme;
+ }
}
/* <3047e0> ../cstrike/dlls/bot/cs_bot_chatter.cpp:863 */
-NOBODY CCSBot *BotStatement::GetOwner(void) const
+CCSBot *BotStatement::GetOwner(void) const
{
-
+ return m_chatter->GetOwner();
}
+// Attach a meme to this statement, to be transmitted to other friendly bots when spoken
+
/* <304803> ../cstrike/dlls/bot/cs_bot_chatter.cpp:872 */
-NOBODY void BotStatement::AttachMeme(BotMeme *meme)
+void BotStatement::AttachMeme(BotMeme *meme)
{
+ m_meme = meme;
}
+// Add a conditions that must be true for the statement to be spoken
+
/* <30482f> ../cstrike/dlls/bot/cs_bot_chatter.cpp:881 */
-NOBODY void BotStatement::AddCondition(ConditionType condition)
+void BotStatement::AddCondition(ConditionType condition)
{
+ if (m_conditionCount < MAX_BOT_CONDITIONS)
+ m_condition[ m_conditionCount++ ] = condition;
}
+// Return true if this statement is "important" and not personality chatter
+
/* <30485b> ../cstrike/dlls/bot/cs_bot_chatter.cpp:891 */
-NOBODY bool BotStatement::IsImportant(void) const
+bool BotStatement::IsImportant(void) const
{
-// {
-// int i; // 894
-// }
+ // if a statement contains any important phrases, it is important
+ for (int i = 0; i < m_count; ++i)
+ {
+ if (m_statement[i].isPhrase && m_statement[i].phrase->IsImportant())
+ return true;
+
+ // hack for now - phrases with enemy counts are important
+ if (!m_statement[i].isPhrase && m_statement[i].context == BotStatement::CURRENT_ENEMY_COUNT)
+ return true;
+ }
+
+ return false;
}
+// Verify all attached conditions
+
/* <3048bc> ../cstrike/dlls/bot/cs_bot_chatter.cpp:911 */
-NOBODY bool BotStatement::IsValid(void) const
+bool BotStatement::IsValid(void) const
{
-// {
-// int i; // 913
-// GetOwner(const class BotStatement *const this); // 919
-// GetOwner(const class BotStatement *const this); // 935
-// }
+ for (int i = 0; i < m_conditionCount; ++i)
+ {
+ switch (m_condition[i])
+ {
+ case IS_IN_COMBAT:
+ {
+ if (!GetOwner()->IsAttacking())
+ return false;
+ break;
+ }
+ /*case RADIO_SILENCE:
+ {
+ if (GetOwner()->GetChatter()->GetRadioSilenceDuration() < 10.0f)
+ return false;
+ break;
+ }*/
+ case ENEMIES_REMAINING:
+ {
+ if (GetOwner()->GetEnemiesRemaining() == 0)
+ return false;
+ break;
+ }
+ }
+ }
+
+ return true;
}
+// Return true if this statement is essentially the same as the given one
+
/* <30492d> ../cstrike/dlls/bot/cs_bot_chatter.cpp:950 */
-NOBODY bool BotStatement::IsRedundant(const BotStatement *say) const
+bool BotStatement::IsRedundant(const BotStatement *say) const
{
+ // special cases
+ if (GetType() == REPORT_MY_PLAN ||
+ GetType() == REPORT_REQUEST_HELP ||
+ GetType() == REPORT_CRITICAL_EVENT ||
+ GetType() == REPORT_ACKNOWLEDGE)
+ return false;
+
+ // check if topics are different
+ if (say->GetType() != GetType())
+ return false;
+
+ if (!say->HasPlace() && !HasPlace() && !say->HasSubject() && !HasSubject())
+ {
+ // neither has place or subject, so they are the same
+ return true;
+ }
+
+ // check if subject matter is the same
+ if (say->HasPlace() && HasPlace() && say->GetPlace() == GetPlace())
+ {
+ // talking about the same place
+ return true;
+ }
+
+ if (say->HasSubject() && HasSubject() && say->GetSubject() == GetSubject())
+ {
+ // talking about the same player
+ return true;
+ }
+
+ return false;
}
+// Return true if this statement is no longer appropriate to say
+
/* <304977> ../cstrike/dlls/bot/cs_bot_chatter.cpp:990 */
-NOBODY bool BotStatement::IsObsolete(void) const
+bool BotStatement::IsObsolete(void) const
{
-// GetOwner(const class BotStatement *const this); // 993
+ // if the round is over, the only things we should say are emotes
+ if (GetOwner()->GetGameState()->IsRoundOver())
+ {
+ if (m_type != REPORT_EMOTE)
+ return true;
+ }
+
+#if 0
+ // If we're wanting to say "I lost him" but we've spotted another enemy,
+ // we no longer need to report losing someone.
+ if (GetOwner()->GetChatter()->SeesAtLeastOneEnemy() && m_type == REPORT_ENEMY_LOST)
+ {
+ return true;
+ }
+#endif
+
+ // check if statement lifetime has expired
+ return (gpGlobals->time > m_expireTime);
}
+// Possibly change what were going to say base on what teammate is saying
+
/* <3049b6> ../cstrike/dlls/bot/cs_bot_chatter.cpp:1008 */
-NOBODY void BotStatement::Convert(const class BotStatement *say)
+void BotStatement::Convert(const BotStatement *say)
{
-// {
-// const class BotPhrase *meToo; // 1012
-// GetPhrase(const class BotPhraseManager *const this,
-// const char *name); // 1012
-// }
+ if (GetType() == REPORT_MY_PLAN && say->GetType() == REPORT_MY_PLAN)
+ {
+ static const BotPhrase *meToo = TheBotPhrases->GetPhrase("AgreeWithPlan");
+
+ // don't reconvert
+ if (m_statement[0].phrase == meToo)
+ return;
+
+ // if our plans are the same, change our statement to "me too"
+ if (m_statement[0].phrase == say->m_statement[0].phrase)
+ {
+ if (m_place == say->m_place)
+ {
+ // same plan at the same place - convert to "me too"
+ m_statement[0].phrase = meToo;
+ m_startTime = gpGlobals->time + RANDOM_FLOAT(0.5f, 1.0f);
+ }
+ else
+ {
+ // same plan at different place - wait a bit to allow others to respond "me too"
+ m_startTime = gpGlobals->time + RANDOM_FLOAT(3.0f, 4.0f);
+ }
+ }
+ }
}
/* <304a7c> ../cstrike/dlls/bot/cs_bot_chatter.cpp:1037 */
-NOBODY void BotStatement::AppendPhrase(const class BotPhrase *phrase)
+void BotStatement::AppendPhrase(const BotPhrase *phrase)
{
-// AppendPhrase(BotStatement *const this,
-// const class BotPhrase *phrase); // 1037
+ if (phrase == NULL)
+ return;
+
+ if (m_count < MAX_BOT_PHRASES)
+ {
+ m_statement[ m_count ].isPhrase = true;
+ m_statement[ m_count++ ].phrase = phrase;
+ }
}
+// Special phrases that depend on the context
+
/* <304acf> ../cstrike/dlls/bot/cs_bot_chatter.cpp:1052 */
-NOBODY void BotStatement::AppendPhrase(ContextType contextPhrase)
+void BotStatement::AppendPhrase(ContextType contextPhrase)
{
-// AppendPhrase(BotStatement *const this,
-// enum ContextType contextPhrase); // 1052
+ if (m_count < MAX_BOT_PHRASES)
+ {
+ m_statement[ m_count ].isPhrase = false;
+ m_statement[ m_count++ ].context = contextPhrase;
+ }
}
+// Say our statement
+// m_index refers to the phrase currently being spoken, or -1 if we havent started yet
+
/* <304b22> ../cstrike/dlls/bot/cs_bot_chatter.cpp:1065 */
-NOBODY bool BotStatement::Update(void)
+bool BotStatement::Update(void)
{
-// {
-// class CCSBot *me; // 1067
-// GetOwner(const class BotStatement *const this); // 1067
-// {
-// float const reportTime; // 1083
-// GetNearbyEnemyCount(const class CCSBot *const this); // 1084
-// }
-// {
-// float duration; // 1105
-// const class BotPhrase *phrase; // 1106
-// {
-// const char *const speak; // 1138
-// int enemyCount; // 1143
-// GetPhrase(const class BotPhraseManager *const this,
-// const char *name); // 1152
-// }
-// {
-// int enemyCount; // 1120
-// GetNearbyEnemyCount(const class CCSBot *const this); // 1120
-// GetNearbyFriendCount(const class CCSBot *const this); // 1123
-// GetPhrase(const class BotPhraseManager *const this,
-// const char *name); // 1130
-// SetCountCriteria(const class BotPhrase *const this,
-// CountCriteria count); // 1131
-// GetPhrase(const class BotPhraseManager *const this,
-// const char *name); // 1125
-// BotHelpMeme(BotHelpMeme *const this,
-// Place place); // 1126
-// AttachMeme(BotStatement *const this,
-// class BotMeme *meme); // 1126
-// }
-// {
-// float const gap; // 1249
-// GetVerbosity(const class BotChatterInterface *const this); // 1181
-// {
-// enum GameEventType radioEvent;// 1183
-// ResetRadioSilenceDuration(BotChatterInterface *const this); // 1192
-// }
-// {
-// const char *filename; // 1202
-// bool sayIt; // 1205
-// {
-// enum GameEventType radioEvent; // 1226
-// ResetRadioSilenceDuration(BotChatterInterface *const this); // 1236
-// }
-// ResetRadioSilenceDuration(BotChatterInterface *const this); // 1243
-// SetPlaceCriteria(const class BotPhrase *const this,
-// PlaceCriteria place); // 1200
-// GetSpeakable(const class BotPhrase *const this,
-// int bankIndex,
-// float *duration); // 1202
-// {
-// float timeSince; // 1210
-// float const minRepeatTime; // 1211
-// GetPlaceStatementInterval(const class BotPhraseManager *const this,
-// Place place); // 1210
-// ResetPlaceStatementInterval(BotPhraseManager *const this,
-// Place place); // 1218
-// }
-// }
-// }
-// }
-// }
+ CCSBot *me = GetOwner();
+
+ // if all of our teammates are dead, the only non-redundant statements are emotes
+ if (me->GetFriendsRemaining() == 0 && GetType() != REPORT_EMOTE)
+ return false;
+
+ if (!m_isSpeaking)
+ {
+ m_isSpeaking = true;
+ m_speakTimestamp = gpGlobals->time;
+ }
+
+ // special case - context dependent delay
+ if (m_index >= 0 && m_statement[ m_index ].context == ACCUMULATE_ENEMIES_DELAY)
+ {
+ // report if we see a lot of enemies, or if enough time has passed
+ const float reportTime = 2.0f;
+ if (me->GetNearbyEnemyCount() > 3 || gpGlobals->time - m_speakTimestamp > reportTime)
+ {
+ // enough enemies have accumulated to expire this delay
+ m_nextTime = 0.0f;
+ }
+ }
+
+ if (gpGlobals->time > m_nextTime)
+ {
+ // check for end of statement
+ if (++m_index == m_count)
+ {
+ // transmit any memes carried in this statement to our teammates
+ if (m_meme != NULL)
+ {
+ m_meme->Transmit(me);
+ }
+
+ return false;
+ }
+
+ // start next part of statement
+ float duration = 0.0f;
+ const BotPhrase *phrase = NULL;
+
+ if (m_statement[ m_index ].isPhrase)
+ {
+ // normal phrase
+ phrase = m_statement[ m_index ].phrase;
+ }
+ else
+ {
+ // context-dependant phrase
+ switch (m_statement[ m_index ].context)
+ {
+ case CURRENT_ENEMY_COUNT:
+ {
+ int enemyCount = me->GetNearbyEnemyCount();
+
+ // if we are outnumbered, ask for help
+ if (enemyCount - 1 > me->GetNearbyFriendCount())
+ {
+ phrase = TheBotPhrases->GetPhrase("Help");
+ AttachMeme(new BotHelpMeme());
+ }
+ else if (enemyCount > 1)
+ {
+ phrase = TheBotPhrases->GetPhrase("EnemySpotted");
+ phrase->SetCountCriteria(enemyCount);
+ }
+ break;
+ }
+ case REMAINING_ENEMY_COUNT:
+ {
+ static const char *speak[] =
+ {
+ "NoEnemiesLeft", "OneEnemyLeft", "TwoEnemiesLeft", "ThreeEnemiesLeft"
+ };
+
+ int enemyCount = me->GetEnemiesRemaining();
+
+ // dont report if there are lots of enemies left
+ if (enemyCount < 0 || enemyCount > 3)
+ {
+ phrase = NULL;
+ }
+ else
+ {
+ phrase = TheBotPhrases->GetPhrase(speak[ enemyCount ]);
+ }
+ break;
+ }
+ case SHORT_DELAY:
+ {
+ m_nextTime = gpGlobals->time + RANDOM_FLOAT(0.1f, 0.5f);
+ return true;
+ }
+ case LONG_DELAY:
+ {
+ m_nextTime = gpGlobals->time + RANDOM_FLOAT(1.0f, 2.0f);
+ return true;
+ }
+ case ACCUMULATE_ENEMIES_DELAY:
+ {
+ // wait until test becomes true
+ m_nextTime = 99999999.9f;
+ return true;
+ }
+ }
+ }
+
+ if (phrase != NULL)
+ {
+ // if chatter system is in "standard radio" mode, send the equivalent radio command
+ if (me->GetChatter()->GetVerbosity() == BotChatterInterface::RADIO)
+ {
+ GameEventType radioEvent = phrase->GetRadioEquivalent();
+ if (radioEvent == EVENT_INVALID)
+ {
+ // skip directly to the next phrase
+ m_nextTime = 0.0f;
+ }
+ else
+ {
+ // use the standard radio
+ me->GetChatter()->ResetRadioSilenceDuration();
+ me->SendRadioMessage(radioEvent);
+ duration = 2.0f;
+ }
+ }
+ else
+ {
+ // set place criteria
+ phrase->SetPlaceCriteria(m_place);
+
+ const char *filename = phrase->GetSpeakable(me->GetProfile()->GetVoiceBank(), &duration);
+ // CONSOLE_ECHO("%s: Radio('%s')\n", STRING(me->pev->netname), filename);
+
+ bool sayIt = true;
+ if (phrase->IsPlace())
+ {
+ // don't repeat the place if someone just mentioned it not too long ago
+ float timeSince = TheBotPhrases->GetPlaceStatementInterval(phrase->GetID());
+ const float minRepeatTime = 20.0f;
+
+ if (timeSince < minRepeatTime)
+ {
+ sayIt = false;
+ }
+ else
+ {
+ TheBotPhrases->ResetPlaceStatementInterval(phrase->GetID());
+ }
+ }
+
+ if (sayIt)
+ {
+ if (filename == NULL)
+ {
+ GameEventType radioEvent = phrase->GetRadioEquivalent();
+ if (radioEvent == EVENT_INVALID)
+ {
+ // skip directly to the next phrase
+ m_nextTime = 0.0f;
+ }
+ else
+ {
+ me->SendRadioMessage(radioEvent);
+ me->GetChatter()->ResetRadioSilenceDuration();
+ duration = 2.0f;
+ }
+ }
+ else
+ {
+ me->Radio(filename, NULL, me->GetProfile()->GetVoicePitch(), false);
+ me->GetChatter()->ResetRadioSilenceDuration();
+ me->StartVoiceFeedback(duration + 1.0f);
+ }
+ }
+ }
+
+ const float gap = 0.1f;
+ m_nextTime = gpGlobals->time + duration + gap;
+ }
+ else
+ {
+ // skip directly to the next phrase
+ m_nextTime = 0.0f;
+ }
+ }
+
+ return true;
}
+// If this statement refers to a specific place, return that place
+// Places can be implicit in the statement, or explicitly defined
+
/* <2fee36> ../cstrike/dlls/bot/cs_bot_chatter.cpp:1266 */
-NOBODY Place BotStatement::GetPlace(void) const
+Place BotStatement::GetPlace(void) const
{
-// {
-// int i; // 1273
-// }
+ // return any explicitly set place if we have one
+ if (m_place != UNDEFINED_PLACE)
+ return m_place;
+
+ // look for an implicit place in our statement
+ for (int i = 0; i < m_count; ++i)
+ {
+ if (m_statement[i].isPhrase && m_statement[i].phrase->IsPlace())
+ return m_statement[i].phrase->GetID();
+ }
+
+ return 0;
}
+// Return true if this statement has an associated count
+
/* <305289> ../cstrike/dlls/bot/cs_bot_chatter.cpp:1283 */
-NOBODY bool BotStatement::HasCount(void) const
+bool BotStatement::HasCount(void) const
{
-// {
-// int i; // 1285
-// }
+ for (int i = 0; i < m_count; ++i)
+ {
+ if (!m_statement[i].isPhrase && m_statement[i].context == CURRENT_ENEMY_COUNT)
+ return true;
+ }
+
+ return false;
}
+enum PitchHack { P_HI, P_NORMAL, P_LOW };
+
+static int nextPitch = P_HI;
+
/* <305543> ../cstrike/dlls/bot/cs_bot_chatter.cpp:1308 */
-NOBODY BotChatterInterface::BotChatterInterface(CCSBot *me)
+BotChatterInterface::BotChatterInterface(CCSBot *me)
{
-// IntervalTimer(IntervalTimer *const this); // 1308
-// IntervalTimer(IntervalTimer *const this); // 1308
-// IntervalTimer(IntervalTimer *const this); // 1308
-// IntervalTimer(IntervalTimer *const this); // 1308
-// CountdownTimer(CountdownTimer *const this); // 1308
-// CountdownTimer(CountdownTimer *const this); // 1308
-// CountdownTimer(CountdownTimer *const this); // 1308
+ m_me = me;
+ m_statementList = NULL;
+
+ switch (nextPitch)
+ {
+ case P_HI:
+ m_pitch = RANDOM_LONG(105, 110);
+ break;
+ case P_NORMAL:
+ m_pitch = RANDOM_LONG(95, 105);
+ break;
+ case P_LOW:
+ m_pitch = RANDOM_LONG(85, 95);
+ break;
+ }
+
+ nextPitch = (nextPitch + 1) % 3;
+ Reset();
}
/* <305307> ../cstrike/dlls/bot/cs_bot_chatter.cpp:1334 */
-NOBODY BotChatterInterface::~BotChatterInterface(void)
+BotChatterInterface::~BotChatterInterface(void)
{
-// {
-// class BotStatement *msg; // 1337
-// ~BotStatement(BotStatement *const this,
-// int const __in_chrg); // 1339
-// }
+ // free pending statements
+ BotStatement *next;
+ for (BotStatement *msg = m_statementList; msg != NULL; msg = next)
+ {
+ next = msg->m_next;
+ delete msg;
+ }
}
+// Reset to initial state
+
/* <305386> ../cstrike/dlls/bot/cs_bot_chatter.cpp:1347 */
-NOBODY void BotChatterInterface::Reset(void)
+void BotChatterInterface::Reset(void)
{
-// {
-// class BotStatement *msg; // 1349
-// class BotStatement *nextMsg; // 1349
-// RemoveStatement(BotChatterInterface *const this,
-// class BotStatement *statement); // 1357
-// ResetRadioSilenceDuration(BotChatterInterface *const this); // 1365
-// Invalidate(CountdownTimer *const this); // 1373
-// Invalidate(IntervalTimer *const this); // 1367
-// Invalidate(IntervalTimer *const this); // 1368
-// Invalidate(CountdownTimer *const this); // 1369
-// Invalidate(CountdownTimer *const this); // 1370
-// Invalidate(IntervalTimer *const this); // 1371
-// Invalidate(IntervalTimer *const this); // 1372
-// Invalidate(CountdownTimer *const this); // 1374
-// }
+ BotStatement *msg, *nextMsg;
+
+ // removing pending statements - except for those about the round results
+ for (msg = m_statementList; msg; msg = nextMsg)
+ {
+ nextMsg = msg->m_next;
+
+ if (msg->GetType() != REPORT_ROUND_END)
+ RemoveStatement(msg);
+ }
+
+ m_seeAtLeastOneEnemy = false;
+ m_timeWhenSawFirstEnemy = 0.0f;
+ m_reportedEnemies = false;
+ m_requestedBombLocation = false;
+
+ ResetRadioSilenceDuration();
+
+ m_needBackupInterval.Invalidate();
+ m_spottedBomberInterval.Invalidate();
+ m_spottedLooseBombTimer.Invalidate();
+ m_heardNoiseTimer.Invalidate();
+ m_scaredInterval.Invalidate();
+ m_planInterval.Invalidate();
+ IMPL(m_encourageTimer).Invalidate();
+ m_escortingHostageTimer.Invalidate();
}
+// Register a statement for speaking
+
/* <305661> ../cstrike/dlls/bot/cs_bot_chatter.cpp:1381 */
-NOBODY void BotChatterInterface::AddStatement(BotStatement *statement, bool mustAdd)
+void BotChatterInterface::AddStatement(BotStatement *statement, bool mustAdd)
{
-// {
-// class BotStatement *s; // 1403
-// class BotStatement *earlier; // 1428
-// GetVerbosity(const class BotChatterInterface *const this); // 1384
-// IsImportant(const class BotStatement *const this); // 1388
-// }
+ // don't add statements if bot chatter is shut off
+ if (GetVerbosity() == OFF)
+ {
+ delete statement;
+ return;
+ }
+
+ // if we only want mission-critical radio chatter, ignore non-important phrases
+ if (GetVerbosity() == MINIMAL && !statement->IsImportant())
+ {
+ delete statement;
+ return;
+ }
+
+ // don't add statements if we're dead
+ if (!m_me->IsAlive() && !mustAdd)
+ {
+ delete statement;
+ return;
+ }
+
+ // don't add empty statements
+ if (statement->m_count == 0)
+ {
+ delete statement;
+ return;
+ }
+
+ // don't add statements that are redundant with something we're already waiting to say
+ BotStatement *s;
+ for (s = m_statementList; s != NULL; s = s->m_next)
+ {
+ if (statement->IsRedundant(s))
+ {
+ m_me->PrintIfWatched("I tried to say something I'm already saying.\n");
+ delete statement;
+ return;
+ }
+ }
+
+ // keep statements in order of start time
+
+ // check list is empty
+ if (m_statementList == NULL)
+ {
+ statement->m_next = NULL;
+ statement->m_prev = NULL;
+ m_statementList = statement;
+ return;
+ }
+
+ // list has at least one statement on it
+
+ // insert into list in order
+ BotStatement *earlier = NULL;
+ for (s = m_statementList; s != NULL; s = s->m_next)
+ {
+ if (s->GetStartTime() > statement->GetStartTime())
+ break;
+
+ earlier = s;
+ }
+
+ // insert just after "earlier"
+ if (earlier != NULL)
+ {
+ if (earlier->m_next != NULL)
+ earlier->m_next->m_prev = statement;
+
+ statement->m_next = earlier->m_next;
+
+ earlier->m_next = statement;
+ statement->m_prev = earlier;
+ }
+ else
+ {
+ // insert at head
+ statement->m_prev = NULL;
+ statement->m_next = m_statementList;
+ m_statementList->m_prev = statement;
+ m_statementList = statement;
+ }
}
+// Remove a statement
+
/* <3056fa> ../cstrike/dlls/bot/cs_bot_chatter.cpp:1462 */
-NOBODY void BotChatterInterface::RemoveStatement(BotStatement *statement)
+void BotChatterInterface::RemoveStatement(BotStatement *statement)
{
-// ~BotStatement(BotStatement *const this,
-// int const __in_chrg); // 1472
+ if (statement->m_next != NULL)
+ statement->m_next->m_prev = statement->m_prev;
+
+ if (statement->m_prev != NULL)
+ statement->m_prev->m_next = statement->m_next;
+ else
+ m_statementList = statement->m_next;
+
+ delete statement;
}
+// Track nearby enemy count and report enemy activity
+
/* <3087ee> ../cstrike/dlls/bot/cs_bot_chatter.cpp:1479 */
-NOBODY void BotChatterInterface::ReportEnemies(void)
+void BotChatterInterface::ReportEnemies(void)
{
-// GetNearbyEnemyCount(const class CCSBot *const this); // 1484
+ if (!m_me->IsAlive())
+ return;
+
+ if (m_me->GetNearbyEnemyCount() == 0)
+ {
+ m_seeAtLeastOneEnemy = false;
+ m_reportedEnemies = false;
+ }
+ else if (!m_seeAtLeastOneEnemy)
+ {
+ m_seeAtLeastOneEnemy = true;
+ m_timeWhenSawFirstEnemy = gpGlobals->time;
+ }
+
+ // determine whether we should report enemy activity
+ if (!m_reportedEnemies && m_seeAtLeastOneEnemy)
+ {
+ // request backup if we're outnumbered
+ if (m_me->IsOutnumbered() && NeedBackup())
+ {
+ m_reportedEnemies = true;
+ return;
+ }
+
+ m_me->GetChatter()->EnemySpotted();
+ m_reportedEnemies = true;
+ }
}
/* <305743> ../cstrike/dlls/bot/cs_bot_chatter.cpp:1515 */
-NOBODY void BotChatterInterface::OnEvent(GameEventType event, CBaseEntity *entity, CBaseEntity *other)
+void BotChatterInterface::OnEvent(GameEventType event, CBaseEntity *entity, CBaseEntity *other)
{
-
+ ;
}
+// Invoked when we die
+
/* <30579e> ../cstrike/dlls/bot/cs_bot_chatter.cpp:1524 */
-NOBODY void BotChatterInterface::OnDeath(void)
+void BotChatterInterface::OnDeath(void)
{
-// {
-// const class BotPhrase *pain; // 1532
-// GetSpeakable(const class BotPhrase *const this,
-// int bankIndex,
-// float *duration); // 1535
-// ResetRadioSilenceDuration(BotChatterInterface *const this); // 1536
-// GetPhrase(const class BotPhraseManager *const this,
-// const char *name); // 1532
-// }
-// IsTalking(const class BotChatterInterface *const this); // 1526
-// GetVerbosity(const class BotChatterInterface *const this); // 1528
-// GetVerbosity(const class BotChatterInterface *const this); // 1529
+ if (IsTalking())
+ {
+ if (m_me->GetChatter()->GetVerbosity() == BotChatterInterface::MINIMAL
+ || m_me->GetChatter()->GetVerbosity() == BotChatterInterface::NORMAL)
+ {
+ // we've died mid-sentance - emit a gargle of pain
+ static const BotPhrase *pain = TheBotPhrases->GetPhrase("pain");
+
+ if (pain != NULL)
+ {
+ m_me->Radio(pain->GetSpeakable(m_me->GetProfile()->GetVoiceBank()), NULL, m_me->GetProfile()->GetVoicePitch());
+ m_me->GetChatter()->ResetRadioSilenceDuration();
+ }
+ }
+ }
+
+ // remove all of our statements
+ Reset();
}
+// Process ongoing chatter for this bot
+
/* <308852> ../cstrike/dlls/bot/cs_bot_chatter.cpp:1549 */
-NOBODY void BotChatterInterface::Update(void)
+void BotChatterInterface::Update(void)
{
-// {
-// class BotStatement *say; // 1565
-// const class BotStatement *friendSay; // 1586
-// class BotStatement *nextSay; // 1590
-// ShouldSpeak(const class BotChatterInterface *const this); // 1555
-// GetOwner(const class BotStatement *const this); // 1570
-// GetOwner(const class BotStatement *const this); // 1587
-// IsValid(const class BotStatement *const this); // 1596
-// RemoveStatement(BotChatterInterface *const this,
-// class BotStatement *statement); // 1598
-// RemoveStatement(BotChatterInterface *const this,
-// class BotStatement *statement); // 1625
-// IsObsolete(const class BotStatement *const this); // 1607
-// IsRedundant(const class BotStatement *const this,
-// const class BotStatement *say); // 1621
-// {
-// float const longTime; // 1557
-// GetRadioSilenceDuration(BotChatterInterface *const this); // 1558
-// }
-// RemoveStatement(BotChatterInterface *const this,
-// class BotStatement *statement); // 1575
-// }
+ // report enemy activity
+ ReportEnemies();
+
+ // ask team to report in if we havent heard anything in awhile
+ if (ShouldSpeak())
+ {
+ const float longTime = 30.0f;
+ if (m_me->GetEnemiesRemaining() > 0 && GetRadioSilenceDuration() > longTime)
+ {
+ ReportIn();
+ }
+ }
+
+ // speak if it is our turn
+ BotStatement *say = GetActiveStatement();
+ if (say != NULL)
+ {
+ // if our statement is active, speak it
+ if (say->GetOwner() == m_me)
+ {
+ if (say->Update() == false)
+ {
+ // this statement is complete - destroy it
+ RemoveStatement(say);
+ }
+ }
+ }
+
+ // Process active statements.
+ // Removed expired statements, re-order statements according to their relavence and importance
+ // Remove redundant statements (ie: our teammates already said them)
+ const BotStatement *friendSay = GetActiveStatement();
+ if (friendSay != NULL && friendSay->GetOwner() == m_me)
+ friendSay = NULL;
+
+ BotStatement *nextSay;
+ for (say = m_statementList; say != NULL; say = nextSay)
+ {
+ nextSay = say->m_next;
+
+ // check statement conditions
+ if (!say->IsValid())
+ {
+ RemoveStatement(say);
+ continue;
+ }
+
+ // don't interrupt ourselves
+ if (say->IsSpeaking())
+ continue;
+
+ // check for obsolete statements
+ if (say->IsObsolete())
+ {
+ m_me->PrintIfWatched("Statement obsolete - removing.\n");
+ RemoveStatement(say);
+ continue;
+ }
+
+ // if a teammate is saying what we were going to say, dont repeat it
+ if (friendSay != NULL)
+ {
+ // convert what we're about to say based on what our teammate is currently saying
+ say->Convert(friendSay);
+
+ // don't say things our teammates have just said
+ if (say->IsRedundant(friendSay))
+ {
+ // thie statement is redundant - destroy it
+ //m_me->PrintIfWatched("Teammate said what I was going to say - shutting up.\n");
+ m_me->PrintIfWatched("Teammate said what I was going to say - shutting up.\n");
+ RemoveStatement(say);
+ }
+ }
+ }
}
+// Returns the statement that is being spoken, or is next to be spoken if no-one is speaking now
+
/* <305915> ../cstrike/dlls/bot/cs_bot_chatter.cpp:1635 */
-NOBODY BotStatement *BotChatterInterface::GetActiveStatement(void)
+BotStatement *BotChatterInterface::GetActiveStatement(void)
{
-// {
-// class BotStatement *earliest; // 1638
-// float earlyTime; // 1639
-// {
-// int i; // 1641
-// {
-// class CBasePlayer *player; // 1643
-// class CCSBot *bot; // 1667
-// FNullEnt(entvars_t *pev); // 1648
-// {
-// class BotStatement *say; // 1669
-// }
-// }
-// }
-// }
+ // keep track of statement waiting longest to be spoken - it is next
+ BotStatement *earliest = NULL;
+ float earlyTime = 999999999.9f;
+
+ for (int i = 1; i <= gpGlobals->maxClients; ++i)
+ {
+ CBasePlayer *player = static_cast(UTIL_PlayerByIndex(i));
+
+ if (player == NULL)
+ continue;
+
+ if (FNullEnt(player->pev))
+ continue;
+
+ if (FStrEq(STRING(player->pev->netname), ""))
+ continue;
+
+ // ignore dead humans
+ if (!player->IsBot() && !player->IsAlive())
+ continue;
+
+ // ignore enemies, since we can't hear them talk
+ if (m_me->m_iTeam != player->m_iTeam)
+ continue;
+
+ CCSBot *bot = dynamic_cast(player);
+
+ // if not a bot, fail the test
+ // TODO: Check if human is currently talking
+ if (!bot)
+ continue;
+
+ for (BotStatement *say = bot->GetChatter()->m_statementList; say != NULL; say = say->m_next)
+ {
+ // if this statement is currently being spoken, return it
+ if (say->IsSpeaking())
+ return say;
+
+ // keep track of statement that has been waiting longest to be spoken of anyone on our team
+ if (say->GetStartTime() < earlyTime)
+ {
+ earlyTime = say->GetTimestamp();
+ earliest = say;
+ }
+ }
+ }
+
+ // make sure it is time to start this statement
+ if (earliest != NULL && earliest->GetStartTime() > gpGlobals->time)
+ return NULL;
+
+ return earliest;
}
+// Return true if we speaking makes sense now
+
/* <305a35> ../cstrike/dlls/bot/cs_bot_chatter.cpp:1694 */
-NOBODY bool BotChatterInterface::ShouldSpeak(void) const
+bool BotChatterInterface::ShouldSpeak(void) const
{
-// GetNearbyFriendCount(const class CCSBot *const this); // 1701
+ // don't talk to non-existent friends
+ if (m_me->GetFriendsRemaining() == 0)
+ return false;
+
+ // if everyone is together, no need to tell them what's going on
+ if (m_me->GetNearbyFriendCount() == m_me->GetFriendsRemaining())
+ return false;
+
+ return true;
}
/* <305a8f> ../cstrike/dlls/bot/cs_bot_chatter.cpp:1708 */
-NOBODY float BotChatterInterface::GetRadioSilenceDuration(void)
+float BotChatterInterface::GetRadioSilenceDuration(void)
{
-// GetElapsedTime(const class IntervalTimer *const this); // 1710
+ return IMPL(m_radioSilenceInterval)[ m_me->m_iTeam - 1 ].GetElapsedTime();
}
/* <305b15> ../cstrike/dlls/bot/cs_bot_chatter.cpp:1714 */
-NOBODY void BotChatterInterface::ResetRadioSilenceDuration(void)
+void BotChatterInterface::ResetRadioSilenceDuration(void)
{
-// Reset(IntervalTimer *const this); // 1716
+ IMPL(m_radioSilenceInterval)[m_me->m_iTeam - 1].Reset();
}
/* <305d7b> ../cstrike/dlls/bot/cs_bot_chatter.cpp:1732 */
-NOBODY inline void SayWhere(BotStatement *say, Place place)
+inline void SayWhere(BotStatement *say, Place place)
{
+ say->AppendPhrase(TheBotPhrases->GetPlace(place));
}
+// Report enemy sightings
+
/* <305b50> ../cstrike/dlls/bot/cs_bot_chatter.cpp:1740 */
-NOBODY void BotChatterInterface::EnemySpotted(void)
+void BotChatterInterface::EnemySpotted(void)
{
-// {
-// Place place; // 1743
-// class BotStatement *say; // 1745
-// GetPlace(const class BotPhraseManager *const this,
-// PlaceCriteria place); // 1748
-// BotStatement(BotStatement *const this,
-// class BotChatterInterface *chatter,
-// enum BotStatementType type,
-// float expireDuration); // 1745
-// AppendPhrase(BotStatement *const this,
-// enum ContextType contextPhrase); // 1751
-// AppendPhrase(BotStatement *const this,
-// enum ContextType contextPhrase); // 1752
-// AddCondition(BotStatement *const this,
-// enum ConditionType condition); // 1753
-// AppendPhrase(BotStatement *const this,
-// const class BotPhrase *phrase); // 1748
-// }
+ // NOTE: This could be a few seconds out of date (enemy is in an adjacent place)
+ Place place = m_me->GetEnemyPlace();
+
+ BotStatement *say = new BotStatement(this, REPORT_VISIBLE_ENEMIES, 10.0f);
+
+ // where are the enemies
+ say->AppendPhrase(TheBotPhrases->GetPlace(place));
+
+ // how many are there
+ say->AppendPhrase(BotStatement::ACCUMULATE_ENEMIES_DELAY);
+ say->AppendPhrase(BotStatement::CURRENT_ENEMY_COUNT);
+ say->AddCondition(BotStatement::IS_IN_COMBAT);
+
+ AddStatement(say);
}
/* <305da4> ../cstrike/dlls/bot/cs_bot_chatter.cpp:1759 */
-NOBODY void BotChatterInterface::Clear(Place place)
+NOXREF void BotChatterInterface::Clear(Place place)
{
-// {
-// class BotStatement *say; // 1761
-// SayWhere(BotStatement *say,
-// Place place); // 1763
-// BotStatement(BotStatement *const this,
-// class BotChatterInterface *chatter,
-// enum BotStatementType type,
-// float expireDuration); // 1761
-// GetPhrase(const class BotPhraseManager *const this,
-// const char *name); // 1764
-// AppendPhrase(BotStatement *const this,
-// const class BotPhrase *phrase); // 1764
-// }
+ BotStatement *say = new BotStatement(this, REPORT_INFORMATION, 10.0f);
+
+ SayWhere(say, place);
+ say->AppendPhrase(TheBotPhrases->GetPhrase("Clear"));
+
+ AddStatement(say);
}
+// Request enemy activity report
+
/* <305ffa> ../cstrike/dlls/bot/cs_bot_chatter.cpp:1773 */
-NOBODY void BotChatterInterface::ReportIn(void)
+void BotChatterInterface::ReportIn(void)
{
-// {
-// class BotStatement *say; // 1775
-// BotStatement(BotStatement *const this,
-// class BotChatterInterface *chatter,
-// enum BotStatementType type,
-// float expireDuration); // 1775
-// GetPhrase(const class BotPhraseManager *const this,
-// const char *name); // 1777
-// AppendPhrase(BotStatement *const this,
-// const class BotPhrase *phrase); // 1777
-// AddCondition(BotStatement *const this,
-// enum ConditionType condition); // 1778
-// BotRequestReportMeme(BotRequestReportMeme *const this); // 1779
-// AttachMeme(BotStatement *const this,
-// class BotMeme *meme); // 1779
-// }
+ BotStatement *say = new BotStatement(this, REPORT_REQUEST_INFORMATION, 10.0f);
+
+ say->AppendPhrase(TheBotPhrases->GetPhrase("RequestReport"));
+ say->AddCondition(BotStatement::RADIO_SILENCE);
+ say->AttachMeme(new BotRequestReportMeme());
+
+ AddStatement(say);
}
+// Report our situtation
+
/* <309851> ../cstrike/dlls/bot/cs_bot_chatter.cpp:1788 */
-NOBODY void BotChatterInterface::ReportingIn(void)
+void BotChatterInterface::ReportingIn(void)
{
-// {
-// class CCSBotManager *ctrl; // 1790
-// class BotStatement *say; // 1792
-// Place place; // 1795
-// BotStatement(BotStatement *const this,
-// class BotChatterInterface *chatter,
-// enum BotStatementType type,
-// float expireDuration); // 1792
-// SayWhere(BotStatement *say,
-// Place place); // 1796
-// GoingToPlantTheBomb(BotChatterInterface *const this,
-// Place place); // 1803
-// {
-// float const recentTime; // 1874
-// SetStartTime(BotStatement *const this,
-// float timestamp); // 1872
-// GetTimeSinceLastSawEnemy(const class CCSBot *const this); // 1875
-// GetPhrase(const class BotPhraseManager *const this,
-// const char *name); // 1878
-// AppendPhrase(BotStatement *const this,
-// const class BotPhrase *phrase); // 1888
-// GetPhrase(const class BotPhraseManager *const this,
-// const char *name); // 1888
-// GetPhrase(const class BotPhraseManager *const this,
-// const char *name); // 1883
-// }
-// GetPhrase(const class BotPhraseManager *const this,
-// const char *name); // 1860
-// AppendPhrase(BotStatement *const this,
-// const class BotPhrase *phrase); // 1860
-// BotHelpMeme(BotHelpMeme *const this,
-// Place place); // 1861
-// AttachMeme(BotStatement *const this,
-// class BotMeme *meme); // 1861
-// GetPhrase(const class BotPhraseManager *const this,
-// const char *name); // 1866
-// Say(BotChatterInterface *const this,
-// const char *phraseName,
-// float lifetime,
-// float delay); // 1809
-// GuardingHostages(BotChatterInterface *const this,
-// Place place,
-// bool isPlan); // 1825
-// GuardingHostageEscapeZone(BotChatterInterface *const this,
-// bool isPlan); // 1831
-// GetLooseBomb(CCSBotManager *const this); // 1815
-// GetPhrase(const class BotPhraseManager *const this,
-// const char *name); // 1817
-// AppendPhrase(BotStatement *const this,
-// const class BotPhrase *phrase); // 1817
-// GetLooseBomb(CCSBotManager *const this); // 1818
-// BotBombStatusMeme(BotBombStatusMeme *const this,
-// enum BombState state,
-// const Vector *pos); // 1818
-// AttachMeme(BotStatement *const this,
-// class BotMeme *meme); // 1818
-// }
+ CCSBotManager *ctrl = TheCSBots();
+ BotStatement *say = new BotStatement(this, REPORT_INFORMATION, 10.0f);
+
+ // where are we
+ Place place = m_me->GetPlace();
+ SayWhere(say, place);
+
+ // what are we doing
+ switch (m_me->GetTask())
+ {
+ case CCSBot::PLANT_BOMB:
+ {
+ m_me->GetChatter()->GoingToPlantTheBomb(UNDEFINED_PLACE);
+ break;
+ }
+ case CCSBot::DEFUSE_BOMB:
+ {
+ m_me->GetChatter()->Say("DefusingBomb");
+ break;
+ }
+ case CCSBot::GUARD_LOOSE_BOMB:
+ {
+ if (ctrl->GetLooseBomb())
+ {
+ say->AppendPhrase(TheBotPhrases->GetPhrase("GuardingLooseBomb"));
+ say->AttachMeme(new BotBombStatusMeme(CSGameState::LOOSE, ctrl->GetLooseBomb()->pev->origin));
+ }
+ break;
+ }
+ case CCSBot::GUARD_HOSTAGES:
+ {
+ m_me->GetChatter()->GuardingHostages(UNDEFINED_PLACE, !m_me->IsAtHidingSpot());
+ break;
+ }
+ case CCSBot::GUARD_HOSTAGE_RESCUE_ZONE:
+ {
+ m_me->GetChatter()->GuardingHostageEscapeZone(!m_me->IsAtHidingSpot());
+ break;
+ }
+ case CCSBot::COLLECT_HOSTAGES:
+ {
+ break;
+ }
+ case CCSBot::RESCUE_HOSTAGES:
+ {
+ m_me->GetChatter()->EscortingHostages();
+ break;
+ }
+ case CCSBot::GUARD_VIP_ESCAPE_ZONE:
+ {
+ break;
+ }
+ }
+
+ // what do we see
+ if (m_me->IsAttacking())
+ {
+ if (m_me->IsOutnumbered())
+ {
+ // in trouble in a firefight
+ say->AppendPhrase(TheBotPhrases->GetPhrase("Help"));
+ say->AttachMeme(new BotHelpMeme(place));
+ }
+ else
+ {
+ // battling enemies
+ say->AppendPhrase(TheBotPhrases->GetPhrase("InCombat"));
+ }
+ }
+ else
+ {
+ // not in combat, start our report a little later
+ say->SetStartTime(gpGlobals->time + 2.0f);
+
+ const float recentTime = 10.0f;
+ if (m_me->GetEnemyDeathTimestamp() < recentTime && m_me->GetEnemyDeathTimestamp() >= m_me->GetTimeSinceLastSawEnemy() + 0.5f)
+ {
+ // recently saw an enemy die
+ say->AppendPhrase(TheBotPhrases->GetPhrase("EnemyDown"));
+ }
+ else if (m_me->GetTimeSinceLastSawEnemy() < recentTime)
+ {
+ // recently saw an enemy
+ say->AppendPhrase(TheBotPhrases->GetPhrase("EnemySpotted"));
+ }
+ else
+ {
+ // haven't seen enemies
+ say->AppendPhrase(TheBotPhrases->GetPhrase("Clear"));
+ }
+ }
+
+ AddStatement(say);
}
/* <3084cf> ../cstrike/dlls/bot/cs_bot_chatter.cpp:1896 */
-NOBODY bool BotChatterInterface::NeedBackup(void)
+bool BotChatterInterface::NeedBackup(void)
{
-// {
-// float const minRequestInterval; // 1898
-// IsLessThen(const class IntervalTimer *const this,
-// float duration); // 1899
-// {
-// class BotStatement *say; // 1913
-// Place place; // 1916
-// BotStatement(BotStatement *const this,
-// class BotChatterInterface *chatter,
-// enum BotStatementType type,
-// float expireDuration); // 1913
-// SayWhere(BotStatement *say,
-// Place place); // 1917
-// GetPhrase(const class BotPhraseManager *const this,
-// const char *name); // 1919
-// AppendPhrase(BotStatement *const this,
-// const class BotPhrase *phrase); // 1919
-// BotHelpMeme(BotHelpMeme *const this,
-// Place place); // 1920
-// AttachMeme(BotStatement *const this,
-// class BotMeme *meme); // 1920
-// }
-// Reset(IntervalTimer *const this); // 1902
-// }
+ const float minRequestInterval = 10.0f;
+ if (m_needBackupInterval.IsLessThen(minRequestInterval))
+ return false;
+
+ m_needBackupInterval.Reset();
+
+ if (m_me->GetFriendsRemaining() == 0)
+ {
+ // we're all alone...
+ Scared();
+ return true;
+ }
+ else
+ {
+ // ask friends for help
+ BotStatement *say = new BotStatement(this, REPORT_REQUEST_HELP, 10.0f);
+
+ // where are we
+ Place place = m_me->GetPlace();
+ SayWhere(say, place);
+
+ say->AppendPhrase(TheBotPhrases->GetPhrase("Help"));
+ say->AttachMeme(new BotHelpMeme(place));
+
+ AddStatement(say);
+ }
+
+ return true;
}
/* <3061a8> ../cstrike/dlls/bot/cs_bot_chatter.cpp:1929 */
-NOBODY void BotChatterInterface::PinnedDown(void)
+void BotChatterInterface::PinnedDown(void)
{
-// {
-// float const minRequestInterval; // 1932
-// class BotStatement *say; // 1938
-// Place place; // 1941
-// IsLessThen(const class IntervalTimer *const this,
-// float duration); // 1933
-// Reset(IntervalTimer *const this); // 1936
-// BotStatement(BotStatement *const this,
-// class BotChatterInterface *chatter,
-// enum BotStatementType type,
-// float expireDuration); // 1938
-// SayWhere(BotStatement *say,
-// Place place); // 1942
-// GetPhrase(const class BotPhraseManager *const this,
-// const char *name); // 1944
-// AppendPhrase(BotStatement *const this,
-// const class BotPhrase *phrase); // 1944
-// BotHelpMeme(BotHelpMeme *const this,
-// Place place); // 1945
-// AttachMeme(BotStatement *const this,
-// class BotMeme *meme); // 1945
-// AddCondition(BotStatement *const this,
-// enum ConditionType condition); // 1946
-// }
+ // this is a form of "need backup"
+ const float minRequestInterval = 10.0f;
+ if (m_needBackupInterval.IsLessThen(minRequestInterval))
+ return;
+
+ m_needBackupInterval.Reset();
+
+ BotStatement *say = new BotStatement(this, REPORT_REQUEST_HELP, 10.0f);
+
+ // where are we
+ Place place = m_me->GetPlace();
+ SayWhere(say, place);
+
+ say->AppendPhrase(TheBotPhrases->GetPhrase("PinnedDown"));
+ say->AttachMeme(new BotHelpMeme(place));
+ say->AddCondition(BotStatement::IS_IN_COMBAT);
+
+ AddStatement(say);
}
/* <3064e2> ../cstrike/dlls/bot/cs_bot_chatter.cpp:1952 */
-NOBODY void BotChatterInterface::HeardNoise(const Vector *pos)
+void BotChatterInterface::HeardNoise(const Vector *pos)
{
-// {
-// class CCSBotManager *ctrl; // 1954
-// IsElapsed(const class CountdownTimer *const this); // 1958
-// Start(CountdownTimer *const this,
-// float duration); // 1961
-// {
-// class BotStatement *say; // 1966
-// BotStatement(BotStatement *const this,
-// class BotChatterInterface *chatter,
-// enum BotStatementType type,
-// float expireDuration); // 1966
-// GetPhrase(const class BotPhraseManager *const this,
-// const char *name); // 1968
-// AppendPhrase(BotStatement *const this,
-// const class BotPhrase *phrase); // 1968
-// SetPlace(BotStatement *const this,
-// Place where); // 1969
-// }
-// }
+ if (TheCSBots()->IsRoundOver())
+ return;
+
+ if (m_heardNoiseTimer.IsElapsed())
+ {
+ // throttle frequency
+ m_heardNoiseTimer.Start(20.0f);
+
+ // make rare, since many teammates may try to say this
+ if (RANDOM_FLOAT(0.0f, 100.0f) < 33.0f)
+ {
+ BotStatement *say = new BotStatement(this, REPORT_INFORMATION, 5.0f);
+
+ say->AppendPhrase(TheBotPhrases->GetPhrase("HeardNoise"));
+ say->SetPlace(TheNavAreaGrid.GetPlace(pos));
+
+ AddStatement(say);
+ }
+ }
}
/* <3066a7> ../cstrike/dlls/bot/cs_bot_chatter.cpp:1978 */
-NOBODY void BotChatterInterface::KilledMyEnemy(int victimID)
+void BotChatterInterface::KilledMyEnemy(int victimID)
{
-// {
-// class BotStatement *say; // 1984
-// GetNearbyEnemyCount(const class CCSBot *const this); // 1981
-// BotStatement(BotStatement *const this,
-// class BotChatterInterface *chatter,
-// enum BotStatementType type,
-// float expireDuration); // 1984
-// GetPhrase(const class BotPhraseManager *const this,
-// const char *name); // 1986
-// AppendPhrase(BotStatement *const this,
-// const class BotPhrase *phrase); // 1986
-// SetSubject(BotStatement *const this,
-// int playerID); // 1987
-// }
+ // only report if we killed the last enemy in the area
+ if (m_me->GetNearbyEnemyCount() <= 1)
+ return;
+
+ BotStatement *say = new BotStatement(this, REPORT_ENEMY_ACTION, 3.0f);
+
+ say->AppendPhrase(TheBotPhrases->GetPhrase("KilledMyEnemy"));
+ say->SetSubject(victimID);
+
+ AddStatement(say);
}
/* <306853> ../cstrike/dlls/bot/cs_bot_chatter.cpp:1993 */
-NOBODY void BotChatterInterface::EnemiesRemaining(void)
+void BotChatterInterface::EnemiesRemaining(void)
{
-// {
-// class BotStatement *say; // 1999
-// GetNearbyEnemyCount(const class CCSBot *const this); // 1996
-// BotStatement(BotStatement *const this,
-// class BotChatterInterface *chatter,
-// enum BotStatementType type,
-// float expireDuration); // 1999
-// AppendPhrase(BotStatement *const this,
-// enum ContextType contextPhrase); // 2000
-// SetStartTime(BotStatement *const this,
-// float timestamp); // 2001
-// }
+ // only report if we killed the last enemy in the area
+ if (m_me->GetNearbyEnemyCount() > 1)
+ return;
+
+ BotStatement *say = new BotStatement(this, REPORT_ENEMIES_REMAINING, 5.0f);
+ say->AppendPhrase(BotStatement::REMAINING_ENEMY_COUNT);
+ say->SetStartTime(gpGlobals->time + RANDOM_FLOAT(2.0f, 4.0f));
+
+ AddStatement(say);
}
/* <306974> ../cstrike/dlls/bot/cs_bot_chatter.cpp:2008 */
-NOBODY void BotChatterInterface::Affirmative(void)
+void BotChatterInterface::Affirmative(void)
{
-// {
-// class BotStatement *say; // 2010
-// BotStatement(BotStatement *const this,
-// class BotChatterInterface *chatter,
-// enum BotStatementType type,
-// float expireDuration); // 2010
-// GetPhrase(const class BotPhraseManager *const this,
-// const char *name); // 2012
-// AppendPhrase(BotStatement *const this,
-// const class BotPhrase *phrase); // 2012
-// }
+ BotStatement *say = new BotStatement(this, REPORT_ACKNOWLEDGE, 3.0f);
+
+ say->AppendPhrase(TheBotPhrases->GetPhrase("Affirmative"));
+
+ AddStatement(say);
}
/* <306bb2> ../cstrike/dlls/bot/cs_bot_chatter.cpp:2018 */
-NOBODY void BotChatterInterface::Negative(void)
+void BotChatterInterface::Negative(void)
{
-// {
-// class BotStatement *say; // 2020
-// BotStatement(BotStatement *const this,
-// class BotChatterInterface *chatter,
-// enum BotStatementType type,
-// float expireDuration); // 2020
-// GetPhrase(const class BotPhraseManager *const this,
-// const char *name); // 2022
-// AppendPhrase(BotStatement *const this,
-// const class BotPhrase *phrase); // 2022
-// }
+ BotStatement *say = new BotStatement(this, REPORT_ACKNOWLEDGE, 3.0f);
+
+ say->AppendPhrase(TheBotPhrases->GetPhrase("Negative"));
+
+ AddStatement(say);
}
/* <306cf4> ../cstrike/dlls/bot/cs_bot_chatter.cpp:2028 */
-NOBODY void BotChatterInterface::GoingToPlantTheBomb(Place place)
+void BotChatterInterface::GoingToPlantTheBomb(Place place)
{
-// {
-// class CCSBotManager *ctrl; // 2030
-// float const minInterval; // 2034
-// class BotStatement *say; // 2040
-// IsLessThen(const class IntervalTimer *const this,
-// float duration); // 2035
-// Reset(IntervalTimer *const this); // 2038
-// BotStatement(BotStatement *const this,
-// class BotChatterInterface *chatter,
-// enum BotStatementType type,
-// float expireDuration); // 2040
-// GetPhrase(const class BotPhraseManager *const this,
-// const char *name); // 2042
-// AppendPhrase(BotStatement *const this,
-// const class BotPhrase *phrase); // 2042
-// SetPlace(BotStatement *const this,
-// Place where); // 2043
-// BotFollowMeme(BotFollowMeme *const this); // 2044
-// AttachMeme(BotStatement *const this,
-// class BotMeme *meme); // 2044
-// }
+ if (TheCSBots()->IsRoundOver())
+ return;
+
+ const float minInterval = 10.0f; // 20.0f
+ if (m_planInterval.IsLessThen(minInterval))
+ return;
+
+ m_planInterval.Reset();
+
+ BotStatement *say = new BotStatement(this, REPORT_CRITICAL_EVENT, 10.0f);
+
+ say->AppendPhrase(TheBotPhrases->GetPhrase("GoingToPlantBomb"));
+ say->SetPlace(place);
+ say->AttachMeme(new BotFollowMeme());
+
+ AddStatement(say);
}
/* <306ef6> ../cstrike/dlls/bot/cs_bot_chatter.cpp:2050 */
-NOBODY void BotChatterInterface::PlantingTheBomb(Place place)
+void BotChatterInterface::PlantingTheBomb(Place place)
{
-// {
-// class CCSBotManager *ctrl; // 2052
-// class BotStatement *say; // 2056
-// BotStatement(BotStatement *const this,
-// class BotChatterInterface *chatter,
-// enum BotStatementType type,
-// float expireDuration); // 2056
-// GetPhrase(const class BotPhraseManager *const this,
-// const char *name); // 2058
-// AppendPhrase(BotStatement *const this,
-// const class BotPhrase *phrase); // 2058
-// SetPlace(BotStatement *const this,
-// Place where); // 2059
-// BotDefendHereMeme(BotDefendHereMeme *const this,
-// const Vector *pos); // 2060
-// AttachMeme(BotStatement *const this,
-// class BotMeme *meme); // 2060
-// }
+ if (TheCSBots()->IsRoundOver())
+ return;
+
+ BotStatement *say = new BotStatement(this, REPORT_CRITICAL_EVENT, 10.0f);
+
+ say->AppendPhrase(TheBotPhrases->GetPhrase("PlantingBomb"));
+ say->SetPlace(place);
+
+ say->AttachMeme(new BotDefendHereMeme(m_me->pev->origin));
+
+ AddStatement(say);
}
/* <3070c8> ../cstrike/dlls/bot/cs_bot_chatter.cpp:2066 */
-NOBODY void BotChatterInterface::TheyPickedUpTheBomb(void)
+void BotChatterInterface::TheyPickedUpTheBomb(void)
{
-// {
-// class CCSBotManager *ctrl; // 2068
-// class BotStatement *say; // 2080
-// BotStatement(BotStatement *const this,
-// class BotChatterInterface *chatter,
-// enum BotStatementType type,
-// float expireDuration); // 2080
-// GetPhrase(const class BotPhraseManager *const this,
-// const char *name); // 2082
-// AppendPhrase(BotStatement *const this,
-// const class BotPhrase *phrase); // 2082
-// BotBombStatusMeme(BotBombStatusMeme *const this,
-// enum BombState state,
-// const Vector *pos); // 2084
-// AttachMeme(BotStatement *const this,
-// class BotMeme *meme); // 2084
-// }
+ if (TheCSBots()->IsRoundOver())
+ return;
+
+ // if we already know the bomb is not loose, this is old news
+ if (!m_me->GetGameState()->IsBombLoose())
+ return;
+
+ // update our gamestate - use our own position for now
+ m_me->GetGameState()->UpdateBomber(&m_me->pev->origin);
+
+ // tell our teammates
+ BotStatement *say = new BotStatement(this, REPORT_INFORMATION, 10.0f);
+
+ say->AppendPhrase(TheBotPhrases->GetPhrase("TheyPickedUpTheBomb"));
+ say->AttachMeme(new BotBombStatusMeme(CSGameState::MOVING, m_me->pev->origin));
+
+ AddStatement(say);
}
/* <307272> ../cstrike/dlls/bot/cs_bot_chatter.cpp:2090 */
-NOBODY void BotChatterInterface::SpottedBomber(CBasePlayer *bomber)
+void BotChatterInterface::SpottedBomber(CBasePlayer *bomber)
{
-// {
-// class BotStatement *say; // 2105
-// Place place; // 2108
-// {
-// const Vector *bomberPos; // 2095
-// float const closeRangeSq; // 2096
-// operator-(const Vector *const this,
-// const Vector &v); // 2097
-// LengthSquared(const Vector *const this); // 2097
-// }
-// BotStatement(BotStatement *const this,
-// class BotChatterInterface *chatter,
-// enum BotStatementType type,
-// float expireDuration); // 2105
-// SayWhere(BotStatement *say,
-// Place place); // 2109
-// GetPhrase(const class BotPhraseManager *const this,
-// const char *name); // 2111
-// AppendPhrase(BotStatement *const this,
-// const class BotPhrase *phrase); // 2111
-// entindex(CBaseEntity *const this); // 2113
-// SetSubject(BotStatement *const this,
-// int playerID); // 2113
-// BotBombStatusMeme(BotBombStatusMeme *const this,
-// enum BombState state,
-// const Vector *pos); // 2116
-// AttachMeme(BotStatement *const this,
-// class BotMeme *meme); // 2116
-// }
+ if (m_me->GetGameState()->IsBombMoving())
+ {
+ // if we knew where the bomber was, this is old news
+ const Vector *bomberPos = m_me->GetGameState()->GetBombPosition();
+ const float closeRangeSq = 1000.0f * 1000.0f;
+ if (bomberPos != NULL && (bomber->pev->origin - *bomberPos).LengthSquared() < closeRangeSq)
+ return;
+ }
+
+ // update our gamestate
+ m_me->GetGameState()->UpdateBomber(&bomber->pev->origin);
+
+ // tell our teammates
+ BotStatement *say = new BotStatement(this, REPORT_INFORMATION, 10.0f);
+
+ // where is the bomber
+ Place place = TheNavAreaGrid.GetPlace(&bomber->pev->origin);
+ SayWhere(say, place);
+
+ say->AppendPhrase(TheBotPhrases->GetPhrase("SpottedBomber"));
+ say->SetSubject(bomber->entindex());
+
+ //say->AttachMeme(new BotHelpMeme(place));
+ say->AttachMeme(new BotBombStatusMeme(CSGameState::MOVING, bomber->pev->origin));
+
+ AddStatement(say);
}
/* <30761a> ../cstrike/dlls/bot/cs_bot_chatter.cpp:2122 */
-NOBODY void BotChatterInterface::SpottedLooseBomb(CBaseEntity *bomb)
+void BotChatterInterface::SpottedLooseBomb(CBaseEntity *bomb)
{
-// {
-// class CCSBotManager *ctrl; // 2124
-// IsElapsed(const class CountdownTimer *const this); // 2135
-// {
-// class BotStatement *say; // 2141
-// Place place; // 2144
-// Start(CountdownTimer *const this,
-// float duration); // 2138
-// BotStatement(BotStatement *const this,
-// class BotChatterInterface *chatter,
-// enum BotStatementType type,
-// float expireDuration); // 2141
-// SayWhere(BotStatement *say,
-// Place place); // 2145
-// GetPhrase(const class BotPhraseManager *const this,
-// const char *name); // 2147
-// AppendPhrase(BotStatement *const this,
-// const class BotPhrase *phrase); // 2147
-// GetLooseBomb(CCSBotManager *const this); // 2149
-// BotBombStatusMeme(BotBombStatusMeme *const this,
-// enum BombState state,
-// const Vector *pos); // 2150
-// AttachMeme(BotStatement *const this,
-// class BotMeme *meme); // 2150
-// }
-// }
+ if (TheCSBots()->IsRoundOver())
+ return;
+
+ // if we already know the bomb is loose, this is old news
+ if (m_me->GetGameState()->IsBombLoose())
+ return;
+
+ // update our gamestate
+ m_me->GetGameState()->UpdateLooseBomb(&bomb->pev->origin);
+
+ if (m_spottedLooseBombTimer.IsElapsed())
+ {
+ // throttle frequency
+ m_spottedLooseBombTimer.Start(10.0f);
+
+ // tell our teammates
+ BotStatement *say = new BotStatement(this, REPORT_INFORMATION, 10.0f);
+
+ // where is the bomb
+ Place place = TheNavAreaGrid.GetPlace(&bomb->pev->origin);
+ SayWhere(say, place);
+
+ say->AppendPhrase(TheBotPhrases->GetPhrase("SpottedLooseBomb"));
+
+ if (TheCSBots()->GetLooseBomb())
+ say->AttachMeme(new BotBombStatusMeme(CSGameState::LOOSE, bomb->pev->origin));
+
+ AddStatement(say);
+ }
}
/* <30795b> ../cstrike/dlls/bot/cs_bot_chatter.cpp:2157 */
-NOBODY void BotChatterInterface::GuardingLooseBomb(CBaseEntity *bomb)
+NOXREF void BotChatterInterface::GuardingLooseBomb(CBaseEntity *bomb)
{
-// {
-// class CCSBotManager *ctrl; // 2163
-// class BotStatement *say; // 2171
-// Place place; // 2174
-// BotStatement(BotStatement *const this,
-// class BotChatterInterface *chatter,
-// enum BotStatementType type,
-// float expireDuration); // 2171
-// SayWhere(BotStatement *say,
-// Place place); // 2175
-// GetPhrase(const class BotPhraseManager *const this,
-// const char *name); // 2177
-// AppendPhrase(BotStatement *const this,
-// const class BotPhrase *phrase); // 2177
-// GetLooseBomb(CCSBotManager *const this); // 2179
-// BotBombStatusMeme(BotBombStatusMeme *const this,
-// enum BombState state,
-// const Vector *pos); // 2180
-// AttachMeme(BotStatement *const this,
-// class BotMeme *meme); // 2180
-// }
+ if (TheCSBots()->IsRoundOver() || !bomb)
+ return;
+
+#ifdef REGAMEDLL_FIXES
+ const float minInterval = 20.0f;
+ if (m_planInterval.IsLessThen(minInterval))
+ return;
+
+ m_planInterval.Reset();
+#endif // REGAMEDLL_FIXES
+
+ // update our gamestate
+ m_me->GetGameState()->UpdateLooseBomb(&bomb->pev->origin);
+
+ // tell our teammates
+ BotStatement *say = new BotStatement(this, REPORT_INFORMATION, 10.0f);
+
+ // where is the bomb
+ Place place = TheNavAreaGrid.GetPlace(&bomb->pev->origin);
+ SayWhere(say, place);
+
+ say->AppendPhrase(TheBotPhrases->GetPhrase("GuardingLooseBomb"));
+
+ if (TheCSBots()->GetLooseBomb())
+ say->AttachMeme(new BotBombStatusMeme(CSGameState::LOOSE, bomb->pev->origin));
+
+ AddStatement(say);
}
/* <307c56> ../cstrike/dlls/bot/cs_bot_chatter.cpp:2186 */
-NOBODY void BotChatterInterface::RequestBombLocation(void)
+void BotChatterInterface::RequestBombLocation(void)
{
-// {
-// class BotStatement *say; // 2195
-// BotStatement(BotStatement *const this,
-// class BotChatterInterface *chatter,
-// enum BotStatementType type,
-// float expireDuration); // 2195
-// GetPhrase(const class BotPhraseManager *const this,
-// const char *name); // 2197
-// AppendPhrase(BotStatement *const this,
-// const class BotPhrase *phrase); // 2197
-// BotWhereBombMeme(BotWhereBombMeme *const this); // 2199
-// AttachMeme(BotStatement *const this,
-// class BotMeme *meme); // 2199
-// }
+ // only ask once per round
+ if (m_requestedBombLocation)
+ return;
+
+ m_requestedBombLocation = true;
+
+ // tell our teammates
+ BotStatement *say = new BotStatement(this, REPORT_REQUEST_INFORMATION, 10.0f);
+
+ say->AppendPhrase(TheBotPhrases->GetPhrase("WhereIsTheBomb"));
+
+ say->AttachMeme(new BotWhereBombMeme());
+
+ AddStatement(say);
}
/* <307de2> ../cstrike/dlls/bot/cs_bot_chatter.cpp:2205 */
-NOBODY void BotChatterInterface::BombsiteClear(int zoneIndex)
+void BotChatterInterface::BombsiteClear(int zoneIndex)
{
-// {
-// class CCSBotManager *ctrl; // 2207
-// const class Zone *zone; // 2208
-// class BotStatement *say; // 2212
-// BotStatement(BotStatement *const this,
-// class BotChatterInterface *chatter,
-// enum BotStatementType type,
-// float expireDuration); // 2212
-// SayWhere(BotStatement *say,
-// Place place); // 2214
-// GetPhrase(const class BotPhraseManager *const this,
-// const char *name); // 2215
-// AppendPhrase(BotStatement *const this,
-// const class BotPhrase *phrase); // 2215
-// BotBombsiteStatusMeme(BotBombsiteStatusMeme *const this,
-// int zoneIndex,
-// enum StatusType status); // 2217
-// AttachMeme(BotStatement *const this,
-// class BotMeme *meme); // 2217
-// }
+ const CCSBotManager::Zone *zone = TheCSBots()->GetZone(zoneIndex);
+ if (zone == NULL)
+ return;
+
+ BotStatement *say = new BotStatement(this, REPORT_INFORMATION, 10.0f);
+
+ SayWhere(say, TheNavAreaGrid.GetPlace(&zone->m_center));
+ say->AppendPhrase(TheBotPhrases->GetPhrase("BombsiteClear"));
+
+ say->AttachMeme(new BotBombsiteStatusMeme(zoneIndex, BotBombsiteStatusMeme::CLEAR));
+
+ AddStatement(say);
}
/* <3080b8> ../cstrike/dlls/bot/cs_bot_chatter.cpp:2223 */
-NOBODY void BotChatterInterface::FoundPlantedBomb(int zoneIndex)
+void BotChatterInterface::FoundPlantedBomb(int zoneIndex)
{
-// {
-// class CCSBotManager *ctrl; // 2225
-// const class Zone *zone; // 2226
-// class BotStatement *say; // 2230
-// BotStatement(BotStatement *const this,
-// class BotChatterInterface *chatter,
-// enum BotStatementType type,
-// float expireDuration); // 2230
-// GetPhrase(const class BotPhraseManager *const this,
-// const char *name); // 2232
-// AppendPhrase(BotStatement *const this,
-// const class BotPhrase *phrase); // 2232
-// SetPlace(BotStatement *const this,
-// Place where); // 2233
-// BotBombsiteStatusMeme(BotBombsiteStatusMeme *const this,
-// int zoneIndex,
-// enum StatusType status); // 2235
-// AttachMeme(BotStatement *const this,
-// class BotMeme *meme); // 2235
-// }
+ const CCSBotManager::Zone *zone = TheCSBots()->GetZone(zoneIndex);
+ if (zone == NULL)
+ return;
+
+ BotStatement *say = new BotStatement(this, REPORT_INFORMATION, 3.0f);
+
+ say->AppendPhrase(TheBotPhrases->GetPhrase("PlantedBombPlace"));
+ say->SetPlace(TheNavAreaGrid.GetPlace(&zone->m_center));
+
+ say->AttachMeme(new BotBombsiteStatusMeme(zoneIndex, BotBombsiteStatusMeme::PLANTED));
+
+ AddStatement(say);
}
/* <308308> ../cstrike/dlls/bot/cs_bot_chatter.cpp:2242 */
-NOBODY void BotChatterInterface::Scared(void)
+void BotChatterInterface::Scared(void)
{
-// {
-// float const minInterval; // 2244
-// class BotStatement *say; // 2250
-// IsLessThen(const class IntervalTimer *const this,
-// float duration); // 2245
-// Reset(IntervalTimer *const this); // 2248
-// BotStatement(BotStatement *const this,
-// class BotChatterInterface *chatter,
-// enum BotStatementType type,
-// float expireDuration); // 2250
-// GetPhrase(const class BotPhraseManager *const this,
-// const char *name); // 2252
-// AppendPhrase(BotStatement *const this,
-// const class BotPhrase *phrase); // 2252
-// AddCondition(BotStatement *const this,
-// enum ConditionType condition); // 2253
-// }
+ const float minInterval = 10.0f;
+ if (m_scaredInterval.IsLessThen(minInterval))
+ return;
+
+ m_scaredInterval.Reset();
+
+ BotStatement *say = new BotStatement(this, REPORT_EMOTE, 1.0f);
+
+ say->AppendPhrase(TheBotPhrases->GetPhrase("ScaredEmote"));
+ say->AddCondition(BotStatement::IS_IN_COMBAT);
+
+ AddStatement(say);
}
/* <308b60> ../cstrike/dlls/bot/cs_bot_chatter.cpp:2259 */
-NOBODY void BotChatterInterface::CelebrateWin(void)
+void BotChatterInterface::CelebrateWin(void)
{
-// {
-// class BotStatement *say; // 2261
-// float const quickRound; // 2266
-// class CCSBotManager *ctrl; // 2267
-// BotStatement(BotStatement *const this,
-// class BotChatterInterface *chatter,
-// enum BotStatementType type,
-// float expireDuration); // 2261
-// SetStartTime(BotStatement *const this,
-// float timestamp); // 2264
-// GetElapsedRoundTime(const class CCSBotManager *const this); // 2272
-// GetPhrase(const class BotPhraseManager *const this,
-// const char *name); // 2282
-// AppendPhrase(BotStatement *const this,
-// const class BotPhrase *phrase); // 2286
-// GetPhrase(const class BotPhraseManager *const this,
-// const char *name); // 2286
-// GetPhrase(const class BotPhraseManager *const this,
-// const char *name); // 2273
-// GetPhrase(const class BotPhraseManager *const this,
-// const char *name); // 2275
-// }
+ BotStatement *say = new BotStatement(this, REPORT_EMOTE, 15.0f);
+
+ // wait a bit before speaking
+ say->SetStartTime(gpGlobals->time + RANDOM_FLOAT(2.0f, 5.0f));
+
+ const float quickRound = 45.0f;
+ CCSBotManager *ctrl = TheCSBots();
+
+ if (m_me->GetFriendsRemaining() == 0)
+ {
+ // we were the last man standing
+ if (ctrl->GetElapsedRoundTime() < quickRound)
+ say->AppendPhrase(TheBotPhrases->GetPhrase("WonRoundQuickly"));
+ else if (RANDOM_FLOAT(0.0f, 100.0f) < 33.3f)
+ say->AppendPhrase(TheBotPhrases->GetPhrase("LastManStanding"));
+ }
+ else
+ {
+ if (ctrl->GetElapsedRoundTime() < quickRound)
+ {
+ if (RANDOM_FLOAT(0.0f, 100.0f) < 33.3f)
+ say->AppendPhrase(TheBotPhrases->GetPhrase("WonRoundQuickly"));
+ }
+ else if (RANDOM_FLOAT(0.0f, 100.0f) < 10.0f)
+ {
+ say->AppendPhrase(TheBotPhrases->GetPhrase("WonRound"));
+ }
+ }
+
+ AddStatement(say);
}
/* <308e52> ../cstrike/dlls/bot/cs_bot_chatter.cpp:2294 */
-NOBODY void BotChatterInterface::AnnouncePlan(const char *phraseName, Place place)
+void BotChatterInterface::AnnouncePlan(const char *phraseName, Place place)
{
-// {
-// class CCSBotManager *ctrl; // 2296
-// class BotStatement *say; // 2300
-// BotStatement(BotStatement *const this,
-// class BotChatterInterface *chatter,
-// enum BotStatementType type,
-// float expireDuration); // 2300
-// GetPhrase(const class BotPhraseManager *const this,
-// const char *name); // 2302
-// AppendPhrase(BotStatement *const this,
-// const class BotPhrase *phrase); // 2302
-// SetPlace(BotStatement *const this,
-// Place where); // 2303
-// SetStartTime(BotStatement *const this,
-// float timestamp); // 2306
-// }
+ CCSBotManager *ctrl = TheCSBots();
+ if (ctrl->IsRoundOver())
+ return;
+
+ BotStatement *say = new BotStatement(this, REPORT_MY_PLAN, 10.0f);
+
+ say->AppendPhrase(TheBotPhrases->GetPhrase(phraseName));
+ say->SetPlace(place);
+
+ // wait at least a short time after round start
+ say->SetStartTime(ctrl->GetRoundStartTime() + RANDOM_FLOAT(2.0, 3.0f));
+
+ AddStatement(say);
}
/* <308fdd> ../cstrike/dlls/bot/cs_bot_chatter.cpp:2312 */
-NOBODY void BotChatterInterface::GuardingHostages(Place place, bool isPlan)
+void BotChatterInterface::GuardingHostages(Place place, bool isPlan)
{
-// {
-// class CCSBotManager *ctrl; // 2314
-// float const minInterval; // 2318
-// IsLessThen(const class IntervalTimer *const this,
-// float duration); // 2319
-// Say(BotChatterInterface *const this,
-// const char *phraseName,
-// float lifetime,
-// float delay); // 2325
-// }
+ if (TheCSBots()->IsRoundOver())
+ return;
+
+ const float minInterval = 20.0f;
+ if (m_planInterval.IsLessThen(minInterval))
+ return;
+
+#ifdef REGAMEDLL_FIXES
+ m_planInterval.Reset();
+#endif // REGAMEDLL_FIXES
+
+ if (isPlan)
+ AnnouncePlan("GoingToGuardHostages", place);
+ else
+ Say("GuardingHostages");
}
/* <3091eb> ../cstrike/dlls/bot/cs_bot_chatter.cpp:2329 */
-NOBODY void BotChatterInterface::GuardingHostageEscapeZone(bool isPlan)
+void BotChatterInterface::GuardingHostageEscapeZone(bool isPlan)
{
-// {
-// class CCSBotManager *ctrl; // 2331
-// float const minInterval; // 2335
-// IsLessThen(const class IntervalTimer *const this,
-// float duration); // 2336
-// Say(BotChatterInterface *const this,
-// const char *phraseName,
-// float lifetime,
-// float delay); // 2342
-// }
+ if (TheCSBots()->IsRoundOver())
+ return;
+
+ const float minInterval = 20.0f;
+ if (m_planInterval.IsLessThen(minInterval))
+ return;
+
+#ifdef REGAMEDLL_FIXES
+ m_planInterval.Reset();
+#endif // REGAMEDLL_FIXES
+
+ if (isPlan)
+ AnnouncePlan("GoingToGuardHostageEscapeZone", UNDEFINED_PLACE);
+ else
+ Say("GuardingHostageEscapeZone");
}
/* <3093a9> ../cstrike/dlls/bot/cs_bot_chatter.cpp:2346 */
-NOBODY void BotChatterInterface::HostagesBeingTaken(void)
+void BotChatterInterface::HostagesBeingTaken(void)
{
-// {
-// class CCSBotManager *ctrl; // 2348
-// class BotStatement *say; // 2352
-// BotStatement(BotStatement *const this,
-// class BotChatterInterface *chatter,
-// enum BotStatementType type,
-// float expireDuration); // 2352
-// GetPhrase(const class BotPhraseManager *const this,
-// const char *name); // 2354
-// AppendPhrase(BotStatement *const this,
-// const class BotPhrase *phrase); // 2354
-// BotHostageBeingTakenMeme(BotHostageBeingTakenMeme *const this); // 2355
-// AttachMeme(BotStatement *const this,
-// class BotMeme *meme); // 2355
-// }
+ if (TheCSBots()->IsRoundOver())
+ return;
+
+ BotStatement *say = new BotStatement(this, REPORT_INFORMATION, 3.0f);
+
+ say->AppendPhrase(TheBotPhrases->GetPhrase("HostagesBeingTaken"));
+ say->AttachMeme(new BotHostageBeingTakenMeme());
+
+ AddStatement(say);
}
/* <309542> ../cstrike/dlls/bot/cs_bot_chatter.cpp:2361 */
-NOBODY void BotChatterInterface::HostagesTaken(void)
+void BotChatterInterface::HostagesTaken(void)
{
-// {
-// class CCSBotManager *ctrl; // 2363
-// class BotStatement *say; // 2367
-// BotStatement(BotStatement *const this,
-// class BotChatterInterface *chatter,
-// enum BotStatementType type,
-// float expireDuration); // 2367
-// GetPhrase(const class BotPhraseManager *const this,
-// const char *name); // 2369
-// AppendPhrase(BotStatement *const this,
-// const class BotPhrase *phrase); // 2369
-// }
+ if (TheCSBots()->IsRoundOver())
+ return;
+
+ BotStatement *say = new BotStatement(this, REPORT_INFORMATION, 3.0f);
+
+ say->AppendPhrase(TheBotPhrases->GetPhrase("HostagesTaken"));
+
+ AddStatement(say);
}
/* <309691> ../cstrike/dlls/bot/cs_bot_chatter.cpp:2375 */
-NOBODY void BotChatterInterface::TalkingToHostages(void)
+void BotChatterInterface::TalkingToHostages(void)
{
+ ;
}
/* <3096bc> ../cstrike/dlls/bot/cs_bot_chatter.cpp:2380 */
-NOBODY void BotChatterInterface::EscortingHostages(void)
+void BotChatterInterface::EscortingHostages(void)
{
-// {
-// class CCSBotManager *ctrl; // 2382
-// IsElapsed(const class CountdownTimer *const this); // 2386
-// {
-// class BotStatement *say; // 2391
-// Start(CountdownTimer *const this,
-// float duration); // 2389
-// BotStatement(BotStatement *const this,
-// class BotChatterInterface *chatter,
-// enum BotStatementType type,
-// float expireDuration); // 2391
-// GetPhrase(const class BotPhraseManager *const this,
-// const char *name); // 2393
-// AppendPhrase(BotStatement *const this,
-// const class BotPhrase *phrase); // 2393
-// }
-// }
+ if (TheCSBots()->IsRoundOver())
+ return;
+
+ if (m_escortingHostageTimer.IsElapsed())
+ {
+ // throttle frequency
+ m_escortingHostageTimer.Start(10.0f);
+
+ BotStatement *say = new BotStatement(this, REPORT_MY_PLAN, 5.0f);
+
+ say->AppendPhrase(TheBotPhrases->GetPhrase("EscortingHostages"));
+
+ AddStatement(say);
+ }
}
/* <30a5b9> ../cstrike/dlls/bot/cs_bot_chatter.cpp:2400 */
-NOBODY void BotChatterInterface::HostageDown(void)
+NOXREF void BotChatterInterface::HostageDown(void)
{
-// {
-// class CCSBotManager *ctrl; // 2402
-// class BotStatement *say; // 2406
-// BotStatement(BotStatement *const this,
-// class BotChatterInterface *chatter,
-// enum BotStatementType type,
-// float expireDuration); // 2406
-// GetPhrase(const class BotPhraseManager *const this,
-// const char *name); // 2408
-// AppendPhrase(BotStatement *const this,
-// const class BotPhrase *phrase); // 2408
-// }
+ if (TheCSBots()->IsRoundOver())
+ return;
+
+ BotStatement *say = new BotStatement(this, REPORT_INFORMATION, 3.0f);
+
+ say->AppendPhrase(TheBotPhrases->GetPhrase("HostageDown"));
+
+ AddStatement(say);
}
/* <30a708> ../cstrike/dlls/bot/cs_bot_chatter.cpp:2414 */
-NOBODY void BotChatterInterface::Encourage(const char *phraseName, float repeatInterval, float lifetime)
+void BotChatterInterface::Encourage(const char *phraseName, float repeatInterval, float lifetime)
{
-// {
-// class CCSBotManager *ctrl; // 2416
-// IsElapsed(const class CountdownTimer *const this); // 2418
-// Say(BotChatterInterface *const this,
-// const char *phraseName,
-// float lifetime,
-// float delay); // 2420
-// Start(CountdownTimer *const this,
-// float duration); // 2421
-// }
+ if (IMPL(m_encourageTimer).IsElapsed())
+ {
+ Say(phraseName, lifetime);
+ IMPL(m_encourageTimer).Start(repeatInterval);
+ }
}
/* <30a905> ../cstrike/dlls/bot/cs_bot_chatter.cpp:2427 */
-NOBODY void BotChatterInterface::KilledFriend(void)
+void BotChatterInterface::KilledFriend(void)
{
-// {
-// class BotStatement *say; // 2429
-// BotStatement(BotStatement *const this,
-// class BotChatterInterface *chatter,
-// enum BotStatementType type,
-// float expireDuration); // 2429
-// GetPhrase(const class BotPhraseManager *const this,
-// const char *name); // 2431
-// AppendPhrase(BotStatement *const this,
-// const class BotPhrase *phrase); // 2431
-// SetStartTime(BotStatement *const this,
-// float timestamp); // 2434
-// }
+ BotStatement *say = new BotStatement(this, REPORT_KILLED_FRIEND, 2.0f);
+
+ say->AppendPhrase(TheBotPhrases->GetPhrase("KilledFriend"));
+
+ // give them time to react
+ say->SetStartTime(gpGlobals->time + RANDOM_FLOAT(0.5f, 1.0f));
+
+ AddStatement(say);
}
/* <30aa67> ../cstrike/dlls/bot/cs_bot_chatter.cpp:2440 */
-NOBODY void BotChatterInterface::FriendlyFire(void)
+void BotChatterInterface::FriendlyFire(void)
{
-// {
-// class BotStatement *say; // 2442
-// BotStatement(BotStatement *const this,
-// class BotChatterInterface *chatter,
-// enum BotStatementType type,
-// float expireDuration); // 2442
-// GetPhrase(const class BotPhraseManager *const this,
-// const char *name); // 2444
-// AppendPhrase(BotStatement *const this,
-// const class BotPhrase *phrase); // 2444
-// SetStartTime(BotStatement *const this,
-// float timestamp); // 2447
-// }
+ BotStatement *say = new BotStatement(this, REPORT_FRIENDLY_FIRE, 1.0f);
+
+ say->AppendPhrase(TheBotPhrases->GetPhrase("FriendlyFire"));
+
+ // give them time to react
+ say->SetStartTime(gpGlobals->time + RANDOM_FLOAT(0.3f, 0.5f));
+
+ AddStatement(say);
}
+
+#ifdef HOOK_GAMEDLL
+
+void BotAllHostagesGoneMeme::Interpret(CCSBot *sender, CCSBot *receiver) const
+{
+ Interpret_(sender, receiver);
+}
+
+void BotHostageBeingTakenMeme::Interpret(CCSBot *sender, CCSBot *receiver) const
+{
+ Interpret_(sender, receiver);
+}
+
+void BotHelpMeme::Interpret(CCSBot *sender, CCSBot *receiver) const
+{
+ Interpret_(sender, receiver);
+}
+
+void BotBombsiteStatusMeme::Interpret(CCSBot *sender, CCSBot *receiver) const
+{
+ Interpret_(sender, receiver);
+}
+
+void BotBombStatusMeme::Interpret(CCSBot *sender, CCSBot *receiver) const
+{
+ Interpret_(sender, receiver);
+}
+
+void BotFollowMeme::Interpret(CCSBot *sender, CCSBot *receiver) const
+{
+ Interpret_(sender, receiver);
+}
+
+void BotDefendHereMeme::Interpret(CCSBot *sender, CCSBot *receiver) const
+{
+ Interpret_(sender, receiver);
+}
+
+void BotWhereBombMeme::Interpret(CCSBot *sender, CCSBot *receiver) const
+{
+ Interpret_(sender, receiver);
+}
+
+void BotRequestReportMeme::Interpret(CCSBot *sender, CCSBot *receiver) const
+{
+ Interpret_(sender, receiver);
+}
+
+#endif // HOOK_GAMEDLL
diff --git a/regamedll/dlls/bot/cs_bot_chatter.h b/regamedll/dlls/bot/cs_bot_chatter.h
index 1e50e781..8b8f2740 100644
--- a/regamedll/dlls/bot/cs_bot_chatter.h
+++ b/regamedll/dlls/bot/cs_bot_chatter.h
@@ -35,7 +35,7 @@
#define UNDEFINED_COUNT 0xFFFF
#define MAX_PLACES_PER_MAP 64
#define UNDEFINED_SUBJECT (-1)
-#define COUNT_MANY 4
+#define COUNT_MANY 4 // equal to or greater than this is "many"
class CCSBot;
class BotChatterInterface;
@@ -43,27 +43,41 @@ class BotChatterInterface;
typedef unsigned int PlaceCriteria;
typedef unsigned int CountCriteria;
+// A meme is a unit information that bots use to
+// transmit information to each other via the radio
/* <2fe97b> ../cstrike/dlls/bot/cs_bot_chatter.h:42 */
class BotMeme
{
public:
- NOBODY void Transmit(CCSBot *sender) const;
- NOBODY virtual void Interpret(CCSBot *sender, CCSBot *receiver) const = 0;
+ void Transmit(CCSBot *sender) const; // transmit meme to other bots
+ virtual void Interpret(CCSBot *sender, CCSBot *receiver) const = 0; // cause the given bot to act on this meme
};/* size: 4, cachelines: 1, members: 1 */
class BotAllHostagesGoneMeme: public BotMeme
{
public:
- NOBODY virtual void Interpret(CCSBot *sender, CCSBot *receiver) const;
+ virtual void Interpret(CCSBot *sender, CCSBot *receiver) const; // cause the given bot to act on this meme
+
+#ifdef HOOK_GAMEDLL
+
+ void Interpret_(CCSBot *sender, CCSBot *receiver) const;
+
+#endif //HOOK_GAMEDLL
};/* size: 4, cachelines: 1, members: 1 */
class BotHostageBeingTakenMeme: public BotMeme
{
public:
- NOBODY virtual void Interpret(CCSBot *sender, CCSBot *receiver) const;
+ virtual void Interpret(CCSBot *sender, CCSBot *receiver) const; // cause the given bot to act on this meme
+
+#ifdef HOOK_GAMEDLL
+
+ void Interpret_(CCSBot *sender, CCSBot *receiver) const;
+
+#endif //HOOK_GAMEDLL
};/* size: 4, cachelines: 1, members: 1 */
@@ -75,7 +89,14 @@ public:
{
m_place = place;
}
- NOBODY virtual void Interpret(CCSBot *sender, CCSBot *receiver) const;
+ virtual void Interpret(CCSBot *sender, CCSBot *receiver) const; // cause the given bot to act on this meme
+
+#ifdef HOOK_GAMEDLL
+
+ void Interpret_(CCSBot *sender, CCSBot *receiver) const;
+
+#endif //HOOK_GAMEDLL
+
private:
Place m_place;
@@ -85,24 +106,27 @@ private:
class BotBombsiteStatusMeme: public BotMeme
{
public:
- enum StatusType
- {
- CLEAR = 0,
- PLANTED
- };
+ enum StatusType { CLEAR, PLANTED };
+
BotBombsiteStatusMeme(int zoneIndex, StatusType status)
{
m_zoneIndex = zoneIndex;
m_status = status;
}
- NOBODY virtual void Interpret(CCSBot *sender, CCSBot *receiver) const;
+ virtual void Interpret(CCSBot *sender, CCSBot *receiver) const; // cause the given bot to act on this meme
+
+#ifdef HOOK_GAMEDLL
+
+ void Interpret_(CCSBot *sender, CCSBot *receiver) const;
+
+#endif //HOOK_GAMEDLL
+
private:
- int m_zoneIndex;
- StatusType m_status;
+ int m_zoneIndex; // the bombsite
+ StatusType m_status; // whether it is cleared or the bomb is there (planted)
};/* size: 12, cachelines: 1, members: 3 */
-
/* <2ff6de> ../cstrike/dlls/bot/cs_bot_chatter.h:87 */
class BotBombStatusMeme: public BotMeme
{
@@ -112,8 +136,16 @@ public:
m_state = state;
m_pos = pos;
}
+
public:
- NOBODY virtual void Interpret(CCSBot *sender, CCSBot *receiver) const;
+ virtual void Interpret(CCSBot *sender, CCSBot *receiver) const; // cause the given bot to act on this meme
+
+#ifdef HOOK_GAMEDLL
+
+ void Interpret_(CCSBot *sender, CCSBot *receiver) const;
+
+#endif //HOOK_GAMEDLL
+
private:
CSGameState::BombState m_state;
Vector m_pos;
@@ -124,7 +156,13 @@ private:
class BotFollowMeme: public BotMeme
{
public:
- NOBODY virtual void Interpret(CCSBot *sender, CCSBot *receiver) const;
+ virtual void Interpret(CCSBot *sender, CCSBot *receiver) const; // cause the given bot to act on this meme
+
+#ifdef HOOK_GAMEDLL
+
+ void Interpret_(CCSBot *sender, CCSBot *receiver) const;
+
+#endif //HOOK_GAMEDLL
};/* size: 4, cachelines: 1, members: 1 */
@@ -136,7 +174,14 @@ public:
{
m_pos = pos;
}
- NOBODY virtual void Interpret(CCSBot *sender, CCSBot *receiver) const;
+ virtual void Interpret(CCSBot *sender, CCSBot *receiver) const; // cause the given bot to act on this meme
+
+#ifdef HOOK_GAMEDLL
+
+ void Interpret_(CCSBot *sender, CCSBot *receiver) const;
+
+#endif //HOOK_GAMEDLL
+
private:
Vector m_pos;
@@ -146,7 +191,13 @@ private:
class BotWhereBombMeme: public BotMeme
{
public:
- NOBODY virtual void Interpret(CCSBot *sender, CCSBot *receiver) const;
+ virtual void Interpret(CCSBot *sender, CCSBot *receiver) const; // cause the given bot to act on this meme
+
+#ifdef HOOK_GAMEDLL
+
+ void Interpret_(CCSBot *sender, CCSBot *receiver) const;
+
+#endif //HOOK_GAMEDLL
};/* size: 4, cachelines: 1, members: 1 */
@@ -154,13 +205,19 @@ public:
class BotRequestReportMeme: public BotMeme
{
public:
- NOBODY virtual void Interpret(CCSBot *sender, CCSBot *receiver) const;
+ virtual void Interpret(CCSBot *sender, CCSBot *receiver) const; // cause the given bot to act on this meme
+
+#ifdef HOOK_GAMEDLL
+
+ void Interpret_(CCSBot *sender, CCSBot *receiver) const;
+
+#endif //HOOK_GAMEDLL
};/* size: 4, cachelines: 1, members: 1 */
enum BotStatementType
{
- REPORT_VISIBLE_ENEMIES = 0,
+ REPORT_VISIBLE_ENEMIES,
REPORT_ENEMY_ACTION,
REPORT_MY_CURRENT_TASK,
REPORT_MY_INTENTION,
@@ -171,13 +228,17 @@ enum BotStatementType
REPORT_MY_PLAN,
REPORT_INFORMATION,
REPORT_EMOTE,
- REPORT_ACKNOWLEDGE,
+ REPORT_ACKNOWLEDGE, // affirmative or negative
REPORT_ENEMIES_REMAINING,
REPORT_FRIENDLY_FIRE,
REPORT_KILLED_FRIEND,
+ //REPORT_ENEMY_LOST
+
NUM_BOT_STATEMENT_TYPES,
};
+// BotSpeakables are the smallest unit of bot chatter.
+// They represent a specific wav file of a phrase, and the criteria for which it is useful
class BotSpeakable
{
public:
@@ -194,53 +255,45 @@ public:
typedef std::STD_VECTOR BotSpeakableVector;
typedef std::STD_VECTOR BotVoiceBankVector;
+// The BotPhrase class is a collection of Speakables associated with a name, ID, and criteria
class BotPhrase
{
public:
- NOBODY BotPhrase(unsigned int id, bool isPlace);
- NOBODY ~BotPhrase(void);
-
- NOBODY void InitVoiceBank(int bankIndex);
- char *GetSpeakable(int bankIndex, float *duration = NULL) const;
+ char *GetSpeakable(int bankIndex, float *duration = NULL) const; // return a random speakable and its duration in seconds that meets the current criteria
+ // NOTE: Criteria must be set just before the GetSpeakable() call, since they are shared among all bots
void ClearCriteria(void) const;
- void SetPlaceCriteria(PlaceCriteria place) const;
- void SetCountCriteria(CountCriteria count) const;
+ void SetPlaceCriteria(PlaceCriteria place) const; // all returned phrases must have this place criteria
+ void SetCountCriteria(CountCriteria count) const; // all returned phrases must have this count criteria
+
+ const char *GetName(void) const { return m_name; }
+ Place GetID(void) const { return m_id; }
+ GameEventType GetRadioEquivalent(void) const { return m_radioEvent; }
+ bool IsImportant(void) const { return m_isImportant; } // return true if this phrase is part of an important statement
+
+ bool IsPlace(void) const { return m_isPlace; }
+ void Randomize(void); // randomly shuffle the speakable order
+
+#ifndef HOOK_GAMEDLL
+private:
+#endif // HOOK_GAMEDLL
- const char *GetName(void) const
- {
- return m_name;
- }
- Place GetID(void) const
- {
- return m_id;
- }
- GameEventType GetRadioEquivalent(void) const
- {
- return m_radioEvent;
- }
- bool IsImportant(void) const
- {
- return m_isImportant;
- }
- bool IsPlace(void) const
- {
- return m_isPlace;
- }
- NOBODY void Randomize(void);
-//private:
-public:
friend class BotPhraseManager;
+ BotPhrase(unsigned int id, bool isPlace);
+ ~BotPhrase(void);
char *m_name;
Place m_id;
- bool m_isPlace;
+ bool m_isPlace; // true if this is a Place phrase
GameEventType m_radioEvent;
- bool m_isImportant;
- mutable BotVoiceBankVector m_voiceBank;
- std::STD_VECTOR m_count;
- mutable std::STD_VECTOR< int > m_index;
- int m_numVoiceBanks;
+ bool m_isImportant; // mission-critical statement
+
+ mutable BotVoiceBankVector m_voiceBank; // array of voice banks (arrays of speakables)
+ std::STD_VECTOR m_count; // number of speakables
+ mutable std::STD_VECTOR< int > m_index; // index of next speakable to return
+ int m_numVoiceBanks; // number of voice banks that have been initialized
+ void InitVoiceBank(int bankIndex); // sets up the vector of voice banks for the first bankIndex voice banks
+
mutable PlaceCriteria m_placeCriteria;
mutable CountCriteria m_countCriteria;
@@ -271,33 +324,30 @@ inline void BotPhrase::SetCountCriteria(CountCriteria count) const
class BotPhraseManager
{
public:
- NOBODY BotPhraseManager(void);
- NOBODY ~BotPhraseManager(void);
+ BotPhraseManager(void);
+ ~BotPhraseManager(void);
// initialize phrase system from database file for a specific voice bank (0 is the default voice bank)
- NOBODY bool Initialize(const char *filename, int bankIndex);
+ bool Initialize(const char *filename, int bankIndex);
// invoked when round resets
void OnRoundRestart(void);
// invoked when map changes
- NOBODY void OnMapChange(void);
+ void OnMapChange(void);
Place NameToID(const char *name) const;
const char *IDToName(Place id) const;
// given a name, return the associated phrase collection
- NOBODY const BotPhrase *GetPhrase(const char *name) const;
+ const BotPhrase *GetPhrase(const char *name) const;
// given a name, return the associated Place phrase collection
- NOBODY const BotPhrase *GetPlace(const char *name) const;
+ const BotPhrase *GetPlace(const char *name) const;
// given an id, return the associated Place phrase collection
- NOBODY const BotPhrase *GetPlace(PlaceCriteria place) const;
+ const BotPhrase *GetPlace(PlaceCriteria place) const;
- const BotPhraseList *GetPlaceList(void) const
- {
- return &m_placeList;
- }
+ const BotPhraseList *GetPlaceList(void) const { return &m_placeList; }
// return time last statement of given type was emitted by a teammate for the given place
float GetPlaceStatementInterval(Place place) const;
@@ -307,8 +357,6 @@ public:
#ifndef HOOK_GAMEDLL
private:
-#else
-public:
#endif // HOOK_GAMEDLL
int FindPlaceIndex(Place where) const;
@@ -338,12 +386,14 @@ inline int BotPhraseManager::FindPlaceIndex(Place where) const
if (m_placeStatementHistory[i].placeID == where)
return i;
}
+
if (m_placeCount < MAX_PLACES_PER_MAP)
{
m_placeStatementHistory[++m_placeCount].placeID = where;
m_placeStatementHistory[++m_placeCount].timer.Invalidate();
- return m_placeCount-1;
+ return m_placeCount - 1;
}
+
return -1;
}
@@ -365,6 +415,7 @@ inline float BotPhraseManager::GetPlaceStatementInterval(Place place) const
inline void BotPhraseManager::ResetPlaceStatementInterval(Place place) const
{
int index = FindPlaceIndex(place);
+
if (index < 0)
return;
@@ -374,56 +425,38 @@ inline void BotPhraseManager::ResetPlaceStatementInterval(Place place) const
m_placeStatementHistory[index].timer.Reset();
}
+// Statements are meaningful collections of phrases
class BotStatement
{
public:
- NOBODY BotStatement(BotChatterInterface *chatter, BotStatementType type, float expireDuration);
- NOBODY ~BotStatement(void);
+ BotStatement(BotChatterInterface *chatter, BotStatementType type, float expireDuration);
+ ~BotStatement(void);
+
public:
- BotChatterInterface *GetChatter(void) const
- {
- return m_chatter;
- }
- NOBODY CCSBot *GetOwner(void) const;
- BotStatementType GetType(void) const
- {
- return m_type;
- }
- NOBODY bool IsImportant(void) const;
- bool HasSubject(void) const
- {
- return (m_subject != UNDEFINED_SUBJECT);
- }
- void SetSubject(int playerID)
- {
- m_subject = playerID;
- }
- int GetSubject(void) const
- {
- return m_subject;
- }
- bool HasPlace(void) const
- {
- return (GetPlace()) ? true : false;
- }
- NOBODY Place GetPlace(void) const;
- void SetPlace(Place where)
- {
- m_place = where;
- }
- NOBODY bool HasCount(void) const;
- NOBODY bool IsRedundant(const BotStatement *say) const;
- NOBODY bool IsObsolete(void) const;
- NOBODY void Convert(const BotStatement *say);
- NOBODY void AppendPhrase(const BotPhrase *phrase);
- void SetStartTime(float timestamp)
- {
- m_startTime = timestamp;
- }
- float GetStartTime(void) const
- {
- return m_startTime;
- }
+ BotChatterInterface *GetChatter(void) const { return m_chatter; }
+ CCSBot *GetOwner(void) const;
+
+ BotStatementType GetType(void) const { return m_type; } // return the type of statement this is
+ bool IsImportant(void) const; // return true if this statement is "important" and not personality chatter
+
+ bool HasSubject(void) const { return (m_subject != UNDEFINED_SUBJECT); }
+ void SetSubject(int playerID) { m_subject = playerID; } // who this statement is about
+ int GetSubject(void) const { return m_subject; } // who this statement is about
+
+ bool HasPlace(void) const { return (GetPlace()) ? true : false; }
+ Place GetPlace(void) const; // if this statement refers to a specific place, return that place
+ void SetPlace(Place where) { m_place = where; } // explicitly set place
+
+ bool HasCount(void) const; // return true if this statement has an associated count
+
+ bool IsRedundant(const BotStatement *say) const; // return true if this statement is the same as the given one
+ bool IsObsolete(void) const; // return true if this statement is no longer appropriate to say
+ void Convert(const BotStatement *say); // possibly change what were going to say base on what teammate is saying
+
+ void AppendPhrase(const BotPhrase *phrase);
+
+ void SetStartTime(float timestamp) { m_startTime = timestamp; } // define the earliest time this statement can be spoken
+ float GetStartTime(void) const { return m_startTime; }
enum ConditionType
{
@@ -433,8 +466,8 @@ public:
NUM_CONDITIONS,
};
- NOBODY void AddCondition(ConditionType condition);
- NOBODY bool IsValid(void) const;
+ void AddCondition(ConditionType condition); // conditions must be true for the statement to be spoken
+ bool IsValid(void) const; // verify all attached conditions
enum ContextType
{
@@ -444,34 +477,33 @@ public:
LONG_DELAY,
ACCUMULATE_ENEMIES_DELAY,
};
- NOBODY void AppendPhrase(ContextType contextPhrase);
+ void AppendPhrase(ContextType contextPhrase); // special phrases that depend on the context
+
+ bool Update(void); // emit statement over time, return false if statement is done
+ bool IsSpeaking(void) const { return m_isSpeaking; } // return true if this statement is currently being spoken
+ float GetTimestamp(void) const { return m_timestamp; } // get time statement was created (but not necessarily started talking)
+
+ void AttachMeme(BotMeme *meme); // attach a meme to this statement, to be transmitted to other friendly bots when spoken
- NOBODY bool Update(void);
- NOBODY bool IsSpeaking(void) const
- {
- return m_isSpeaking;
- }
- NOBODY float GetTimestamp(void) const
- {
- return m_timestamp;
- }
- NOBODY void AttachMeme(BotMeme *meme);
public:
friend class BotChatterInterface;
- BotChatterInterface *m_chatter;
- BotStatement *m_next;
- BotStatement *m_prev;
- BotStatementType m_type;
- int m_subject;
- Place m_place;
- BotMeme *m_meme;
- float m_timestamp;
- float m_startTime;
- float m_expireTime;
- float m_speakTimestamp;
- bool m_isSpeaking;
- float m_nextTime;
+ BotChatterInterface *m_chatter; // the chatter system this statement is part of
+
+ BotStatement *m_next, *m_prev; // linked list hooks
+
+ BotStatementType m_type; // what kind of statement this is
+ int m_subject; // who this subject is about
+ Place m_place; // explicit place - note some phrases have implicit places as well
+ BotMeme *m_meme; // a statement can only have a single meme for now
+
+ float m_timestamp; // time when message was created
+ float m_startTime; // the earliest time this statement can be spoken
+ float m_expireTime; // time when this statement is no longer valid
+ float m_speakTimestamp; // time when message began being spoken
+ bool m_isSpeaking; // true if this statement is current being spoken
+
+ float m_nextTime; // time for next phrase to begin
enum { MAX_BOT_PHRASES = 4 };
struct
@@ -482,115 +514,124 @@ public:
const BotPhrase *phrase;
ContextType context;
};
- } m_statement[ MAX_BOT_PHRASES ];
+
+ }
+ m_statement[ MAX_BOT_PHRASES ];
enum { MAX_BOT_CONDITIONS = 4 };
-
- ConditionType m_condition[ MAX_BOT_CONDITIONS ];
+ ConditionType m_condition[ MAX_BOT_CONDITIONS ]; // conditions that must be true for the statement to be said
int m_conditionCount;
- int m_index;
+
+ int m_index; // m_index refers to the phrase currently being spoken, or -1 if we havent started yet
int m_count;
+
};/* size: 112, cachelines: 2, members: 18 */
+// This class defines the interface to the bot radio chatter system
class BotChatterInterface
{
public:
BotChatterInterface(void) {};
- NOBODY BotChatterInterface(CCSBot *me);
- NOBODY ~BotChatterInterface();
+ BotChatterInterface(CCSBot *me);
+ ~BotChatterInterface();
- NOBODY void Reset(void);
- NOBODY void Update(void);
+ void Reset(void); // reset to initial state
+ void Update(void); // process ongoing chatter
- NOBODY void OnEvent(GameEventType event, CBaseEntity *entity, CBaseEntity *other);
- NOBODY void OnDeath(void);
+ void OnEvent(GameEventType event, CBaseEntity *entity, CBaseEntity *other); // invoked when event occurs in the game (some events have NULL entities)
+ void OnDeath(void); // invoked when we die
enum VerbosityType
{
- NORMAL,
- MINIMAL,
- RADIO,
- OFF,
+ NORMAL, // full chatter
+ MINIMAL, // only scenario-critical events
+ RADIO, // use the standard radio instead
+ OFF // no chatter at all
};
+ VerbosityType GetVerbosity(void) const; // return our current level of verbosity
- VerbosityType GetVerbosity(void) const;
- NOBODY CCSBot *GetOwner(void) const
- {
- return m_me;
- }
- bool IsTalking(void) const;
- NOBODY float GetRadioSilenceDuration(void);
- NOBODY void ResetRadioSilenceDuration(void);
+ CCSBot *GetOwner(void) const { return m_me; }
+ bool IsTalking(void) const; // return true if we are currently talking
+ float GetRadioSilenceDuration(void); // return time since any teammate said anything
+ void ResetRadioSilenceDuration(void);
enum { MUST_ADD = 1 };
+ void AddStatement(BotStatement *statement, bool mustAdd = false); // register a statement for speaking
+ void RemoveStatement(BotStatement *statement); // remove a statement
- NOBODY void AddStatement(BotStatement *statement, bool mustAdd = false);
- NOBODY void RemoveStatement(BotStatement *statement);
+ BotStatement *GetActiveStatement(void); // returns the statement that is being spoken, or is next to be spoken if no-one is speaking now
+ BotStatement *GetStatement(void) const; // returns our current statement, or NULL if we aren't speaking
- NOBODY BotStatement *GetActiveStatement(void);
- BotStatement *GetStatement(void) const;
-
- int GetPitch(void) const
- {
- return m_pitch;
- }
+ int GetPitch(void) const { return m_pitch; }
+ // things the bots can say
void Say(const char *phraseName, float lifetime = 3.0f, float delay = 0.0f);
- NOBODY void AnnouncePlan(const char *phraseName, Place place);
- NOBODY void Affirmative(void);
- NOBODY void Negative(void);
+ void AnnouncePlan(const char *phraseName, Place place);
+ void Affirmative(void);
+ void Negative(void);
- NOBODY void EnemySpotted(void);
- NOBODY void KilledMyEnemy(int victimID);
- NOBODY void EnemiesRemaining(void);
+ void EnemySpotted(void); // report enemy sightings
+ void KilledMyEnemy(int victimID);
+ void EnemiesRemaining(void);
- NOBODY void Clear(Place place);
- NOBODY void ReportIn(void);
- NOBODY void ReportingIn(void);
- NOBODY bool NeedBackup(void);
- NOBODY void PinnedDown(void);
- NOBODY void Scared(void);
- NOBODY void HeardNoise(const Vector *pos);
- NOBODY void TheyPickedUpTheBomb(void);
- NOBODY void GoingToPlantTheBomb(Place place);
- NOBODY void BombsiteClear(int zoneIndex);
- NOBODY void FoundPlantedBomb(int zoneIndex);
- NOBODY void PlantingTheBomb(Place place);
- NOBODY void SpottedBomber(CBasePlayer *bomber);
- NOBODY void SpottedLooseBomb(CBaseEntity *bomb);
- NOBODY void GuardingLooseBomb(CBaseEntity *bomb);
- NOBODY void RequestBombLocation(void);
- NOBODY void GuardingHostages(Place place, bool isPlan);
- NOBODY void GuardingHostageEscapeZone(bool isPlan);
- NOBODY void HostagesBeingTaken(void);
- NOBODY void HostagesTaken(void);
- NOBODY void TalkingToHostages(void);
- NOBODY void EscortingHostages(void);
- NOBODY void HostageDown(void);
- NOBODY void CelebrateWin(void);
+ NOXREF void Clear(Place place);
- NOBODY void Encourage(const char *phraseName, float repeatInterval = 10.0f, float lifetime = 3.0f);
- NOBODY void KilledFriend(void);
- NOBODY void FriendlyFire(void);
-public:
- static CountdownTimer m_encourageTimer;
- static IntervalTimer m_radioSilenceInterval[2];
+ void ReportIn(void); // ask for current situation
+ void ReportingIn(void); // report current situation
+
+ bool NeedBackup(void);
+ void PinnedDown(void);
+ void Scared(void);
+ void HeardNoise(const Vector *pos);
+
+ void TheyPickedUpTheBomb(void);
+ void GoingToPlantTheBomb(Place place);
+ void BombsiteClear(int zoneIndex);
+ void FoundPlantedBomb(int zoneIndex);
+ void PlantingTheBomb(Place place);
+ void SpottedBomber(CBasePlayer *bomber);
+ void SpottedLooseBomb(CBaseEntity *bomb);
+ NOXREF void GuardingLooseBomb(CBaseEntity *bomb);
+ void RequestBombLocation(void);
+
+ void GuardingHostages(Place place, bool isPlan);
+ void GuardingHostageEscapeZone(bool isPlan);
+ void HostagesBeingTaken(void);
+ void HostagesTaken(void);
+ void TalkingToHostages(void);
+ void EscortingHostages(void);
+ NOXREF void HostageDown(void);
+
+ void CelebrateWin(void);
+
+ void Encourage(const char *phraseName, float repeatInterval = 10.0f, float lifetime = 3.0f); // "encourage" the player to do the scenario
+
+ void KilledFriend(void);
+ void FriendlyFire(void);
+
+ bool SeesAtLeastOneEnemy(void) const { return m_seeAtLeastOneEnemy; }
+
+#ifndef HOOK_GAMEDLL
private:
+#endif // HOOK_GAMEDLL
- NOBODY void ReportEnemies(void);
- NOBODY bool ShouldSpeak(void) const;
+ BotStatement *m_statementList; // list of all active/pending messages for this bot
+ void ReportEnemies(void); // track nearby enemy count and generate enemy activity statements
+ bool ShouldSpeak(void) const; // return true if we speaking makes sense now
- BotStatement *m_statementList;
- CCSBot *m_me;
+ CCSBot *m_me; // the bot this chatter is for
bool m_seeAtLeastOneEnemy;
float m_timeWhenSawFirstEnemy;
bool m_reportedEnemies;
- bool m_requestedBombLocation;
+ bool m_requestedBombLocation; // true if we already asked where the bomb has been planted
+
int m_pitch;
+ static IntervalTimer IMPL(m_radioSilenceInterval)[2]; // one timer for each team
+
IntervalTimer m_needBackupInterval;
IntervalTimer m_spottedBomberInterval;
IntervalTimer m_scaredInterval;
@@ -598,6 +639,8 @@ private:
CountdownTimer m_spottedLooseBombTimer;
CountdownTimer m_heardNoiseTimer;
CountdownTimer m_escortingHostageTimer;
+ static CountdownTimer IMPL(m_encourageTimer); // timer to know when we can "encourage" the human player again - shared by all bots
+
};/* size: 64, cachelines: 1, members: 16 */
/* <2fec2d> ../cstrike/dlls/bot/cs_bot_chatter.h:572 */
@@ -623,8 +666,11 @@ inline BotChatterInterface::VerbosityType BotChatterInterface::GetVerbosity(void
/* <2fec4a> ../cstrike/dlls/bot/cs_bot_chatter.h:590 */
inline bool BotChatterInterface::IsTalking(void) const
{
- if (m_statementList)
+ if (m_statementList != NULL)
+ {
return m_statementList->IsSpeaking();
+ }
+
return false;
}
@@ -647,14 +693,14 @@ extern CBaseEntity *g_pSelectedZombieSpawn;
/* <5c4dcf> ../cstrike/dlls/bot/cs_bot_chatter.h:604 */
inline void BotChatterInterface::Say(const char *phraseName, float lifetime, float delay)
{
- /*BotStatement *say = new BotStatement(this, REPORT_MY_INTENTION, lifetime);
+ BotStatement *say = new BotStatement(this, REPORT_MY_INTENTION, lifetime);
say->AppendPhrase(TheBotPhrases->GetPhrase(phraseName));
if (delay > 0.0f)
- say->SetStartTime(gpGlobals->curtime + delay);
+ say->SetStartTime(gpGlobals->time + delay);
- AddStatement(say);*/
+ AddStatement(say);
}
const Vector *GetRandomSpotAtPlace(Place place);
@@ -664,12 +710,12 @@ const Vector *GetRandomSpotAtPlace(Place place);
typedef void (BotStatement::*APPEND_PHRASE_CONTEXT)(BotStatement::ContextType);
typedef void (BotStatement::*APPEND_PHRASE_BOTPHRASE)(const BotPhrase *);
-typedef const BotPhraseManager *(BotPhraseManager::*GET_PLACE_NAME)(const char *name) const;
-typedef const BotPhraseManager *(BotPhraseManager::*GET_PLACE_PLACE)(PlaceCriteria place) const;
-
-#endif // HOOK_GAMEDLL
+typedef const BotPhrase *(BotPhraseManager::*GET_PLACE_NAME)(const char *name) const;
+typedef const BotPhrase *(BotPhraseManager::*GET_PLACE_PLACE)(PlaceCriteria place) const;
// refs
extern void (*pBotPhrase__Randomize)(void);
+#endif // HOOK_GAMEDLL
+
#endif // CS_BOT_CHATTER_H
diff --git a/regamedll/dlls/bot/cs_bot_event.cpp b/regamedll/dlls/bot/cs_bot_event.cpp
index 1da7d58b..93989686 100644
--- a/regamedll/dlls/bot/cs_bot_event.cpp
+++ b/regamedll/dlls/bot/cs_bot_event.cpp
@@ -1,7 +1,7 @@
#include "precompiled.h"
/* <31d087> ../cstrike/dlls/bot/cs_bot_event.cpp:22 */
-void CCSBot::__MAKE_VHOOK(OnEvent)(GameEventType event, CBaseEntity *entity, CBaseEntity *other)
+NOBODY void CCSBot::__MAKE_VHOOK(OnEvent)(GameEventType event, CBaseEntity *entity, CBaseEntity *other)
{
// {
// class CCSBotManager *ctrl; // 63
diff --git a/regamedll/dlls/bot/cs_bot_init.cpp b/regamedll/dlls/bot/cs_bot_init.cpp
index 8750b1b2..fd0e225f 100644
--- a/regamedll/dlls/bot/cs_bot_init.cpp
+++ b/regamedll/dlls/bot/cs_bot_init.cpp
@@ -1,7 +1,76 @@
#include "precompiled.h"
+/*
+* Globals initialization
+*/
+#ifndef HOOK_GAMEDLL
+
+cvar_t cv_bot_traceview = { "bot_traceview", "0", FCVAR_SERVER, 0.0f, NULL };
+cvar_t cv_bot_stop = { "bot_stop", "0", FCVAR_SERVER, 0.0f, NULL };
+cvar_t cv_bot_show_nav = { "bot_show_nav", "0", FCVAR_SERVER, 0.0f, NULL };
+cvar_t cv_bot_show_danger = { "bot_show_danger", "0", FCVAR_SERVER, 0.0f, NULL };
+cvar_t cv_bot_nav_edit = { "bot_nav_edit", "0", FCVAR_SERVER, 0.0f, NULL };
+cvar_t cv_bot_nav_zdraw = { "bot_nav_zdraw", "4", FCVAR_SERVER, 0.0f, NULL };
+cvar_t cv_bot_walk = { "bot_walk", "0", FCVAR_SERVER, 0.0f, NULL };
+cvar_t cv_bot_difficulty = { "bot_difficulty", "0", FCVAR_SERVER, 0.0f, NULL };
+cvar_t cv_bot_debug = { "bot_debug", "0", FCVAR_SERVER, 0.0f, NULL };
+cvar_t cv_bot_quicksave = { "bot_quicksave", "0", FCVAR_SERVER, 0.0f, NULL };
+cvar_t cv_bot_quota = { "bot_quota", "0", FCVAR_SERVER, 0.0f, NULL };
+cvar_t cv_bot_quota_match = { "bot_quota_match", "0", FCVAR_SERVER, 0.0f, NULL };
+cvar_t cv_bot_prefix = { "bot_prefix", "", FCVAR_SERVER, 0.0f, NULL };
+cvar_t cv_bot_allow_rogues = { "bot_allow_rogues", "1", FCVAR_SERVER, 0.0f, NULL };
+cvar_t cv_bot_allow_pistols = { "bot_allow_pistols", "1", FCVAR_SERVER, 0.0f, NULL };
+cvar_t cv_bot_allow_shotguns = { "bot_allow_shotguns", "1", FCVAR_SERVER, 0.0f, NULL };
+cvar_t cv_bot_allow_sub_machine_guns = { "bot_allow_sub_machine_guns", "1", FCVAR_SERVER, 0.0f, NULL };
+cvar_t cv_bot_allow_rifles = { "bot_allow_rifles", "1", FCVAR_SERVER, 0.0f, NULL };
+cvar_t cv_bot_allow_machine_guns = { "bot_allow_machine_guns", "1", FCVAR_SERVER, 0.0f, NULL };
+cvar_t cv_bot_allow_grenades = { "bot_allow_grenades", "1", FCVAR_SERVER, 0.0f, NULL };
+cvar_t cv_bot_allow_snipers = { "bot_allow_snipers", "1", FCVAR_SERVER, 0.0f, NULL };
+cvar_t cv_bot_allow_shield = { "bot_allow_shield", "1", FCVAR_SERVER, 0.0f, NULL };
+cvar_t cv_bot_join_team = { "bot_join_team", "any", FCVAR_SERVER, 0.0f, NULL };
+cvar_t cv_bot_join_after_player = { "bot_join_after_player", "1", FCVAR_SERVER, 0.0f, NULL };
+cvar_t cv_bot_auto_vacate = { "bot_auto_vacate", "1", FCVAR_SERVER, 0.0f, NULL };
+cvar_t cv_bot_zombie = { "bot_zombie", "0", FCVAR_SERVER, 0.0f, NULL };
+cvar_t cv_bot_defer_to_human = { "bot_defer_to_human", "0", FCVAR_SERVER, 0.0f, NULL };
+cvar_t cv_bot_chatter = { "bot_chatter", "normal", FCVAR_SERVER, 0.0f, NULL };
+cvar_t cv_bot_profile_db = { "bot_profile_db", "BotProfile.db", FCVAR_SERVER, 0.0f, NULL };
+
+#else // HOOK_GAMEDLL
+
+cvar_t cv_bot_traceview;
+cvar_t cv_bot_stop;
+cvar_t cv_bot_show_nav;
+cvar_t cv_bot_show_danger;
+cvar_t cv_bot_nav_edit;
+cvar_t cv_bot_nav_zdraw;
+cvar_t cv_bot_walk;
+cvar_t cv_bot_difficulty;
+cvar_t cv_bot_debug;
+cvar_t cv_bot_quicksave;
+cvar_t cv_bot_quota;
+cvar_t cv_bot_quota_match;
+cvar_t cv_bot_prefix;
+cvar_t cv_bot_allow_rogues;
+cvar_t cv_bot_allow_pistols;
+cvar_t cv_bot_allow_shotguns;
+cvar_t cv_bot_allow_sub_machine_guns;
+cvar_t cv_bot_allow_rifles;
+cvar_t cv_bot_allow_machine_guns;
+cvar_t cv_bot_allow_grenades;
+cvar_t cv_bot_allow_snipers;
+cvar_t cv_bot_allow_shield;
+cvar_t cv_bot_join_team;
+cvar_t cv_bot_join_after_player;
+cvar_t cv_bot_auto_vacate;
+cvar_t cv_bot_zombie;
+cvar_t cv_bot_defer_to_human;
+cvar_t cv_bot_chatter;
+cvar_t cv_bot_profile_db;
+
+#endif // HOOK_GAMEDLL
+
/* <333bca> ../cstrike/dlls/bot/cs_bot_init.cpp:57 */
-NOBODY void InstallBotControl(void)
+void InstallBotControl(void)
{
if (TheBots != NULL)
{
@@ -11,6 +80,8 @@ NOBODY void InstallBotControl(void)
TheBots = new CCSBotManager;
}
+// Engine callback for custom server commands
+
/* <333cb3> ../cstrike/dlls/bot/cs_bot_init.cpp:68 */
void Bot_ServerCommand(void)
{
@@ -58,52 +129,35 @@ void Bot_RegisterCvars(void)
}
}
+// Constructor
+
/* <333d1e> ../cstrike/dlls/bot/cs_bot_init.cpp:129 */
-//CCSBot::CCSBot(void)
-//{
-// CountdownTimer(CountdownTimer *const this); // 129
-// IdleState(IdleState *const this); // 129
-// MoveToState(MoveToState *const this); // 129
-// HuntState(HuntState *const this); // 129
-// FetchBombState(FetchBombState *const this); // 129
-// AttackState(AttackState *const this); // 129
-// InvestigateNoiseState(InvestigateNoiseState *const this); // 129
-// BuyState(BuyState *const this); // 129
-// PlantBombState(PlantBombState *const this); // 129
-// DefuseBombState(DefuseBombState *const this); // 129
-// HideState(HideState *const this); // 129
-// EscapeFromBombState(EscapeFromBombState *const this); // 129
-// FollowState(FollowState *const this); // 129
-// UseEntityState(UseEntityState *const this); // 129
-// CountdownTimer(CountdownTimer *const this); // 129
-// CountdownTimer(CountdownTimer *const this); // 129
-// CountdownTimer(CountdownTimer *const this); // 129
-// CountdownTimer(CountdownTimer *const this); // 129
-// CountdownTimer(CountdownTimer *const this); // 129
-// CountdownTimer(CountdownTimer *const this); // 129
-// CountdownTimer(CountdownTimer *const this); // 129
-// CountdownTimer(CountdownTimer *const this); // 129
-// CountdownTimer(CountdownTimer *const this); // 129
-// IntervalTimer(IntervalTimer *const this); // 129
-// _List_iterator(_List_iterator *const this); // 129
-// CountdownTimer(CountdownTimer *const this); // 129
-// CountdownTimer(CountdownTimer *const this); // 129
-// CountdownTimer(CountdownTimer *const this); // 129
-//}
+CCSBot::CCSBot(void) : m_chatter(this), m_gameState(this)
+{
+ ;
+}
+
+// Prepare bot for action
/* <3342ac> ../cstrike/dlls/bot/cs_bot_init.cpp:137 */
-NOBODY bool CCSBot::__MAKE_VHOOK(Initialize)(const BotProfile *profile)
+bool CCSBot::__MAKE_VHOOK(Initialize)(const BotProfile *profile)
{
+ // extend
CBot::Initialize(profile);
+ // CS bot initialization
m_diedLastRound = false;
- m_morale = POSITIVE;
+ m_morale = POSITIVE; // starting a new round makes everyone a little happy
+
+ m_combatRange = RANDOM_FLOAT(325, 425);
+
m_navNodeList = NULL;
m_currentNode = NULL;
- m_combatRange = RANDOM_FLOAT(325, 425);
- m_name[0] = '\0';
- m_safeTime = m_profile->GetAggression() * 5 + 15;
+ // set initial safe time guess for this map
+ m_safeTime = 15.0f + 5.0f * GetProfile()->GetAggression();
+
+ m_name[0] = '\000';
ResetValues();
StartNormalProcess();
@@ -111,18 +165,13 @@ NOBODY bool CCSBot::__MAKE_VHOOK(Initialize)(const BotProfile *profile)
return true;
}
-void (*pCCSBot__ResetValues)(void);
+// Reset internal data to initial state
/* <3341dc> ../cstrike/dlls/bot/cs_bot_init.cpp:167 */
-NOBODY void __declspec(naked) CCSBot::ResetValues(void)
+void CCSBot::ResetValues(void)
{
- __asm
- {
- jmp pCCSBot__ResetValues
- }
-/*
- m_chatter.Reset();//TODO: Reverse me
- m_gameState.Reset();//TODO: Reverse me
+ m_chatter.Reset();
+ m_gameState.Reset();
m_avoid = NULL;
m_avoidTimestamp = 0.0f;
@@ -136,28 +185,28 @@ NOBODY void __declspec(naked) CCSBot::ResetValues(void)
m_pathLength = 0;
m_pathIndex = 0;
-
m_areaEnteredTimestamp = 0.0f;
m_currentArea = NULL;
m_lastKnownArea = NULL;
m_avoidFriendTimer.Invalidate();
-
m_isFriendInTheWay = false;
m_isWaitingBehindFriend = false;
+
m_disposition = ENGAGE_AND_INVESTIGATE;
m_enemy = NULL;
+
m_isWaitingToTossGrenade = false;
m_wasSafe = true;
+
m_nearbyEnemyCount = 0;
m_enemyPlace = 0;
m_nearbyFriendCount = 0;
-
m_closestVisibleFriend = NULL;
m_closestVisibleHumanFriend = NULL;
- for (int w = 0; w < ARRAYSIZE(m_watchInfo); w++)
+ for (int w = 0; w < ARRAYSIZE(m_watchInfo); ++w)
{
m_watchInfo[w].timestamp = 0.0f;
m_watchInfo[w].isEnemy = false;
@@ -165,24 +214,20 @@ NOBODY void __declspec(naked) CCSBot::ResetValues(void)
m_isEnemyVisible = false;
m_visibleEnemyParts = NONE;
-
m_lastSawEnemyTimestamp = 0.0f;
m_firstSawEnemyTimestamp = 0.0f;
m_currentEnemyAcquireTimestamp = 0.0f;
-
m_isLastEnemyDead = true;
-
m_attacker = NULL;
m_attackedTimestamp = 0.0f;
m_enemyDeathTimestamp = 0.0f;
m_lastVictimID = 0;
m_isAimingAtEnemy = false;
-
m_fireWeaponTimestamp = 0.0f;
m_equipTimer.Invalidate();
+
m_isFollowing = false;
m_leader = NULL;
-
m_followTimestamp = 0.0f;
m_allowAutoFollowTime = 0.0f;
@@ -193,47 +238,40 @@ NOBODY void __declspec(naked) CCSBot::ResetValues(void)
m_lookAroundStateTimestamp = 0.0f;
m_inhibitLookAroundTimestamp = 0.0f;
+
m_lookPitch = 0.0f;
m_lookPitchVel = 0.0f;
m_lookYaw = 0.0f;
m_lookYawVel = 0.0f;
+
m_aimOffsetTimestamp = 0.0f;
m_aimSpreadTimestamp = 0.0f;
-
m_lookAtSpotState = NOT_LOOKING_AT_SPOT;
- m_spotEncounter = NULL;
+ m_spotEncounter = NULL;
m_spotCheckTimestamp = 0.0f;
m_peripheralTimestamp = 0.0f;
m_avgVelIndex = 0;
m_avgVelCount = 0;
- if (pev)
- {
- m_lastOrigin = pev->origin;
- }
- else
- m_lastOrigin = Vector(0, 0, 0);
+ m_lastOrigin = (pev != NULL) ? pev->origin : Vector(0, 0, 0);
m_lastRadioCommand = EVENT_INVALID;
-
m_lastRadioRecievedTimestamp = 0.0f;
m_lastRadioSentTimestamp = 0.0f;
m_radioSubject = NULL;
-
- m_noisePosition = Vector(0, 0, 0);
- m_noiseTimestamp = 0.0f;
- m_noiseCheckTimestamp = 0.0f;
-
m_voiceFeedbackEndTimestamp = 0.0f;
m_hostageEscortCount = 0;
m_hostageEscortCountTimestamp = 0.0f;
+ m_noisePosition = Vector(0, 0, 0);
+ m_noiseTimestamp = 0.0f;
+ m_noiseCheckTimestamp = 0.0f;
m_isNoiseTravelRangeChecked = false;
- m_stateTimestamp = 0.0f;
+ m_stateTimestamp = 0.0f;
m_task = SEEK_AND_DESTROY;
m_taskEntity = NULL;
@@ -245,38 +283,49 @@ NOBODY void __declspec(naked) CCSBot::ResetValues(void)
StandUp();
Run();
-
- m_pathLadder = NULL;
m_mustRunTimer.Invalidate();
m_repathTimer.Invalidate();
+ m_pathLadder = NULL;
m_huntState.ClearHuntArea();
// adjust morale - if we died, our morale decreased,
// but if we live, no adjustement (round win/loss also adjusts morale
if (m_diedLastRound)
- {
DecreaseMorale();
- }
m_diedLastRound = false;
+
+ // IsRogue() randomly changes this
m_isRogue = false;
m_surpriseDelay = 0.0f;
m_surpriseTimestamp = 0.0f;
+ // even though these are EHANDLEs, they need to be NULL-ed
m_goalEntity = NULL;
m_avoid = NULL;
m_enemy = NULL;
+#ifdef REGAMEDLL_FIXES
+ for (int i = 0; i < MAX_ENEMY_QUEUE; ++i)
+ {
+ m_enemyQueue[i].player = NULL;
+ m_enemyQueue[i].isReloading = false;
+ m_enemyQueue[i].isProtectedByShield = false;
+ }
+#endif // REGAMEDLL_FIXES
+
// start in idle state
- StopAttacking();//TODO: Reverse me
- Idle();//TODO: Reverse me
-*/
+ StopAttacking();
+ Idle();
}
+// Called when bot is placed in map, and when bots are reset after a round ends.
+// NOTE: For some reason, this can be called twice when a bot is added.
+
/* <3342e4> ../cstrike/dlls/bot/cs_bot_init.cpp:336 */
-NOBODY void CCSBot::__MAKE_VHOOK(SpawnBot)(void)
+void CCSBot::__MAKE_VHOOK(SpawnBot)(void)
{
CCSBotManager *ctrl = TheCSBots();
@@ -288,7 +337,7 @@ NOBODY void CCSBot::__MAKE_VHOOK(SpawnBot)(void)
SetState(&m_buyState);
SetTouch(&CCSBot::BotTouch);
- if (!TheNavAreaList.empty() && !ctrl->IsLearningMap())
+ if (TheNavAreaList.empty() && !ctrl->IsLearningMap())
{
ctrl->SetLearningMapFlag();
StartLearnProcess();
@@ -296,8 +345,11 @@ NOBODY void CCSBot::__MAKE_VHOOK(SpawnBot)(void)
}
/* <3338f7> ../cstrike/dlls/bot/cs_bot_init.cpp:366 */
-NOBODY void CCSBot::__MAKE_VHOOK(RoundRespawn)(void)
+void CCSBot::__MAKE_VHOOK(RoundRespawn)(void)
{
+ // do the normal player spawn process
+ CBasePlayer::RoundRespawn();
+ EndVoiceFeedback();
}
/* <334332> ../cstrike/dlls/bot/cs_bot_init.cpp:378 */
@@ -305,11 +357,9 @@ void CCSBot::Disconnect(void)
{
EndVoiceFeedback();
- if (m_processMode)
+ if (m_processMode != PROCESS_NORMAL)
{
- MESSAGE_BEGIN(MSG_ALL, gmsgBotProgress);
- WRITE_BYTE(FLAG_PROGRESS_HIDE);
- MESSAGE_END();
+ hideProgressMeter();
}
}
diff --git a/regamedll/dlls/bot/cs_bot_learn.cpp b/regamedll/dlls/bot/cs_bot_learn.cpp
index cfde323a..1055a689 100644
--- a/regamedll/dlls/bot/cs_bot_learn.cpp
+++ b/regamedll/dlls/bot/cs_bot_learn.cpp
@@ -1,64 +1,126 @@
#include "precompiled.h"
-/*
-* Globals initialization
-*/
-#ifndef HOOK_GAMEDLL
-
-const float updateTimesliceDuration = 0.0f;
-
-#else
-
-const float updateTimesliceDuration = 0.0;//TODO: what value?? check it.
-
-#endif // HOOK_GAMEDLL
+const float updateTimesliceDuration = 0.5f;
int _navAreaCount;
int _currentIndex;
/* <343cbe> ../cstrike/dlls/bot/cs_bot_learn.cpp:95 */
-NOBODY inline class CNavNode *LadderEndSearch(CBaseEntity *entity, const Vector *pos, NavDirType mountDir)
+inline CNavNode *LadderEndSearch(CBaseEntity *entity, const Vector *pos, NavDirType mountDir)
{
-// {
-// Vector center; // 97
-// {
-// int d; // 103
-// {
-// Vector tryPos; // 105
-// Vector tryNormal; // 118
-// float const fudge; // 123
-// TraceResult result; // 124
-// }
-// }
-// }
+ Vector center = *pos;
+ AddDirectionVector(¢er, mountDir, HalfHumanWidth);
+
+ // Test the ladder dismount point first, then each cardinal direction one and two steps away
+
+ for (int d = (-1); d < 2 * NUM_DIRECTIONS; ++d)
+ {
+ Vector tryPos = center;
+
+ if (d >= NUM_DIRECTIONS)
+ AddDirectionVector(&tryPos, (NavDirType)(d - NUM_DIRECTIONS), GenerationStepSize * 2.0f);
+ else if (d >= 0)
+ AddDirectionVector(&tryPos, (NavDirType)d, GenerationStepSize);
+
+ // step up a rung, to ensure adjacent floors are below us
+ tryPos.z += GenerationStepSize;
+ SnapToGrid(&tryPos);
+
+ // adjust height to account for sloping areas
+ Vector tryNormal;
+ if (GetGroundHeight(&tryPos, &tryPos.z, &tryNormal) == false)
+ continue;
+
+ // make sure this point is not on the other side of a wall
+ const float fudge = 2.0f;
+ TraceResult result;
+ UTIL_TraceLine(center + Vector(0, 0, fudge), tryPos + Vector(0, 0, fudge), ignore_monsters, dont_ignore_glass, ENT(entity->pev), &result);
+
+#ifndef REGAMEDLL_FIXES
+ if (result.flFraction != 1.0f)
+ continue;
+#else
+ if (result.flFraction != 1.0f || result.fStartSolid)
+ continue;
+#endif // REGAMEDLL_ADD
+
+ // if no node exists here, create one and continue the search
+ if (CNavNode::GetNode(&tryPos) == NULL)
+ {
+ return new CNavNode(&tryPos, &tryNormal, NULL);
+ }
+ }
+
+ return NULL;
}
/* <343a56> ../cstrike/dlls/bot/cs_bot_learn.cpp:30 */
-NOBODY CNavNode *CCSBot::AddNode(const Vector *destPos, const Vector *normal, NavDirType dir, CNavNode *source)
+CNavNode *CCSBot::AddNode(const Vector *destPos, const Vector *normal, NavDirType dir, CNavNode *source)
{
-// {
-// class CNavNode *node; // 34
-// bool useNew; // 37
-// float const zTolerance; // 48
-// TraceResult result; // 63
-// Vector floor; // 64
-// Vector ceiling; // 64
-// bool crouch; // 65
-// MarkAsVisited(CNavNode *const this,
-// enum NavDirType dir); // 52
-// {
-// float y; // 66
-// {
-// float x; // 68
-// }
-// }
-// SetAttributes(CNavNode *const this,
-// unsigned char bits); // 89
-// }
+ // check if a node exists at this location
+ CNavNode *node = const_cast(CNavNode::GetNode(destPos));
+
+ // if no node exists, create one
+ bool useNew = false;
+ if (node == NULL)
+ {
+ node = new CNavNode(destPos, normal, source);
+ useNew = true;
+ }
+
+ // connect source node to new node
+ source->ConnectTo(node, dir);
+
+ // optimization: if deltaZ changes very little, assume connection is commutative
+ const float zTolerance = 10.0f; // 50.0f;
+ if (fabs(source->GetPosition()->z - destPos->z) < zTolerance)
+ {
+ node->ConnectTo(source, OppositeDirection(dir));
+ node->MarkAsVisited(OppositeDirection(dir));
+ }
+
+ if (useNew)
+ {
+ // new node becomes current node
+ m_currentNode = node;
+ }
+
+ Vector ceiling;
+ Vector floor;
+ TraceResult result;
+
+ bool crouch = false;
+ const float epsilon = 0.1f;
+
+ for (float y = -16.0f; y <= 16.0f + epsilon; y += 16.0f)
+ {
+ for (float x = -16.0f; x <= 16.0f + epsilon; x += 16.0f)
+ {
+ floor = *destPos + Vector(x, y, 5.0f);
+ ceiling = *destPos + Vector(x, y, 72.0f - epsilon);
+
+ UTIL_TraceLine(floor, ceiling, ignore_monsters, dont_ignore_glass, ENT(pev), &result);
+
+ if (result.flFraction != 1.0f)
+ {
+ crouch = true;
+ break;
+ }
+ }
+
+ if (crouch)
+ {
+ node->SetAttributes(NAV_CROUCH);
+ break;
+
+ }
+ }
+
+ return node;
}
/* <343b40> ../cstrike/dlls/bot/cs_bot_learn.cpp:150 */
-NOXREF void drawProgressMeter(float progress, char *title)
+void drawProgressMeter(float progress, char *title)
{
MESSAGE_BEGIN(MSG_ALL, gmsgBotProgress);
WRITE_BYTE(FLAG_PROGRESS_DRAW);
@@ -68,7 +130,7 @@ NOXREF void drawProgressMeter(float progress, char *title)
}
/* <3435ce> ../cstrike/dlls/bot/cs_bot_learn.cpp:159 */
-NOXREF void startProgressMeter(const char *title)
+void startProgressMeter(const char *title)
{
MESSAGE_BEGIN(MSG_ALL, gmsgBotProgress);
WRITE_BYTE(FLAG_PROGRESS_START);
@@ -77,7 +139,7 @@ NOXREF void startProgressMeter(const char *title)
}
/* <3435a8> ../cstrike/dlls/bot/cs_bot_learn.cpp:167 */
-NOXREF void hideProgressMeter(void)
+void hideProgressMeter(void)
{
MESSAGE_BEGIN(MSG_ALL, gmsgBotProgress);
WRITE_BYTE(FLAG_PROGRESS_HIDE);
@@ -85,115 +147,228 @@ NOXREF void hideProgressMeter(void)
}
/* <343b63> ../cstrike/dlls/bot/cs_bot_learn.cpp:182 */
-NOBODY void CCSBot::StartLearnProcess(void)
+void CCSBot::StartLearnProcess(void)
{
-// {
-// Vector pos; // 192
-// Vector normal; // 195
-// startProgressMeter(const char *title); // 184
-// drawProgressMeter(float progress,
-// char *title); // 185
-// Vector(Vector *const this,
-// const Vector &v); // 192
-// SnapToGrid(Vector *pos); // 193
-// StartNormalProcess(CCSBot *const this); // 199
-// }
-
- Vector pos;
- Vector normal;
-
startProgressMeter("#CZero_LearningMap");
drawProgressMeter(0, "#CZero_LearningMap");
+ BuildLadders();
+ Vector normal;
+ Vector pos = pev->origin;
+
+ SnapToGrid(&pos.x);
+ SnapToGrid(&pos.y);
+ if (!GetGroundHeight(&pos, &pos.z, &normal))
+ {
+ CONSOLE_ECHO("ERROR: Start position invalid\n\n");
+ m_processMode = PROCESS_NORMAL;
+
+ return;
+ }
+
+ m_currentNode = new CNavNode(&pos, &normal);
+ m_goalPosition = pev->origin;
+ m_processMode = PROCESS_LEARN;
}
+// Search the world and build a map of possible movements.
+// The algorithm begins at the bot's current location, and does a recursive search
+// outwards, tracking all valid steps and generating a directed graph of CNavNodes.
+// Sample the map one "step" in a cardinal direction to learn the map.
+// Returns true if sampling needs to continue, or false if done.
+
/* <343d37> ../cstrike/dlls/bot/cs_bot_learn.cpp:217 */
-NOBODY bool CCSBot::LearnStep(void)
+bool CCSBot::LearnStep(void)
{
-// {
-// int dir; // 249
-// {
-// float feetOffset; // 256
-// Vector pos; // 259
-// int cx; // 262
-// int cy; // 263
-// TraceResult result; // 283
-// Vector from; // 284
-// Vector to; // 284
-// Vector toNormal; // 289
-// Vector fromOrigin; // 298
-// Vector toOrigin; // 299
-// bool walkable; // 303
-// IsEntityWalkable(entvars_t *entity,
-// unsigned int flags); // 362
-// {
-// float toGround; // 309
-// float fromGround; // 310
-// float epsilon; // 312
-// {
-// Vector delta; // 322
-// float const inc; // 323
-// float along; // 324
-// bool done; // 325
-// float ground; // 326
-// Vector normal; // 327
-// operator-(const Vector *const this,
-// const Vector &v); // 322
-// {
-// Vector p; // 333
-// operator*(const Vector *const this,
-// float fl); // 343
-// operator+(const Vector *const this,
-// const Vector &v); // 343
-// }
-// }
-// }
-// VARS(edict_t *pent); // 362
-// GetFeetZ(const class CCSBot *const this); // 256
-// Vector(Vector *const this,
-// const Vector &v); // 259
-// MarkAsVisited(CNavNode *const this,
-// enum NavDirType dir); // 280
-// operator+(const Vector *const this,
-// const Vector &v); // 294
-// operator+(const Vector *const this,
-// const Vector &v); // 298
-// operator+(const Vector *const this,
-// const Vector &v); // 299
-// {
-// class CNavNode *newNode; // 376
-// AddNode(CCSBot *const this,
-// const Vector *destPos,
-// const Vector *normal,
-// enum NavDirType dir,
-// class CNavNode *source); // 376
-// }
-// }
-// HasVisited(CNavNode *const this,
-// enum NavDirType dir); // 251
-// }
-// {
-// iterator iter; // 225
-// {
-// class CNavLadder *ladder; // 227
-// LadderEndSearch(CBaseEntity *entity,
-// const Vector *pos,
-// enum NavDirType mountDir); // 230
-// LadderEndSearch(CBaseEntity *entity,
-// const Vector *pos,
-// enum NavDirType mountDir); // 234
-// }
-// operator++(_List_iterator *const this); // 225
-// }
+ UNTESTED
+ // take a step
+ while (true)
+ {
+ if (m_currentNode == NULL)
+ {
+ // search is exhausted - continue search from ends of ladders
+ NavLadderList::iterator iter;
+ for (iter = TheNavLadderList.begin(); iter != TheNavLadderList.end(); ++iter)
+ {
+ CNavLadder *ladder = (*iter);
+
+ // check ladder bottom
+ if ((m_currentNode = LadderEndSearch(ladder->m_entity, &ladder->m_bottom, ladder->m_dir)) != 0)
+ break;
+
+ // check ladder top
+ if ((m_currentNode = LadderEndSearch(ladder->m_entity, &ladder->m_top, ladder->m_dir)) != 0)
+ break;
+ }
+
+ if (m_currentNode == NULL)
+ {
+ // all seeds exhausted, sampling complete
+ GenerateNavigationAreaMesh();
+ return false;
+ }
+ }
+
+ // Take a step from this node
+ for (int dir = NORTH; dir < NUM_DIRECTIONS; dir++)
+ {
+ if (!m_currentNode->HasVisited((NavDirType)dir))
+ {
+ float feetOffset = pev->origin.z - GetFeetZ();
+
+ // start at current node position
+ Vector pos = *m_currentNode->GetPosition();
+
+ // snap to grid
+ int cx = SnapToGrid(pos.x);
+ int cy = SnapToGrid(pos.y);
+
+ // attempt to move to adjacent node
+ switch (dir)
+ {
+ case NORTH: cy -= GenerationStepSize; break;
+ case SOUTH: cy += GenerationStepSize; break;
+ case EAST: cx += GenerationStepSize; break;
+ case WEST: cx -= GenerationStepSize; break;
+ }
+
+ pos.x = cx;
+ pos.y = cy;
+
+ m_generationDir = (NavDirType)dir;
+
+ // mark direction as visited
+ m_currentNode->MarkAsVisited(m_generationDir);
+
+ // test if we can move to new position
+ TraceResult result;
+ Vector from, to;
+
+ // modify position to account for change in ground level during step
+ to.x = pos.x;
+ to.y = pos.y;
+ Vector toNormal;
+ if (GetGroundHeight(&pos, &to.z, &toNormal) == false)
+ {
+ return true;
+ }
+
+ from = *m_currentNode->GetPosition();
+
+ Vector fromOrigin = from + Vector(0, 0, feetOffset);
+ Vector toOrigin = to + Vector(0, 0, feetOffset);
+
+ UTIL_SetOrigin(pev, toOrigin);
+ UTIL_TraceLine(fromOrigin, toOrigin, ignore_monsters, dont_ignore_glass, ENT(pev), &result);
+
+ bool walkable;
+
+ if (result.flFraction == 1.0f && !result.fStartSolid)
+ {
+ // the trace didnt hit anything - clear
+ float toGround = to.z;
+ float fromGround = from.z;
+
+ float epsilon = 0.1f;
+
+ // check if ledge is too high to reach or will cause us to fall to our death
+ if (toGround - fromGround > JumpCrouchHeight + epsilon || fromGround - toGround > DeathDrop)
+ {
+ walkable = false;
+ }
+ else
+ {
+ // check surface normals along this step to see if we would cross any impassable slopes
+ Vector delta = to - from;
+ const float inc = 2.0f;
+ float along = inc;
+ bool done = false;
+ float ground;
+ Vector normal;
+
+ walkable = true;
+
+ while (!done)
+ {
+ Vector p;
+
+ // need to guarantee that we test the exact edges
+ if (along >= GenerationStepSize)
+ {
+ p = to;
+ done = true;
+ }
+ else
+ {
+ p = from + delta * (along / GenerationStepSize);
+ }
+
+ if (GetGroundHeight(&p, &ground, &normal) == false)
+ {
+ walkable = false;
+ break;
+ }
+
+ // check for maximum allowed slope
+ if (normal.z < 0.7f)
+ {
+ walkable = false;
+ break;
+ }
+
+ along += inc;
+ }
+ }
+ }
+ // TraceLine hit something...
+ else
+ {
+ if (IsEntityWalkable(VARS(result.pHit), WALK_THRU_EVERYTHING))
+ {
+ walkable = true;
+ }
+ else
+ {
+ walkable = false;
+ }
+ }
+#ifdef REGAMEDLL_FIXES
+ // if we're incrementally generating, don't overlap existing nav areas
+ CNavArea *overlap = TheNavAreaGrid.GetNavArea(&to, HumanHeight);
+ if (overlap != NULL)
+ {
+ walkable = false;
+ }
+#endif // REGAMEDLL_FIXES
+ if (walkable)
+ {
+ // we can move here
+ // create a new navigation node, and update current node pointer
+ CNavNode *newNode = AddNode(&to, &toNormal, m_generationDir, m_currentNode);
+ }
+
+ return true;
+ }
+ }
+
+ // all directions have been searched from this node - pop back to its parent and continue
+ m_currentNode = m_currentNode->GetParent();
+ }
}
/* <34489e> ../cstrike/dlls/bot/cs_bot_learn.cpp:392 */
-NOBODY void CCSBot::UpdateLearnProcess(void)
+void CCSBot::UpdateLearnProcess(void)
{
-// {
-// float startTime; // 394
-// }
+ float startTime = g_engfuncs.pfnTime();
+ while (g_engfuncs.pfnTime() - startTime >= updateTimesliceDuration)
+ {
+ if (LearnStep() == false)
+ {
+ StartAnalyzeAlphaProcess();
+ break;
+ }
+ }
}
/* <344750> ../cstrike/dlls/bot/cs_bot_learn.cpp:409 */
@@ -213,72 +388,114 @@ void CCSBot::StartAnalyzeAlphaProcess(void)
}
/* <34396c> ../cstrike/dlls/bot/cs_bot_learn.cpp:427 */
-NOBODY inline bool CCSBot::AnalyzeAlphaStep(void)
+bool CCSBot::AnalyzeAlphaStep(void)
{
-// {
-// class CNavArea *area; // 432
-// }
+ if (m_analyzeIter == TheNavAreaList.end())
+ return false;
+
+ CNavArea *area = (*m_analyzeIter);
+
+ ++_currentIndex;
+ area->ComputeHidingSpots();
+ area->ComputeApproachAreas();
+ ++m_analyzeIter;
+
+ return true;
}
/* <3448de> ../cstrike/dlls/bot/cs_bot_learn.cpp:443 */
-NOBODY void CCSBot::UpdateAnalyzeAlphaProcess(void)
+void CCSBot::UpdateAnalyzeAlphaProcess(void)
{
-// {
-// float startTime; // 445
-// float progress; // 462
-// AnalyzeAlphaStep(CCSBot *const this); // 451
-// drawProgressMeter(float progress,
-// char *title); // 454
-// StartAnalyzeBetaProcess(CCSBot *const this); // 456
-// drawProgressMeter(float progress,
-// char *title); // 463
-// }
+ float startTime = g_engfuncs.pfnTime();
+ float progress = _currentIndex / _navAreaCount * 50.0f;
+
+ while (AnalyzeAlphaStep())
+ {
+ if (g_engfuncs.pfnTime() - startTime >= updateTimesliceDuration)
+ {
+ drawProgressMeter(progress, "#CZero_AnalyzingHidingSpots");
+ return;
+ }
+ }
+
+ drawProgressMeter(50, "#CZero_AnalyzingHidingSpots");
+ CleanupApproachAreaAnalysisPrep();
+ StartAnalyzeBetaProcess();
}
/* <344aed> ../cstrike/dlls/bot/cs_bot_learn.cpp:467 */
-NOBODY void CCSBot::StartAnalyzeBetaProcess(void)
+void CCSBot::StartAnalyzeBetaProcess(void)
{
-// size(const class list> *const this); // 471
+ m_processMode = PROCESS_ANALYZE_BETA;
+ m_analyzeIter = TheNavAreaList.begin();
+
+ _navAreaCount = TheNavAreaList.size();
+ _currentIndex = 0;
}
/* <3437c8> ../cstrike/dlls/bot/cs_bot_learn.cpp:479 */
-NOBODY inline bool CCSBot::AnalyzeBetaStep(void)
+bool CCSBot::AnalyzeBetaStep(void)
{
-// {
-// class CNavArea *area; // 484
-// }
+ if (m_analyzeIter == TheNavAreaList.end())
+ return false;
+
+ CNavArea *area = (*m_analyzeIter);
+
+ ++_currentIndex;
+ area->ComputeSpotEncounters();
+ area->ComputeSniperSpots();
+ ++m_analyzeIter;
+
+ return true;
}
/* <344b8d> ../cstrike/dlls/bot/cs_bot_learn.cpp:495 */
-NOBODY void CCSBot::UpdateAnalyzeBetaProcess(void)
+void CCSBot::UpdateAnalyzeBetaProcess(void)
{
-// {
-// float startTime; // 497
-// float progress; // 512
-// AnalyzeBetaStep(CCSBot *const this); // 503
-// drawProgressMeter(float progress,
-// char *title); // 506
-// StartSaveProcess(CCSBot *const this); // 507
-// drawProgressMeter(float progress,
-// char *title); // 513
-// }
+ float startTime = g_engfuncs.pfnTime();
+ float progress = (_currentIndex / _navAreaCount + 1.0f) * 50.0f;
+
+ while (AnalyzeBetaStep())
+ {
+ if (g_engfuncs.pfnTime() - startTime >= updateTimesliceDuration)
+ {
+ drawProgressMeter(progress, "#CZero_AnalyzingApproachPoints");
+ return;
+ }
+ }
+
+ drawProgressMeter(100, "#CZero_AnalyzingApproachPoints");
+ StartSaveProcess();
}
/* <344d1f> ../cstrike/dlls/bot/cs_bot_learn.cpp:517 */
-NOBODY void CCSBot::StartSaveProcess(void)
+void CCSBot::StartSaveProcess(void)
{
+ m_processMode = PROCESS_SAVE;
}
/* <344d41> ../cstrike/dlls/bot/cs_bot_learn.cpp:527 */
-NOBODY void CCSBot::UpdateSaveProcess(void)
+void CCSBot::UpdateSaveProcess(void)
{
-// {
-// char filename; // 530
-// char msg; // 538
-// char cmd; // 548
-// hideProgressMeter(void); // 542
-// StartNormalProcess(CCSBot *const this); // 545
-// }
+ char filename[256];
+ char msg[256];
+ char cmd[128];
+
+ GET_GAME_DIR(filename);
+ filename[Q_strlen(filename)] = '\\';
+ Q_strcat(filename, TheBots->GetNavMapFilename());
+
+ HintMessageToAllPlayers("Saving...");
+ SaveNavigationMap(filename);
+
+ Q_sprintf(msg, "Navigation file '%s' saved.", filename);
+ HintMessageToAllPlayers(msg);
+
+ hideProgressMeter();
+ StartNormalProcess();
+
+ Q_sprintf(cmd, "map %s\n", STRING(gpGlobals->mapname));
+ SERVER_COMMAND(cmd);
}
/* <344e24> ../cstrike/dlls/bot/cs_bot_learn.cpp:554 */
diff --git a/regamedll/dlls/bot/cs_bot_listen.cpp b/regamedll/dlls/bot/cs_bot_listen.cpp
index c40aae4f..db359425 100644
--- a/regamedll/dlls/bot/cs_bot_listen.cpp
+++ b/regamedll/dlls/bot/cs_bot_listen.cpp
@@ -1,92 +1,214 @@
#include "precompiled.h"
+// Listen for enemy noises, and determine if we should react to them.
+// Returns true if heard a noise and should move to investigate.
+
/* <354545> ../cstrike/dlls/bot/cs_bot_listen.cpp:17 */
-NOBODY bool CCSBot::ShouldInvestigateNoise(float *retNoiseDist)
+bool CCSBot::ShouldInvestigateNoise(float *retNoiseDist)
{
-// IsNoiseHeard(const class CCSBot *const this); // 32
-// {
-// float const noiseCheckInterval; // 36
-// Vector toNoise; // 44
-// float noiseDist; // 45
-// float const maxNoiseDist; // 46
-// float const oneStoreyHeight; // 49
-// float chance; // 72
-// operator-(const Vector *const this,
-// const Vector &v); // 44
-// Length(const Vector *const this); // 45
-// {
-// class PathCost pc; // 53
-// float travelDistToNoise; // 54
-// float const tooFar; // 58
-// NavAreaTravelDistance(CNavArea *startArea,
-// class CNavArea *endArea,
-// class PathCost &costFunc); // 54
-// }
-// {
-// float friendFactor; // 78
-// }
-// }
+ if (m_isNoiseTravelRangeChecked)
+ return false;
+
+ // don't investigate noises during safe time
+ if (!IsWellPastSafe())
+ return false;
+
+ // if our disposition is not to investigate, dont investigate
+ if (GetDisposition() != ENGAGE_AND_INVESTIGATE)
+ return false;
+
+ // listen for enemy noises
+ if (IsNoiseHeard() && gpGlobals->time - m_noiseCheckTimestamp >= 0.25f)
+ {
+ m_noiseCheckTimestamp = gpGlobals->time;
+ Vector toNoise = m_noisePosition - pev->origin;
+ float noiseDist = toNoise.Length();
+
+ float const oneStoreyHeight = 120.0f;
+ if (abs(int64(toNoise.z)) > oneStoreyHeight)
+ {
+ PathCost pc(this);
+ float travelDistToNoise = NavAreaTravelDistance(m_lastKnownArea, m_noiseArea, pc);
+ m_isNoiseTravelRangeChecked = true;
+
+ const float tooFar = 1500.0f;
+ if (travelDistToNoise < 0.0f || travelDistToNoise > tooFar)
+ return false;
+
+ if (noiseDist <= travelDistToNoise)
+ noiseDist = travelDistToNoise;
+ }
+
+ // if we are hiding, only react to noises very nearby, depending on how aggressive we are
+ if (IsAtHidingSpot() && noiseDist > 100.0f + 400.0f * GetProfile()->GetAggression())
+ return false;
+
+ // chance of investigating is inversely proportional to distance
+ const float maxNoiseDist = 2000.0f;
+ float chance = (1.0f - (noiseDist / maxNoiseDist));
+
+ // modify chance by number of friends remaining
+ // if we have lots of friends, presumably one of them is closer and will check it out
+ if (GetFriendsRemaining() >= 3)
+ {
+ float friendFactor = 0.05f * GetFriendsRemaining();
+ if (friendFactor > 0.5f)
+ friendFactor = 0.5f;
+
+ chance -= friendFactor;
+ }
+
+ if (RANDOM_FLOAT(0.0f, 1.0f) <= chance)
+ {
+ if (retNoiseDist)
+ *retNoiseDist = noiseDist;
+
+ return true;
+ }
+ }
+
+ return false;
}
+// Return true if we hear nearby threatening enemy gunfire within given range
+// -1 == infinite range
+
/* <354c8d> ../cstrike/dlls/bot/cs_bot_listen.cpp:104 */
-NOBODY bool CCSBot::CanHearNearbyEnemyGunfire(float range)
+bool CCSBot::CanHearNearbyEnemyGunfire(float range) const
{
-// {
-// float gunfireDistSq; // 125
-// float enemyDistSq; // 126
-// float const muchCloserSq; // 127
-// operator-(const Vector *const this,
-// const Vector &v); // 126
-// operator-(const Vector *const this,
-// const Vector &v); // 125
-// LengthSquared(const Vector *const this); // 125
-// LengthSquared(const Vector *const this); // 126
-// }
-// CanSeeNoisePosition(const class CCSBot *const this); // 119
-// operator-(const Vector *const this,
-// const Vector &v); // 115
-// IsLengthGreaterThan(const Vector *const this,
-// float length); // 115
+ // only attend to noise if it just happened
+ if (gpGlobals->time - m_noiseTimestamp > 0.5f)
+ return false;
+
+ // gunfire is high priority
+ if (m_noisePriority < PRIORITY_HIGH)
+ return false;
+
+ // check noise range
+ if (range > 0.0f && (pev->origin - m_noisePosition).IsLengthGreaterThan(range))
+ return false;
+
+ // if we dont have line of sight, it's not threatening (cant get shot)
+ if (!CanSeeNoisePosition())
+ return false;
+
+ if (IsAttacking() && m_enemy != NULL)
+ {
+ // gunfire is only threatening if it is closer than our current enemy
+ float gunfireDistSq = (m_noisePosition - pev->origin).LengthSquared();
+ float enemyDistSq = (m_enemy->pev->origin - pev->origin).LengthSquared();
+ const float muchCloserSq = 100.0f * 100.0f;
+ if (gunfireDistSq > enemyDistSq - muchCloserSq)
+ return false;
+ }
+
+ return true;
}
+// Return true if we directly see where we think the noise came from
+// NOTE: Dont check FOV, since this is used to determine if we should turn our head to look at the noise
+// NOTE: Dont use IsVisible(), because smoke shouldnt cause us to not look toward noises
+
/* <354e7b> ../cstrike/dlls/bot/cs_bot_listen.cpp:141 */
-NOBODY bool CCSBot::CanSeeNoisePosition(void)
+bool CCSBot::CanSeeNoisePosition(void) const
{
-// {
-// TraceResult result; // 143
-// operator+(const Vector *const this,
-// const Vector &v); // 144
-// GetEyePosition(const class CCSBot *const this); // 144
-// }
+ TraceResult result;
+ UTIL_TraceLine(GetEyePosition(), m_noisePosition + Vector(0, 0, HalfHumanHeight), ignore_monsters, ignore_glass, ENT(pev), &result);
+
+ if (result.flFraction == 1.0f)
+ {
+ // we can see the source of the noise
+ return true;
+ }
+
+ return false;
}
+// Return true if we decided to look towards the most recent noise source
+// Assumes m_noisePosition is valid.
+
/* <354f48> ../cstrike/dlls/bot/cs_bot_listen.cpp:160 */
-NOBODY bool CCSBot::UpdateLookAtNoise(void)
+bool CCSBot::UpdateLookAtNoise(void)
{
-// {
-// bool nearbyThreat; // 176
-// float const recentThreatTime; // 177
-// float const closeThreatRange; // 178
-// Vector spot; // 190
-// enum PriorityType pri; // 231
-// IsNoiseHeard(const class CCSBot *const this); // 163
-// operator-(const Vector *const this,
-// const Vector &v); // 181
-// IsLengthLessThan(const Vector *const this,
-// float length); // 181
-// CanSeeNoisePosition(const class CCSBot *const this); // 193
-// {
-// int nearIdx; // 200
-// float nearRangeSq; // 201
-// {
-// int i; // 202
-// {
-// float distanceSq; // 206
-// operator-(const Vector *const this,
-// const Vector &v); // 206
-// LengthSquared(const Vector *const this); // 206
-// }
-// }
-// }
-// }
+ // make sure a noise exists
+ if (!IsNoiseHeard() || gpGlobals->time - m_noiseTimestamp > 0.5f)
+ return false;
+
+ bool nearbyThreat = false;
+ float const recentThreatTime = 5.0f;
+ if (GetTimeSinceLastSawEnemy() < recentThreatTime)
+ {
+ const float closeThreatRange = 750.0f;
+ if ((pev->origin - m_lastEnemyPosition).IsLengthLessThan(closeThreatRange))
+ {
+ nearbyThreat = true;
+ }
+ }
+
+ Vector spot;
+
+ // if we have clear line of sight to noise position, look directly at it
+ if ((!IsAtHidingSpot() && nearbyThreat) || CanSeeNoisePosition())
+ {
+ // TODO: adjust noise Z to keep consistent with current height while fighting
+ spot = m_noisePosition + Vector(0, 0, HalfHumanHeight);
+ }
+ else
+ {
+ // line of sight is blocked, bend it
+
+ if (m_approachPointCount == 0)
+ return false;
+
+ int nearIdx = -1;
+ float nearRangeSq = 9.9999998e10f;
+
+ for (int i = 0; i < m_approachPointCount; ++i)
+ {
+ float distanceSq = (m_approachPoint[i] - m_noisePosition).LengthSquared();
+
+ if (distanceSq < nearRangeSq)
+ {
+ nearRangeSq = distanceSq;
+ nearIdx = i;
+ }
+ }
+
+ if (nearIdx != -1)
+ {
+ // line of sight is blocked, bend it
+ if (BendLineOfSight(&pev->origin, &m_approachPoint[nearIdx], &spot) == false)
+ return false;
+
+ spot.z += HalfHumanHeight;
+ }
+ else
+ {
+ // prior bend failed
+ return false;
+ }
+ }
+
+ // it's always important to look at enemy noises, because they come from ... enemies!
+ PriorityType pri = (GetNoisePriority() == PRIORITY_HIGH) ? PRIORITY_HIGH : PRIORITY_MEDIUM;
+
+ // look longer if we're hiding
+ if (IsAtHidingSpot())
+ {
+ // if there is only one enemy left, look for a long time
+ if (GetEnemiesRemaining() == 1)
+ {
+ SetLookAt("Noise", &spot, pri, RANDOM_FLOAT(5.0f, 15.0f), true);
+ }
+ else
+ {
+ SetLookAt("Noise", &spot, pri, RANDOM_FLOAT(2.0f, 5.0f), true);
+ }
+ }
+ else
+ {
+ SetLookAt("Noise", &spot, pri, RANDOM_FLOAT(1.0f, 2.0f), true);
+ }
+
+ return true;
}
diff --git a/regamedll/dlls/bot/cs_bot_manager.cpp b/regamedll/dlls/bot/cs_bot_manager.cpp
index 15fe12d1..320fe5ba 100644
--- a/regamedll/dlls/bot/cs_bot_manager.cpp
+++ b/regamedll/dlls/bot/cs_bot_manager.cpp
@@ -7,110 +7,112 @@
CBotManager *TheBots = NULL;
-cvar_t cv_bot_traceview = { "bot_traceview", "0", FCVAR_SERVER, 0.0f, NULL };
-cvar_t cv_bot_stop = { "bot_stop", "0", FCVAR_SERVER, 0.0f, NULL };
-cvar_t cv_bot_show_nav = { "bot_show_nav", "0", FCVAR_SERVER, 0.0f, NULL };
-cvar_t cv_bot_show_danger = { "bot_show_danger", "0", FCVAR_SERVER, 0.0f, NULL };
-cvar_t cv_bot_nav_edit = { "bot_nav_edit", "0", FCVAR_SERVER, 0.0f, NULL };
-cvar_t cv_bot_nav_zdraw = { "bot_nav_zdraw", "4", FCVAR_SERVER, 0.0f, NULL };
-cvar_t cv_bot_walk = { "bot_walk", "0", FCVAR_SERVER, 0.0f, NULL };
-cvar_t cv_bot_difficulty = { "bot_difficulty", "0", FCVAR_SERVER, 0.0f, NULL };
-cvar_t cv_bot_debug = { "bot_debug", "0", FCVAR_SERVER, 0.0f, NULL };
-cvar_t cv_bot_quicksave = { "bot_quicksave", "0", FCVAR_SERVER, 0.0f, NULL };
-cvar_t cv_bot_quota = { "bot_quota", "0", FCVAR_SERVER, 0.0f, NULL };
-cvar_t cv_bot_quota_match = { "bot_quota_match", "0", FCVAR_SERVER, 0.0f, NULL };
-cvar_t cv_bot_prefix = { "bot_prefix", "", FCVAR_SERVER, 0.0f, NULL };
-cvar_t cv_bot_allow_rogues = { "bot_allow_rogues", "1", FCVAR_SERVER, 0.0f, NULL };
-cvar_t cv_bot_allow_pistols = { "bot_allow_pistols", "1", FCVAR_SERVER, 0.0f, NULL };
-cvar_t cv_bot_allow_shotguns = { "bot_allow_shotguns", "1", FCVAR_SERVER, 0.0f, NULL };
-cvar_t cv_bot_allow_sub_machine_guns = { "bot_allow_sub_machine_guns", "1", FCVAR_SERVER, 0.0f, NULL };
-cvar_t cv_bot_allow_rifles = { "bot_allow_rifles", "1", FCVAR_SERVER, 0.0f, NULL };
-cvar_t cv_bot_allow_machine_guns = { "bot_allow_machine_guns", "1", FCVAR_SERVER, 0.0f, NULL };
-cvar_t cv_bot_allow_grenades = { "bot_allow_grenades", "1", FCVAR_SERVER, 0.0f, NULL };
-cvar_t cv_bot_allow_snipers = { "bot_allow_snipers", "1", FCVAR_SERVER, 0.0f, NULL };
-cvar_t cv_bot_allow_shield = { "bot_allow_shield", "1", FCVAR_SERVER, 0.0f, NULL };
-cvar_t cv_bot_join_team = { "bot_join_team", "any", FCVAR_SERVER, 0.0f, NULL };
-cvar_t cv_bot_join_after_player = { "bot_join_after_player", "1", FCVAR_SERVER, 0.0f, NULL };
-cvar_t cv_bot_auto_vacate = { "bot_auto_vacate", "1", FCVAR_SERVER, 0.0f, NULL };
-cvar_t cv_bot_zombie = { "bot_zombie", "0", FCVAR_SERVER, 0.0f, NULL };
-cvar_t cv_bot_defer_to_human = { "bot_defer_to_human", "0", FCVAR_SERVER, 0.0f, NULL };
-cvar_t cv_bot_chatter = { "bot_chatter", "normal", FCVAR_SERVER, 0.0f, NULL };
-cvar_t cv_bot_profile_db = { "bot_profile_db", "BotProfile.db", FCVAR_SERVER, 0.0f, NULL };
-
-float CCSBotManager::m_flNextCVarCheck;
-bool CCSBotManager::m_isMapDataLoaded;
-bool CCSBotManager::m_isLearningMap;
-bool CCSBotManager::m_isAnalysisRequested;
-NavEditCmdType CCSBotManager::m_editCmd;
+float CCSBotManager::m_flNextCVarCheck = 0.0f;
+bool CCSBotManager::m_isMapDataLoaded = false;
+bool CCSBotManager::m_isLearningMap = false;
+bool CCSBotManager::m_isAnalysisRequested = false;
+NavEditCmdType CCSBotManager::m_editCmd = EDIT_NONE;
#else // HOOK_GAMEDLL
CBotManager *TheBots;
-cvar_t cv_bot_traceview;
-cvar_t cv_bot_stop;
-cvar_t cv_bot_show_nav;
-cvar_t cv_bot_show_danger;
-cvar_t cv_bot_nav_edit;
-cvar_t cv_bot_nav_zdraw;
-cvar_t cv_bot_walk;
-cvar_t cv_bot_difficulty;
-cvar_t cv_bot_debug;
-cvar_t cv_bot_quicksave;
-cvar_t cv_bot_quota;
-cvar_t cv_bot_quota_match;
-cvar_t cv_bot_prefix;
-cvar_t cv_bot_allow_rogues;
-cvar_t cv_bot_allow_pistols;
-cvar_t cv_bot_allow_shotguns;
-cvar_t cv_bot_allow_sub_machine_guns;
-cvar_t cv_bot_allow_rifles;
-cvar_t cv_bot_allow_machine_guns;
-cvar_t cv_bot_allow_grenades;
-cvar_t cv_bot_allow_snipers;
-cvar_t cv_bot_allow_shield;
-cvar_t cv_bot_join_team;
-cvar_t cv_bot_join_after_player;
-cvar_t cv_bot_auto_vacate;
-cvar_t cv_bot_zombie;
-cvar_t cv_bot_defer_to_human;
-cvar_t cv_bot_chatter;
-cvar_t cv_bot_profile_db;
-
-float (*CCSBotManager::pm_flNextCVarCheck);
-bool (*CCSBotManager::pm_isMapDataLoaded);
-bool (*CCSBotManager::pm_isLearningMap);
-bool (*CCSBotManager::pm_isAnalysisRequested);
-NavEditCmdType (*CCSBotManager::pm_editCmd);
+float IMPL_CLASS(CCSBotManager, m_flNextCVarCheck);
+bool IMPL_CLASS(CCSBotManager, m_isMapDataLoaded);
+bool IMPL_CLASS(CCSBotManager, m_isLearningMap);
+bool IMPL_CLASS(CCSBotManager, m_isAnalysisRequested);
+NavEditCmdType IMPL_CLASS(CCSBotManager, m_editCmd);
#endif // HOOK_GAMEDLL
-/* <36b3b4> ../cstrike/dlls/bot/cs_bot_manager.cpp:45 */
-NOBODY CCSBotManager::CCSBotManager(void)
+// Determine whether bots can be used or not
+inline bool AreBotsAllowed()
{
-// {
-// const char *filename; // 66
-// int dataLength; // 76
-// char *dataPointer; // 77
-// const VoiceBankList *pVoiceBanks; // 100
-// SetLooseBomb(CCSBotManager *const this,
-// class CBaseEntity *bomb); // 49
-// {
-// const char *dataFile; // 84
-// const char *token; // 85
-// {
-// char *clone; // 90
-// CloneString(const char *str); // 90
-// }
-// }
-// {
-// int i; // 101
-// size(const class vector> *const this); // 101
-// }
-// }
-// CountdownTimer(CountdownTimer *const this); // 45
+ // If they pass in -nobots, don't allow bots. This is for people who host servers, to
+ // allow them to disallow bots to enforce CPU limits.
+ int nobots = ENG_CHECK_PARM("-nobots", NULL);
+ if (nobots)
+ {
+ return false;
+ }
+
+ return true;
}
+/* <36b3b4> ../cstrike/dlls/bot/cs_bot_manager.cpp:45 */
+CCSBotManager::CCSBotManager(void)
+{
+ IMPL(m_flNextCVarCheck) = 0.0f;
+
+ m_zoneCount = 0;
+ SetLooseBomb(NULL);
+
+ m_isBombPlanted = false;
+ m_bombDefuser = NULL;
+
+ IMPL(m_isLearningMap) = false;
+ IMPL(m_isAnalysisRequested) = false;
+ IMPL(m_editCmd) = EDIT_NONE;
+
+ m_navPlace = false;
+ m_roundStartTimestamp = 0.0f;
+
+ m_bServerActive = false;
+
+ TheBotPhrases = new BotPhraseManager; // TODO: Reverse me!
+ // load the database of bot radio chatter
+ TheBotPhrases->Initialize("BotChatter.db", 0);
+
+ TheBotProfiles = new BotProfileManager;
+ // make sure default voice bank is first
+ TheBotProfiles->FindVoiceBankIndex("BotChatter.db");
+
+ const char *filename;
+ if (IS_CAREER_MATCH())
+ {
+ filename = "MissionPacks/BotPackList.db";
+ }
+ else
+ {
+ filename = "BotPackList.db";
+ }
+
+ // read in the list of bot profile DBs
+ int dataLength;
+ char *dataPointer = (char *)LOAD_FILE_FOR_ME((char *)filename, &dataLength);
+
+ if (dataPointer == NULL)
+ {
+ TheBotProfiles->Init("BotProfile.db");
+ }
+ else
+ {
+ const char *dataFile = SharedParse(dataPointer);
+ const char *token;
+
+ while (dataFile != NULL)
+ {
+ token = SharedGetToken();
+ char *clone = CloneString(token);
+ TheBotProfiles->Init(clone);
+ delete[] clone;
+ dataFile = SharedParse(dataFile);
+ }
+
+ FREE_FILE(dataPointer);
+ }
+
+ // Now that we've parsed all the profiles, we have a list of the voice banks they're using.
+ // Go back and parse the custom voice speakables.
+ const BotProfileManager::VoiceBankList *pVoiceBanks = TheBotProfiles->GetVoiceBanks();
+ for (uint32 i = 1; i < pVoiceBanks->size(); ++i)
+ {
+ TheBotPhrases->Initialize((*pVoiceBanks)[i], i);
+ }
+}
+
+// Invoked when a new round begins
+
/* <36b22a> ../cstrike/dlls/bot/cs_bot_manager.cpp:111 */
void CCSBotManager::__MAKE_VHOOK(RestartRound)(void)
{
@@ -119,19 +121,20 @@ void CCSBotManager::__MAKE_VHOOK(RestartRound)(void)
SetLooseBomb(NULL);
m_isBombPlanted = false;
-
+ m_earliestBombPlantTimestamp = gpGlobals->time + RANDOM_FLOAT(10.0f, 30.0f);
m_bombDefuser = NULL;
- m_earliestBombPlantTimestamp = gpGlobals->time + RANDOM_FLOAT(10, 30);
IMPL(m_editCmd) = EDIT_NONE;
ResetRadioMessageTimestamps();
+
m_lastSeenEnemyTimestamp = -9999.9f;
+
m_roundStartTimestamp = gpGlobals->time + CVAR_GET_FLOAT("mp_freezetime");
// randomly decide if defensive team wants to "rush" as a whole
const float defenseRushChance = 33.3f; // 25.0f;
- m_isDefenseRushing = (RANDOM_FLOAT(0, 100) <= defenseRushChance) ? true : false;
+ m_isDefenseRushing = (RANDOM_FLOAT(0.0f, 100.0f) <= defenseRushChance) ? true : false;
TheBotPhrases->OnRoundRestart();
@@ -141,29 +144,79 @@ void CCSBotManager::__MAKE_VHOOK(RestartRound)(void)
}
/* <36aebc> ../cstrike/dlls/bot/cs_bot_manager.cpp:142 */
-NOBODY void UTIL_DrawBox(Extent *extent, int lifetime, int red, int green, int blue)
+void UTIL_DrawBox(Extent *extent, int lifetime, int red, int green, int blue)
{
-// {
-// Vector v; // 144
-// int const edge; // 154
-// Vector from; // 165
-// Vector to; // 165
-// bool restart; // 166
-// {
-// int i; // 167
-// {
-// int index; // 178
-// }
-// }
-// }
+ Vector v[8];
+ v[0].x = extent->lo.x; v[0].y = extent->lo.y; v[0].z = extent->lo.z;
+ v[1].x = extent->hi.x; v[1].y = extent->lo.y; v[1].z = extent->lo.z;
+ v[2].x = extent->hi.x; v[2].y = extent->hi.y; v[2].z = extent->lo.z;
+ v[3].x = extent->lo.x; v[3].y = extent->hi.y; v[3].z = extent->lo.z;
+ v[4].x = extent->lo.x; v[4].y = extent->lo.y; v[4].z = extent->hi.z;
+ v[5].x = extent->hi.x; v[5].y = extent->lo.y; v[5].z = extent->hi.z;
+ v[6].x = extent->hi.x; v[6].y = extent->hi.y; v[6].z = extent->hi.z;
+ v[7].x = extent->lo.x; v[7].y = extent->hi.y; v[7].z = extent->hi.z;
+
+ static int edge[] =
+ {
+ 1, 2, 3, 4, -1,
+ 5, 6, 7, 8, -5,
+ 1, -5,
+ 2, -6,
+ 3, -7,
+ 4, -8,
+ 0 // end iterator
+ };
+
+ Vector from, to;
+ bool restart = true;
+
+ for (int i = 0; edge[i] != 0; ++i)
+ {
+ if (restart)
+ {
+ to = v[ edge[i] - 1 ];
+ restart = false;
+ continue;
+ }
+
+ from = to;
+
+ int index = edge[i];
+ if (index < 0)
+ {
+ restart = true;
+ index = -index;
+ }
+
+ to = v[ index - 1 ];
+
+ UTIL_DrawBeamPoints(from, to, lifetime, red, green, blue);
+ UTIL_DrawBeamPoints(to, from, lifetime, red, green, blue);
+ }
}
+// Called each frame
+
/* <36b13d> ../cstrike/dlls/bot/cs_bot_manager.cpp:195 */
-NOBODY void CCSBotManager::__MAKE_VHOOK(StartFrame)(void)
+void CCSBotManager::__MAKE_VHOOK(StartFrame)(void)
{
+ // EXTEND
+ CBotManager::StartFrame();
+ MonitorBotCVars();
+ // debug zone extent visualization
+ if (cv_bot_debug.value == 5.0f)
+ {
+ for (int z = 0; z < m_zoneCount; ++z)
+ {
+ Zone *zone = &m_zone[z];
+ UTIL_DrawBox(&zone->m_extent, 1, 255, 100, 0);
+ }
+ }
}
+// Return true if the bot can use this weapon
+
/* <36b62a> ../cstrike/dlls/bot/cs_bot_manager.cpp:276 */
bool CCSBotManager::IsWeaponUseable(CBasePlayerItem *item) const
{
@@ -172,39 +225,60 @@ bool CCSBotManager::IsWeaponUseable(CBasePlayerItem *item) const
return false;
}
- if (item->m_iId != WEAPON_C4)
- {
- int weaponClass = WeaponIDToWeaponClass(item->m_iId);
+ if (item->m_iId == WEAPON_C4)
+ return true;
- if ((!AllowShotguns() && weaponClass == WEAPONCLASS_SHOTGUN)
- || (!AllowMachineGuns() && weaponClass == WEAPONCLASS_MACHINEGUN)
- || (!AllowRifles() && weaponClass == WEAPONCLASS_RIFLE)
- //|| (!AllowShotguns() && weaponClass == WEAPONCLASS_SHOTGUN) // TODO: already is checked shotguns!
- || (!AllowSnipers() && weaponClass == WEAPONCLASS_SNIPERRIFLE)
- || (!AllowSubMachineGuns() && weaponClass == WEAPONCLASS_SUBMACHINEGUN)
- || (!AllowTacticalShield() && item->m_iId == WEAPON_SHIELDGUN)
- || (!AllowPistols() && weaponClass == WEAPONCLASS_PISTOL)
- || (!AllowGrenades() && weaponClass == WEAPONCLASS_GRENADE))
- {
- return false;
- }
+ int weaponClass = WeaponIDToWeaponClass(item->m_iId);
+
+ if ((!AllowShotguns() && weaponClass == WEAPONCLASS_SHOTGUN)
+ || (!AllowMachineGuns() && weaponClass == WEAPONCLASS_MACHINEGUN)
+ || (!AllowRifles() && weaponClass == WEAPONCLASS_RIFLE)
+#ifndef REGAMEDLL_FIXES
+ // TODO: already is checked shotguns!
+ || (!AllowShotguns() && weaponClass == WEAPONCLASS_SHOTGUN)
+#endif // REGAMEDLL_FIXES
+ || (!AllowSnipers() && weaponClass == WEAPONCLASS_SNIPERRIFLE)
+ || (!AllowSubMachineGuns() && weaponClass == WEAPONCLASS_SUBMACHINEGUN)
+ || (!AllowTacticalShield() && item->m_iId == WEAPON_SHIELDGUN)
+ || (!AllowPistols() && weaponClass == WEAPONCLASS_PISTOL)
+ || (!AllowGrenades() && weaponClass == WEAPONCLASS_GRENADE))
+ {
+ return false;
}
return true;
}
+// Return true if this player is on "defense"
+
/* <36b68c> ../cstrike/dlls/bot/cs_bot_manager.cpp:306 */
-NOBODY bool CCSBotManager::IsOnDefense(CBasePlayer *player) const
+bool CCSBotManager::IsOnDefense(CBasePlayer *player) const
{
+ switch (GetScenario())
+ {
+ case SCENARIO_DEFUSE_BOMB:
+ return (player->m_iTeam == CT);
+
+ case SCENARIO_RESCUE_HOSTAGES:
+ return (player->m_iTeam == TERRORIST);
+
+ case SCENARIO_ESCORT_VIP:
+ return (player->m_iTeam == TERRORIST);
+ }
+
+ return false;
}
+// Return true if this player is on "offense"
+
/* <36b6b8> ../cstrike/dlls/bot/cs_bot_manager.cpp:327 */
-NOBODY bool CCSBotManager::IsOnOffense(CBasePlayer *player) const
+bool CCSBotManager::IsOnOffense(CBasePlayer *player) const
{
-// IsOnDefense(const class CCSBotManager *const this,
-// const class CBasePlayer *player); // 329
+ return !IsOnDefense(player);
}
+// Invoked when a map has just been loaded
+
/* <36a3b6> ../cstrike/dlls/bot/cs_bot_manager.cpp:331 */
void CCSBotManager::__MAKE_VHOOK(ServerActivate)(void)
{
@@ -301,28 +375,33 @@ void CCSBotManager::__MAKE_VHOOK(ServerDeactivate)(void)
/* <36b5fa> ../cstrike/dlls/bot/cs_bot_manager.cpp:415 */
void CCSBotManager::__MAKE_VHOOK(ClientDisconnect)(CBasePlayer *pPlayer)
{
- if (!pPlayer || !pPlayer->IsBot())
- return;
+ if (pPlayer != NULL && pPlayer->IsBot())
+ {
+ entvars_t *temp = VARS(pPlayer->edict());
+ CCSBot *pBot = static_cast(pPlayer);
- CCSBot *pBot = static_cast(pPlayer);
- entvars_t *temp = VARS(pPlayer->edict());
+ if (pBot != NULL)
+ {
+ pBot->Disconnect();
+ }
- pBot->Disconnect();
+ if (!FStringNull(pPlayer->pev->classname))
+ {
+ RemoveEntityHashValue(pPlayer->pev, STRING(pPlayer->pev->classname), CLASSNAME);
+ }
- if (pPlayer->pev->classname)
- RemoveEntityHashValue(pPlayer->pev, STRING(pPlayer->pev->classname), CLASSNAME);
+ FREE_PRIVATE(pPlayer->edict());
- FREE_PRIVATE(pPlayer->edict());
-
- CBasePlayer *player = GetClassPtr((CBasePlayer *)temp);
- AddEntityHashValue(player->pev, STRING(player->pev->classname), CLASSNAME);
- player->pev->flags = FL_DORMANT;
+ CBasePlayer *player = GetClassPtr((CBasePlayer *)temp);
+ AddEntityHashValue(player->pev, STRING(player->pev->classname), CLASSNAME);
+ player->pev->flags = FL_DORMANT;
+ }
}
/* <36b714> ../cstrike/dlls/bot/cs_bot_manager.cpp:464 */
void PrintAllEntities(void)
{
- for (int i = 1; i < gpGlobals->maxEntities; i++)
+ for (int i = 1; i < gpGlobals->maxEntities; ++i)
{
edict_t *edict = INDEXENT(i);
@@ -350,15 +429,15 @@ void CCSBotManager::__MAKE_VHOOK(ServerCommand)(const char *pcmd)
}
else if (FStrEq(pcmd, "bot_add"))
{
- BotAddCommand(BOT_TEAM_ANY);
+ BotAddCommand(BOT_TEAM_ANY, FROM_CONSOLE);
}
else if (FStrEq(pcmd, "bot_add_t"))
{
- BotAddCommand(BOT_TEAM_T);
+ BotAddCommand(BOT_TEAM_T, FROM_CONSOLE);
}
else if (FStrEq(pcmd, "bot_add_ct"))
{
- BotAddCommand(BOT_TEAM_CT);
+ BotAddCommand(BOT_TEAM_CT, FROM_CONSOLE);
}
else if (FStrEq(pcmd, "bot_kill"))
{
@@ -368,9 +447,9 @@ void CCSBotManager::__MAKE_VHOOK(ServerCommand)(const char *pcmd)
else
killThemAll = false;
- for (int iIndex = 1; iIndex <= gpGlobals->maxClients; iIndex++)
+ for (int iIndex = 1; iIndex <= gpGlobals->maxClients; ++iIndex)
{
- CBasePlayer *pPlayer = reinterpret_cast(UTIL_PlayerByIndex(iIndex));
+ CBasePlayer *pPlayer = static_cast(UTIL_PlayerByIndex(iIndex));
if (pPlayer == NULL)
continue;
@@ -400,9 +479,9 @@ void CCSBotManager::__MAKE_VHOOK(ServerCommand)(const char *pcmd)
else
kickThemAll = false;
- for (int iIndex = 1; iIndex <= gpGlobals->maxClients; iIndex++)
+ for (int iIndex = 1; iIndex <= gpGlobals->maxClients; ++iIndex)
{
- CBasePlayer *pPlayer = reinterpret_cast(UTIL_PlayerByIndex(iIndex));
+ CBasePlayer *pPlayer = static_cast(UTIL_PlayerByIndex(iIndex));
if (pPlayer == NULL)
continue;
@@ -419,8 +498,10 @@ void CCSBotManager::__MAKE_VHOOK(ServerCommand)(const char *pcmd)
{
if (kickThemAll || FStrEq(name, msg))
{
+ // adjust bot quota so kicked bot is not immediately added back in
+ int newQuota = cv_bot_quota.value - 1;
SERVER_COMMAND(UTIL_VarArgs("kick \"%s\"\n", name));
- CVAR_SET_FLOAT("bot_quota", cv_bot_quota.value - 1);
+ CVAR_SET_FLOAT("bot_quota", clamp(newQuota, 0, (int)cv_bot_quota.value));
}
}
}
@@ -480,63 +561,63 @@ void CCSBotManager::__MAKE_VHOOK(ServerCommand)(const char *pcmd)
}
else if (FStrEq(pcmd, "bot_nav_delete"))
{
- IMPL_CLASS(CCSBotManager, m_editCmd) = EDIT_DELETE;
+ IMPL(m_editCmd) = EDIT_DELETE;
}
else if (FStrEq(pcmd, "bot_nav_split"))
{
- IMPL_CLASS(CCSBotManager, m_editCmd) = EDIT_SPLIT;
+ IMPL(m_editCmd) = EDIT_SPLIT;
}
else if (FStrEq(pcmd, "bot_nav_merge"))
{
- IMPL_CLASS(CCSBotManager, m_editCmd) = EDIT_MERGE;
+ IMPL(m_editCmd) = EDIT_MERGE;
}
else if (FStrEq(pcmd, "bot_nav_mark"))
{
- IMPL_CLASS(CCSBotManager, m_editCmd) = EDIT_MARK;
+ IMPL(m_editCmd) = EDIT_MARK;
}
else if (FStrEq(pcmd, "bot_nav_begin_area"))
{
- IMPL_CLASS(CCSBotManager, m_editCmd) = EDIT_BEGIN_AREA;
+ IMPL(m_editCmd) = EDIT_BEGIN_AREA;
}
else if (FStrEq(pcmd, "bot_nav_end_area"))
{
- IMPL_CLASS(CCSBotManager, m_editCmd) = EDIT_END_AREA;
+ IMPL(m_editCmd) = EDIT_END_AREA;
}
else if (FStrEq(pcmd, "bot_nav_connect"))
{
- IMPL_CLASS(CCSBotManager, m_editCmd) = EDIT_CONNECT;
+ IMPL(m_editCmd) = EDIT_CONNECT;
}
else if (FStrEq(pcmd, "bot_nav_disconnect"))
{
- IMPL_CLASS(CCSBotManager, m_editCmd) = EDIT_DISCONNECT;
+ IMPL(m_editCmd) = EDIT_DISCONNECT;
}
else if (FStrEq(pcmd, "bot_nav_splice"))
{
- IMPL_CLASS(CCSBotManager, m_editCmd) = EDIT_SPLICE;
+ IMPL(m_editCmd) = EDIT_SPLICE;
}
else if (FStrEq(pcmd, "bot_nav_crouch"))
{
- IMPL_CLASS(CCSBotManager, m_editCmd) = EDIT_ATTRIB_CROUCH;
+ IMPL(m_editCmd) = EDIT_ATTRIB_CROUCH;
}
else if (FStrEq(pcmd, "bot_nav_jump"))
{
- IMPL_CLASS(CCSBotManager, m_editCmd) = EDIT_ATTRIB_JUMP;
+ IMPL(m_editCmd) = EDIT_ATTRIB_JUMP;
}
else if (FStrEq(pcmd, "bot_nav_precise"))
{
- IMPL_CLASS(CCSBotManager, m_editCmd) = EDIT_ATTRIB_PRECISE;
+ IMPL(m_editCmd) = EDIT_ATTRIB_PRECISE;
}
else if (FStrEq(pcmd, "bot_nav_no_jump"))
{
- IMPL_CLASS(CCSBotManager, m_editCmd) = EDIT_ATTRIB_NO_JUMP;
+ IMPL(m_editCmd) = EDIT_ATTRIB_NO_JUMP;
}
else if (FStrEq(pcmd, "bot_nav_analyze"))
{
- IMPL_CLASS(CCSBotManager, m_isAnalysisRequested) = true;
+ IMPL(m_isAnalysisRequested) = true;
}
else if (FStrEq(pcmd, "bot_nav_strip"))
{
- StripNavigationAreas();// TODO: reverse me
+ StripNavigationAreas();
}
else if (FStrEq(pcmd, "bot_nav_save"))
{
@@ -545,7 +626,7 @@ void CCSBotManager::__MAKE_VHOOK(ServerCommand)(const char *pcmd)
Q_strcat(buffer, CBotManager::GetNavMapFilename());
- if (SaveNavigationMap(buffer))// TODO: reverse me
+ if (SaveNavigationMap(buffer))
CONSOLE_ECHO("Navigation map '%s' saved.\n", buffer);
else
CONSOLE_ECHO("ERROR: Cannot save navigation map '%s'.\n", buffer);
@@ -558,10 +639,10 @@ void CCSBotManager::__MAKE_VHOOK(ServerCommand)(const char *pcmd)
{
if (CMD_ARGC() == 1)
{
+ // no arguments = list all available places
int i = 0;
const BotPhraseList *placeList = TheBotPhrases->GetPlaceList();
-
- for (BotPhraseList::const_iterator iter = placeList->begin(); iter != placeList->end(); ++iter, i++)
+ for (BotPhraseList::const_iterator iter = placeList->begin(); iter != placeList->end(); ++iter, ++i)
{
if ((*iter)->GetID() == GetNavPlace())
CONSOLE_ECHO("--> %-26s", (*iter)->GetName());
@@ -575,34 +656,38 @@ void CCSBotManager::__MAKE_VHOOK(ServerCommand)(const char *pcmd)
}
else
{
+ // single argument = set current place
const BotPhraseList *placeList = TheBotPhrases->GetPlaceList();
const BotPhrase *found = NULL;
bool isAmbiguous = false;
-
for (BotPhraseList::const_iterator iter = placeList->begin(); iter != placeList->end(); ++iter)
{
if (!Q_strnicmp((*iter)->GetName(), msg, Q_strlen(msg)))
{
+ // check for exact match in case of subsets of other strings
if (!Q_strcmp((*iter)->GetName(), msg))
{
found = (*iter);
+ isAmbiguous = false;
break;
}
if (found != NULL)
+ {
isAmbiguous = true;
+ }
else
+ {
found = (*iter);
+ }
}
}
if (isAmbiguous)
{
CONSOLE_ECHO("Ambiguous\n");
- return;
}
-
- if (found != NULL)
+ else
{
CONSOLE_ECHO("Current place set to '%s'\n", found->GetName());
m_navPlace = found->GetID();
@@ -611,24 +696,24 @@ void CCSBotManager::__MAKE_VHOOK(ServerCommand)(const char *pcmd)
}
else if (FStrEq(pcmd, "bot_nav_toggle_place_mode"))
{
- IMPL_CLASS(CCSBotManager, m_editCmd) = EDIT_TOGGLE_PLACE_MODE;
+ IMPL(m_editCmd) = EDIT_TOGGLE_PLACE_MODE;
}
else if (FStrEq(pcmd, "bot_nav_place_floodfill"))
{
- IMPL_CLASS(CCSBotManager, m_editCmd) = EDIT_PLACE_FLOODFILL;
+ IMPL(m_editCmd) = EDIT_PLACE_FLOODFILL;
}
else if (FStrEq(pcmd, "bot_nav_place_pick"))
{
- IMPL_CLASS(CCSBotManager, m_editCmd) = EDIT_PLACE_PICK;
+ IMPL(m_editCmd) = EDIT_PLACE_PICK;
}
else if (FStrEq(pcmd, "bot_nav_toggle_place_painting"))
{
- IMPL_CLASS(CCSBotManager, m_editCmd) = EDIT_TOGGLE_PLACE_PAINTING;
+ IMPL(m_editCmd) = EDIT_TOGGLE_PLACE_PAINTING;
}
else if (FStrEq(pcmd, "bot_goto_mark"))
{
// tell the first bot we find to go to our marked area
- CNavArea *area = GetMarkedArea();// TODO: reverse me
+ CNavArea *area = GetMarkedArea();
if (area != NULL)
{
CBaseEntity *pEntity = NULL;
@@ -644,9 +729,13 @@ void CCSBotManager::__MAKE_VHOOK(ServerCommand)(const char *pcmd)
if (playerOrBot->IsBot())
{
- CCSBot *bot = reinterpret_cast(playerOrBot);
- bot->MoveTo(&area->m_center, FASTEST_ROUTE);// TODO: reverse me
- return;
+ CCSBot *bot = static_cast(playerOrBot);
+ if (bot != NULL)
+ {
+ bot->MoveTo(&area->m_center, FASTEST_ROUTE);
+ }
+
+ break;
}
}
}
@@ -671,7 +760,6 @@ void CCSBotManager::__MAKE_VHOOK(ServerCommand)(const char *pcmd)
for (SpotEncounterList::iterator siter = area->m_spotEncounterList.begin(); siter != area->m_spotEncounterList.end(); ++siter)
{
- // TODO: Fix me, this is crashed in HOOK_GAMEDLL
SpotEncounter se = (*siter);
encounterMem += sizeof(SpotEncounter);
@@ -683,23 +771,23 @@ void CCSBotManager::__MAKE_VHOOK(ServerCommand)(const char *pcmd)
}
else if (FStrEq(pcmd, "bot_nav_mark_unnamed"))
{
- IMPL_CLASS(CCSBotManager, m_editCmd) = EDIT_MARK_UNNAMED;
+ IMPL(m_editCmd) = EDIT_MARK_UNNAMED;
}
else if (FStrEq(pcmd, "bot_nav_warp"))
{
- IMPL_CLASS(CCSBotManager, m_editCmd) = EDIT_WARP_TO_MARK;
+ IMPL(m_editCmd) = EDIT_WARP_TO_MARK;
}
else if (FStrEq(pcmd, "bot_nav_corner_select"))
{
- IMPL_CLASS(CCSBotManager, m_editCmd) = EDIT_SELECT_CORNER;
+ IMPL(m_editCmd) = EDIT_SELECT_CORNER;
}
else if (FStrEq(pcmd, "bot_nav_corner_raise"))
{
- IMPL_CLASS(CCSBotManager, m_editCmd) = EDIT_RAISE_CORNER;
+ IMPL(m_editCmd) = EDIT_RAISE_CORNER;
}
else if (FStrEq(pcmd, "bot_nav_corner_lower"))
{
- IMPL_CLASS(CCSBotManager, m_editCmd) = EDIT_LOWER_CORNER;
+ IMPL(m_editCmd) = EDIT_LOWER_CORNER;
}
else if (FStrEq(pcmd, "bot_nav_check_consistency"))
{
@@ -709,23 +797,42 @@ void CCSBotManager::__MAKE_VHOOK(ServerCommand)(const char *pcmd)
return;
}
- SanityCheckNavigationMap(msg);// TODO: reverse me
+ SanityCheckNavigationMap(msg);
}
}
-/* <36c3c2> ../cstrike/dlls/bot/cs_bot_manager.cpp:903 */
-NOBODY bool CCSBotManager::BotAddCommand(BotProfileTeamType team, bool isFromConsole)
+/* <36b6e1> ../cstrike/dlls/bot/cs_bot_manager.cpp:896 */
+BOOL CCSBotManager::__MAKE_VHOOK(ClientCommand)(CBasePlayer *pPlayer, const char *pcmd)
{
- if (IMPL(m_isLearningMap) || ENG_CHECK_PARM("-nobots", NULL))
+#ifndef REGAMEDLL_FIXES
+ if (pPlayer && UTIL_GetLocalPlayer())
+ {
+ UTIL_GetLocalPlayer();
+ }
+#endif // REGAMEDLL_FIXES
+
+ return FALSE;
+}
+
+// Process the "bot_add" console command
+
+/* <36c3c2> ../cstrike/dlls/bot/cs_bot_manager.cpp:903 */
+bool CCSBotManager::BotAddCommand(BotProfileTeamType team, bool isFromConsole)
+{
+ // dont allow bots to join if the Navigation Area is being generated
+ if (IMPL(m_isLearningMap))
+ return false;
+
+ if (!AreBotsAllowed())
return false;
const BotProfile *profile = NULL;
if (!isFromConsole || CMD_ARGC() < 2)
{
+ // if team not specified, check cv_bot_join_team cvar for preference
if (team == BOT_TEAM_ANY)
{
- // if team not specified, check cv_bot_join_team cvar for preference
if (!Q_stricmp(cv_bot_join_team.string, "T"))
team = BOT_TEAM_T;
@@ -758,7 +865,7 @@ NOBODY bool CCSBotManager::BotAddCommand(BotProfileTeamType team, bool isFromCon
bool ignoreHumans = false;
CHalfLifeMultiplay *mp = g_pGameRules;
- if (mp && mp->IsCareer())
+ if (mp != NULL && mp->IsCareer())
ignoreHumans = true;
if (UTIL_IsNameTaken(CMD_ARGV(1), ignoreHumans))
@@ -776,7 +883,7 @@ NOBODY bool CCSBotManager::BotAddCommand(BotProfileTeamType team, bool isFromCon
}
// create the bot
- if (CCSBotManager::AddBot(profile, team)) // TODO: Reverse me
+ if (AddBot(profile, team))
{
if (isFromConsole)
{
@@ -788,37 +895,178 @@ NOBODY bool CCSBotManager::BotAddCommand(BotProfileTeamType team, bool isFromCon
return true;
}
+// Keep a minimum quota of bots in the game
+
/* <36d10f> ../cstrike/dlls/bot/cs_bot_manager.cpp:979 */
-NOBODY void CCSBotManager::MaintainBotQuota(void)
+void CCSBotManager::MaintainBotQuota(void)
{
-// {
-// int totalHumansInGame; // 984
-// int humanPlayersInGame; // 985
-// class CHalfLifeMultiplay *mp; // 991
-// int desiredBotCount; // 993
-// BotAddCommand(BotProfileTeamType team,
-// bool isFromConsole); // 1017
-// {
-// enum TeamName kickTeam; // 1027
-// }
-// {
-// bool humansAreCTs; // 1067
-// }
-// }
+ if (IMPL(m_isLearningMap))
+ return;
+
+ CHalfLifeMultiplay *mp = g_pGameRules;
+ int totalHumansInGame = UTIL_HumansInGame();
+ int humanPlayersInGame = UTIL_HumansInGame(IGNORE_SPECTATORS);
+
+ // don't add bots until local player has been registered, to make sure he's player ID #1
+ if (!IS_DEDICATED_SERVER() && totalHumansInGame == 0)
+ return;
+
+ int desiredBotCount = (int)cv_bot_quota.value;
+ int botsInGame = UTIL_BotsInGame();
+
+ if (cv_bot_quota_match.value > 0.0)
+ {
+ desiredBotCount = (int)(humanPlayersInGame * cv_bot_quota_match.value);
+ }
+
+ // wait for a player to join, if necessary
+ if (cv_bot_join_after_player.value > 0.0)
+ {
+ if (humanPlayersInGame == 0)
+ desiredBotCount = 0;
+ }
+
+ // if bots will auto-vacate, we need to keep one slot open to allow players to join
+ if (cv_bot_auto_vacate.value > 0.0)
+ desiredBotCount = Q_min(desiredBotCount, gpGlobals->maxClients - (totalHumansInGame + 1));
+ else
+ desiredBotCount = Q_min(desiredBotCount, gpGlobals->maxClients - totalHumansInGame);
+
+ // add bots if necessary
+ if (desiredBotCount > botsInGame)
+ {
+ // don't try to add a bot if all teams are full
+ if (!mp->TeamFull(TERRORIST) || !mp->TeamFull(CT))
+ BotAddCommand(BOT_TEAM_ANY);
+ }
+ else if (desiredBotCount < botsInGame)
+ {
+ // kick a bot to maintain quota
+
+ // first remove any unassigned bots
+ if (UTIL_KickBotFromTeam(UNASSIGNED))
+ return;
+
+ TeamName kickTeam;
+
+ // remove from the team that has more players
+ if (mp->m_iNumTerrorist > mp->m_iNumCT)
+ {
+ kickTeam = TERRORIST;
+ }
+ else if (mp->m_iNumTerrorist < mp->m_iNumCT)
+ {
+ kickTeam = CT;
+ }
+ // remove from the team that's winning
+ else if (mp->m_iNumTerroristWins > mp->m_iNumCTWins)
+ {
+ kickTeam = TERRORIST;
+ }
+ else if (mp->m_iNumCTWins > mp->m_iNumTerroristWins)
+ {
+ kickTeam = CT;
+ }
+ else
+ {
+ // teams and scores are equal, pick a team at random
+ kickTeam = (RANDOM_LONG(0, 1) == 0) ? CT : TERRORIST;
+ }
+
+ // attempt to kick a bot from the given team
+ if (UTIL_KickBotFromTeam(kickTeam))
+ return;
+
+ // if there were no bots on the team, kick a bot from the other team
+ if (kickTeam == TERRORIST)
+ UTIL_KickBotFromTeam(CT);
+ else
+ UTIL_KickBotFromTeam(TERRORIST);
+ }
+ else
+ {
+ if (mp != NULL && !mp->IsCareer())
+ return;
+
+ bool humansAreCTs = (Q_strcmp(humans_join_team.string, "CT") == 0);
+
+ if (humansAreCTs)
+ {
+ if (mp->m_iNumCT <= 6)
+ return;
+
+ UTIL_KickBotFromTeam(CT);
+ }
+ else
+ {
+ if (mp->m_iNumTerrorist <= 6)
+ return;
+
+ UTIL_KickBotFromTeam(TERRORIST);
+ }
+
+ CVAR_SET_FLOAT("bot_quota", cv_bot_quota.value - 1.0f);
+ }
}
/* <36d1dd> ../cstrike/dlls/bot/cs_bot_manager.cpp:1086 */
-NOBODY void CCSBotManager::MonitorBotCVars(void)
+void CCSBotManager::MonitorBotCVars(void)
{
+ if (cv_bot_nav_edit.value != 0.0f)
+ {
+ EditNavAreas(IMPL(m_editCmd));
+ IMPL(m_editCmd) = EDIT_NONE;
+ }
+
+ if (gpGlobals->time >= IMPL(m_flNextCVarCheck))
+ {
+ if (cv_bot_show_danger.value != 0.0f)
+ DrawDanger();
+
+ MaintainBotQuota();
+ IMPL(m_flNextCVarCheck) = gpGlobals->time + 0.3f;
+ }
}
+// Collect all nav areas that overlap the given zone
+class CollectOverlappingAreas
+{
+public:
+ CollectOverlappingAreas(CCSBotManager::Zone *zone)
+ {
+ m_zone = zone;
+ zone->m_areaCount = 0;
+ }
+ bool operator()(CNavArea *area)
+ {
+ const Extent *areaExtent = area->GetExtent();
+
+ if (areaExtent->hi.x >= m_zone->m_extent.lo.x && areaExtent->lo.x <= m_zone->m_extent.hi.x
+ && areaExtent->hi.y >= m_zone->m_extent.lo.y && areaExtent->lo.y <= m_zone->m_extent.hi.y
+ && areaExtent->hi.z >= m_zone->m_extent.lo.z && areaExtent->lo.z <= m_zone->m_extent.hi.z)
+ {
+ // area overlaps m_zone
+ m_zone->m_area[ m_zone->m_areaCount++ ] = area;
+ if (m_zone->m_areaCount == CCSBotManager::MAX_ZONE_NAV_AREAS)
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+private:
+ CCSBotManager::Zone *m_zone;
+};
+
+// Search the map entities to determine the game scenario and define important zones.
+
/* <36b780> ../cstrike/dlls/bot/cs_bot_manager.cpp:1109 */
void CCSBotManager::ValidateMapData(void)
{
if (IMPL(m_isMapDataLoaded) || !UTIL_IsGame("czero"))
- {
return;
- }
IMPL(m_isMapDataLoaded) = true;
@@ -838,8 +1086,7 @@ void CCSBotManager::ValidateMapData(void)
CBaseEntity *entity = NULL;
int i;
-
- for (i = 1; i < gpGlobals->maxEntities; i++)
+ for (i = 1; i < gpGlobals->maxEntities; ++i)
{
entity = CBaseEntity::Instance(INDEXENT(i));
@@ -851,31 +1098,27 @@ void CCSBotManager::ValidateMapData(void)
if (FClassnameIs(entity->pev, "func_bomb_target"))
{
+ m_gameScenario = SCENARIO_DEFUSE_BOMB;
found = true;
isLegacy = false;
-
- m_gameScenario = SCENARIO_DEFUSE_BOMB;
}
else if (FClassnameIs(entity->pev, "info_bomb_target"))
{
+ m_gameScenario = SCENARIO_DEFUSE_BOMB;
found = true;
isLegacy = true;
-
- m_gameScenario = SCENARIO_DEFUSE_BOMB;
}
else if (FClassnameIs(entity->pev, "func_hostage_rescue"))
{
+ m_gameScenario = SCENARIO_RESCUE_HOSTAGES;
found = true;
isLegacy = false;
-
- m_gameScenario = SCENARIO_RESCUE_HOSTAGES;
}
else if (FClassnameIs(entity->pev, "info_hostage_rescue"))
{
+ m_gameScenario = SCENARIO_RESCUE_HOSTAGES;
found = true;
isLegacy = true;
-
- m_gameScenario = SCENARIO_RESCUE_HOSTAGES;
}
else if (FClassnameIs(entity->pev, "hostage_entity"))
{
@@ -886,26 +1129,19 @@ void CCSBotManager::ValidateMapData(void)
}
else if (FClassnameIs(entity->pev, "func_vip_safetyzone"))
{
+ m_gameScenario = SCENARIO_ESCORT_VIP;
found = true;
isLegacy = false;
-
- m_gameScenario = SCENARIO_ESCORT_VIP;
}
if (found)
{
if (m_zoneCount < MAX_ZONES)
{
- if (isLegacy)
- m_zone[ m_zoneCount ].m_center = entity->pev->origin;
- else
- m_zone[ m_zoneCount ].m_center = (entity->pev->absmax + entity->pev->absmin) / 2.0f;
-
+ m_zone[ m_zoneCount ].m_center = (isLegacy) ? entity->pev->origin : (entity->pev->absmax + entity->pev->absmin) / 2.0f;
m_zone[ m_zoneCount ].m_isLegacy = isLegacy;
m_zone[ m_zoneCount ].m_index = m_zoneCount;
- m_zone[ m_zoneCount ].m_entity = entity;
-
- ++m_zoneCount;
+ m_zone[ m_zoneCount++ ].m_entity = entity;
}
else
CONSOLE_ECHO("Warning: Too many zones, some will be ignored.\n");
@@ -928,9 +1164,7 @@ void CCSBotManager::ValidateMapData(void)
m_zone[ m_zoneCount ].m_center = entity->pev->origin;
m_zone[ m_zoneCount ].m_isLegacy = true;
m_zone[ m_zoneCount ].m_index = m_zoneCount;
- m_zone[ m_zoneCount ].m_entity = entity;
-
- ++m_zoneCount;
+ m_zone[ m_zoneCount++ ].m_entity = entity;
}
else
CONSOLE_ECHO("Warning: Too many zones, some will be ignored.\n");
@@ -938,18 +1172,16 @@ void CCSBotManager::ValidateMapData(void)
}
// Collect nav areas that overlap each zone
- for (i = 0; i < m_zoneCount; i++)
+ for (i = 0; i < m_zoneCount; ++i)
{
Zone *zone = &m_zone[i];
if (zone->m_isLegacy)
{
const float legacyRange = 256.0f;
-
zone->m_extent.lo.x = zone->m_center.x - legacyRange;
zone->m_extent.lo.y = zone->m_center.y - legacyRange;
zone->m_extent.lo.z = zone->m_center.z - legacyRange;
-
zone->m_extent.hi.x = zone->m_center.x + legacyRange;
zone->m_extent.hi.y = zone->m_center.y + legacyRange;
zone->m_extent.hi.z = zone->m_center.z + legacyRange;
@@ -962,30 +1194,12 @@ void CCSBotManager::ValidateMapData(void)
// ensure Z overlap
const float zFudge = 50.0f;
-
- zone->m_areaCount = 0;
zone->m_extent.lo.z -= zFudge;
zone->m_extent.hi.z += zFudge;
// build a list of nav areas that overlap this zone
- for (NavAreaList::iterator iter = TheNavAreaList.begin(); iter != TheNavAreaList.end(); ++iter)
- {
- CNavArea *area = (*iter);
- const Extent *areaExtent = area->GetExtent();
-
- if (areaExtent->hi.x >= zone->m_extent.lo.x && areaExtent->lo.x <= zone->m_extent.hi.x
- && areaExtent->hi.y >= zone->m_extent.lo.y && areaExtent->lo.y <= zone->m_extent.hi.y
- && areaExtent->hi.z >= zone->m_extent.lo.z && areaExtent->lo.z <= zone->m_extent.hi.z)
- {
- // area overlaps zone
- zone->m_area[ zone->m_areaCount++ ] = area;
-
- if (zone->m_areaCount == MAX_ZONE_NAV_AREAS)
- {
- break;
- }
- }
- }
+ CollectOverlappingAreas collector(zone);
+ ForAllAreas(collector);
}
}
@@ -994,94 +1208,102 @@ void (*pCCSBotManager__AddBot)(void);
/* <36c2b2> ../cstrike/dlls/bot/cs_bot_manager.cpp:1278 */
NOBODY bool __declspec(naked) CCSBotManager::AddBot(const BotProfile *profile, BotProfileTeamType team)
{
+#if 1
__asm
{
jmp pCCSBotManager__AddBot
}
+#else
+ if (!UTIL_IsGame("czero"))
+ return false;
- //if (!UTIL_IsGame("czero"))
- // return false;
+ CHalfLifeMultiplay *mp = g_pGameRules;
- //CHalfLifeMultiplay *mp = g_pGameRules;
+ int nTeamSlot = UNASSIGNED;
+
+ if (team == BOT_TEAM_ANY)
+ {
+ // if team not specified, check cv_bot_join_team cvar for preference
+ if (!Q_stricmp(cv_bot_join_team.string, "T"))
+ nTeamSlot = TERRORIST;
- //int nTeamSlot = UNASSIGNED;
- //
- //if (team == BOT_TEAM_ANY)
- //{
- // // if team not specified, check cv_bot_join_team cvar for preference
- // if (!Q_stricmp(cv_bot_join_team.string, "T"))
- // nTeamSlot = TERRORIST;
+ else if (!Q_stricmp(cv_bot_join_team.string, "CT"))
+ nTeamSlot = CT;
+ }
+ else if (team == BOT_TEAM_CT)
+ nTeamSlot = CT;
- // else if (!Q_stricmp(cv_bot_join_team.string, "CT"))
- // nTeamSlot = CT;
- //}
- //else if (team == BOT_TEAM_CT)
- // nTeamSlot = CT;
+ else if (team == BOT_TEAM_T)
+ nTeamSlot = TERRORIST;
- //else if (team == BOT_TEAM_T)
- // nTeamSlot = TERRORIST;
+ if (nTeamSlot == UNASSIGNED)
+ {
+ nTeamSlot = SelectDefaultTeam();
+ }
- //if (nTeamSlot == UNASSIGNED)
- //{
- // nTeamSlot = SelectDefaultTeam();
- //}
+ if (nTeamSlot == UNASSIGNED || mp->TeamFull(nTeamSlot))
+ {
+ CONSOLE_ECHO("Could not add bot to the game: Team is full\n");
+ return false;
+ }
- //if (nTeamSlot == UNASSIGNED || mp->TeamFull(nTeamSlot))
- //{
- // CONSOLE_ECHO("Could not add bot to the game: Team is full\n");
- // return false;
- //}
+ if (mp->TeamStacked(nTeamSlot, UNASSIGNED))
+ {
+ CONSOLE_ECHO("Could not add bot to the game: Team is stacked (to disable this check, set mp_limitteams and mp_autoteambalance to zero and restart the round).\n");
+ return false;
+ }
- //if (mp->TeamStacked(nTeamSlot, UNASSIGNED))
- //{
- // CONSOLE_ECHO("Could not add bot to the game: Team is stacked (to disable this check, set mp_limitteams and mp_autoteambalance to zero and restart the round).\n");
- // return false;
- //}
+ CCSBot *pBot = CreateBot(profile);
+ if (pBot == NULL)
+ {
+ return false;
+ }
- //CCSBot *pBot = CreateBot(profile);
- //if (pBot == NULL)
- //{
- // return false;
- //}
+ //int nJoinedTeam;
+ ClientPutInServer(pBot->edict());
+ SET_CLIENT_KEY_VALUE(pBot->entindex(), GET_INFO_BUFFER(pBot->edict()), "*bot", "1");
- ////int nJoinedTeam;
- //ClientPutInServer(pBot->edict());
- //SET_CLIENT_KEY_VALUE(pBot->entindex(), GET_INFO_BUFFER(pBot->edict()), "*bot", "1");
+ pBot->m_iMenu = Menu_ChooseTeam;
+ pBot->m_iJoiningState = PICKINGTEAM;
- //pBot->m_iMenu = Menu_ChooseTeam;
- //pBot->m_iJoiningState = PICKINGTEAM;
+ if (HandleMenu_ChooseTeam(pBot, nTeamSlot))
+ {
+ int skin = profile->GetSkin();
- //if (HandleMenu_ChooseTeam(pBot, nTeamSlot))//TODO: Reverse me
- //{
- // int skin = profile->GetSkin();
+ if (!skin)
+ skin = 6;// MODEL_GIGN?
- // if (!skin)
- // skin = 6;// MODEL_GIGN?
+ HandleMenu_ChooseAppearance(pBot, skin);
- // HandleMenu_ChooseAppearance(pBot, skin);//TODO: Reverse me
+ if (IS_DEDICATED_SERVER())
+ {
+ UTIL_DPrintf("Added bot %s to server\n", STRING(pBot->pev->netname));
+ }
- // if (IS_DEDICATED_SERVER())
- // {
- // UTIL_DPrintf("Added bot %s to server\n", STRING(pBot->pev->netname));
- // }
+ return true;
+ }
- // return true;
- //}
+ SERVER_COMMAND(UTIL_VarArgs("kick \"%s\"\n", STRING(pBot->pev->netname)));
+ CONSOLE_ECHO("Could not add bot to the game.\n");
- //SERVER_COMMAND(UTIL_VarArgs("kick \"%s\"\n", STRING(pBot->pev->netname)));
- //CONSOLE_ECHO("Could not add bot to the game.\n");
-
- //return false;
+ return false;
+#endif
}
+// Return the zone that contains the given position
+
/* <36bb90> ../cstrike/dlls/bot/cs_bot_manager.cpp:1375 */
-NOBODY const CCSBotManager::Zone *CCSBotManager::GetZone(const Vector *pos) const
+const CCSBotManager::Zone *CCSBotManager::GetZone(const Vector *pos) const
{
-// {
-// int z; // 1377
-// Contains(const class Extent *const this,
-// const Vector *pos); // 1379
-// }
+ for (int z = 0; z < m_zoneCount; ++z)
+ {
+ if (m_zone[z].m_extent.Contains(pos))
+ {
+ return &m_zone[z];
+ }
+ }
+
+ return NULL;
}
// Return the closest zone to the given position
@@ -1092,7 +1314,7 @@ const CCSBotManager::Zone *CCSBotManager::GetClosestZone(const Vector *pos) cons
const Zone *close = NULL;
float closeRangeSq = 1e9f;
- for (int z = 0; z < m_zoneCount; z++)
+ for (int z = 0; z < m_zoneCount; ++z)
{
float rangeSq = (m_zone[z].m_center - (*pos)).LengthSquared();
@@ -1106,26 +1328,56 @@ const CCSBotManager::Zone *CCSBotManager::GetClosestZone(const Vector *pos) cons
return close;
}
+// Return a random position inside the given zone
+
/* <36bcc9> ../cstrike/dlls/bot/cs_bot_manager.cpp:1415 */
-NOBODY const Vector *CCSBotManager::GetRandomPositionInZone(const Zone *zone) const
+const Vector *CCSBotManager::GetRandomPositionInZone(const Zone *zone) const
{
-// {
-// Vector pos; // 1417
-// int a; // 1426
-// class CNavArea *area; // 1427
-// {
-// const class Extent *areaExtent; // 1439
-// class Extent overlap; // 1440
-// }
-// }
+ static Vector pos;
+
+ if (zone == NULL)
+ return NULL;
+
+ if (zone->m_areaCount == 0)
+ return NULL;
+
+ // pick a random overlapping area
+ CNavArea *area = GetRandomAreaInZone(zone);
+
+ // pick a location inside both the nav area and the zone
+ // TODO: Randomize this
+ if (zone->m_isLegacy)
+ {
+ // TODO: It is possible that the radius might not overlap this area at all...
+ area->GetClosestPointOnArea(&zone->m_center, &pos);
+ }
+ else
+ {
+ const Extent &areaExtent = *area->GetExtent();
+ Extent overlap;
+ overlap.lo.x = Q_max(areaExtent.lo.x, zone->m_extent.lo.x);
+ overlap.lo.y = Q_max(areaExtent.lo.y, zone->m_extent.lo.y);
+ overlap.hi.x = Q_min(areaExtent.hi.x, zone->m_extent.hi.x);
+ overlap.hi.y = Q_min(areaExtent.hi.y, zone->m_extent.hi.y);
+
+ pos.x = (overlap.lo.x + overlap.hi.x) / 2.0f;
+ pos.y = (overlap.lo.y + overlap.hi.y) / 2.0f;
+ pos.z = area->GetZ(&pos);
+ }
+
+ return &pos;
}
+// Return a random area inside the given zone
+
/* <36bd64> ../cstrike/dlls/bot/cs_bot_manager.cpp:1458 */
-NOBODY CNavArea *CCSBotManager::GetRandomAreaInZone(const Zone *zone) const
+CNavArea *CCSBotManager::GetRandomAreaInZone(const Zone *zone) const
{
-// {
-// int a; // 1466
-// }
+ // TODO: improvement is needed
+ if (!zone->m_areaCount)
+ return NULL;
+
+ return zone->m_area[ RANDOM_LONG(0, zone->m_areaCount - 1) ];
}
/* <36b02d> ../cstrike/dlls/bot/cs_bot_manager.cpp:1477 */
@@ -1169,22 +1421,12 @@ void CCSBotManager::__MAKE_VHOOK(OnEvent)(GameEventType event, CBaseEntity *enti
CBotManager::OnEvent(event, entity, other);
}
-BOOL CCSBotManager::__MAKE_VHOOK(ClientCommand)(CBasePlayer *pPlayer, const char *pcmd)
-{
- // TODO: rly?
-#ifndef REGAMEDLL_FIXES
- if (pPlayer && UTIL_GetLocalPlayer())
- {
- UTIL_GetLocalPlayer();
- }
-#endif // REGAMEDLL_FIXES
-
- return FALSE;
-}
+// Get the time remaining before the planted bomb explodes
/* <36bdb3> ../cstrike/dlls/bot/cs_bot_manager.cpp:1541 */
-NOBODY float CCSBotManager::GetBombTimeLeft(void) const
+float CCSBotManager::GetBombTimeLeft(void) const
{
+ return (g_pGameRules->m_iC4Timer - (gpGlobals->time - m_bombPlantTimestamp));
}
/* <36bddb> ../cstrike/dlls/bot/cs_bot_manager.cpp:1547 */
@@ -1193,44 +1435,140 @@ void CCSBotManager::SetLooseBomb(CBaseEntity *bomb)
m_looseBomb = bomb;
if (bomb)
+ {
m_looseBombArea = TheNavAreaGrid.GetNearestNavArea(&bomb->pev->origin);
+ }
else
+ {
m_looseBombArea = NULL;
+ }
}
+// Return true if player is important to scenario (VIP, bomb carrier, etc)
+
/* <36b14d> ../cstrike/dlls/bot/cs_bot_manager.cpp:1565 */
-NOBODY bool CCSBotManager::__MAKE_VHOOK(IsImportantPlayer)(CBasePlayer *player)
+bool CCSBotManager::__MAKE_VHOOK(IsImportantPlayer)(CBasePlayer *player) const
{
-// IsImportantPlayer(const class CCSBotManager *const this,
-// class CBasePlayer *player); // 1565
+ switch (GetScenario())
+ {
+ case SCENARIO_DEFUSE_BOMB:
+ {
+ if (player->m_iTeam == TERRORIST && player->IsBombGuy())
+ return true;
+
+ // TODO: TEAM_CT's defusing the bomb are important
+ return false;
+ }
+ case SCENARIO_ESCORT_VIP:
+ {
+ if (player->m_iTeam == CT && player->m_bIsVIP)
+ return true;
+
+ return false;
+ }
+ case SCENARIO_RESCUE_HOSTAGES:
+ {
+ // TODO: TEAM_CT's escorting hostages are important
+ return false;
+ }
+ }
+
+ // everyone is equally important in a deathmatch
+ return false;
}
+// Return priority of player (0 = max pri)
+
/* <36b1a7> ../cstrike/dlls/bot/cs_bot_manager.cpp:1602 */
-NOBODY unsigned int CCSBotManager::__MAKE_VHOOK(GetPlayerPriority)(CBasePlayer *player) const
+unsigned int CCSBotManager::__MAKE_VHOOK(GetPlayerPriority)(CBasePlayer *player) const
{
-// {
-// unsigned int const lowestPriority; // 1604
-// class CCSBot *bot; // 1613
-// }
-// GetPlayerPriority(const class CCSBotManager *const this,
-// class CBasePlayer *player); // 1602
+ const unsigned int lowestPriority = 0xFFFFFFFF;
+
+ if (!player->IsPlayer())
+ return lowestPriority;
+
+ // human players have highest priority
+ if (!player->IsBot())
+ return 0;
+
+ CCSBot *bot = dynamic_cast(player);
+
+ if (!bot)
+ return 0;
+
+ // bots doing something important for the current scenario have high priority
+ switch (GetScenario())
+ {
+ case SCENARIO_DEFUSE_BOMB:
+ {
+ // the bomb carrier has high priority
+ if (bot->m_iTeam == TERRORIST && bot->m_bHasC4)
+ return 1;
+
+ break;
+ }
+ case SCENARIO_ESCORT_VIP:
+ {
+ // the VIP has high priority
+ if (bot->m_iTeam == CT && bot->m_bIsVIP)
+ return 1;
+
+ break;
+ }
+ case SCENARIO_RESCUE_HOSTAGES:
+ {
+ // TEAM_CT's rescuing hostages have high priority
+ if (bot->m_iTeam == CT && bot->GetHostageEscortCount())
+ return 1;
+
+ break;
+ }
+ }
+
+ // everyone else is ranked by their unique ID (which cannot be zero)
+ return 1 + bot->GetID();
}
+// Return the last time the given radio message was sent for given team
+// 'teamID' can be TEAM_CT or TEAM_TERRORIST
+
/* <36be2e> ../cstrike/dlls/bot/cs_bot_manager.cpp:1655 */
-NOBODY float CCSBotManager::GetRadioMessageTimestamp(GameEventType event, int teamID)
+float CCSBotManager::GetRadioMessageTimestamp(GameEventType event, int teamID) const
{
+ if (event <= EVENT_START_RADIO_1 || event >= EVENT_END_RADIO)
+ return 0.0f;
+
+ int i = (teamID == TERRORIST) ? 0 : 1;
+ return m_radioMsgTimestamp[ event - EVENT_START_RADIO_1 ][ i ];
}
+// Return the interval since the last time this message was sent
+
/* <36be76> ../cstrike/dlls/bot/cs_bot_manager.cpp:1667 */
-NOBODY float CCSBotManager::GetRadioMessageInterval(GameEventType event, int teamID)
+float CCSBotManager::GetRadioMessageInterval(GameEventType event, int teamID) const
{
+ if (event <= EVENT_START_RADIO_1 || event >= EVENT_END_RADIO)
+ return 99999999.9f;
+
+ int i = (teamID == TERRORIST) ? 0 : 1;
+ return gpGlobals->time - m_radioMsgTimestamp[ event - EVENT_START_RADIO_1 ][ i ];
}
+// Set the given radio message timestamp.
+// 'teamID' can be TEAM_CT or TEAM_TERRORIST
+
/* <36bebe> ../cstrike/dlls/bot/cs_bot_manager.cpp:1680 */
-NOBODY void CCSBotManager::SetRadioMessageTimestamp(GameEventType event, int teamID)
+void CCSBotManager::SetRadioMessageTimestamp(GameEventType event, int teamID)
{
+ if (event <= EVENT_START_RADIO_1 || event >= EVENT_END_RADIO)
+ return;
+
+ int i = (teamID == TERRORIST) ? 0 : 1;
+ m_radioMsgTimestamp[ event - 1 ][ i ] = gpGlobals->time;
}
+// Reset all radio message timestamps
+
/* <36bf06> ../cstrike/dlls/bot/cs_bot_manager.cpp:1690 */
void CCSBotManager::ResetRadioMessageTimestamps(void)
{
@@ -1300,7 +1638,7 @@ unsigned int CCSBotManager::GetPlayerPriority(CBasePlayer *player) const
return GetPlayerPriority_(player);
}
-bool CCSBotManager::IsImportantPlayer(CBasePlayer *player)
+bool CCSBotManager::IsImportantPlayer(CBasePlayer *player) const
{
return IsImportantPlayer_(player);
}
diff --git a/regamedll/dlls/bot/cs_bot_manager.h b/regamedll/dlls/bot/cs_bot_manager.h
index d74d5d18..9af572d4 100644
--- a/regamedll/dlls/bot/cs_bot_manager.h
+++ b/regamedll/dlls/bot/cs_bot_manager.h
@@ -36,36 +36,6 @@
#define TheBots (*pTheBots)
-#define cv_bot_traceview (*pcv_bot_traceview)
-#define cv_bot_stop (*pcv_bot_stop)
-#define cv_bot_show_nav (*pcv_bot_show_nav)
-#define cv_bot_show_danger (*pcv_bot_show_danger)
-#define cv_bot_nav_edit (*pcv_bot_nav_edit)
-#define cv_bot_nav_zdraw (*pcv_bot_nav_zdraw)
-#define cv_bot_walk (*pcv_bot_walk)
-#define cv_bot_difficulty (*pcv_bot_difficulty)
-#define cv_bot_debug (*pcv_bot_debug)
-#define cv_bot_quicksave (*pcv_bot_quicksave)
-#define cv_bot_quota (*pcv_bot_quota)
-#define cv_bot_quota_match (*pcv_bot_quota_match)
-#define cv_bot_prefix (*pcv_bot_prefix)
-#define cv_bot_allow_rogues (*pcv_bot_allow_rogues)
-#define cv_bot_allow_pistols (*pcv_bot_allow_pistols)
-#define cv_bot_allow_shotguns (*pcv_bot_allow_shotguns)
-#define cv_bot_allow_sub_machine_guns (*pcv_bot_allow_sub_machine_guns)
-#define cv_bot_allow_rifles (*pcv_bot_allow_rifles)
-#define cv_bot_allow_machine_guns (*pcv_bot_allow_machine_guns)
-#define cv_bot_allow_grenades (*pcv_bot_allow_grenades)
-#define cv_bot_allow_snipers (*pcv_bot_allow_snipers)
-#define cv_bot_allow_shield (*pcv_bot_allow_shield)
-#define cv_bot_join_team (*pcv_bot_join_team)
-#define cv_bot_join_after_player (*pcv_bot_join_after_player)
-#define cv_bot_auto_vacate (*pcv_bot_auto_vacate)
-#define cv_bot_zombie (*pcv_bot_zombie)
-#define cv_bot_defer_to_human (*pcv_bot_defer_to_human)
-#define cv_bot_chatter (*pcv_bot_chatter)
-#define cv_bot_profile_db (*pcv_bot_profile_db)
-
//#define m_flNextCVarCheck (*pm_flNextCVarCheck)
//#define m_isMapDataLoaded (*pm_isMapDataLoaded)
//#define m_editCmd (*pm_editCmd)
@@ -77,57 +47,28 @@
extern CBotManager *TheBots;
-extern cvar_t cv_bot_traceview;
-extern cvar_t cv_bot_stop;
-extern cvar_t cv_bot_show_nav;
-extern cvar_t cv_bot_show_danger;
-extern cvar_t cv_bot_nav_edit;
-extern cvar_t cv_bot_nav_zdraw;
-extern cvar_t cv_bot_walk;
-extern cvar_t cv_bot_difficulty;
-extern cvar_t cv_bot_debug;
-extern cvar_t cv_bot_quicksave;
-extern cvar_t cv_bot_quota;
-extern cvar_t cv_bot_quota_match;
-extern cvar_t cv_bot_prefix;
-extern cvar_t cv_bot_allow_rogues;
-extern cvar_t cv_bot_allow_pistols;
-extern cvar_t cv_bot_allow_shotguns;
-extern cvar_t cv_bot_allow_sub_machine_guns;
-extern cvar_t cv_bot_allow_rifles;
-extern cvar_t cv_bot_allow_machine_guns;
-extern cvar_t cv_bot_allow_grenades;
-extern cvar_t cv_bot_allow_snipers;
-extern cvar_t cv_bot_allow_shield;
-extern cvar_t cv_bot_join_team;
-extern cvar_t cv_bot_join_after_player;
-extern cvar_t cv_bot_auto_vacate;
-extern cvar_t cv_bot_zombie;
-extern cvar_t cv_bot_defer_to_human;
-extern cvar_t cv_bot_chatter;
-extern cvar_t cv_bot_profile_db;
-
+// The manager for Counter-Strike specific bots
class CCSBotManager: public CBotManager
{
public:
- CCSBotManager(void);
-public:
+ CCSBotManager();
+
virtual void ClientDisconnect(CBasePlayer *pPlayer);
virtual BOOL ClientCommand(CBasePlayer *pPlayer, const char *pcmd);
virtual void ServerActivate(void);
virtual void ServerDeactivate(void);
- NOBODY virtual void ServerCommand(const char *pcmd);
+ virtual void ServerCommand(const char *pcmd);
virtual void AddServerCommand(const char *cmd);
virtual void AddServerCommands(void);
- virtual void RestartRound(void);
- NOBODY virtual void StartFrame(void);
+ virtual void RestartRound(void); // (EXTEND) invoked when a new round begins
+ virtual void StartFrame(void); // (EXTEND) called each frame
virtual void OnEvent(GameEventType event, CBaseEntity *entity = NULL, CBaseEntity *other = NULL);
- NOBODY virtual unsigned int GetPlayerPriority(CBasePlayer *player) const;
- NOBODY virtual bool IsImportantPlayer(CBasePlayer *player);
+ virtual unsigned int GetPlayerPriority(CBasePlayer *player) const; // return priority of player (0 = max pri)
+ virtual bool IsImportantPlayer(CBasePlayer *player) const; // return true if player is important to scenario (VIP, bomb carrier, etc)
#ifdef HOOK_GAMEDLL
@@ -142,31 +83,19 @@ public:
void StartFrame_(void);
void OnEvent_(GameEventType event, CBaseEntity *entity, CBaseEntity *other);
unsigned int GetPlayerPriority_(CBasePlayer *player) const;
- bool IsImportantPlayer_(CBasePlayer *player);
+ bool IsImportantPlayer_(CBasePlayer *player) const;
#endif // HOOK_GAMEDLL
+
public:
void ValidateMapData(void);
- bool IsLearningMap(void)
- {
- return IMPL(m_isLearningMap);
- }
- void SetLearningMapFlag(void)
- {
- IMPL(m_isLearningMap) = true;
- }
- bool IsAnalysisRequested(void)
- {
- return IMPL(m_isAnalysisRequested);
- }
- void RequestAnalysis(void)
- {
- IMPL(m_isAnalysisRequested) = true;
- }
- void AckAnalysisRequest(void)
- {
- IMPL(m_isAnalysisRequested) = false;
- }
+ bool IsLearningMap(void) const { return IMPL(m_isLearningMap); }
+ void SetLearningMapFlag(void) { IMPL(m_isLearningMap) = true;}
+ bool IsAnalysisRequested(void) const { return IMPL(m_isAnalysisRequested); }
+ void RequestAnalysis(void) { IMPL(m_isAnalysisRequested) = true; }
+ void AckAnalysisRequest(void) { IMPL(m_isAnalysisRequested) = false; }
+
+ // difficulty levels
static BotDifficultyType GetDifficultyLevel(void)
{
if (cv_bot_difficulty.value < 0.9f)
@@ -181,41 +110,42 @@ public:
return BOT_EXPERT;
}
+ // the supported game scenarios
enum GameScenarioType
{
SCENARIO_DEATHMATCH,
SCENARIO_DEFUSE_BOMB,
SCENARIO_RESCUE_HOSTAGES,
- SCENARIO_ESCORT_VIP,
+ SCENARIO_ESCORT_VIP
};
- GameScenarioType GetScenario(void)
- {
- return m_gameScenario;
- }
+ GameScenarioType GetScenario(void) const { return m_gameScenario; }
- enum { MAX_ZONES = 4, MAX_ZONE_NAV_AREAS = 16 };
+ // "zones"
+ // depending on the game mode, these are bomb zones, rescue zones, etc.
+ enum { MAX_ZONES = 4 }; // max # of zones in a map
+ enum { MAX_ZONE_NAV_AREAS = 16 }; // max # of nav areas in a zone
struct Zone
{
- CBaseEntity *m_entity;
- CNavArea *m_area[MAX_ZONE_NAV_AREAS];
+ CBaseEntity *m_entity; // the map entity
+ CNavArea *m_area[MAX_ZONE_NAV_AREAS]; // nav areas that overlap this zone
int m_areaCount;
Vector m_center;
- bool m_isLegacy;
+ bool m_isLegacy; // if true, use pev->origin and 256 unit radius as zone
int m_index;
Extent m_extent;
};/* size: 116, cachelines: 2, members: 7 */
- const Zone *GetZone(int i) const
- {
- return &m_zone[i];
- }
- NOBODY const Zone *GetZone(const Vector *pos) const;
- const Zone *GetClosestZone(const Vector *pos) const;
- const Zone *GetClosestZone(const CBaseEntity *entity) const
- {
- return GetClosestZone(&entity->pev->origin);
- }
+ const Zone *GetZone(int i) const { return &m_zone[i]; }
+ const Zone *GetZone(const Vector *pos) const; // return the zone that contains the given position
+ const Zone *GetClosestZone(const Vector *pos) const; // return the closest zone to the given position
+ const Zone *GetClosestZone(const CBaseEntity *entity) const { return GetClosestZone(&entity->pev->origin); } // return the closest zone to the given entity
+ int GetZoneCount(void) const { return m_zoneCount; }
+
+ const Vector *GetRandomPositionInZone(const Zone *zone) const;
+ CNavArea *GetRandomAreaInZone(const Zone *zone) const;
+
+ // Return the zone closest to the given position, using the given cost heuristic
template
const Zone *GetClosestZone(CNavArea *startArea, CostFunctor costFunc, float *travelDistance = NULL) const
{
@@ -225,7 +155,7 @@ public:
if (startArea == NULL)
return NULL;
- for (int i = 0; i < m_zoneCount; i++)
+ for (int i = 0; i < m_zoneCount; ++i)
{
if (m_zone[i].m_areaCount == 0)
continue;
@@ -233,7 +163,9 @@ public:
if (m_zone[i].m_isBlocked)
continue;
+ // just use the first overlapping nav area as a reasonable approximation
float dist = NavAreaTravelDistance(startArea, m_zone[i].m_area[0], costFunc);
+
if (dist >= 0.0f && dist < closeDist)
{
closeZone = &m_zone[i];
@@ -241,17 +173,11 @@ public:
}
}
- if (travelDistance)
+ if (travelDistance != NULL)
*travelDistance = closeDist;
return closeZone;
}
- int GetZoneCount(void) const
- {
- return m_zoneCount;
- }
- NOBODY const Vector *GetRandomPositionInZone(const Zone *zone) const;
- NOBODY CNavArea *GetRandomAreaInZone(const Zone *zone) const;
// pick a zone at random and return it
const Zone *GetRandomZone(void) const
@@ -261,172 +187,89 @@ public:
return &m_zone[ RANDOM_LONG(0, m_zoneCount - 1) ];
}
- // returns true if bomb has been planted
- bool IsBombPlanted(void) const
- {
- return m_isBombPlanted;
- }
- // return time bomb was planted
- float GetBombPlantTimestamp(void)
- {
- return m_bombPlantTimestamp;
- }
- // return true if it's ok to try to plant bomb
- bool IsTimeToPlantBomb(void) const
- {
- return (gpGlobals->time >= m_earliestBombPlantTimestamp);
- }
- CBasePlayer *GetBombDefuser(void) const
- {
- return m_bombDefuser;
- }
- NOBODY float GetBombTimeLeft(void) const;
- // return the bomb if it is loose on the ground
- CBaseEntity *GetLooseBomb(void)
- {
- return m_looseBomb;
- }
- // return area that bomb is in/near
- CNavArea *GetLooseBombArea(void) const
- {
- return m_looseBombArea;
- }
+
+ bool IsBombPlanted(void) const { return m_isBombPlanted; } // returns true if bomb has been planted
+ float GetBombPlantTimestamp(void) const { return m_bombPlantTimestamp; } // return time bomb was planted
+ bool IsTimeToPlantBomb(void) const { return (gpGlobals->time >= m_earliestBombPlantTimestamp); } // return true if it's ok to try to plant bomb
+ CBasePlayer *GetBombDefuser(void) const { return m_bombDefuser; } // return the player currently defusing the bomb, or NULL
+ float GetBombTimeLeft(void) const; // get the time remaining before the planted bomb explodes
+ CBaseEntity *GetLooseBomb(void) { return m_looseBomb; } // return the bomb if it is loose on the ground
+ CNavArea *GetLooseBombArea(void) const { return m_looseBombArea; } // return area that bomb is in/near
void SetLooseBomb(CBaseEntity *bomb);
- NOBODY float GetRadioMessageTimestamp(GameEventType event, int teamID);
- NOBODY float GetRadioMessageInterval(GameEventType event, int teamID);
- NOBODY void SetRadioMessageTimestamp(GameEventType event, int teamID);
+
+ float GetRadioMessageTimestamp(GameEventType event, int teamID) const; // return the last time the given radio message was sent for given team
+ float GetRadioMessageInterval(GameEventType event, int teamID) const; // return the interval since the last time this message was sent
+ void SetRadioMessageTimestamp(GameEventType event, int teamID);
void ResetRadioMessageTimestamps(void);
- // return the last time anyone has seen an enemy
- float GetLastSeenEnemyTimestamp(void) const
- {
- return m_lastSeenEnemyTimestamp;
- }
- void SetLastSeenEnemyTimestamp(void)
- {
- m_lastSeenEnemyTimestamp = gpGlobals->time;
- }
- float GetRoundStartTime(void) const
- {
- return m_roundStartTimestamp;
- }
- // return the elapsed time since the current round began
- float GetElapsedRoundTime(void) const
- {
- return gpGlobals->time - m_roundStartTimestamp;
- }
- bool AllowRogues(void) const
- {
- return cv_bot_allow_rogues.value != 0;
- }
- bool AllowPistols(void) const
- {
- return cv_bot_allow_pistols.value != 0;
- }
- bool AllowShotguns(void) const
- {
- return cv_bot_allow_shotguns.value != 0;
- }
- bool AllowSubMachineGuns(void) const
- {
- return cv_bot_allow_sub_machine_guns.value != 0;
- }
- bool AllowRifles(void) const
- {
- return cv_bot_allow_rifles.value != 0;
- }
- bool AllowMachineGuns(void) const
- {
- return cv_bot_allow_machine_guns.value != 0;
- }
- bool AllowGrenades(void) const
- {
- return cv_bot_allow_grenades.value != 0;
- }
- bool AllowSnipers(void) const
- {
- return cv_bot_allow_snipers.value != 0;
- }
- bool AllowTacticalShield(void) const
- {
- return cv_bot_allow_shield.value != 0;
- }
- bool AllowFriendlyFireDamage(void) const
- {
- return friendlyfire.value != 0;
- }
- bool IsWeaponUseable(CBasePlayerItem *item) const;
- bool IsDefenseRushing(void) const
- {
- return m_isDefenseRushing;
- }
- NOBODY bool IsOnDefense(CBasePlayer *player) const;
- NOBODY bool IsOnOffense(CBasePlayer *player) const;
- bool IsRoundOver(void) const
- {
- return m_isRoundOver;
- }
- unsigned int GetNavPlace(void) const
- {
- return m_navPlace;
- }
- void SetNavPlace(unsigned int place)
- {
- m_navPlace = place;
- }
+ float GetLastSeenEnemyTimestamp(void) const { return m_lastSeenEnemyTimestamp; } // return the last time anyone has seen an enemy
+ void SetLastSeenEnemyTimestamp(void) { m_lastSeenEnemyTimestamp = gpGlobals->time; }
- enum SkillType
- {
- LOW,
- AVERAGE,
- HIGH,
- RANDOM
- };
+ float GetRoundStartTime(void) const { return m_roundStartTimestamp; }
+ float GetElapsedRoundTime(void) const { return gpGlobals->time - m_roundStartTimestamp; } // return the elapsed time since the current round began
+
+ bool AllowRogues(void) const { return cv_bot_allow_rogues.value != 0.0f; }
+ bool AllowPistols(void) const { return cv_bot_allow_pistols.value != 0.0f; }
+ bool AllowShotguns(void) const { return cv_bot_allow_shotguns.value != 0.0f; }
+ bool AllowSubMachineGuns(void) const { return cv_bot_allow_sub_machine_guns.value != 0.0f; }
+ bool AllowRifles(void) const { return cv_bot_allow_rifles.value != 0.0f; }
+ bool AllowMachineGuns(void) const { return cv_bot_allow_machine_guns.value != 0.0f; }
+ bool AllowGrenades(void) const { return cv_bot_allow_grenades.value != 0.0f; }
+ bool AllowSnipers(void) const { return cv_bot_allow_snipers.value != 0.0f; }
+ bool AllowTacticalShield(void) const { return cv_bot_allow_shield.value != 0.0f; }
+ bool AllowFriendlyFireDamage(void) const { return friendlyfire.value != 0.0f; }
+
+ bool IsWeaponUseable(CBasePlayerItem *item) const; // return true if the bot can use this weapon
+
+ bool IsDefenseRushing(void) const { return m_isDefenseRushing; } // returns true if defense team has "decided" to rush this round
+ bool IsOnDefense(CBasePlayer *player) const; // return true if this player is on "defense"
+ bool IsOnOffense(CBasePlayer *player) const; // return true if this player is on "offense"
+
+ bool IsRoundOver(void) const { return m_isRoundOver; } // return true if the round has ended
+
+ unsigned int GetNavPlace(void) const { return m_navPlace; }
+ void SetNavPlace(unsigned int place) { m_navPlace = place; }
+
+ enum SkillType { LOW, AVERAGE, HIGH, RANDOM };
NOXREF NOBODY const char *GetRandomBotName(SkillType skill);
- NOBODY static void MonitorBotCVars(void);
- NOBODY static void MaintainBotQuota(void);
+ static void MonitorBotCVars(void);
+ static void MaintainBotQuota(void);
NOBODY static bool AddBot(const BotProfile *profile, BotProfileTeamType team);
- NOBODY static bool BotAddCommand(BotProfileTeamType team, bool isFromConsole = true);
+
+ #define FROM_CONSOLE true
+ static bool BotAddCommand(BotProfileTeamType team, bool isFromConsole = false); // process the "bot_add" console command
#ifndef HOOK_GAMEDLL
private:
-#else
-public:
#endif // HOOK_GAMEDLL
static float IMPL(m_flNextCVarCheck);
- static bool IMPL(m_isMapDataLoaded);
+ static bool IMPL(m_isMapDataLoaded); // true if we've attempted to load map data
static bool IMPL(m_isLearningMap);
static bool IMPL(m_isAnalysisRequested);
-#ifdef HOOK_GAMEDLL
-private:
-#endif // HOOK_GAMEDLL
- GameScenarioType m_gameScenario;// TODO: must be on Windows offsetof - 16
+ GameScenarioType m_gameScenario; // what kind of game are we playing
+
Zone m_zone[ MAX_ZONES ];
int m_zoneCount;
- bool m_isBombPlanted;
- float m_bombPlantTimestamp;
- float m_earliestBombPlantTimestamp;
- CBasePlayer *m_bombDefuser;
- EHANDLE m_looseBomb;
- CNavArea *m_looseBombArea;
- bool m_isRoundOver;
+
+ bool m_isBombPlanted; // true if bomb has been planted
+ float m_bombPlantTimestamp; // time bomb was planted
+ float m_earliestBombPlantTimestamp; // don't allow planting until after this time has elapsed
+ CBasePlayer *m_bombDefuser; // the player currently defusing a bomb
+ EHANDLE m_looseBomb; // will be non-NULL if bomb is loose on the ground
+ CNavArea *m_looseBombArea; // area that bomb is is/near
+
+ bool m_isRoundOver; // true if the round has ended
+
float m_radioMsgTimestamp[24][2];
+
float m_lastSeenEnemyTimestamp;
- float m_roundStartTimestamp;
- bool m_isDefenseRushing;
+ float m_roundStartTimestamp; // the time when the current round began
+
+ bool m_isDefenseRushing; // whether defensive team is rushing this round or not
-#ifndef HOOK_GAMEDLL
-private:
-#else
-public:
-#endif // HOOK_GAMEDLL
static NavEditCmdType IMPL(m_editCmd);
-#ifdef HOOK_GAMEDLL
-private:
-#endif // HOOK_GAMEDLL
-
unsigned int m_navPlace;
CountdownTimer m_respawnTimer;
bool m_isRespawnStarted;
@@ -448,7 +291,7 @@ inline CCSBotManager *TheCSBots(void)
}
void PrintAllEntities(void);
-NOBODY void UTIL_DrawBox(Extent *extent, int lifetime, int red, int green, int blue);
+void UTIL_DrawBox(Extent *extent, int lifetime, int red, int green, int blue);
#ifdef HOOK_GAMEDLL
diff --git a/regamedll/dlls/bot/cs_bot_nav.cpp b/regamedll/dlls/bot/cs_bot_nav.cpp
index 4b692f41..7a1b0b25 100644
--- a/regamedll/dlls/bot/cs_bot_nav.cpp
+++ b/regamedll/dlls/bot/cs_bot_nav.cpp
@@ -1,218 +1,468 @@
#include "precompiled.h"
+// Reset the stuck-checker.
+
/* <37c284> ../cstrike/dlls/bot/cs_bot_nav.cpp:16 */
-NOBODY void CCSBot::ResetStuckMonitor(void)
+void CCSBot::ResetStuckMonitor(void)
{
+ if (m_isStuck)
+ {
+ if (IsLocalPlayerWatchingMe() && cv_bot_debug.value > 0.0f)
+ {
+ EMIT_SOUND(edict(), CHAN_ITEM, "buttons/bell1.wav", VOL_NORM, ATTN_NORM);
+ }
+ }
+
+ m_isStuck = false;
+ m_stuckTimestamp = 0.0f;
+ m_stuckJumpTimestamp = 0.0f;
+
+ m_avgVelIndex = 0;
+ m_avgVelCount = 0;
+
+ m_areaEnteredTimestamp = gpGlobals->time;
}
+// Test if we have become stuck
+
/* <37c2a6> ../cstrike/dlls/bot/cs_bot_nav.cpp:37 */
-NOBODY void CCSBot::StuckCheck(void)
+void CCSBot::StuckCheck(void)
{
-// {
-// Vector delta; // 42
-// float const unstuckRange; // 44
-// operator-(const Vector *const this,
-// const Vector &v); // 42
-// IsLengthGreaterThan(const Vector *const this,
-// float length); // 45
-// ResetStuckMonitor(CCSBot *const this); // 48
-// }
-// {
-// Vector vel; // 57
-// float moveDist; // 64
-// float deltaT; // 66
-// operator-(const Vector *const this,
-// const Vector &v); // 57
-// Length(const Vector *const this); // 64
-// {
-// float avgVel; // 81
-// float stuckVel; // 88
-// {
-// int t; // 82
-// }
-// }
-// }
+ if (m_isStuck)
+ {
+ // we are stuck - see if we have moved far enough to be considered unstuck
+ Vector delta = pev->origin - m_stuckSpot;
+
+ const float unstuckRange = 75.0f;
+ if (delta.IsLengthGreaterThan(unstuckRange))
+ {
+ // we are no longer stuck
+ ResetStuckMonitor();
+ PrintIfWatched("UN-STUCK\n");
+ }
+ }
+ else
+ {
+ // check if we are stuck
+ // compute average velocity over a short period (for stuck check)
+ Vector vel = pev->origin - m_lastOrigin;
+
+ // if we are jumping, ignore Z
+ if (IsJumping())
+ vel.z = 0.0f;
+
+ // cannot be Length2D, or will break ladder movement (they are only Z)
+ float moveDist = vel.Length();
+ float deltaT = g_flBotFullThinkInterval;
+
+ m_avgVel[ m_avgVelIndex++ ] = moveDist / deltaT;
+
+ if (m_avgVelIndex == MAX_VEL_SAMPLES)
+ m_avgVelIndex = 0;
+
+ if (m_avgVelCount < MAX_VEL_SAMPLES)
+ {
+ m_avgVelCount++;
+ }
+ else
+ {
+ // we have enough samples to know if we're stuck
+ float avgVel = 0.0f;
+ for (int t = 0; t < m_avgVelCount; ++t)
+ avgVel += m_avgVel[t];
+
+ avgVel /= m_avgVelCount;
+
+ // cannot make this velocity too high, or bots will get "stuck" when going down ladders
+ float stuckVel = (IsUsingLadder()) ? 10.0f : 20.0f;
+
+ if (avgVel < stuckVel)
+ {
+ // we are stuck - note when and where we initially become stuck
+ m_stuckTimestamp = gpGlobals->time;
+ m_stuckSpot = pev->origin;
+ m_stuckJumpTimestamp = gpGlobals->time + RANDOM_FLOAT(0.0f, 0.5f);
+
+ PrintIfWatched("STUCK\n");
+ if (IsLocalPlayerWatchingMe() && cv_bot_debug.value > 0.0f)
+ {
+ EMIT_SOUND(ENT(pev), CHAN_ITEM, "buttons/button11.wav", VOL_NORM, ATTN_NORM);
+ }
+
+ m_isStuck = true;
+ }
+ }
+ }
+
+ // always need to track this
+ m_lastOrigin = pev->origin;
}
+// Check if we need to jump due to height change
+
/* <37c05d> ../cstrike/dlls/bot/cs_bot_nav.cpp:114 */
-NOBODY bool CCSBot::DiscontinuityJump(float ground, bool onlyJumpDown, bool mustJump)
+bool CCSBot::DiscontinuityJump(float ground, bool onlyJumpDown, bool mustJump)
{
-// {
-// float dz; // 119
-// }
+ // don't try to jump again.
+ if (m_isJumpCrouching)
+ return false;
+
+ float_precision dz = ground - GetFeetZ();
+
+ if (dz > StepHeight && !onlyJumpDown)
+ {
+ // dont restrict jump time when going up
+ if (Jump(MUST_JUMP))
+ {
+ m_isJumpCrouching = true;
+ m_isJumpCrouched = false;
+
+ StandUp();
+
+ m_jumpCrouchTimestamp = gpGlobals->time;
+ return true;
+ }
+ }
+ else if (!IsUsingLadder() && dz < -JumpHeight)
+ {
+ if (Jump(mustJump))
+ {
+ m_isJumpCrouching = true;
+ m_isJumpCrouched = false;
+
+ StandUp();
+
+ m_jumpCrouchTimestamp = gpGlobals->time;
+ return true;
+ }
+ }
+
+ return false;
}
+// Find "simple" ground height, treating current nav area as part of the floor
+
/* <37c448> ../cstrike/dlls/bot/cs_bot_nav.cpp:154 */
-NOBODY bool CCSBot::GetSimpleGroundHeightWithFloor(const Vector *pos, float *height, Vector *normal)
+bool CCSBot::GetSimpleGroundHeightWithFloor(const Vector *pos, float *height, Vector *normal)
{
-// GetSimpleGroundHeightWithFloor(CCSBot *const this,
-// const Vector *pos,
-// float *height,
-// Vector *normal); // 154
+ if (GetSimpleGroundHeight(pos, height, normal))
+ {
+ // our current nav area also serves as a ground polygon
+ if (m_lastKnownArea != NULL && m_lastKnownArea->IsOverlapping(pos))
+ {
+ *height = Q_max((*height), m_lastKnownArea->GetZ(pos));
+ }
+
+ return true;
+ }
+
+ return false;
}
/* <37c4b8> ../cstrike/dlls/bot/cs_bot_nav.cpp:172 */
-NOBODY Place CCSBot::GetPlace(void)
+Place CCSBot::GetPlace(void) const
{
+ if (m_lastKnownArea != NULL)
+ return m_lastKnownArea->GetPlace();
+
+ return UNDEFINED_PLACE;
}
/* <37c4de> ../cstrike/dlls/bot/cs_bot_nav.cpp:184 */
-NOBODY void CCSBot::MoveTowardsPosition(const Vector *pos)
+void CCSBot::MoveTowardsPosition(const Vector *pos)
{
-// {
-// float angle; // 249
-// class Vector2D dir; // 251
-// class Vector2D lat; // 252
-// class Vector2D to; // 255
-// float toProj; // 259
-// float latProj; // 260
-// float const c; // 262
-// {
-// float ground; // 200
-// Vector aheadRay; // 201
-// bool jumped; // 207
-// NormalizeInPlace(Vector *const this); // 202
-// {
-// float const farLookAheadRange; // 210
-// Vector normal; // 211
-// Vector stepAhead; // 212
-// operator*(float fl,
-// const Vector &v); // 212
-// GetSimpleGroundHeightWithFloor(CCSBot *const this,
-// const Vector *pos,
-// float *height,
-// Vector *normal); // 215
-// operator+(const Vector *const this,
-// const Vector &v); // 212
-// DiscontinuityJump(CCSBot *const this,
-// float ground,
-// bool onlyJumpDown,
-// bool mustJump); // 218
-// }
-// {
-// float const lookAheadRange; // 225
-// Vector stepAhead; // 226
-// operator*(float fl,
-// const Vector &v); // 226
-// operator+(const Vector *const this,
-// const Vector &v); // 226
-// GetSimpleGroundHeightWithFloor(CCSBot *const this,
-// const Vector *pos,
-// float *height,
-// Vector *normal); // 228
-// DiscontinuityJump(CCSBot *const this,
-// float ground,
-// bool onlyJumpDown,
-// bool mustJump); // 230
-// }
-// {
-// float const lookAheadRange; // 237
-// Vector stepAhead; // 238
-// operator*(float fl,
-// const Vector &v); // 238
-// operator+(const Vector *const this,
-// const Vector &v); // 238
-// GetSimpleGroundHeightWithFloor(CCSBot *const this,
-// const Vector *pos,
-// float *height,
-// Vector *normal); // 240
-// DiscontinuityJump(CCSBot *const this,
-// float ground,
-// bool onlyJumpDown,
-// bool mustJump); // 242
-// }
-// }
-// NormalizeInPlace(Vector2D *const this); // 256
-// }
+ // Jump up on ledges
+ // Because we may not be able to get to our goal position and enter the next
+ // area because our extent collides with a nearby vertical ledge, make sure
+ // we look far enough ahead to avoid this situation.
+ // Can't look too far ahead, or bots will try to jump up slopes.
+
+ // NOTE: We need to do this frequently to catch edges at the right time
+ // TODO: Look ahead *along path* instead of straight line
+ if ((m_lastKnownArea == NULL || !(m_lastKnownArea->GetAttributes() & NAV_NO_JUMP)) &&
+ !IsOnLadder() && !m_isJumpCrouching)
+ {
+ float ground;
+ Vector aheadRay(pos->x - pev->origin.x, pos->y - pev->origin.y, 0);
+ aheadRay.NormalizeInPlace();
+
+ // look far ahead to allow us to smoothly jump over gaps, ledges, etc
+ // only jump if ground is flat at lookahead spot to avoid jumping up slopes
+ bool jumped = false;
+
+ if (IsRunning())
+ {
+ const float farLookAheadRange = 80.0f;
+ Vector normal;
+ Vector stepAhead = pev->origin + farLookAheadRange * aheadRay;
+ stepAhead.z += HalfHumanHeight;
+
+ if (GetSimpleGroundHeightWithFloor(&stepAhead, &ground, &normal))
+ {
+ if (normal.z > 0.9f)
+ jumped = DiscontinuityJump(ground, ONLY_JUMP_DOWN);
+ }
+ }
+
+ if (!jumped)
+ {
+ // close up jumping
+ // cant be less or will miss jumps over low walls
+ const float lookAheadRange = 30.0f;
+ Vector stepAhead = pev->origin + lookAheadRange * aheadRay;
+ stepAhead.z += HalfHumanHeight;
+
+ if (GetSimpleGroundHeightWithFloor(&stepAhead, &ground))
+ {
+ jumped = DiscontinuityJump(ground);
+ }
+ }
+
+ if (!jumped)
+ {
+ // about to fall gap-jumping
+ const float lookAheadRange = 10.0f;
+ Vector stepAhead = pev->origin + lookAheadRange * aheadRay;
+ stepAhead.z += HalfHumanHeight;
+
+ if (GetSimpleGroundHeightWithFloor(&stepAhead, &ground))
+ {
+ jumped = DiscontinuityJump(ground, ONLY_JUMP_DOWN, MUST_JUMP);
+ }
+ }
+ }
+
+ // compute our current forward and lateral vectors
+ float angle = pev->v_angle.y;
+
+ Vector2D dir(BotCOS(angle), BotSIN(angle));
+ Vector2D lat(-dir.y, dir.x);
+
+ // compute unit vector to goal position
+ Vector2D to(pos->x - pev->origin.x, pos->y - pev->origin.y);
+ to.NormalizeInPlace();
+
+ // move towards the position independant of our view direction
+ float toProj = to.x * dir.x + to.y * dir.y;
+ float latProj = to.x * lat.x + to.y * lat.y;
+
+ const float c = 0.25f;
+ if (toProj > c)
+ MoveForward();
+ else if (toProj < -c)
+ MoveBackward();
+
+ // if we are avoiding someone via strafing, don't override
+ if (m_avoid != NULL)
+ return;
+
+ if (latProj >= c)
+ StrafeLeft();
+ else if (latProj <= -c)
+ StrafeRight();
}
+// Move away from position, independant of view angle
+
/* <37ca96> ../cstrike/dlls/bot/cs_bot_nav.cpp:282 */
-NOBODY void CCSBot::MoveAwayFromPosition(const Vector *pos)
+NOXREF void CCSBot::MoveAwayFromPosition(const Vector *pos)
{
-// {
-// float angle; // 285
-// class Vector2D dir; // 287
-// class Vector2D lat; // 288
-// class Vector2D to; // 291
-// float toProj; // 295
-// float latProj; // 296
-// float const c; // 298
-// NormalizeInPlace(Vector2D *const this); // 292
-// }
+ // compute our current forward and lateral vectors
+ float angle = pev->v_angle[ YAW ];
+
+ Vector2D dir(BotCOS(angle), BotSIN(angle));
+ Vector2D lat(-dir.y, dir.x);
+
+ // compute unit vector to goal position
+ Vector2D to(pos->x - pev->origin.x, pos->y - pev->origin.y);
+ to.NormalizeInPlace();
+
+ // move away from the position independant of our view direction
+ float toProj = to.x * dir.x + to.y * dir.y;
+ float latProj = to.x * lat.x + to.y * lat.y;
+
+ const float c = 0.5f;
+ if (toProj > c)
+ MoveBackward();
+ else if (toProj < -c)
+ MoveForward();
+
+ if (latProj >= c)
+ StrafeRight();
+ else if (latProj <= -c)
+ StrafeLeft();
}
+// Strafe (sidestep) away from position, independant of view angle
+
/* <37cb85> ../cstrike/dlls/bot/cs_bot_nav.cpp:314 */
-NOBODY void CCSBot::StrafeAwayFromPosition(const Vector *pos)
+void CCSBot::StrafeAwayFromPosition(const Vector *pos)
{
-// {
-// float angle; // 317
-// class Vector2D dir; // 319
-// class Vector2D lat; // 320
-// class Vector2D to; // 323
-// float latProj; // 326
-// NormalizeInPlace(Vector2D *const this); // 324
-// }
+ // compute our current forward and lateral vectors
+ float angle = pev->v_angle[ YAW ];
+
+ Vector2D dir(BotCOS(angle), BotSIN(angle));
+ Vector2D lat(-dir.y, dir.x);
+
+ // compute unit vector to goal position
+ Vector2D to(pos->x - pev->origin.x, pos->y - pev->origin.y);
+ to.NormalizeInPlace();
+
+ float latProj = to.x * lat.x + to.y * lat.y;
+
+ if (latProj >= 0.0f)
+ StrafeRight();
+ else
+ StrafeLeft();
}
+// For getting un-stuck
+
/* <37cc52> ../cstrike/dlls/bot/cs_bot_nav.cpp:338 */
-NOBODY void CCSBot::Wiggle(void)
+void CCSBot::Wiggle(void)
{
-// ResetStuckMonitor(CCSBot *const this); // 342
+ if (IsCrouching())
+ {
+ ResetStuckMonitor();
+ return;
+ }
+
+ // for wiggling
+ if (gpGlobals->time >= m_wiggleTimestamp)
+ {
+ m_wiggleDirection = (NavRelativeDirType)RANDOM_LONG(0, 3);
+ m_wiggleTimestamp = RANDOM_FLOAT(0.5, 1.5) + gpGlobals->time;
+ }
+
+ // TODO: implement checking of the movement to fall down
+ switch (m_wiggleDirection)
+ {
+ case LEFT:
+ StrafeLeft();
+ break;
+ case RIGHT:
+ StrafeRight();
+ break;
+ case FORWARD:
+ MoveForward();
+ break;
+ case BACKWARD:
+ MoveBackward();
+ break;
+ }
+
+ if (gpGlobals->time >= m_stuckJumpTimestamp)
+ {
+ if (Jump())
+ {
+ m_stuckJumpTimestamp = RANDOM_FLOAT(1.0, 2.0) + gpGlobals->time;
+ }
+ }
}
+// Determine approach points from eye position and approach areas of current area
+
/* <37cc94> ../cstrike/dlls/bot/cs_bot_nav.cpp:383 */
-NOBODY void CCSBot::ComputeApproachPoints(void)
+void CCSBot::ComputeApproachPoints(void)
{
-// {
-// Vector eye; // 391
-// Vector ap; // 393
-// float halfWidth; // 394
-// Vector(Vector *const this,
-// const Vector &v); // 391
-// {
-// int i; // 395
-// {
-// const class ApproachInfo *info; // 397
-// Vector bendPoint; // 415
-// }
-// GetApproachInfoCount(const class CNavArea *const this); // 395
-// }
-// }
+ m_approachPointCount = 0;
+
+ if (m_lastKnownArea == NULL)
+ {
+ return;
+ }
+
+ // assume we're crouching for now
+ Vector eye = pev->origin;
+
+ Vector ap;
+ float halfWidth;
+ for (int i = 0; i < m_lastKnownArea->GetApproachInfoCount() && m_approachPointCount < MAX_APPROACH_POINTS; ++i)
+ {
+ const CNavArea::ApproachInfo *info = m_lastKnownArea->GetApproachInfo(i);
+
+ if (info->here.area == NULL || info->prev.area == NULL)
+ {
+ continue;
+ }
+
+ // compute approach point (approach area is "info->here")
+ if (info->prevToHereHow <= GO_WEST)
+ {
+ info->prev.area->ComputePortal(info->here.area, (NavDirType)info->prevToHereHow, &ap, &halfWidth);
+ ap.z = info->here.area->GetZ(&ap);
+ }
+ else
+ {
+ // use the area's center as an approach point
+ ap = *info->here.area->GetCenter();
+ }
+
+ // "bend" our line of sight around corners until we can see the approach point
+ Vector bendPoint;
+ if (BendLineOfSight(&eye, &ap, &bendPoint))
+ {
+ m_approachPoint[ m_approachPointCount++ ] = bendPoint;
+ }
+ }
}
/* <37cd67> ../cstrike/dlls/bot/cs_bot_nav.cpp:422 */
-NOBODY void CCSBot::DrawApproachPoints(void)
+void CCSBot::DrawApproachPoints(void)
{
-// {
-// int i; // 427
-// operator+(const Vector *const this,
-// const Vector &v); // 428
-// Vector(Vector *const this,
-// const Vector &v); // 428
-// }
+ for (int i = 0; i < m_approachPointCount; ++i)
+ {
+ UTIL_DrawBeamPoints(m_approachPoint[i], m_approachPoint[i] + Vector(0, 0, 50), 3, 0, 255, 255);
+ }
}
+// Find the approach point that is nearest to our current path, ahead of us
+
/* <37ce12> ../cstrike/dlls/bot/cs_bot_nav.cpp:435 */
-NOBODY bool CCSBot::FindApproachPointNearestPath(const Vector *pos)
+NOXREF bool CCSBot::FindApproachPointNearestPath(Vector *pos)
{
-// {
-// Vector target; // 446
-// Vector close; // 446
-// float targetRangeSq; // 447
-// bool found; // 448
-// int start; // 450
-// int end; // 451
-// float const nearPathSq; // 457
-// {
-// int i; // 459
-// {
-// float rangeSq; // 464
-// operator-(const Vector *const this,
-// const Vector &v); // 464
-// LengthSquared(const Vector *const this); // 464
-// }
-// }
-// operator+(const Vector *const this,
-// const Vector &v); // 478
-// }
+ if (!HasPath())
+ return false;
+
+ // make sure approach points are accurate
+ ComputeApproachPoints();
+
+ if (m_approachPointCount == 0)
+ return false;
+
+ Vector target = Vector(0, 0, 0), close;
+ float targetRangeSq = 0.0f;
+ bool found = false;
+
+ int start = m_pathIndex;
+ int end = m_pathLength;
+
+ // We dont want the strictly closest point, but the farthest approach point
+ // from us that is near our path
+ const float nearPathSq = 10000.0f;
+
+ for (int i = 0; i < m_approachPointCount; ++i)
+ {
+ if (FindClosestPointOnPath(&m_approachPoint[i], start, end, &close) == false)
+ continue;
+
+ float rangeSq = (m_approachPoint[i] - close).LengthSquared();
+ if (rangeSq > nearPathSq)
+ continue;
+
+ if (rangeSq > targetRangeSq)
+ {
+ target = close;
+ targetRangeSq = rangeSq;
+ found = true;
+ }
+ }
+
+ if (found)
+ {
+ *pos = target + Vector(0, 0, HalfHumanHeight);
+ return true;
+ }
+
+ return false;
}
diff --git a/regamedll/dlls/bot/cs_bot_pathfind.cpp b/regamedll/dlls/bot/cs_bot_pathfind.cpp
index f1ac6bf3..e57ec79a 100644
--- a/regamedll/dlls/bot/cs_bot_pathfind.cpp
+++ b/regamedll/dlls/bot/cs_bot_pathfind.cpp
@@ -1,729 +1,1775 @@
#include "precompiled.h"
+// Determine actual path positions bot will move between along the path
+
/* <38db02> ../cstrike/dlls/bot/cs_bot_pathfind.cpp:30 */
-NOBODY bool CCSBot::ComputePathPositions(void)
+bool CCSBot::ComputePathPositions(void)
{
-// {
-// int i; // 40
-// {
-// const class ConnectInfo *from; // 42
-// class ConnectInfo *to; // 43
-// {
-// const NavLadderList *list; // 124
-// const_iterator iter; // 125
-// end(const class list> *const this); // 126
-// {
-// class CNavLadder *ladder; // 128
-// AddDirectionVector(Vector *v,
-// enum NavDirType dir,
-// float amount); // 134
-// }
-// operator++(_List_const_iterator *const this); // 126
-// }
-// {
-// const NavLadderList *list; // 97
-// const_iterator iter; // 98
-// {
-// class CNavLadder *ladder; // 101
-// AddDirectionVector(Vector *v,
-// enum NavDirType dir,
-// float amount); // 110
-// }
-// end(const class list> *const this); // 99
-// operator++(_List_const_iterator *const this); // 99
-// }
-// {
-// float const stepInDist; // 53
-// AddDirectionVector(Vector *v,
-// enum NavDirType dir,
-// float amount); // 54
-// {
-// class Vector2D dir; // 65
-// float const pushDist; // 69
-// DirectionToVector2D(NavDirType dir,
-// class Vector2D *v); // 66
-// {
-// int j; // 77
-// }
-// }
-// }
-// }
-// }
+ if (m_pathLength == 0)
+ return false;
+
+ // start in first area's center
+ m_path[0].pos = *m_path[0].area->GetCenter();
+ m_path[0].ladder = NULL;
+ m_path[0].how = NUM_TRAVERSE_TYPES;
+
+ for (int i = 1; i < m_pathLength; ++i)
+ {
+ const ConnectInfo *from = &m_path[i - 1];
+ ConnectInfo *to = &m_path[ i ];
+
+ // walk along the floor to the next area
+ if (to->how <= GO_WEST)
+ {
+ to->ladder = NULL;
+
+ // compute next point, keeping path as straight as possible
+ from->area->ComputeClosestPointInPortal(to->area, (NavDirType)to->how, &from->pos, &to->pos);
+
+ // move goal position into the goal area a bit
+ // how far to "step into" an area - must be less than min area size
+ const float stepInDist = 5.0f;
+ AddDirectionVector(&to->pos, (NavDirType)to->how, stepInDist);
+
+ // we need to walk out of "from" area, so keep Z where we can reach it
+ to->pos.z = from->area->GetZ(&to->pos);
+
+ // if this is a "jump down" connection, we must insert an additional point on the path
+ if (to->area->IsConnected(from->area, NUM_DIRECTIONS) == false)
+ {
+ // this is a "jump down" link
+ // compute direction of path just prior to "jump down"
+ Vector2D dir;
+ DirectionToVector2D((NavDirType)to->how, &dir);
+
+ // shift top of "jump down" out a bit to "get over the ledge"
+ const float pushDist = 25.0f; // 75.0f;
+ to->pos.x += pushDist * dir.x;
+ to->pos.y += pushDist * dir.y;
+
+ // insert a duplicate node to represent the bottom of the fall
+ if (m_pathLength < MAX_PATH_LENGTH - 1)
+ {
+ // copy nodes down
+ for (int j = m_pathLength; j > i; --j)
+ m_path[j] = m_path[j - 1];
+
+ // path is one node longer
+ ++m_pathLength;
+
+ // move index ahead into the new node we just duplicated
+ ++i;
+
+ m_path[i].pos.x = to->pos.x + pushDist * dir.x;
+ m_path[i].pos.y = to->pos.y + pushDist * dir.y;
+
+ // put this one at the bottom of the fall
+ m_path[i].pos.z = to->area->GetZ(&m_path[i].pos);
+ }
+ }
+ }
+ // to get to next area, must go up a ladder
+ else if (to->how == GO_LADDER_UP)
+ {
+ // find our ladder
+ const NavLadderList *list = from->area->GetLadderList(LADDER_UP);
+ NavLadderList::const_iterator iter;
+ for (iter = list->begin(); iter != list->end(); ++iter)
+ {
+ CNavLadder *ladder = (*iter);
+
+ // can't use "behind" area when ascending...
+ if (ladder->m_topForwardArea == to->area || ladder->m_topLeftArea == to->area || ladder->m_topRightArea == to->area)
+ {
+ to->ladder = ladder;
+ to->pos = ladder->m_bottom;
+ AddDirectionVector(&to->pos, ladder->m_dir, HalfHumanWidth * 2.0f);
+ break;
+ }
+ }
+
+ if (iter == list->end())
+ {
+ PrintIfWatched("ERROR: Can't find ladder in path\n");
+ return false;
+ }
+ }
+ // to get to next area, must go down a ladder
+ else if (to->how == GO_LADDER_DOWN)
+ {
+ // find our ladder
+ const NavLadderList *list = from->area->GetLadderList(LADDER_DOWN);
+ NavLadderList::const_iterator iter;
+ for (iter = list->begin(); iter != list->end(); ++iter)
+ {
+ CNavLadder *ladder = (*iter);
+
+ if (ladder->m_bottomArea == to->area)
+ {
+ to->ladder = ladder;
+ to->pos = ladder->m_top;
+ AddDirectionVector(&to->pos, OppositeDirection(ladder->m_dir), HalfHumanWidth * 2.0f);
+ break;
+ }
+ }
+
+ if (iter == list->end())
+ {
+ PrintIfWatched("ERROR: Can't find ladder in path\n");
+ return false;
+ }
+ }
+ }
+
+ return true;
}
+// If next step of path uses a ladder, prepare to traverse it
+
/* <38d424> ../cstrike/dlls/bot/cs_bot_pathfind.cpp:155 */
-NOBODY void CCSBot::SetupLadderMovement(void)
+void CCSBot::SetupLadderMovement(void)
{
-// {
-// const class ConnectInfo *to; // 160
-// {
-// TraceResult result; // 186
-// Vector from; // 187
-// Vector to; // 188
-// AddDirectionVector(Vector *v,
-// enum NavDirType dir,
-// float amount); // 184
-// Vector(Vector *const this,
-// const Vector &v); // 187
-// Vector(Vector *const this,
-// const Vector &v); // 188
-// DirectionToAngle(NavDirType dir); // 196
-// OppositeDirection(NavDirType dir); // 203
-// DirectionToAngle(NavDirType dir); // 203
-// AddDirectionVector(Vector *v,
-// enum NavDirType dir,
-// float amount); // 205
-// }
-// AddDirectionVector(Vector *v,
-// enum NavDirType dir,
-// float amount); // 177
-// OppositeDirection(NavDirType dir); // 178
-// DirectionToAngle(NavDirType dir); // 178
-// }
+ if (m_pathIndex < 1 || m_pathLength == 0)
+ return;
+
+ const ConnectInfo *to = &m_path[ m_pathIndex ];
+
+ if (to->ladder != NULL)
+ {
+ m_spotEncounter = NULL;
+ m_areaEnteredTimestamp = gpGlobals->time;
+
+ m_pathLadder = to->ladder;
+ m_pathLadderTimestamp = gpGlobals->time;
+
+ // to get to next area, we must traverse a ladder
+ if (to->how == GO_LADDER_UP)
+ {
+ m_pathLadderState = APPROACH_ASCENDING_LADDER;
+ m_pathLadderFaceIn = true;
+ PrintIfWatched("APPROACH_ASCENDING_LADDER\n");
+ m_goalPosition = m_pathLadder->m_bottom;
+
+ AddDirectionVector(&m_goalPosition, m_pathLadder->m_dir, HalfHumanWidth * 2.0f);
+ m_lookAheadAngle = DirectionToAngle(OppositeDirection(m_pathLadder->m_dir));
+ }
+ else
+ {
+ // try to mount ladder "face out" first
+ m_goalPosition = m_pathLadder->m_top;
+ AddDirectionVector(&m_goalPosition, OppositeDirection(m_pathLadder->m_dir), HalfHumanWidth * 2.0f);
+
+ TraceResult result;
+ Vector from = m_pathLadder->m_top;
+ Vector to = m_goalPosition;
+
+ UTIL_TraceLine(from, to, ignore_monsters, ENT(m_pathLadder->m_entity->pev), &result);
+
+ if (result.flFraction == 1.0f)
+ {
+ PrintIfWatched("APPROACH_DESCENDING_LADDER (face out)\n");
+
+ m_pathLadderState = APPROACH_DESCENDING_LADDER;
+ m_pathLadderFaceIn = false;
+ m_lookAheadAngle = DirectionToAngle(m_pathLadder->m_dir);
+ }
+ else
+ {
+ PrintIfWatched("APPROACH_DESCENDING_LADDER (face in)\n");
+ m_pathLadderState = APPROACH_DESCENDING_LADDER;
+ m_pathLadderFaceIn = true;
+ m_lookAheadAngle = DirectionToAngle(OppositeDirection(m_pathLadder->m_dir));
+ m_goalPosition = m_pathLadder->m_top;
+ AddDirectionVector(&m_goalPosition, m_pathLadder->m_dir, HalfHumanWidth);
+ }
+ }
+ }
}
+// TODO: What about ladders whose top AND bottom are messed up?
+
/* <38dd85> ../cstrike/dlls/bot/cs_bot_pathfind.cpp:213 */
-NOBODY void CCSBot::ComputeLadderEndpoint(bool isAscending)
+void CCSBot::ComputeLadderEndpoint(bool isAscending)
{
-// {
-// TraceResult result; // 215
-// {
-// Vector from; // 221
-// Vector(Vector *const this,
-// float X,
-// float Y,
-// float Z); // 221
-// }
-// {
-// Vector from; // 233
-// Vector(Vector *const this,
-// float X,
-// float Y,
-// float Z); // 233
-// }
-// }
+ TraceResult result;
+ Vector from, to;
+
+ if (isAscending)
+ {
+ // find actual top in case m_pathLadder penetrates the ceiling
+ // trace from our chest height at m_pathLadder base
+ from = m_pathLadder->m_bottom;
+ from.z = pev->origin.z;
+ to = m_pathLadder->m_top;
+ }
+ else
+ {
+ // find actual bottom in case m_pathLadder penetrates the floor
+ // trace from our chest height at m_pathLadder top
+ from = m_pathLadder->m_top;
+ from.z = pev->origin.z;
+ to = m_pathLadder->m_bottom;
+ }
+
+ UTIL_TraceLine(from, to, ignore_monsters, ENT(m_pathLadder->m_entity->pev), &result);
+
+ if (result.flFraction == 1.0f)
+ m_pathLadderEnd = to.z;
+ else
+ m_pathLadderEnd = from.z + result.flFraction * (to.z - from.z);
}
+// Navigate our current ladder. Return true if we are doing ladder navigation.
+// TODO: Need Push() and Pop() for run/walk context to keep ladder speed contained.
+
/* <38de76> ../cstrike/dlls/bot/cs_bot_pathfind.cpp:248 */
-NOBODY bool CCSBot::UpdateLadderMovement(void)
+bool CCSBot::UpdateLadderMovement(void)
{
-// {
-// bool giveUp; // 253
-// float const ladderTimeoutDuration; // 256
-// float const tolerance; // 315
-// float const closeToGoal; // 316
-// {
-// float const farAway; // 299
-// operator-(const class Vector2D *const this,
-// const class Vector2D &v); // 300
-// IsLengthGreaterThan(const class Vector2D *const this,
-// float length); // 300
-// DestroyPath(CCSBot *const this); // 304
-// }
-// AddDirectionVector(Vector *v,
-// enum NavDirType dir,
-// float amount); // 543
-// GetFeetZ(const class CCSBot *const this); // 510
-// GetFeetZ(const class CCSBot *const this); // 475
-// {
-// Vector to; // 446
-// Vector idealAngle; // 447
-// operator-(const Vector *const this,
-// const Vector &v); // 446
-// AnglesAreEqual(float a,
-// float b,
-// float tolerance); // 449
-// }
-// {
-// Vector to; // 429
-// Vector idealAngle; // 430
-// operator-(const Vector *const this,
-// const Vector &v); // 429
-// AnglesAreEqual(float a,
-// float b,
-// float tolerance); // 432
-// }
-// GetFeetZ(const class CCSBot *const this); // 368
-// {
-// bool approached; // 380
-// class Vector2D d; // 382
-// {
-// class Vector2D perp; // 386
-// Length(const class Vector2D *const this); // 388
-// }
-// {
-// float const walkRange; // 395
-// IsLengthLessThan(const class Vector2D *const this,
-// float length); // 396
-// }
-// }
-// {
-// bool approached; // 322
-// class Vector2D d; // 324
-// float const walkRange; // 335
-// {
-// class Vector2D perp; // 328
-// Length(const class Vector2D *const this); // 330
-// }
-// IsLengthLessThan(const class Vector2D *const this,
-// float length); // 336
-// }
-// AddDirectionVector(Vector *v,
-// enum NavDirType dir,
-// float amount); // 481
-// DestroyPath(CCSBot *const this); // 528
-// GetFeetZ(const class CCSBot *const this); // 538
-// SetPathIndex(CCSBot *const this,
-// int newIndex); // 592
-// }
+ if (m_pathLadder == NULL)
+ return false;
+
+ bool giveUp = false;
+
+ // check for timeout
+ const float ladderTimeoutDuration = 10.0f;
+ if (gpGlobals->time - m_pathLadderTimestamp > ladderTimeoutDuration)
+ {
+ PrintIfWatched("Ladder timeout!\n");
+ giveUp = true;
+ }
+
+ else if (m_pathLadderState == APPROACH_ASCENDING_LADDER
+ || m_pathLadderState == APPROACH_DESCENDING_LADDER
+ || m_pathLadderState == ASCEND_LADDER
+ || m_pathLadderState == DESCEND_LADDER
+ || m_pathLadderState == DISMOUNT_ASCENDING_LADDER
+ || m_pathLadderState == MOVE_TO_DESTINATION)
+ {
+ if (m_isStuck)
+ {
+ PrintIfWatched("Giving up ladder - stuck\n");
+ giveUp = true;
+ }
+ }
+
+ if (giveUp)
+ {
+ // jump off ladder and give up
+ Jump(MUST_JUMP);
+ Wiggle();
+ ResetStuckMonitor();
+ DestroyPath();
+ Run();
+ return false;
+ }
+
+ ResetStuckMonitor();
+
+ // check if somehow we totally missed the ladder
+ switch (m_pathLadderState)
+ {
+ case MOUNT_ASCENDING_LADDER:
+ case MOUNT_DESCENDING_LADDER:
+ case ASCEND_LADDER:
+ case DESCEND_LADDER:
+ {
+ const float farAway = 200.0f;
+ Vector2D d = (m_pathLadder->m_top - pev->origin).Make2D();
+ if (d.IsLengthGreaterThan(farAway))
+ {
+ PrintIfWatched("Missed ladder\n");
+ Jump(MUST_JUMP);
+ DestroyPath();
+ Run();
+ return false;
+ }
+ break;
+ }
+ }
+
+ m_areaEnteredTimestamp = gpGlobals->time;
+
+ const float tolerance = 10.0f;
+ const float closeToGoal = 25.0f;
+
+ switch (m_pathLadderState)
+ {
+ case APPROACH_ASCENDING_LADDER:
+ {
+ bool approached = false;
+ Vector2D d(pev->origin.x - m_goalPosition.x, pev->origin.y - m_goalPosition.y);
+
+ if (d.x * m_pathLadder->m_dirVector.x + d.y * m_pathLadder->m_dirVector.y < 0.0f)
+ {
+ Vector2D perp(-m_pathLadder->m_dirVector.y, m_pathLadder->m_dirVector.x);
+
+ if (abs(int64(d.x * perp.x + d.y * perp.y)) < tolerance && d.Length() < closeToGoal)
+ approached = true;
+ }
+
+ // small radius will just slow them down a little for more accuracy in hitting their spot
+ const float walkRange = 50.0f;
+ if (d.IsLengthLessThan(walkRange))
+ {
+ Walk();
+ StandUp();
+ }
+
+ // TODO: Check that we are on the ladder we think we are
+ if (IsOnLadder())
+ {
+ m_pathLadderState = ASCEND_LADDER;
+ PrintIfWatched("ASCEND_LADDER\n");
+
+ // find actual top in case m_pathLadder penetrates the ceiling
+ ComputeLadderEndpoint(true);
+ }
+ else if (approached)
+ {
+ // face the m_pathLadder
+ m_pathLadderState = FACE_ASCENDING_LADDER;
+ PrintIfWatched("FACE_ASCENDING_LADDER\n");
+ }
+ else
+ {
+ // move toward ladder mount point
+ MoveTowardsPosition(&m_goalPosition);
+ }
+ break;
+ }
+ case APPROACH_DESCENDING_LADDER:
+ {
+ // fall check
+ if (GetFeetZ() <= m_pathLadder->m_bottom.z + HalfHumanHeight)
+ {
+ PrintIfWatched("Fell from ladder.\n");
+
+ m_pathLadderState = MOVE_TO_DESTINATION;
+ m_path[ m_pathIndex ].area->GetClosestPointOnArea(&m_pathLadder->m_bottom, &m_goalPosition);
+
+ AddDirectionVector(&m_goalPosition, m_pathLadder->m_dir, HalfHumanWidth);
+ PrintIfWatched("MOVE_TO_DESTINATION\n");
+ }
+ else
+ {
+ bool approached = false;
+ Vector2D d(pev->origin.x - m_goalPosition.x, pev->origin.y - m_goalPosition.y);
+
+ if (d.x * m_pathLadder->m_dirVector.x + d.y * m_pathLadder->m_dirVector.y > 0.0f)
+ {
+ Vector2D perp(-m_pathLadder->m_dirVector.y, m_pathLadder->m_dirVector.x);
+
+ if (abs(int64(d.x * perp.x + d.y * perp.y)) < tolerance && d.Length() < closeToGoal)
+ approached = true;
+ }
+
+ // if approaching ladder from the side or "ahead", walk
+ if (m_pathLadder->m_topBehindArea != m_lastKnownArea)
+ {
+ const float walkRange = 150.0f;
+ if (!IsCrouching() && d.IsLengthLessThan(walkRange))
+ Walk();
+ }
+
+ // TODO: Check that we are on the ladder we think we are
+ if (IsOnLadder())
+ {
+ // we slipped onto the ladder - climb it
+ m_pathLadderState = DESCEND_LADDER;
+ Run();
+ PrintIfWatched("DESCEND_LADDER\n");
+
+ // find actual bottom in case m_pathLadder penetrates the floor
+ ComputeLadderEndpoint(false);
+ }
+ else if (approached)
+ {
+ // face the ladder
+ m_pathLadderState = FACE_DESCENDING_LADDER;
+ PrintIfWatched("FACE_DESCENDING_LADDER\n");
+ }
+ else
+ {
+ // move toward ladder mount point
+ MoveTowardsPosition(&m_goalPosition);
+ }
+ }
+ break;
+ }
+ case FACE_ASCENDING_LADDER:
+ {
+ // find yaw to directly aim at ladder
+ Vector to = m_pathLadder->m_bottom - pev->origin;
+ Vector idealAngle = UTIL_VecToAngles(to);
+
+ const float angleTolerance = 5.0f;
+ if (AnglesAreEqual(pev->v_angle.y, idealAngle.y, angleTolerance))
+ {
+ // move toward ladder until we become "on" it
+ Run();
+ ResetStuckMonitor();
+ m_pathLadderState = MOUNT_ASCENDING_LADDER;
+ PrintIfWatched("MOUNT_ASCENDING_LADDER\n");
+ }
+ break;
+ }
+ case FACE_DESCENDING_LADDER:
+ {
+ // find yaw to directly aim at ladder
+ Vector to = m_pathLadder->m_top - pev->origin;
+ Vector idealAngle = UTIL_VecToAngles(to);
+
+ const float angleTolerance = 5.0f;
+ if (AnglesAreEqual(pev->v_angle.y, idealAngle.y, angleTolerance))
+ {
+ // move toward ladder until we become "on" it
+ m_pathLadderState = MOUNT_DESCENDING_LADDER;
+ ResetStuckMonitor();
+ PrintIfWatched("MOUNT_DESCENDING_LADDER\n");
+ }
+ break;
+ }
+ case MOUNT_ASCENDING_LADDER:
+ {
+ if (IsOnLadder())
+ {
+ m_pathLadderState = ASCEND_LADDER;
+ PrintIfWatched("ASCEND_LADDER\n");
+
+ // find actual top in case m_pathLadder penetrates the ceiling
+ ComputeLadderEndpoint(true);
+ }
+
+ MoveForward();
+ break;
+ }
+ case MOUNT_DESCENDING_LADDER:
+ {
+ // fall check
+ if (GetFeetZ() <= m_pathLadder->m_bottom.z + HalfHumanHeight)
+ {
+ PrintIfWatched("Fell from ladder.\n");
+
+ m_pathLadderState = MOVE_TO_DESTINATION;
+ m_path[ m_pathIndex ].area->GetClosestPointOnArea(&m_pathLadder->m_bottom, &m_goalPosition);
+
+ AddDirectionVector(&m_goalPosition, m_pathLadder->m_dir, HalfHumanWidth);
+ PrintIfWatched("MOVE_TO_DESTINATION\n");
+ }
+ else
+ {
+ if (IsOnLadder())
+ {
+ m_pathLadderState = DESCEND_LADDER;
+ PrintIfWatched("DESCEND_LADDER\n");
+
+ // find actual bottom in case m_pathLadder penetrates the floor
+ ComputeLadderEndpoint(false);
+ }
+
+ // move toward ladder mount point
+ MoveForward();
+ }
+ break;
+ }
+ case ASCEND_LADDER:
+ {
+ // run, so we can make our dismount jump to the side, if necessary
+ Run();
+
+ // if our destination area requires us to crouch, do it
+ if (m_path[ m_pathIndex ].area->GetAttributes() & NAV_CROUCH)
+ Crouch();
+
+ // did we reach the top?
+ if (GetFeetZ() >= m_pathLadderEnd)
+ {
+ // we reached the top - dismount
+ m_pathLadderState = DISMOUNT_ASCENDING_LADDER;
+ PrintIfWatched("DISMOUNT_ASCENDING_LADDER\n");
+
+ if (m_path[ m_pathIndex ].area == m_pathLadder->m_topForwardArea)
+ m_pathLadderDismountDir = FORWARD;
+ else if (m_path[ m_pathIndex ].area == m_pathLadder->m_topLeftArea)
+ m_pathLadderDismountDir = LEFT;
+ else if (m_path[ m_pathIndex ].area == m_pathLadder->m_topRightArea)
+ m_pathLadderDismountDir = RIGHT;
+
+ m_pathLadderDismountTimestamp = gpGlobals->time;
+ }
+ else if (!IsOnLadder())
+ {
+ // we fall off the ladder, repath
+ DestroyPath();
+ return false;
+ }
+
+ // move up ladder
+ MoveForward();
+ break;
+ }
+ case DESCEND_LADDER:
+ {
+ Run();
+
+ float destHeight = m_pathLadderEnd + HalfHumanHeight;
+ if (!IsOnLadder() || GetFeetZ() <= destHeight)
+ {
+ // we reached the bottom, or we fell off - dismount
+ m_pathLadderState = MOVE_TO_DESTINATION;
+ m_path[ m_pathIndex ].area->GetClosestPointOnArea(&m_pathLadder->m_bottom, &m_goalPosition);
+
+ AddDirectionVector(&m_goalPosition, m_pathLadder->m_dir, HalfHumanWidth);
+ PrintIfWatched("MOVE_TO_DESTINATION\n");
+ }
+
+ // Move down ladder
+ MoveForward();
+ break;
+ }
+ case DISMOUNT_ASCENDING_LADDER:
+ {
+ if (gpGlobals->time - m_pathLadderDismountTimestamp >= 0.4f)
+ {
+ m_pathLadderState = MOVE_TO_DESTINATION;
+ m_path[ m_pathIndex ].area->GetClosestPointOnArea(&pev->origin, &m_goalPosition);
+ PrintIfWatched("MOVE_TO_DESTINATION\n");
+ }
+
+ // We should already be facing the dismount point
+ if (m_pathLadderFaceIn)
+ {
+ switch (m_pathLadderDismountDir)
+ {
+ case LEFT: StrafeLeft(); break;
+ case RIGHT: StrafeRight(); break;
+ case FORWARD: MoveForward(); break;
+ }
+ }
+ else
+ {
+ switch (m_pathLadderDismountDir)
+ {
+ case LEFT: StrafeRight(); break;
+ case RIGHT: StrafeLeft(); break;
+ case FORWARD: MoveBackward(); break;
+ }
+ }
+ break;
+ }
+ case MOVE_TO_DESTINATION:
+ {
+ if (m_path[ m_pathIndex ].area->Contains(&pev->origin))
+ {
+ // successfully traversed ladder and reached destination area
+ // exit ladder state machine
+ PrintIfWatched("Ladder traversed.\n");
+ m_pathLadder = NULL;
+
+ // incrememnt path index to next step beyond this ladder
+ SetPathIndex(m_pathIndex + 1);
+
+ return false;
+ }
+
+ MoveTowardsPosition(&m_goalPosition);
+ break;
+ }
+ }
+
+ return true;
}
+// Compute closest point on path to given point
+// NOTE: This does not do line-of-sight tests, so closest point may be thru the floor, etc
+
/* <38e44d> ../cstrike/dlls/bot/cs_bot_pathfind.cpp:609 */
-NOBODY bool CCSBot::FindClosestPointOnPath(Vector *worldPos, int startIndex, int endIndex, Vector *close)
+bool CCSBot::FindClosestPointOnPath(const Vector *worldPos, int startIndex, int endIndex, Vector *close) const
{
-// {
-// Vector along; // 614
-// Vector toWorldPos; // 614
-// Vector pos; // 615
-// const Vector *from; // 616
-// const Vector *to; // 616
-// float length; // 617
-// float closeLength; // 618
-// float closeDistSq; // 619
-// float distSq; // 620
-// {
-// int i; // 622
-// NormalizeInPlace(Vector *const this); // 631
-// operator-(const Vector *const this,
-// const Vector &v); // 634
-// DotProduct(Vector &a,
-// const Vector &b); // 637
-// operator-(const Vector *const this,
-// const Vector &v); // 647
-// LengthSquared(const Vector *const this); // 647
-// operator-(const Vector *const this,
-// const Vector &v); // 628
-// operator*(float fl,
-// const Vector &v); // 645
-// operator+(const Vector *const this,
-// const Vector &v); // 645
-// }
-// }
+ if (!HasPath() || close == NULL)
+ return false;
+
+ Vector along, toWorldPos;
+ Vector pos;
+ const Vector *from, *to;
+ float length;
+ float closeLength;
+ float closeDistSq = 9999999999.9f;
+ float distSq;
+
+ for (int i = startIndex; i <= endIndex; ++i)
+ {
+ from = &m_path[i - 1].pos;
+ to = &m_path[i].pos;
+
+ // compute ray along this path segment
+ along = *to - *from;
+
+ // make it a unit vector along the path
+ length = along.NormalizeInPlace();
+
+ // compute vector from start of segment to our point
+ toWorldPos = *worldPos - *from;
+
+ // find distance of closest point on ray
+ closeLength = DotProduct(toWorldPos, along);
+
+ // constrain point to be on path segment
+ if (closeLength <= 0.0f)
+ pos = *from;
+ else if (closeLength >= length)
+ pos = *to;
+ else
+ pos = *from + closeLength * along;
+
+ distSq = (pos - *worldPos).LengthSquared();
+
+ // keep the closest point so far
+ if (distSq < closeDistSq)
+ {
+ closeDistSq = distSq;
+ *close = pos;
+ }
+ }
+
+ return true;
}
+// Return the closest point to our current position on our current path
+// If "local" is true, only check the portion of the path surrounding m_pathIndex.
+
/* <38e6d0> ../cstrike/dlls/bot/cs_bot_pathfind.cpp:665 */
-NOBODY int CCSBot::FindOurPositionOnPath(Vector *close, bool local)
+int CCSBot::FindOurPositionOnPath(Vector *close, bool local) const
{
-// {
-// Vector along; // 670
-// Vector toFeet; // 670
-// Vector feet; // 671
-// Vector eyes; // 672
-// Vector pos; // 673
-// const Vector *from; // 674
-// const Vector *to; // 674
-// float length; // 675
-// float closeLength; // 676
-// float closeDistSq; // 677
-// int closeIndex; // 678
-// float distSq; // 679
-// int start; // 681
-// int end; // 681
-// {
-// int i; // 699
-// operator-(const Vector *const this,
-// const Vector &v); // 724
-// LengthSquared(const Vector *const this); // 724
-// {
-// Vector probe; // 730
-// operator+(const Vector *const this,
-// const Vector &v); // 730
-// IsWalkableTraceLineClear(Vector &from,
-// Vector &to,
-// unsigned int flags); // 731
-// }
-// operator-(const Vector *const this,
-// const Vector &v); // 705
-// NormalizeInPlace(Vector *const this); // 708
-// operator-(const Vector *const this,
-// const Vector &v); // 711
-// DotProduct(Vector &a,
-// const Vector &b); // 714
-// operator*(float fl,
-// const Vector &v); // 722
-// operator+(const Vector *const this,
-// const Vector &v); // 722
-// }
-// GetFeetZ(const class CCSBot *const this); // 671
-// operator+(const Vector *const this,
-// const Vector &v); // 672
-// }
+ if (!HasPath())
+ return -1;
+
+ Vector along, toFeet;
+ Vector feet = Vector(pev->origin.x, pev->origin.y, GetFeetZ());
+ Vector eyes = feet + Vector(0, 0, HalfHumanHeight); // in case we're crouching
+ Vector pos;
+ const Vector *from, *to;
+ float_precision length;
+ float closeLength;
+ float closeDistSq = 9999999999.9;
+ int closeIndex = -1;
+ float_precision distSq;
+
+ int start, end;
+
+ if (local)
+ {
+ start = m_pathIndex - 3;
+ if (start < 1)
+ start = 1;
+
+ end = m_pathIndex + 3;
+ if (end > m_pathLength)
+ end = m_pathLength;
+ }
+ else
+ {
+ start = 1;
+ end = m_pathLength;
+ }
+
+ for (int i = start; i < end; ++i)
+ {
+ from = &m_path[i - 1].pos;
+ to = &m_path[i].pos;
+
+ // compute ray along this path segment
+ along = *to - *from;
+
+ // make it a unit vector along the path
+ length = along.NormalizeInPlace();
+
+ // compute vector from start of segment to our point
+ toFeet = feet - *from;
+
+ // find distance of closest point on ray
+ closeLength = DotProduct(toFeet, along);
+
+ // constrain point to be on path segment
+ if (closeLength <= 0.0f)
+ pos = *from;
+ else if (closeLength >= length)
+ pos = *to;
+ else
+ pos = *from + closeLength * along;
+
+ distSq = (pos - feet).LengthSquared();
+
+ // keep the closest point so far
+ if (distSq < closeDistSq)
+ {
+ // don't use points we cant see
+ Vector probe = pos + Vector(0, 0, HalfHumanHeight);
+ if (!IsWalkableTraceLineClear(eyes, probe, WALK_THRU_EVERYTHING))
+ continue;
+
+ // don't use points we cant reach
+ if (!IsStraightLinePathWalkable(&pos))
+ continue;
+
+ closeDistSq = distSq;
+ if (close)
+ *close = pos;
+
+ closeIndex = i - 1;
+ }
+ }
+
+ return closeIndex;
}
+// Test for un-jumpable height change, or unrecoverable fall
+
/* <38c911> ../cstrike/dlls/bot/cs_bot_pathfind.cpp:752 */
-NOBODY bool CCSBot::IsStraightLinePathWalkable(Vector *goal)
+bool CCSBot::IsStraightLinePathWalkable(const Vector *goal) const
{
-// {
-// float const inc; // 757
-// Vector feet; // 759
-// Vector dir; // 760
-// float length; // 761
-// float lastGround; // 763
-// float along; // 769
-// Vector pos; // 770
-// float ground; // 771
-// bool done; // 772
-// }
+// this is causing hang-up problems when crawling thru ducts/windows that drop off into rooms (they fail the "falling" check)
+return true;
+
+ const float inc = GenerationStepSize;
+
+ Vector feet = pev->origin;
+ Vector dir = *goal - feet;
+ float length = dir.NormalizeInPlace();
+
+ float lastGround;
+
+ //if (!GetSimpleGroundHeight(&pev->origin, &lastGround))
+ // return false;
+
+ lastGround = feet.z;
+
+ float along = 0.0f;
+ Vector pos;
+ float ground;
+ bool done = false;
+
+ while (!done)
+ {
+ along += inc;
+ if (along > length)
+ {
+ along = length;
+ done = true;
+ }
+
+ // compute step along path
+ pos = feet + along * dir;
+ pos.z += HalfHumanHeight;
+
+ if (!GetSimpleGroundHeight(&pos, &ground))
+ return false;
+
+ // check for falling
+ if (ground - lastGround < -StepHeight)
+ return false;
+
+ // check for unreachable jump
+ // use slightly shorter jump limit, to allow for some fudge room
+ if (ground - lastGround > JumpHeight)
+ return false;
+
+ lastGround = ground;
+ }
+
+ return true;
}
+// Compute a point a fixed distance ahead along our path.
+// Returns path index just after point.
+
/* <38ec40> ../cstrike/dlls/bot/cs_bot_pathfind.cpp:810 */
-NOBODY int CCSBot::FindPathPoint(float aheadRange, Vector *point, int *prevIndex)
+int CCSBot::FindPathPoint(float aheadRange, Vector *point, int *prevIndex)
{
-// {
-// int afterIndex; // 813
-// Vector close; // 816
-// int startIndex; // 817
-// Vector initDir; // 898
-// Vector feet; // 901
-// Vector eyes; // 902
-// float rangeSoFar; // 903
-// bool visible; // 906
-// Vector prevDir; // 908
-// bool isCorner; // 911
-// int i; // 912
-// {
-// int index; // 834
-// float const closeEpsilon; // 842
-// operator-(const Vector *const this,
-// const Vector &v); // 843
-// IsLengthLessThan(const class Vector2D *const this,
-// float length); // 843
-// }
-// {
-// Vector pos; // 862
-// float const closeEpsilon; // 865
-// operator-(const Vector *const this,
-// const Vector &v); // 866
-// IsLengthLessThan(const class Vector2D *const this,
-// float length); // 866
-// }
-// operator-(const Vector *const this,
-// const Vector &v); // 898
-// NormalizeInPlace(Vector *const this); // 899
-// GetFeetZ(const class CCSBot *const this); // 901
-// {
-// Vector pos; // 915
-// Vector to; // 916
-// Vector dir; // 917
-// Vector probe; // 936
-// Vector along; // 957
-// Vector(Vector *const this,
-// const Vector &v); // 915
-// operator-(const Vector *const this,
-// const Vector &v); // 916
-// Normalize(const Vector *const this); // 917
-// DotProduct(Vector &a,
-// const Vector &b); // 920
-// DotProduct(Vector &a,
-// const Vector &b); // 927
-// operator+(const Vector *const this,
-// const Vector &v); // 936
-// IsWalkableTraceLineClear(Vector &from,
-// Vector &to,
-// unsigned int flags); // 937
-// operator-(const Vector *const this,
-// const Vector &v); // 957
-// Length2D(const Vector *const this); // 958
-// operator-(const Vector *const this,
-// const Vector &v); // 957
-// }
-// operator+(const Vector *const this,
-// const Vector &v); // 902
-// {
-// const Vector *afterPoint; // 981
-// const Vector *beforePoint; // 982
-// Vector to; // 984
-// float length; // 985
-// float t; // 987
-// operator-(const Vector *const this,
-// const Vector &v); // 984
-// Length2D(const Vector *const this); // 985
-// operator*(float fl,
-// const Vector &v); // 994
-// {
-// float const sightStepSize; // 999
-// float dt; // 1000
-// Vector probe; // 1002
-// operator+(const Vector *const this,
-// const Vector &v); // 1002
-// IsWalkableTraceLineClear(Vector &from,
-// Vector &to,
-// unsigned int flags); // 1003
-// operator+(const Vector *const this,
-// const Vector &v); // 1006
-// operator*(float fl,
-// const Vector &v); // 1006
-// }
-// operator+(const Vector *const this,
-// const Vector &v); // 994
-// }
-// {
-// float const epsilon; // 1017
-// class Vector2D toPoint; // 1018
-// DotProduct(const class Vector2D &a,
-// const class Vector2D &b); // 1021
-// IsLengthLessThan(const class Vector2D *const this,
-// float length); // 1021
-// {
-// int i; // 1023
-// IsLengthGreaterThan(const class Vector2D *const this,
-// float length); // 1028
-// }
-// }
-// }
+ // find path index just past aheadRange
+ int afterIndex;
+
+ // finds the closest point on local area of path, and returns the path index just prior to it
+ Vector close;
+ int startIndex = FindOurPositionOnPath(&close, true);
+
+ if (prevIndex)
+ *prevIndex = startIndex;
+
+ if (startIndex <= 0)
+ {
+ // went off the end of the path
+ // or next point in path is unwalkable (ie: jump-down)
+ // keep same point
+ return m_pathIndex;
+ }
+
+ // if we are crouching, just follow the path exactly
+ if (IsCrouching())
+ {
+ // we want to move to the immediately next point along the path from where we are now
+ int index = startIndex + 1;
+ if (index >= m_pathLength)
+ index = m_pathLength - 1;
+
+ *point = m_path[ index ].pos;
+
+ // if we are very close to the next point in the path, skip ahead to the next one to avoid wiggling
+ // we must do a 2D check here, in case the goal point is floating in space due to jump down, etc
+ const float closeEpsilon = 20.0f; // 10.0f
+ while ((*point - close).Make2D().IsLengthLessThan(closeEpsilon))
+ {
+ ++index;
+
+ if (index >= m_pathLength)
+ {
+ index = m_pathLength - 1;
+ break;
+ }
+
+ *point = m_path[ index ].pos;
+ }
+
+ return index;
+ }
+
+ // make sure we use a node a minimum distance ahead of us, to avoid wiggling
+ while (startIndex < m_pathLength - 1)
+ {
+ Vector pos = m_path[ startIndex + 1 ].pos;
+
+ // we must do a 2D check here, in case the goal point is floating in space due to jump down, etc
+ const float closeEpsilon = 20.0f;
+ if ((pos - close).Make2D().IsLengthLessThan(closeEpsilon))
+ {
+ ++startIndex;
+ }
+ else
+ {
+ break;
+ }
+ }
+
+ // if we hit a ladder, stop, or jump area, must stop (dont use ladder behind us)
+ if (startIndex > m_pathIndex && startIndex < m_pathLength
+ && (m_path[ startIndex ].ladder != NULL || (m_path[ startIndex ].area->GetAttributes() & NAV_JUMP)))
+ {
+ *point = m_path[ startIndex ].pos;
+ return startIndex;
+ }
+
+ // we need the point just *ahead* of us
+ ++startIndex;
+ if (startIndex >= m_pathLength)
+ startIndex = m_pathLength - 1;
+
+ // if we hit a ladder, stop, or jump area, must stop
+ if (startIndex < m_pathLength && (m_path[ startIndex ].ladder != NULL || (m_path[ startIndex ].area->GetAttributes() & NAV_JUMP)))
+ {
+ *point = m_path[ startIndex ].pos;
+ return startIndex;
+ }
+
+ // note direction of path segment we are standing on
+ Vector initDir = m_path[ startIndex ].pos - m_path[ startIndex - 1 ].pos;
+ initDir.NormalizeInPlace();
+
+ Vector feet = Vector(pev->origin.x, pev->origin.y, GetFeetZ());
+ Vector eyes = feet + Vector(0, 0, HalfHumanHeight);
+ float rangeSoFar = 0;
+
+ // this flag is true if our ahead point is visible
+ bool visible = true;
+ Vector prevDir = initDir;
+
+ // step along the path until we pass aheadRange
+ bool isCorner = false;
+ int i;
+ for (i = startIndex; i < m_pathLength; ++i)
+ {
+ Vector pos = m_path[i].pos;
+ Vector to = pos - m_path[i - 1].pos;
+ Vector dir = to;
+ dir.NormalizeInPlace();
+
+ // don't allow path to double-back from our starting direction (going upstairs, down curved passages, etc)
+ if (DotProduct(dir, initDir) < 0.0f) // -0.25f
+ {
+ --i;
+ break;
+ }
+
+ // if the path turns a corner, we want to move towards the corner, not into the wall/stairs/etc
+ if (DotProduct(dir, prevDir) < 0.5f)
+ {
+ isCorner = true;
+ --i;
+ break;
+ }
+
+ prevDir = dir;
+
+ // don't use points we cant see
+ Vector probe = pos + Vector(0, 0, HalfHumanHeight);
+ if (!IsWalkableTraceLineClear(eyes, probe, WALK_THRU_BREAKABLES))
+ {
+ // presumably, the previous point is visible, so we will interpolate
+ visible = false;
+ break;
+ }
+
+ // if we encounter a ladder or jump area, we must stop
+ if (i < m_pathLength && (m_path[ i ].ladder != NULL || (m_path[ i ].area->GetAttributes() & NAV_JUMP)))
+ break;
+
+ // Check straight-line path from our current position to this position
+ // Test for un-jumpable height change, or unrecoverable fall
+ if (!IsStraightLinePathWalkable(&pos))
+ {
+ --i;
+ break;
+ }
+
+ Vector along = (i == startIndex) ? (pos - feet) : (pos - m_path[i - 1].pos);
+ rangeSoFar += along.Length2D();
+
+ // stop if we have gone farther than aheadRange
+ if (rangeSoFar >= aheadRange)
+ break;
+ }
+
+ if (i < startIndex)
+ afterIndex = startIndex;
+ else if (i < m_pathLength)
+ afterIndex = i;
+ else
+ afterIndex = m_pathLength - 1;
+
+ // compute point on the path at aheadRange
+ if (afterIndex == 0)
+ {
+ *point = m_path[0].pos;
+ }
+ else
+ {
+ // interpolate point along path segment
+ const Vector *afterPoint = &m_path[ afterIndex ].pos;
+ const Vector *beforePoint = &m_path[ afterIndex - 1 ].pos;
+
+ Vector to = *afterPoint - *beforePoint;
+ float length = to.Length2D();
+
+ float t = 1.0f - ((rangeSoFar - aheadRange) / length);
+
+ if (t < 0.0f)
+ t = 0.0f;
+ else if (t > 1.0f)
+ t = 1.0f;
+
+ *point = *beforePoint + t * to;
+
+ // if afterPoint wasn't visible, slide point backwards towards beforePoint until it is
+ if (!visible)
+ {
+ const float sightStepSize = 25.0f;
+ float dt = sightStepSize / length;
+
+ Vector probe = *point + Vector(0, 0, HalfHumanHeight);
+ while (t > 0.0f && !IsWalkableTraceLineClear(eyes, probe, WALK_THRU_BREAKABLES))
+ {
+ t -= dt;
+ *point = *beforePoint + t * to;
+ }
+
+ if (t <= 0.0f)
+ *point = *beforePoint;
+ }
+ }
+
+ // if position found is too close to us, or behind us, force it farther down the path so we don't stop and wiggle
+ if (!isCorner)
+ {
+ const float epsilon = 50.0f;
+ Vector2D toPoint;
+ toPoint.x = point->x - pev->origin.x;
+ toPoint.y = point->y - pev->origin.y;
+ if (DotProduct(toPoint, initDir.Make2D()) < 0.0f || toPoint.IsLengthLessThan(epsilon))
+ {
+ int i;
+ for (i = startIndex; i < m_pathLength; ++i)
+ {
+ toPoint.x = m_path[i].pos.x - pev->origin.x;
+ toPoint.y = m_path[i].pos.y - pev->origin.y;
+ if (m_path[i].ladder != NULL || (m_path[i].area->GetAttributes() & NAV_JUMP) || toPoint.IsLengthGreaterThan(epsilon))
+ {
+ *point = m_path[i].pos;
+ startIndex = i;
+ break;
+ }
+ }
+
+ if (i == m_pathLength)
+ {
+ *point = GetPathEndpoint();
+ startIndex = m_pathLength - 1;
+ }
+ }
+ }
+
+ // m_pathIndex should always be the next point on the path, even if we're not moving directly towards it
+ return startIndex;
}
+// Set the current index along the path
+
/* <38f761> ../cstrike/dlls/bot/cs_bot_pathfind.cpp:1052 */
-NOBODY void CCSBot::SetPathIndex(int newIndex)
+void CCSBot::SetPathIndex(int newIndex)
{
-// SetupLadderMovement(CCSBot *const this); // 1059
-// SetPathIndex(CCSBot *const this,
-// int newIndex); // 1052
+ m_pathIndex = Q_min(newIndex, m_pathLength - 1);
+ m_areaEnteredTimestamp = gpGlobals->time;
+
+ if (m_path[ m_pathIndex ].ladder)
+ {
+ SetupLadderMovement();
+ }
+ else
+ {
+ // get our "encounter spots" for this leg of the path
+ if (m_pathIndex < m_pathLength && m_pathIndex >= 2)
+ m_spotEncounter = m_path[ m_pathIndex - 1 ].area->GetSpotEncounter(m_path[ m_pathIndex - 2 ].area, m_path[ m_pathIndex ].area);
+ else
+ m_spotEncounter = NULL;
+
+ m_pathLadder = NULL;
+ }
}
+// Return true if nearing a jump in the path
+
/* <38cafc> ../cstrike/dlls/bot/cs_bot_pathfind.cpp:1077 */
-bool CCSBot::IsNearJump(void)
+bool CCSBot::IsNearJump(void) const
{
-// {
-// int i; // 1082
-// {
-// float dz; // 1086
-// }
-// }
+ if (m_pathIndex == 0 || m_pathIndex >= m_pathLength)
+ return false;
+
+ for (int i = m_pathIndex - 1; i < m_pathIndex; ++i)
+ {
+ if (m_path[ i ].area->GetAttributes() & NAV_JUMP)
+ {
+ float dz = m_path[ i + 1 ].pos.z - m_path[ i ].pos.z;
+
+ if (dz > 0.0f)
+ return true;
+ }
+ }
+
+ return false;
}
+// Return approximately how much damage will will take from the given fall height
+
/* <38f844> ../cstrike/dlls/bot/cs_bot_pathfind.cpp:1100 */
-NOBODY float CCSBot::GetApproximateFallDamage(float height)
+float CCSBot::GetApproximateFallDamage(float height) const
{
-// {
-// float const slope; // 1103
-// float const intercept; // 1104
-// float damage; // 1106
-// }
+ // empirically discovered height values
+ const float slope = 0.2178f;
+ const float intercept = 26.0f;
+
+ float_precision damage = slope * height - intercept;
+
+ if (damage < 0.0f)
+ return 0.0f;
+
+ return damage;
}
+// Return true if a friend is between us and the given position
+
/* <38f89b> ../cstrike/dlls/bot/cs_bot_pathfind.cpp:1118 */
-NOBODY bool CCSBot::IsFriendInTheWay(Vector *goalPos)
+bool CCSBot::IsFriendInTheWay(const Vector *goalPos) const
{
-// {
-// float const avoidFriendInterval; // 1126
-// Vector moveDir; // 1130
-// float length; // 1133
-// IsElapsed(const class CountdownTimer *const this); // 1121
-// {
-// int i; // 1138
-// {
-// class CBasePlayer *player; // 1140
-// Vector toFriend; // 1158
-// float const personalSpace; // 1161
-// float friendDistAlong; // 1166
-// Vector pos; // 1173
-// float const friendRadius; // 1180
-// FNullEnt(entvars_t *pev); // 1145
-// operator-(const Vector *const this,
-// const Vector &v); // 1158
-// IsLengthGreaterThan(const Vector *const this,
-// float length); // 1162
-// DotProduct(Vector &a,
-// const Vector &b); // 1166
-// operator*(float fl,
-// const Vector &v); // 1177
-// operator+(const Vector *const this,
-// const Vector &v); // 1177
-// operator-(const Vector *const this,
-// const Vector &v); // 1181
-// IsLengthLessThan(const Vector *const this,
-// float length); // 1181
-// }
-// }
-// Start(CountdownTimer *const this,
-// float duration); // 1127
-// operator-(const Vector *const this,
-// const Vector &v); // 1130
-// NormalizeInPlace(Vector *const this); // 1133
-// }
+ // do this check less often to ease CPU burden
+ if (!m_avoidFriendTimer.IsElapsed())
+ {
+ return m_isFriendInTheWay;
+ }
+
+ const float avoidFriendInterval = 0.5f;
+ m_avoidFriendTimer.Start(avoidFriendInterval);
+
+ // compute ray along intended path
+ Vector moveDir = *goalPos - pev->origin;
+
+ // make it a unit vector
+ float length = moveDir.NormalizeInPlace();
+
+ m_isFriendInTheWay = false;
+
+ // check if any friends are overlapping this linear path
+ for (int i = 1; i <= gpGlobals->maxClients; ++i)
+ {
+ CBasePlayer *player = static_cast(UTIL_PlayerByIndex(i));
+
+ if (player == NULL)
+ continue;
+
+ if (FNullEnt(player->pev))
+ continue;
+
+ if (!player->IsAlive())
+ continue;
+
+ if (player->m_iTeam != m_iTeam)
+ continue;
+
+ if (player == this)
+ continue;
+
+ // compute vector from us to our friend
+ Vector toFriend = player->pev->origin - pev->origin;
+
+ // check if friend is in our "personal space"
+ const float personalSpace = 100.0f;
+ if (toFriend.IsLengthGreaterThan(personalSpace))
+ continue;
+
+ // find distance of friend along our movement path
+ float friendDistAlong = DotProduct(toFriend, moveDir);
+
+ // if friend is behind us, ignore him
+ if (friendDistAlong <= 0.0f)
+ continue;
+
+ // constrain point to be on path segment
+ Vector pos;
+ if (friendDistAlong >= length)
+ pos = *goalPos;
+ else
+ pos = pev->origin + friendDistAlong * moveDir;
+
+ // check if friend overlaps our intended line of movement
+ const float friendRadius = 30.0f;
+ if ((pos - player->pev->origin).IsLengthLessThan(friendRadius))
+ {
+ // friend is in our personal space and overlaps our intended line of movement
+ m_isFriendInTheWay = true;
+ break;
+ }
+ }
+
+ return m_isFriendInTheWay;
}
+// Do reflex avoidance movements if our "feelers" are touched
+
/* <38fbd5> ../cstrike/dlls/bot/cs_bot_pathfind.cpp:1197 */
-NOBODY void CCSBot::FeelerReflexAdjustment(Vector *goalPosition)
+void CCSBot::FeelerReflexAdjustment(Vector *goalPosition)
{
-// {
-// Vector dir; // 1203
-// Vector lat; // 1204
-// float const feelerOffset; // 1206
-// float const feelerLengthRun; // 1207
-// float const feelerLengthWalk; // 1208
-// float const feelerHeight; // 1209
-// float feelerLength; // 1211
-// float ground; // 1218
-// Vector normal; // 1219
-// Vector feet; // 1230
-// Vector from; // 1231
-// Vector to; // 1232
-// float testZ; // 1233
-// bool leftClear; // 1235
-// bool rightClear; // 1260
-// float const avoidRange; // 1279
-// GetEyePosition(const class CCSBot *const this); // 1220
-// GetFeetZ(const class CCSBot *const this); // 1230
-// CrossProduct(Vector &a,
-// const Vector &b); // 1224
-// CrossProduct(Vector &a,
-// const Vector &b); // 1227
-// IsWalkableTraceLineClear(Vector &from,
-// Vector &to,
-// unsigned int flags); // 1235
-// operator*(float fl,
-// const Vector &v); // 1231
-// operator+(const Vector *const this,
-// const Vector &v); // 1231
-// operator*(float fl,
-// const Vector &v); // 1232
-// operator+(const Vector *const this,
-// const Vector &v); // 1232
-// Vector(Vector *const this,
-// const Vector &v); // 1252
-// Vector(Vector *const this,
-// const Vector &v); // 1252
-// operator-(const Vector *const this,
-// const Vector &v); // 1257
-// IsWalkableTraceLineClear(Vector &from,
-// Vector &to,
-// unsigned int flags); // 1260
-// operator+(const Vector *const this,
-// const Vector &v); // 1258
-// Vector(Vector *const this,
-// const Vector &v); // 1274
-// Vector(Vector *const this,
-// const Vector &v); // 1274
-// operator*(float fl,
-// const Vector &v); // 1286
-// operator+(const Vector *const this,
-// const Vector &v); // 1286
-// operator*(float fl,
-// const Vector &v); // 1292
-// operator-(const Vector *const this,
-// const Vector &v); // 1292
-// Vector(Vector *const this,
-// const Vector &v); // 1254
-// Vector(Vector *const this,
-// const Vector &v); // 1254
-// Vector(Vector *const this,
-// const Vector &v); // 1276
-// Vector(Vector *const this,
-// const Vector &v); // 1276
-// }
+ // if we are in a "precise" area, do not do feeler adjustments
+ if (m_lastKnownArea != NULL && (m_lastKnownArea->GetAttributes() & NAV_PRECISE))
+ return;
+
+ Vector dir(BotCOS(m_forwardAngle), BotSIN(m_forwardAngle), 0.0f);
+ Vector lat(-dir.y, dir.x, 0.0f);
+
+ const float feelerOffset = (IsCrouching()) ? 15.0f : 20.0f;
+ const float feelerLengthRun = 50.0f; // 100 - too long for tight hallways (cs_747)
+ const float feelerLengthWalk = 30.0f;
+ const float feelerHeight = StepHeight + 0.1f; // if obstacle is lower than StepHeight, we'll walk right over it
+
+ float feelerLength = (IsRunning()) ? feelerLengthRun : feelerLengthWalk;
+
+ feelerLength = (IsCrouching()) ? 20.0f : feelerLength;
+
+ // Feelers must follow floor slope
+ float ground;
+ Vector normal;
+
+ //m_eyePos = EyePosition();
+ m_eyePos.x = pev->origin.x + pev->view_ofs.x;
+ m_eyePos.y = pev->origin.y + pev->view_ofs.y;
+ m_eyePos.z = pev->origin.z + pev->view_ofs.z;
+
+ if (GetSimpleGroundHeightWithFloor(&m_eyePos, &ground, &normal) == false)
+ return;
+
+ // get forward vector along floor
+ dir = CrossProduct(lat, normal);
+
+ // correct the sideways vector
+ lat = CrossProduct(dir, normal);
+
+ Vector feet = Vector(pev->origin.x, pev->origin.y, GetFeetZ());
+ feet.z += feelerHeight;
+
+ Vector from = feet + feelerOffset * lat;
+ Vector to = from + feelerLength * dir;
+
+ bool leftClear = IsWalkableTraceLineClear(from, to, WALK_THRU_EVERYTHING);
+
+ // avoid ledges, too
+ // use 'from' so it doesn't interfere with legitimate gap jumping (its at our feet)
+ // TODO: Rethink this - it causes lots of wiggling when bots jump down from vents, etc
+/*
+ float ground;
+ if (GetSimpleGroundHeightWithFloor(&from, &ground))
+ {
+ if (GetFeetZ() - ground > JumpHeight)
+ leftClear = false;
+ }
+*/
+
+ if ((cv_bot_traceview.value == 1.0f && IsLocalPlayerWatchingMe()) || cv_bot_traceview.value == 10.0f)
+ {
+ if (leftClear)
+ UTIL_DrawBeamPoints(from, to, 1, 0, 255, 0);
+ else
+ UTIL_DrawBeamPoints(from, to, 1, 255, 0, 0);
+ }
+
+ from = feet - feelerOffset * lat;
+ to = from + feelerLength * dir;
+
+ bool rightClear = IsWalkableTraceLineClear(from, to, WALK_THRU_EVERYTHING);
+
+/*
+ // avoid ledges, too
+ if (GetSimpleGroundHeightWithFloor(&from, &ground))
+ {
+ if (GetFeetZ() - ground > JumpHeight)
+ rightClear = false;
+ }
+*/
+
+ if ((cv_bot_traceview.value == 1.0f && IsLocalPlayerWatchingMe()) || cv_bot_traceview.value == 10.0f)
+ {
+ if (rightClear)
+ UTIL_DrawBeamPoints(from, to, 1, 0, 255, 0);
+ else
+ UTIL_DrawBeamPoints(from, to, 1, 255, 0, 0);
+ }
+
+ const float avoidRange = (IsCrouching()) ? 150.0f : 300.0f; // 50.0f : 300.0f
+
+ if (!rightClear)
+ {
+ if (leftClear)
+ {
+ // right hit, left clear - veer left
+ *goalPosition = *goalPosition + avoidRange * lat;
+ }
+ }
+ else if (!leftClear)
+ {
+ // right clear, left hit - veer right
+ *goalPosition = *goalPosition - avoidRange * lat;
+ }
}
+// Move along the path. Return false if end of path reached.
+
/* <3912bf> ../cstrike/dlls/bot/cs_bot_pathfind.cpp:1300 */
-NOBODY CCSBot::PathResult CCSBot::UpdatePathMovement(bool allowSpeedChange)
+CCSBot::PathResult CCSBot::UpdatePathMovement(bool allowSpeedChange)
{
-// {
-// bool nearEndOfPath; // 1329
-// int prevIndex; // 1373
-// float const aheadRange; // 1374
-// int newIndex; // 1375
-// float const nearCornerRange; // 1378
-// Vector toGoal; // 1448
-// Vector adjustedGoal; // 1510
-// bool didFall; // 1583
-// float const giveUpDuration; // 1608
-// {
-// Vector toEnd; // 1332
-// Vector d; // 1337
-// float const walkRange; // 1339
-// GetFeetZ(const class CCSBot *const this); // 1335
-// IsLengthLessThan(const Vector *const this,
-// float length); // 1342
-// {
-// float const nearEndRange; // 1349
-// float const closeEpsilon; // 1353
-// IsLengthLessThan(const Vector *const this,
-// float length); // 1350
-// DestroyPath(CCSBot *const this); // 1357
-// }
-// }
-// FindPathPoint(CCSBot *const this,
-// float aheadRange,
-// Vector *point,
-// int *prevIndex); // 1375
-// operator-(const Vector *const this,
-// const Vector &v); // 1379
-// IsLengthLessThan(const Vector *const this,
-// float length); // 1379
-// ClearLookAt(CCSBot *const this); // 1381
-// SetPathIndex(CCSBot *const this,
-// int newIndex); // 1388
-// {
-// float const crouchRange; // 1409
-// bool didCrouch; // 1410
-// {
-// int i; // 1411
-// {
-// const class CNavArea *to; // 1413
-// Vector close; // 1419
-// operator-(const Vector *const this,
-// const Vector &v); // 1422
-// IsLengthGreaterThan(const class Vector2D *const this,
-// float length); // 1422
-// }
-// }
-// }
-// operator-(const Vector *const this,
-// const Vector &v); // 1443
-// {
-// float const lookAheadRange; // 1458
-// operator-(const Vector *const this,
-// const Vector &v); // 1455
-// IsLengthLessThan(const class Vector2D *const this,
-// float length); // 1461
-// {
-// float along; // 1463
-// int i; // 1464
-// Length2D(const Vector *const this); // 1463
-// {
-// Vector delta; // 1467
-// float segmentLength; // 1468
-// operator-(const Vector *const this,
-// const Vector &v); // 1467
-// Length2D(const Vector *const this); // 1468
-// {
-// float t; // 1473
-// Vector target; // 1474
-// operator-(const Vector *const this,
-// const Vector &v); // 1483
-// operator*(float fl,
-// const Vector &v); // 1481
-// operator+(const Vector *const this,
-// const Vector &v); // 1481
-// }
-// operator-(const Vector *const this,
-// const Vector &v); // 1490
-// }
-// GetPathEndpoint(const class CCSBot *const this); // 1498
-// }
-// }
-// operator-(const Vector *const this,
-// const Vector &v); // 1503
-// Vector(Vector *const this,
-// const Vector &v); // 1510
-// {
-// const Vector *pos; // 1528
-// operator+(const Vector *const this,
-// const Vector &v); // 1529
-// Vector(Vector *const this,
-// const Vector &v); // 1529
-// operator+(const Vector *const this,
-// const Vector &v); // 1531
-// Vector(Vector *const this,
-// const Vector &v); // 1531
-// operator+(const Vector *const this,
-// const Vector &v); // 1532
-// Vector(Vector *const this,
-// const Vector &v); // 1532
-// }
-// {
-// float const politeDuration; // 1542
-// Start(CountdownTimer *const this,
-// float duration); // 1543
-// }
-// IsElapsed(const class CountdownTimer *const this); // 1545
-// DestroyPath(CCSBot *const this); // 1552
-// GetFeetZ(const class CCSBot *const this); // 1584
-// {
-// float const closeRange; // 1586
-// class Vector2D to; // 1587
-// IsLengthLessThan(const class Vector2D *const this,
-// float length); // 1588
-// GetFeetZ(const class CCSBot *const this); // 1594
-// }
-// DestroyPath(CCSBot *const this); // 1622
-// IsNearJump(const class CCSBot *const this); // 1518
-// }
+ if (m_pathLength == 0)
+ return PATH_FAILURE;
+
+ if (cv_bot_walk.value != 0.0f)
+ Walk();
+
+ // If we are navigating a ladder, it overrides all other path movement until complete
+ if (UpdateLadderMovement())
+ return PROGRESSING;
+
+ // ladder failure can destroy the path
+ if (m_pathLength == 0)
+ return PATH_FAILURE;
+
+ // we are not supposed to be on a ladder - if we are, jump off
+ if (IsOnLadder())
+ Jump(MUST_JUMP);
+
+ assert(m_pathIndex < m_pathLength);
+
+ // Check if reached the end of the path
+ bool nearEndOfPath = false;
+ if (m_pathIndex >= m_pathLength - 1)
+ {
+ Vector toEnd(pev->origin.x, pev->origin.y, GetFeetZ());
+ Vector d = GetPathEndpoint() - toEnd; // can't use 2D because path end may be below us (jump down)
+
+ const float walkRange = 200.0f;
+
+ // walk as we get close to the goal position to ensure we hit it
+ if (d.IsLengthLessThan(walkRange))
+ {
+ // don't walk if crouching - too slow
+ if (allowSpeedChange && !IsCrouching())
+ Walk();
+
+ // note if we are near the end of the path
+ const float nearEndRange = 50.0f;
+ if (d.IsLengthLessThan(nearEndRange))
+ nearEndOfPath = true;
+
+ const float closeEpsilon = 20.0f;
+ if (d.IsLengthLessThan(closeEpsilon))
+ {
+ // reached goal position - path complete
+ DestroyPath();
+
+ // TODO: We should push and pop walk state here, in case we want to continue walking after reaching goal
+ if (allowSpeedChange)
+ Run();
+
+ return END_OF_PATH;
+ }
+ }
+ }
+
+ // To keep us moving smoothly, we will move towards
+ // a point farther ahead of us down our path.
+ int prevIndex = 0; // closest index on path just prior to where we are now
+ const float aheadRange = 300.0f;
+ int newIndex = FindPathPoint(aheadRange, &m_goalPosition, &prevIndex);
+
+ // BOTPORT: Why is prevIndex sometimes -1?
+ if (prevIndex < 0)
+ prevIndex = 0;
+
+ // if goal position is near to us, we must be about to go around a corner - so look ahead!
+ const float nearCornerRange = 100.0f;
+ if (m_pathIndex < m_pathLength - 1 && (m_goalPosition - pev->origin).IsLengthLessThan(nearCornerRange))
+ {
+ ClearLookAt();
+ InhibitLookAround(0.5f);
+ }
+
+ // if we moved to a new node on the path, setup movement
+ if (newIndex > m_pathIndex)
+ {
+ SetPathIndex(newIndex);
+ }
+
+ // Crouching
+ if (!IsUsingLadder())
+ {
+ // if we are approaching a crouch area, crouch
+ // if there are no crouch areas coming up, stand
+ const float crouchRange = 50.0f;
+ bool didCrouch = false;
+ for (int i = prevIndex; i < m_pathLength; ++i)
+ {
+ const CNavArea *to = m_path[i].area;
+
+ // if there is a jump area on the way to the crouch area, don't crouch as it messes up the jump
+ // unless we are already higher than the jump area - we must've jumped already but not moved into next area
+ if ((to->GetAttributes() & NAV_JUMP)/* && to->GetCenter()->z > GetFeetZ()*/)
+ break;
+
+ Vector close;
+ to->GetClosestPointOnArea(&pev->origin, &close);
+
+ if ((close - pev->origin).Make2D().IsLengthGreaterThan(crouchRange))
+ break;
+
+ if (to->GetAttributes() & NAV_CROUCH)
+ {
+ Crouch();
+ didCrouch = true;
+ break;
+ }
+ }
+
+ if (!didCrouch && !IsJumping())
+ {
+ // no crouch areas coming up
+ StandUp();
+ }
+ // end crouching logic
+ }
+
+ // compute our forward facing angle
+ m_forwardAngle = UTIL_VecToYaw(m_goalPosition - pev->origin);
+
+ // Look farther down the path to "lead" our view around corners
+ Vector toGoal;
+
+ if (m_pathIndex == 0)
+ {
+ toGoal = m_path[1].pos;
+ }
+ else if (m_pathIndex < m_pathLength)
+ {
+ toGoal = m_path[ m_pathIndex ].pos - pev->origin;
+
+ // actually aim our view farther down the path
+ const float lookAheadRange = 500.0f;
+ if (!m_path[ m_pathIndex ].ladder && !IsNearJump() && toGoal.Make2D().IsLengthLessThan(lookAheadRange))
+ {
+ float along = toGoal.Length2D();
+ int i;
+ for (i = m_pathIndex + 1; i < m_pathLength; ++i)
+ {
+ Vector delta = m_path[i].pos - m_path[i - 1].pos;
+ float segmentLength = delta.Length2D();
+
+ if (along + segmentLength >= lookAheadRange)
+ {
+ // interpolate between points to keep look ahead point at fixed distance
+ float t = (lookAheadRange - along) / (segmentLength + along);
+ Vector target;
+
+ if (t <= 0.0f)
+ target = m_path[i - 1].pos;
+ else if (t >= 1.0f)
+ target = m_path[i].pos;
+ else
+ target = m_path[i - 1].pos + t * delta;
+
+ toGoal = target - pev->origin;
+ break;
+ }
+
+ // if we are coming up to a ladder or a jump, look at it
+ if (m_path[i].ladder || (m_path[i].area->GetAttributes() & NAV_JUMP))
+ {
+ toGoal = m_path[i].pos - pev->origin;
+ break;
+ }
+
+ along += segmentLength;
+ }
+
+ if (i == m_pathLength)
+ toGoal = GetPathEndpoint() - pev->origin;
+ }
+ }
+ else
+ {
+ toGoal = GetPathEndpoint() - pev->origin;
+ }
+
+ m_lookAheadAngle = UTIL_VecToYaw(toGoal);
+
+ // initialize "adjusted" goal to current goal
+ Vector adjustedGoal = m_goalPosition;
+
+ // Use short "feelers" to veer away from close-range obstacles
+ // Feelers come from our ankles, just above StepHeight, so we avoid short walls, too
+ // Don't use feelers if very near the end of the path, or about to jump
+ // TODO: Consider having feelers at several heights to deal with overhangs, etc.
+ if (!nearEndOfPath && !IsNearJump() && !IsJumping())
+ {
+ FeelerReflexAdjustment(&adjustedGoal);
+ }
+
+ // draw debug visualization
+ if ((cv_bot_traceview.value == 1.0f && IsLocalPlayerWatchingMe()) || cv_bot_traceview.value == 10.0f)
+ {
+ DrawPath();
+
+ const Vector *pos = &m_path[ m_pathIndex ].pos;
+ UTIL_DrawBeamPoints(*pos, *pos + Vector(0, 0, 50), 1, 255, 255, 0);
+ UTIL_DrawBeamPoints(adjustedGoal, adjustedGoal + Vector(0, 0, 50), 1, 255, 0, 255);
+ UTIL_DrawBeamPoints(pev->origin, adjustedGoal + Vector(0, 0, 50), 1, 255, 0, 255);
+ }
+
+ // dont use adjustedGoal, as it can vary wildly from the feeler adjustment
+ if (!IsAttacking() && IsFriendInTheWay(&m_goalPosition))
+ {
+ if (!m_isWaitingBehindFriend)
+ {
+ m_isWaitingBehindFriend = true;
+
+ const float politeDuration = 5.0f - 3.0f * GetProfile()->GetAggression();
+ m_politeTimer.Start(politeDuration);
+ }
+ else if (m_politeTimer.IsElapsed())
+ {
+ // we have run out of patience
+ m_isWaitingBehindFriend = false;
+ ResetStuckMonitor();
+
+ // repath to avoid clump of friends in the way
+ DestroyPath();
+ }
+ }
+ else if (m_isWaitingBehindFriend)
+ {
+ // we're done waiting for our friend to move
+ m_isWaitingBehindFriend = false;
+ ResetStuckMonitor();
+ }
+
+ // Move along our path if there are no friends blocking our way,
+ // or we have run out of patience
+ if (!m_isWaitingBehindFriend || m_politeTimer.IsElapsed())
+ {
+ // Move along path
+ MoveTowardsPosition(&adjustedGoal);
+
+ // Stuck check
+ if (m_isStuck && !IsJumping())
+ {
+ Wiggle();
+ }
+ }
+
+ // if our goal is high above us, we must have fallen
+ bool didFall = false;
+ if (m_goalPosition.z - GetFeetZ() > JumpCrouchHeight)
+ {
+ const float closeRange = 75.0f;
+ Vector2D to(pev->origin.x - m_goalPosition.x, pev->origin.y - m_goalPosition.y);
+ if (to.IsLengthLessThan(closeRange))
+ {
+ // we can't reach the goal position
+ // check if we can reach the next node, in case this was a "jump down" situation
+ if (m_pathIndex < m_pathLength - 1)
+ {
+ if (m_path[ m_pathIndex + 1 ].pos.z - GetFeetZ() > JumpCrouchHeight)
+ {
+ // the next node is too high, too - we really did fall of the path
+ didFall = true;
+ }
+ }
+ else
+ {
+ // fell trying to get to the last node in the path
+ didFall = true;
+ }
+ }
+ }
+
+ // This timeout check is needed if the bot somehow slips way off
+ // of its path and cannot progress, but also moves around
+ // enough that it never becomes "stuck"
+ const float giveUpDuration = 5.0f; // 4.0f
+ if (didFall || gpGlobals->time - m_areaEnteredTimestamp > giveUpDuration)
+ {
+ if (didFall)
+ {
+ PrintIfWatched("I fell off!\n");
+ }
+
+ // if we havent made any progress in a long time, give up
+ if (m_pathIndex < m_pathLength - 1)
+ {
+ PrintIfWatched("Giving up trying to get to area #%d\n", m_path[ m_pathIndex ].area->GetID());
+ }
+ else
+ {
+ PrintIfWatched("Giving up trying to get to end of path\n");
+ }
+
+ Run();
+ StandUp();
+ DestroyPath();
+
+ return PATH_FAILURE;
+ }
+
+ return PROGRESSING;
}
+// Build trivial path to goal, assuming we are already in the same area
+
/* <3906a6> ../cstrike/dlls/bot/cs_bot_pathfind.cpp:1634 */
-NOBODY void CCSBot::BuildTrivialPath(const Vector *goal)
+void CCSBot::BuildTrivialPath(const Vector *goal)
{
+ m_pathIndex = 1;
+ m_pathLength = 2;
+
+ m_path[0].area = m_lastKnownArea;
+ m_path[0].pos = pev->origin;
+ m_path[0].pos.z = m_lastKnownArea->GetZ(&pev->origin);
+ m_path[0].ladder = NULL;
+ m_path[0].how = NUM_TRAVERSE_TYPES;
+
+ m_path[1].area = m_lastKnownArea;
+ m_path[1].pos = *goal;
+ m_path[1].pos.z = m_lastKnownArea->GetZ(goal);
+ m_path[1].ladder = NULL;
+ m_path[1].how = NUM_TRAVERSE_TYPES;
+
+ m_areaEnteredTimestamp = gpGlobals->time;
+ m_spotEncounter = NULL;
+ m_pathLadder = NULL;
+
+ m_goalPosition = *goal;
}
+// Compute shortest path to goal position via A* algorithm
+// If 'goalArea' is NULL, path will get as close as it can.
+
/* <3907cd> ../cstrike/dlls/bot/cs_bot_pathfind.cpp:1664 */
-NOBODY bool CCSBot::ComputePath(CNavArea *goalArea, const Vector *goal, RouteType route)
+bool CCSBot::ComputePath(CNavArea *goalArea, const Vector *goal, RouteType route)
{
-// {
-// class CNavArea *startArea; // 1679
-// Vector pathEndPosition; // 1687
-// class CNavArea *closestArea; // 1705
-// class PathCost pathCost; // 1706
-// bool pathToGoalExists; // 1707
-// class CNavArea *effectiveGoalArea; // 1709
-// int count; // 1716
-// class CNavArea *area; // 1717
-// IsElapsed(const class CountdownTimer *const this); // 1669
-// Start(CountdownTimer *const this,
-// float duration); // 1673
-// DestroyPath(CCSBot *const this); // 1675
-// Vector(Vector *const this,
-// const Vector &v); // 1687
-// NavAreaBuildPath(CNavArea *startArea,
-// class CNavArea *goalArea,
-// const Vector *goalPos,
-// class PathCost &costFunc,
-// class CNavArea ** closestArea); // 1707
-// SetupLadderMovement(CCSBot *const this); // 1786
-// DestroyPath(CCSBot *const this); // 1747
-// }
+ // Throttle re-pathing
+ if (!m_repathTimer.IsElapsed())
+ return false;
+
+ // randomize to distribute CPU load
+ m_repathTimer.Start(RANDOM_FLOAT(0.4f, 0.6f));
+
+ DestroyPath();
+
+ CNavArea *startArea = m_lastKnownArea;
+ if (startArea == NULL)
+ return false;
+
+ // note final specific position
+ Vector pathEndPosition;
+
+ if (goal == NULL && goalArea == NULL)
+ return false;
+
+ if (goal == NULL)
+ pathEndPosition = *goalArea->GetCenter();
+ else
+ pathEndPosition = *goal;
+
+ // make sure path end position is on the ground
+ if (goalArea)
+ pathEndPosition.z = goalArea->GetZ(&pathEndPosition);
+ else
+ GetGroundHeight(&pathEndPosition, &pathEndPosition.z);
+
+ // if we are already in the goal area, build trivial path
+ if (startArea == goalArea)
+ {
+ BuildTrivialPath(&pathEndPosition);
+ return true;
+ }
+
+ // Compute shortest path to goal
+ CNavArea *closestArea = NULL;
+ PathCost pathCost(this, route);
+ bool pathToGoalExists = NavAreaBuildPath(startArea, goalArea, goal, pathCost, &closestArea);
+
+ CNavArea *effectiveGoalArea = (pathToGoalExists) ? goalArea : closestArea;
+
+ // Build path by following parent links
+ // get count
+ int count = 0;
+ CNavArea *area;
+ for (area = effectiveGoalArea; area != NULL; area = area->GetParent())
+ {
+ ++count;
+ }
+
+ // save room for endpoint
+ if (count > MAX_PATH_LENGTH - 1)
+ count = MAX_PATH_LENGTH - 1;
+
+ if (count == 0)
+ return false;
+
+ if (count == 1)
+ {
+ BuildTrivialPath(&pathEndPosition);
+ return true;
+ }
+
+ // build path
+ m_pathLength = count;
+ for (area = effectiveGoalArea; count && area != NULL; area = area->GetParent())
+ {
+ --count;
+ m_path[ count ].area = area;
+ m_path[ count ].how = area->GetParentHow();
+ }
+
+ // compute path positions
+ if (ComputePathPositions() == false)
+ {
+ PrintIfWatched("Error building path\n");
+ DestroyPath();
+ return false;
+ }
+
+ if (goal == NULL)
+ {
+ switch (m_path[m_pathLength - 1].how)
+ {
+ case GO_NORTH:
+ case GO_SOUTH:
+ pathEndPosition.x = m_path[m_pathLength - 1].pos.x;
+ pathEndPosition.y = effectiveGoalArea->GetCenter()->y;
+ break;
+
+ case GO_EAST:
+ case GO_WEST:
+ pathEndPosition.x = effectiveGoalArea->GetCenter()->x;
+ pathEndPosition.y = m_path[m_pathLength - 1].pos.y;
+ break;
+ }
+
+ GetGroundHeight(&pathEndPosition, &pathEndPosition.z);
+ }
+
+ // append path end position
+ m_path[ m_pathLength ].area = effectiveGoalArea;
+ m_path[ m_pathLength ].pos = pathEndPosition;
+ m_path[ m_pathLength ].ladder = NULL;
+ m_path[ m_pathLength ].how = NUM_TRAVERSE_TYPES;
+ ++m_pathLength;
+
+ // do movement setup
+ m_pathIndex = 1;
+ m_areaEnteredTimestamp = gpGlobals->time;
+ m_spotEncounter = NULL;
+ m_goalPosition = m_path[1].pos;
+
+ if (m_path[1].ladder != NULL)
+ SetupLadderMovement();
+ else
+ m_pathLadder = NULL;
+
+ return true;
}
+// Return estimated distance left to travel along path
+
/* <390ef6> ../cstrike/dlls/bot/cs_bot_pathfind.cpp:1798 */
-NOBODY float CCSBot::GetPathDistanceRemaining(void)
+float CCSBot::GetPathDistanceRemaining(void) const
{
-// {
-// int idx; // 1803
-// float dist; // 1805
-// const Vector *prevCenter; // 1806
-// {
-// int i; // 1808
-// operator-(const Vector *const this,
-// const Vector &v); // 1810
-// Length(const Vector *const this); // 1810
-// }
-// }
+ if (!HasPath())
+ return -1.0f;
+
+ int idx = (m_pathIndex < m_pathLength) ? m_pathIndex : m_pathLength - 1;
+
+ float dist = 0.0f;
+ const Vector *prevCenter = m_path[m_pathIndex].area->GetCenter();
+
+ for (int i = idx + 1; i < m_pathLength; ++i)
+ {
+ dist += (*m_path[i].area->GetCenter() - *prevCenter).Length();
+ prevCenter = m_path[i].area->GetCenter();
+ }
+
+ return dist;
}
+// Draw a portion of our current path for debugging.
+
/* <390fb1> ../cstrike/dlls/bot/cs_bot_pathfind.cpp:1821 */
-NOBODY void CCSBot::DrawPath(void)
+void CCSBot::DrawPath(void)
{
-// {
-// Vector close; // 1830
-// {
-// int i; // 1826
-// operator+(const Vector *const this,
-// const Vector &v); // 1828
-// operator+(const Vector *const this,
-// const Vector &v); // 1828
-// }
-// Vector(Vector *const this,
-// const Vector &v); // 1835
-// operator+(const Vector *const this,
-// const Vector &v); // 1835
-// operator+(const Vector *const this,
-// const Vector &v); // 1836
-// operator+(const Vector *const this,
-// const Vector &v); // 1836
-// operator+(const Vector *const this,
-// const Vector &v); // 1837
-// operator+(const Vector *const this,
-// const Vector &v); // 1837
-// }
+ if (!HasPath())
+ return;
+
+ for (int i = 1; i < m_pathLength; ++i)
+ {
+ UTIL_DrawBeamPoints(m_path[i - 1].pos, m_path[i].pos, 2, 255, 75, 0);
+ }
+
+ Vector close;
+ if (FindOurPositionOnPath(&close, true) >= 0)
+ {
+ UTIL_DrawBeamPoints(close + Vector(0, 0, 25), close, 1, 0, 255, 0);
+ UTIL_DrawBeamPoints(close + Vector(25, 0, 0), close + Vector(-25, 0, 0), 1, 0, 255, 0);
+ UTIL_DrawBeamPoints(close + Vector(0, 25, 0), close + Vector(0, -25, 0), 1, 0, 255, 0);
+ }
}
diff --git a/regamedll/dlls/bot/cs_bot_radio.cpp b/regamedll/dlls/bot/cs_bot_radio.cpp
index f6c3ca04..9094013c 100644
--- a/regamedll/dlls/bot/cs_bot_radio.cpp
+++ b/regamedll/dlls/bot/cs_bot_radio.cpp
@@ -1,64 +1,334 @@
#include "precompiled.h"
-/* <3a397f> ../cstrike/dlls/bot/cs_bot_radio.cpp:220 */
-NOBODY void CCSBot::StartVoiceFeedback(float duration)
-{
-// {
-// class CBasePlayer *pPlayer; // 227
-// MESSAGE_BEGIN(int msg_dest,
-// int msg_type,
-// const float *pOrigin,
-// entvars_t *ent); // 230
-// edict(CBaseEntity *const this); // 232
-// ENTINDEX(edict_t *pEdict); // 232
-// }
+// Returns true if the radio message is an order to do something
+// NOTE: "Report in" is not considered a "command" because it doesnt ask the bot to go somewhere, or change its mind
+/* <3a3689> ../cstrike/dlls/bot/cs_bot_radio.cpp:19 */
+bool CCSBot::IsRadioCommand(GameEventType event) const
+{
+ if (event == EVENT_RADIO_AFFIRMATIVE
+ || event == EVENT_RADIO_NEGATIVE
+ || event == EVENT_RADIO_ENEMY_SPOTTED
+ || event == EVENT_RADIO_SECTOR_CLEAR
+ || event == EVENT_RADIO_REPORTING_IN
+ || event == EVENT_RADIO_REPORT_IN_TEAM
+ || event == EVENT_RADIO_ENEMY_DOWN)
+ return false;
+
+ return true;
}
-/* <3a3a32> ../cstrike/dlls/bot/cs_bot_radio.cpp:241 */
-void CCSBot::EndVoiceFeedback(bool force)
-{
- if (!force && !m_voiceFeedbackEndTimestamp)
- return;
-
- m_voiceFeedbackEndTimestamp = 0;
-
- MESSAGE_BEGIN(MSG_ALL, gmsgBotVoice);
- WRITE_BYTE(0);
- WRITE_BYTE(ENTINDEX(edict()));
- MESSAGE_END();
-}
+// Respond to radio commands from HUMAN players
-/* <3a3bcd> ../cstrike/dlls/bot/cs_bot_radio.cpp:259 */
-NOBODY bool CCSBot::RespondToHelpRequest(CBasePlayer *them, Place place, float maxRange)
-{
-// {
-// class PathCost pc; // 272
-// float travelDistance; // 273
-// NavAreaTravelDistance(CNavArea *startArea,
-// class CNavArea *endArea,
-// class PathCost &costFunc); // 273
-// }
-// {
-// float rangeSq; // 287
-// float const close; // 288
-// operator-(const Vector *const this,
-// const Vector &v); // 287
-// LengthSquared(const Vector *const this); // 287
-// }
-// {
-// const Vector *pos; // 301
-// }
-// Say(BotChatterInterface *const this,
-// const char *phraseName,
-// float lifetime,
-// float delay); // 309
+/* <3a36e0> ../cstrike/dlls/bot/cs_bot_radio.cpp:37 */
+void CCSBot::RespondToRadioCommands(void)
+{
+ // bots use the chatter system to respond to each other
+ if (m_radioSubject != NULL && m_radioSubject->IsPlayer())
+ {
+ CBasePlayer *player = m_radioSubject;
+ if (player->IsBot())
+ {
+ m_lastRadioCommand = EVENT_INVALID;
+ return;
+ }
+ }
+
+ if (m_lastRadioCommand == EVENT_INVALID)
+ return;
+
+ // a human player has issued a radio command
+ GetChatter()->ResetRadioSilenceDuration();
+
+ // if we are doing something important, ignore the radio
+ // unless it is a "report in" request - we can do that while we continue to do other things
+ // TODO: Create "uninterruptable" flag
+ if (m_lastRadioCommand != EVENT_RADIO_REPORT_IN_TEAM)
+ {
+ if (IsBusy())
+ {
+ // consume command
+ m_lastRadioCommand = EVENT_INVALID;
+ return;
+ }
+ }
+
+ // wait for reaction time before responding
+ // delay needs to be long enough for the radio message we're responding to to finish
+ float respondTime = 1.0f + 2.0f * GetProfile()->GetReactionTime();
+ if (IsRogue())
+ respondTime += 2.0f;
+
+ if (gpGlobals->time - m_lastRadioRecievedTimestamp < respondTime)
+ return;
+
+ // rogues won't follow commands, unless already following the player
+ if (!IsFollowing() && IsRogue())
+ {
+ if (IsRadioCommand(m_lastRadioCommand))
+ {
+ GetChatter()->Negative();
+ }
+
+ // consume command
+ m_lastRadioCommand = EVENT_INVALID;
+ return;
+ }
+
+ CBasePlayer *player = m_radioSubject;
+ if (player == NULL)
+ return;
+
+ // respond to command
+ bool canDo = false;
+ const float inhibitAutoFollowDuration = 60.0f;
+ switch (m_lastRadioCommand)
+ {
+ case EVENT_RADIO_REPORT_IN_TEAM:
+ {
+ GetChatter()->ReportingIn();
+ break;
+ }
+ case EVENT_RADIO_FOLLOW_ME:
+ case EVENT_RADIO_COVER_ME:
+ case EVENT_RADIO_STICK_TOGETHER_TEAM:
+ case EVENT_RADIO_REGROUP_TEAM:
+ {
+ if (!IsFollowing())
+ {
+ Follow(player);
+ player->AllowAutoFollow();
+ canDo = true;
+ }
+ break;
+ }
+ case EVENT_RADIO_ENEMY_SPOTTED:
+ case EVENT_RADIO_NEED_BACKUP:
+ case EVENT_RADIO_TAKING_FIRE:
+ {
+ if (!IsFollowing())
+ {
+ Follow(player);
+ GetChatter()->Say("OnMyWay");
+ player->AllowAutoFollow();
+ canDo = false;
+ }
+ break;
+ }
+ case EVENT_RADIO_TEAM_FALL_BACK:
+ {
+ if (TryToRetreat())
+ canDo = true;
+ break;
+ }
+ case EVENT_RADIO_HOLD_THIS_POSITION:
+ {
+ // find the leader's area
+ SetTask(HOLD_POSITION);
+ StopFollowing();
+ player->InhibitAutoFollow(inhibitAutoFollowDuration);
+ Hide(TheNavAreaGrid.GetNearestNavArea(&m_radioPosition));
+ canDo = true;
+ break;
+ }
+ case EVENT_RADIO_GO_GO_GO:
+ case EVENT_RADIO_STORM_THE_FRONT:
+ {
+ StopFollowing();
+ Hunt();
+ canDo = true;
+ player->InhibitAutoFollow(inhibitAutoFollowDuration);
+ break;
+ }
+ case EVENT_RADIO_GET_OUT_OF_THERE:
+ {
+ if (TheCSBots()->IsBombPlanted())
+ {
+ EscapeFromBomb();
+ player->InhibitAutoFollow(inhibitAutoFollowDuration);
+ canDo = true;
+ }
+ break;
+ }
+ case EVENT_RADIO_SECTOR_CLEAR:
+ {
+ // if this is a defusal scenario, and the bomb is planted,
+ // and a human player cleared a bombsite, check it off our list too
+ if (TheCSBots()->GetScenario() == CCSBotManager::SCENARIO_DEFUSE_BOMB)
+ {
+ if (m_iTeam == CT && TheCSBots()->IsBombPlanted())
+ {
+ const CCSBotManager::Zone *zone = TheCSBots()->GetClosestZone(player);
+
+ if (zone != NULL)
+ {
+ GetGameState()->ClearBombsite(zone->m_index);
+
+ // if we are huting for the planted bomb, re-select bombsite
+ if (GetTask() == FIND_TICKING_BOMB)
+ Idle();
+
+ canDo = true;
+ }
+ }
+ }
+ break;
+ }
+ default:
+ // ignore all other radio commands for now
+ return;
+ }
+
+ if (canDo)
+ {
+ // affirmative
+ GetChatter()->Affirmative();
+
+ // if we agreed to follow a new command, put away our grenade
+ if (IsRadioCommand(m_lastRadioCommand) && IsUsingGrenade())
+ {
+ EquipBestWeapon();
+ }
+ }
+
+ // consume command
+ m_lastRadioCommand = EVENT_INVALID;
}
-/* <3a4316> ../cstrike/dlls/bot/cs_bot_radio.cpp:319 */
-NOBODY void CCSBot::SendRadioMessage(GameEventType event)
-{
-// {
-// class CCSBotManager *ctrl; // 328
-// char slot; // 333
-// }
-}
+// Send voice chatter. Also sends the entindex.
+
+/* <3a397f> ../cstrike/dlls/bot/cs_bot_radio.cpp:220 */
+void CCSBot::StartVoiceFeedback(float duration)
+{
+ m_voiceFeedbackStartTimestamp = gpGlobals->time;
+ m_voiceFeedbackEndTimestamp = duration + gpGlobals->time;
+
+ CBasePlayer *pPlayer = NULL;
+ while ((pPlayer = GetNextRadioRecipient(pPlayer)) != NULL)
+ {
+ MESSAGE_BEGIN(MSG_ONE, gmsgBotVoice, NULL, pPlayer->pev);
+ WRITE_BYTE(1); // active is talking
+ WRITE_BYTE(entindex()); // client index speaking
+ MESSAGE_END();
+ }
+}
+
+/* <3a3a32> ../cstrike/dlls/bot/cs_bot_radio.cpp:241 */
+void CCSBot::EndVoiceFeedback(bool force)
+{
+ if (!force && !m_voiceFeedbackEndTimestamp)
+ return;
+
+ m_voiceFeedbackEndTimestamp = 0;
+
+ MESSAGE_BEGIN(MSG_ALL, gmsgBotVoice);
+ WRITE_BYTE(0);
+ WRITE_BYTE(ENTINDEX(edict()));
+ MESSAGE_END();
+}
+
+// Decide if we should move to help the player, return true if we will
+
+/* <3a3bcd> ../cstrike/dlls/bot/cs_bot_radio.cpp:259 */
+bool CCSBot::RespondToHelpRequest(CBasePlayer *them, Place place, float maxRange)
+{
+ if (IsRogue())
+ return false;
+
+ // if we're busy, ignore
+ if (IsBusy())
+ return false;
+
+ // if we are too far away, ignore
+ if (maxRange > 0.0f)
+ {
+ // compute actual travel distance
+ PathCost pc(this);
+ float_precision travelDistance = NavAreaTravelDistance(m_lastKnownArea, TheNavAreaGrid.GetNearestNavArea(&them->pev->origin), pc);
+ if (travelDistance < 0.0f)
+ return false;
+
+ if (travelDistance > maxRange)
+ return false;
+ }
+
+ if (place == UNDEFINED_PLACE)
+ {
+ // if we have no "place" identifier, go directly to them
+
+ // if we are already there, ignore
+ float rangeSq = (them->pev->origin - pev->origin).LengthSquared();
+ const float close = 750.0f * 750.0f;
+
+ if (rangeSq < close)
+ return true;
+
+ MoveTo(&them->pev->origin, FASTEST_ROUTE);
+ }
+ else
+ {
+ // if we are already there, ignore
+ if (GetPlace() == place)
+ return true;
+
+ // go to where help is needed
+ const Vector *pos = GetRandomSpotAtPlace(place);
+ if (pos != NULL)
+ {
+ MoveTo(pos, FASTEST_ROUTE);
+ }
+ else
+ {
+ MoveTo(&them->pev->origin, FASTEST_ROUTE);
+ }
+ }
+
+ // acknowledge
+ GetChatter()->Say("OnMyWay");
+
+ return true;
+}
+
+// Send a radio message
+
+/* <3a4316> ../cstrike/dlls/bot/cs_bot_radio.cpp:319 */
+void CCSBot::SendRadioMessage(GameEventType event)
+{
+ // make sure this is a radio event
+ if (event <= EVENT_START_RADIO_1 || event >= EVENT_END_RADIO)
+ {
+ return;
+ }
+
+ CCSBotManager *ctrl = TheCSBots();
+ PrintIfWatched("%3.1f: SendRadioMessage( %s )\n", gpGlobals->time, GameEventName[ event ]);
+
+ // note the time the message was sent
+ ctrl->SetRadioMessageTimestamp(event, m_iTeam);
+
+ m_lastRadioSentTimestamp = gpGlobals->time;
+
+ char slot[2];
+ slot[1] = '\000';
+
+ if (event > EVENT_START_RADIO_1 && event < EVENT_START_RADIO_2)
+ {
+ slot[0] = event - EVENT_START_RADIO_1;
+ ClientCommand("radio1");
+ //Radio1(this, event - EVENT_START_RADIO_3);
+ }
+ else if (event > EVENT_START_RADIO_2 && event < EVENT_START_RADIO_3)
+ {
+ slot[0] = event - EVENT_START_RADIO_2;
+ ClientCommand("radio2");
+ //Radio2(this, event - EVENT_START_RADIO_3);
+ }
+ else
+ {
+ slot[0] = event - EVENT_START_RADIO_3;
+ ClientCommand("radio3");
+ //Radio3(this, event - EVENT_START_RADIO_3);
+ }
+
+ ClientCommand("menuselect", slot);
+ ClientCommand("menuselect", "10");
+}
diff --git a/regamedll/dlls/bot/cs_bot_statemachine.cpp b/regamedll/dlls/bot/cs_bot_statemachine.cpp
index 24705bdc..c5784533 100644
--- a/regamedll/dlls/bot/cs_bot_statemachine.cpp
+++ b/regamedll/dlls/bot/cs_bot_statemachine.cpp
@@ -1,19 +1,18 @@
#include "precompiled.h"
+// This method is the ONLY legal way to change a bot's current state
+
/* <3b3a2a> ../cstrike/dlls/bot/cs_bot_statemachine.cpp:16 */
void CCSBot::SetState(BotState *state)
{
PrintIfWatched("SetState: %s -> %s\n", (m_state != NULL) ? m_state->GetName() : "NULL", state->GetName());
+ // if we changed state from within the special Attack state, we are no longer attacking
if (m_isAttacking)
- {
StopAttacking();
- }
- if (m_state)
- {
+ if (m_state != NULL)
m_state->OnExit(this);
- }
state->OnEnter(this);
@@ -29,144 +28,256 @@ void CCSBot::Idle(void)
}
/* <3b3afa> ../cstrike/dlls/bot/cs_bot_statemachine.cpp:41 */
-NOBODY void CCSBot::EscapeFromBomb(void)
+void CCSBot::EscapeFromBomb(void)
{
-// SetTask(CCSBot::EscapeFromBomb(// enum TaskType task,
-// class CBaseEntity *entity); // 43
+ SetTask(ESCAPE_FROM_BOMB);
+ SetState(&m_escapeFromBombState);
}
/* <3b3b4b> ../cstrike/dlls/bot/cs_bot_statemachine.cpp:48 */
-NOBODY void CCSBot::Follow(CBasePlayer *player)
+void CCSBot::Follow(CBasePlayer *player)
{
-// SetTask(CCSBot *const this,
-// enum TaskType task,
-// class CBaseEntity *entity); // 60
-// SetLeader(FollowState *const this,
-// class CBasePlayer *player); // 61
+ if (player == NULL)
+ return;
+
+ // note when we began following
+ if (!m_isFollowing || m_leader != player)
+ m_followTimestamp = gpGlobals->time;
+
+ m_isFollowing = true;
+ m_leader = player;
+
+ SetTask(FOLLOW);
+ m_followState.SetLeader(player);
+ SetState(&m_followState);
}
+// Continue following our leader after finishing what we were doing
+
/* <3b3bd1> ../cstrike/dlls/bot/cs_bot_statemachine.cpp:69 */
-NOBODY void CCSBot::ContinueFollowing(void)
+void CCSBot::ContinueFollowing(void)
{
-// {
-// class CBasePlayer *leader; // 73
-// SetTask(CCSBot *const this,
-// enum TaskType task,
-// class CBaseEntity *entity); // 71
-// SetLeader(FollowState *const this,
-// class CBasePlayer *player); // 74
-// }
+ SetTask(FOLLOW);
+ m_followState.SetLeader(m_leader);
+ SetState(&m_followState);
}
+// Stop following
+
/* <3b3c57> ../cstrike/dlls/bot/cs_bot_statemachine.cpp:83 */
-NOBODY void CCSBot::StopFollowing(void)
+void CCSBot::StopFollowing(void)
{
+ m_isFollowing = false;
+ m_leader = NULL;
+ m_allowAutoFollowTime = gpGlobals->time + 10.0f;
}
+// Begin process of rescuing hostages
+
/* <3b3c7e> ../cstrike/dlls/bot/cs_bot_statemachine.cpp:94 */
-NOBODY void CCSBot::RescueHostages(void)
+void CCSBot::RescueHostages(void)
{
-// SetTask(CCSBot::RescueHostages(// enum TaskType task,
-// class CBaseEntity *entity); // 96
+ SetTask(RESCUE_HOSTAGES);
}
+// Use the entity
+
/* <3b3cc9> ../cstrike/dlls/bot/cs_bot_statemachine.cpp:103 */
-NOBODY void CCSBot::UseEntity(CBaseEntity *entity)
+void CCSBot::UseEntity(CBaseEntity *entity)
{
-// SetEntity(UseEntityState *const this,
-// class CBaseEntity *entity); // 105
+ m_useEntityState.SetEntity(entity);
+ SetState(&m_useEntityState);
}
+// DEPRECATED: Use TryToHide() instead.
+// Move to a hiding place.
+// If 'searchFromArea' is non-NULL, hiding spots are looked for from that area first.
+
/* <3b3d23> ../cstrike/dlls/bot/cs_bot_statemachine.cpp:116 */
-NOBODY void CCSBot::Hide(CNavArea *searchFromArea, float duration, float hideRange, bool holdPosition)
+void CCSBot::Hide(CNavArea *searchFromArea, float duration, float hideRange, bool holdPosition)
{
-// {
-// class CNavArea *source; // 120
-// Vector sourcePos; // 121
-// const Vector *pos; // 146
-// DestroyPath(CCSBot *const this); // 118
-// SetDuration(HideState *const this,
-// float time); // 142
-// SetSearchArea(HideState *const this,
-// class CNavArea *area); // 140
-// SetSearchRange(HideState *const this,
-// float range); // 141
-// SetHoldPosition(HideState *const this,
-// bool hold); // 143
-// SetHidingSpot(HideState *const this,
-// const Vector *pos); // 154
-// Idle(CCSBot *const this); // 160
-// }
+ DestroyPath();
+
+ CNavArea *source;
+ Vector sourcePos;
+ if (searchFromArea)
+ {
+ source = searchFromArea;
+ sourcePos = *searchFromArea->GetCenter();
+ }
+ else
+ {
+ source = m_lastKnownArea;
+ sourcePos = pev->origin;
+ }
+
+ if (source == NULL)
+ {
+ PrintIfWatched("Hide from area is NULL.\n");
+ Idle();
+ return;
+ }
+
+ m_hideState.SetSearchArea(source);
+ m_hideState.SetSearchRange(hideRange);
+ m_hideState.SetDuration(duration);
+ m_hideState.SetHoldPosition(holdPosition);
+
+ // search around source area for a good hiding spot
+ Vector useSpot;
+
+ const Vector *pos = FindNearbyHidingSpot(this, &sourcePos, source, hideRange, IsSniper());
+ if (pos == NULL)
+ {
+ PrintIfWatched("No available hiding spots.\n");
+ // hide at our current position
+ useSpot = pev->origin;
+ }
+ else
+ {
+ useSpot = *pos;
+ }
+
+ m_hideState.SetHidingSpot(useSpot);
+
+ // build a path to our new hiding spot
+ if (ComputePath(TheNavAreaGrid.GetNavArea(&useSpot), &useSpot, FASTEST_ROUTE) == false)
+ {
+ PrintIfWatched("Can't pathfind to hiding spot\n");
+ Idle();
+ return;
+ }
+
+ SetState(&m_hideState);
}
+// Move to the given hiding place
+
/* <3b3e98> ../cstrike/dlls/bot/cs_bot_statemachine.cpp:171 */
-NOBODY void CCSBot::Hide(const Vector *hidingSpot, float duration, bool holdPosition)
+void CCSBot::Hide(const Vector *hidingSpot, float duration, bool holdPosition)
{
-// {
-// class CNavArea *hideArea; // 173
-// DestroyPath(CCSBot *const this); // 181
-// SetHoldPosition(HideState *const this,
-// bool hold); // 186
-// SetSearchArea(HideState *const this,
-// class CNavArea *area); // 183
-// SetSearchRange(HideState *const this,
-// float range); // 184
-// SetDuration(HideState *const this,
-// float time); // 185
-// SetHidingSpot(HideState *const this,
-// const Vector *pos); // 187
-// Idle(CCSBot *const this); // 193
-// }
+ CNavArea *hideArea = TheNavAreaGrid.GetNearestNavArea(hidingSpot);
+ if (hideArea == NULL)
+ {
+ PrintIfWatched("Hiding spot off nav mesh\n");
+ Idle();
+ return;
+ }
+
+ DestroyPath();
+
+ m_hideState.SetSearchArea(hideArea);
+ m_hideState.SetSearchRange(750.0f);
+ m_hideState.SetDuration(duration);
+ m_hideState.SetHoldPosition(holdPosition);
+ m_hideState.SetHidingSpot(*hidingSpot);
+
+ // build a path to our new hiding spot
+ if (ComputePath(hideArea, hidingSpot, FASTEST_ROUTE) == false)
+ {
+ PrintIfWatched("Can't pathfind to hiding spot\n");
+ Idle();
+ return;
+ }
+
+ SetState(&m_hideState);
}
+// Try to hide nearby. Return true if hiding, false if can't hide here.
+// If 'searchFromArea' is non-NULL, hiding spots are looked for from that area first.
+
/* <3b3fc1> ../cstrike/dlls/bot/cs_bot_statemachine.cpp:205 */
-NOBODY bool CCSBot::TryToHide(CNavArea *searchFromArea, float duration, float hideRange, bool holdPosition, bool useNearest)
+bool CCSBot::TryToHide(CNavArea *searchFromArea, float duration, float hideRange, bool holdPosition, bool useNearest)
{
-// {
-// class CNavArea *source; // 207
-// Vector sourcePos; // 208
-// const Vector *pos; // 232
-// SetDuration(HideState *const this,
-// float time); // 228
-// SetSearchArea(HideState *const this,
-// class CNavArea *area); // 226
-// SetSearchRange(HideState *const this,
-// float range); // 227
-// SetHoldPosition(HideState *const this,
-// bool hold); // 229
-// SetHidingSpot(HideState *const this,
-// const Vector *pos); // 239
-// }
+ CNavArea *source;
+ Vector sourcePos;
+ if (searchFromArea)
+ {
+ source = searchFromArea;
+ sourcePos = *searchFromArea->GetCenter();
+ }
+ else
+ {
+ source = m_lastKnownArea;
+ sourcePos = pev->origin;
+ }
+
+ if (source == NULL)
+ {
+ PrintIfWatched("Hide from area is NULL.\n");
+ return false;
+ }
+
+ m_hideState.SetSearchArea(source);
+ m_hideState.SetSearchRange(hideRange);
+ m_hideState.SetDuration(duration);
+ m_hideState.SetHoldPosition(holdPosition);
+
+ // search around source area for a good hiding spot
+ const Vector *pos = FindNearbyHidingSpot(this, &sourcePos, source, hideRange, IsSniper(), useNearest);
+ if (pos == NULL)
+ {
+ PrintIfWatched("No available hiding spots.\n");
+ return false;
+ }
+
+ m_hideState.SetHidingSpot(*pos);
+
+ // build a path to our new hiding spot
+ if (ComputePath(TheNavAreaGrid.GetNavArea(pos), pos, FASTEST_ROUTE) == false)
+ {
+ PrintIfWatched("Can't pathfind to hiding spot\n");
+ return false;
+ }
+
+ SetState(&m_hideState);
+ return true;
}
+// Retreat to a nearby hiding spot, away from enemies
+
/* <3b40ed> ../cstrike/dlls/bot/cs_bot_statemachine.cpp:256 */
-NOBODY bool CCSBot::TryToRetreat(void)
+bool CCSBot::TryToRetreat(void)
{
-// {
-// const Vector *spot; // 258
-// {
-// float holdTime; // 265
-// Hide(CCSBot *const this,
-// const Vector *hidingSpot,
-// float duration,
-// bool holdPosition); // 268
-// }
-// }
+ const float maxRange = 1000.0f;
+ const Vector *spot = FindNearbyRetreatSpot(this, maxRange);
+
+ if (spot != NULL)
+ {
+ // ignore enemies for a second to give us time to hide
+ // reaching our hiding spot clears our disposition
+ IgnoreEnemies(10.0f);
+
+ float holdTime = RANDOM_FLOAT(3.0f, 15.0f);
+
+ StandUp();
+ Run();
+ Hide(spot, holdTime);
+
+ PrintIfWatched("Retreating to a safe spot!\n");
+ return true;
+ }
+
+ return false;
}
/* <3b426a> ../cstrike/dlls/bot/cs_bot_statemachine.cpp:280 */
-NOBODY void CCSBot::Hunt(void)
+void CCSBot::Hunt(void)
{
+ SetState(&m_huntState);
}
+// Attack our the given victim
+// NOTE: Attacking does not change our task.
+
/* <3b4291> ../cstrike/dlls/bot/cs_bot_statemachine.cpp:290 */
-NOBODY void CCSBot::Attack(CBasePlayer *victim)
+void CCSBot::Attack(CBasePlayer *victim)
{
if (victim == NULL)
return;
// zombies never attack
- if (cv_bot_zombie.value)
+ if (cv_bot_zombie.value != 0.0f)
return;
// cannot attack if we are reloading
@@ -183,11 +294,11 @@ NOBODY void CCSBot::Attack(CBasePlayer *victim)
if (IsAtHidingSpot())
m_attackState.SetCrouchAndHold((RANDOM_FLOAT(0, 100) < 60.0f) != 0);
else
- m_attackState.SetCrouchAndHold(0);
+ m_attackState.SetCrouchAndHold(false);
PrintIfWatched("ATTACK BEGIN (reaction time = %g (+ update time), surprise time = %g, attack delay = %g)\n");
m_isAttacking = true;
- m_attackState.OnEnter(this);// TODO: Reverse me
+ m_attackState.OnEnter(this);
// cheat a bit and give the bot the initial location of its victim
m_lastEnemyPosition = victim->pev->origin;
@@ -196,18 +307,16 @@ NOBODY void CCSBot::Attack(CBasePlayer *victim)
// compute the angle difference between where are looking, and where we need to look
Vector toEnemy = victim->pev->origin - pev->origin;
- Vector idealAngle;
+ Vector idealAngle = UTIL_VecToAngles(toEnemy);
- idealAngle = UTIL_VecToAngles(toEnemy);
-
- float deltaYaw = (float)abs(m_lookYaw - idealAngle.y);
+ float deltaYaw = abs((int)(m_lookYaw - idealAngle.y));
while (deltaYaw > 180.0f)
deltaYaw -= 360.0f;
if (deltaYaw < 0.0f)
deltaYaw = -deltaYaw;
-
+
// immediately aim at enemy - accuracy penalty depending on how far we must turn to aim
// accuracy is halved if we have to turn 180 degrees
float turn = deltaYaw / 180.0f;
@@ -220,11 +329,13 @@ NOBODY void CCSBot::Attack(CBasePlayer *victim)
m_aimOffsetTimestamp = gpGlobals->time + RANDOM_FLOAT(0.25f + turn, 1.5f);
}
+// Exit the Attack state
+
/* <3b4416> ../cstrike/dlls/bot/cs_bot_statemachine.cpp:366 */
void CCSBot::StopAttacking(void)
{
PrintIfWatched("ATTACK END\n");
- m_attackState.OnExit(this);//TODO: Reverse me
+ m_attackState.OnExit(this);
m_isAttacking = false;
// if we are following someone, go to the Idle state after the attack to decide whether we still want to follow
@@ -240,11 +351,19 @@ bool CCSBot::IsAttacking(void) const
return m_isAttacking;
}
+// Return true if we are escaping from the bomb
+
/* <3b449f> ../cstrike/dlls/bot/cs_bot_statemachine.cpp:387 */
-NOBODY bool CCSBot::IsEscapingFromBomb(void) const
+bool CCSBot::IsEscapingFromBomb(void) const
{
+ if (m_state == static_cast(&m_escapeFromBombState))
+ return true;
+
+ return false;
}
+// Return true if we are defusing the bomb
+
/* <3b44c6> ../cstrike/dlls/bot/cs_bot_statemachine.cpp:399 */
bool CCSBot::IsDefusingBomb(void) const
{
@@ -254,6 +373,8 @@ bool CCSBot::IsDefusingBomb(void) const
return false;
}
+// Return true if we are hiding
+
/* <3b44ed> ../cstrike/dlls/bot/cs_bot_statemachine.cpp:411 */
bool CCSBot::IsHiding(void) const
{
@@ -263,6 +384,8 @@ bool CCSBot::IsHiding(void) const
return false;
}
+// Return true if we are hiding and at our hiding spot
+
/* <3b450f> ../cstrike/dlls/bot/cs_bot_statemachine.cpp:423 */
bool CCSBot::IsAtHidingSpot(void) const
{
@@ -272,16 +395,30 @@ bool CCSBot::IsAtHidingSpot(void) const
return m_hideState.IsAtSpot();
}
+// Return true if we are huting
+
/* <3b454a> ../cstrike/dlls/bot/cs_bot_statemachine.cpp:435 */
-NOBODY bool CCSBot::IsHunting(void) const
+bool CCSBot::IsHunting(void) const
{
+ if (m_state == static_cast(&m_huntState))
+ return true;
+
+ return false;
}
+// Return true if we are in the MoveTo state
+
/* <3b4571> ../cstrike/dlls/bot/cs_bot_statemachine.cpp:447 */
-NOBODY bool CCSBot::IsMovingTo(void) const
+bool CCSBot::IsMovingTo(void) const
{
+ if (m_state == static_cast(&m_moveToState))
+ return true;
+
+ return false;
}
+// Return true if we are buying
+
/* <3b4598> ../cstrike/dlls/bot/cs_bot_statemachine.cpp:460 */
bool CCSBot::IsBuying(void) const
{
@@ -291,31 +428,40 @@ bool CCSBot::IsBuying(void) const
return false;
}
+// Move to potentially distant position
+
/* <3b45bf> ../cstrike/dlls/bot/cs_bot_statemachine.cpp:472 */
-NOBODY void CCSBot::MoveTo(const Vector *pos, RouteType route)
+void CCSBot::MoveTo(const Vector *pos, RouteType route)
{
-// SetGoalPosition(MoveToState *const this,
-// const Vector *pos); // 474
-// SetRouteType(MoveToState *const this,
-// enum RouteType route); // 475
+ m_moveToState.SetGoalPosition(*pos);
+ m_moveToState.SetRouteType(route);
+ SetState(&m_moveToState);
}
/* <3b463c> ../cstrike/dlls/bot/cs_bot_statemachine.cpp:480 */
-NOBODY void CCSBot::PlantBomb(void)
+void CCSBot::PlantBomb(void)
{
+ SetState(&m_plantBombState);
}
+// Bomb has been dropped - go get it
+
/* <3b4663> ../cstrike/dlls/bot/cs_bot_statemachine.cpp:489 */
-NOBODY void CCSBot::FetchBomb(void)
+void CCSBot::FetchBomb(void)
{
+ SetState(&m_fetchBombState);
}
/* <3b468a> ../cstrike/dlls/bot/cs_bot_statemachine.cpp:495 */
-NOBODY void CCSBot::DefuseBomb(void)
+void CCSBot::DefuseBomb(void)
{
+ SetState(&m_defuseBombState);
}
+// Investigate recent enemy noise
+
/* <3b46b1> ../cstrike/dlls/bot/cs_bot_statemachine.cpp:504 */
-NOBODY void CCSBot::InvestigateNoise(void)
+void CCSBot::InvestigateNoise(void)
{
+ SetState(&m_investigateNoiseState);
}
diff --git a/regamedll/dlls/bot/cs_bot_update.cpp b/regamedll/dlls/bot/cs_bot_update.cpp
index 0bdac0d9..f2cad623 100644
--- a/regamedll/dlls/bot/cs_bot_update.cpp
+++ b/regamedll/dlls/bot/cs_bot_update.cpp
@@ -1,5 +1,7 @@
#include "precompiled.h"
+// Lightweight maintenance, invoked frequently
+
/* <3c635f> ../cstrike/dlls/bot/cs_bot_update.cpp:26 */
void CCSBot::__MAKE_VHOOK(Upkeep)(void)
{
@@ -11,10 +13,12 @@ void CCSBot::__MAKE_VHOOK(Upkeep)(void)
if (m_isRapidFiring)
TogglePrimaryAttack();
+ // aiming must be smooth - update often
if (IsAimingAtEnemy())
{
UpdateAimOffset();
+ // aim at enemy, if he's still alive
if (m_enemy != NULL)
{
float feetOffset = pev->origin.z - GetFeetZ();
@@ -30,13 +34,14 @@ void CCSBot::__MAKE_VHOOK(Upkeep)(void)
m_aimSpot = m_enemy->pev->origin;
bool aimBlocked = false;
+ const float sharpshooter = 0.8f;
- if (IsUsingAWP() || IsUsingShotgun() || IsUsingMachinegun() || GetProfile()->GetSkill() < 0.8f
+ if (IsUsingAWP() || IsUsingShotgun() || IsUsingMachinegun() || GetProfile()->GetSkill() < sharpshooter
|| (IsActiveWeaponRecoilHigh() && !IsUsingPistol() && !IsUsingSniperRifle()))
{
if (IsEnemyPartVisible(CHEST))
{
- // No headshots in this game, go for the chest.
+ // No headshots, go for the chest.
aimBlocked = true;
}
}
@@ -130,11 +135,12 @@ void CCSBot::__MAKE_VHOOK(Upkeep)(void)
}
float driftAmplitude = 2.0f;
- const float sharpshooter = 0.5f;
// have view "drift" very slowly, so view looks "alive"
if (IsUsingSniperRifle() && IsUsingScope())
- driftAmplitude = sharpshooter;
+ {
+ driftAmplitude = 0.5f;
+ }
m_lookYaw += driftAmplitude * BotCOS(33.0f * gpGlobals->time);
m_lookPitch += driftAmplitude * BotSIN(13.0f * gpGlobals->time);
@@ -147,7 +153,7 @@ void CCSBot::__MAKE_VHOOK(Upkeep)(void)
void (*pCCSBot__Update)(void);
/* <3c6e1e> ../cstrike/dlls/bot/cs_bot_update.cpp:208 */
-void __declspec(naked) CCSBot::__MAKE_VHOOK(Update)(void)
+NOBODY void __declspec(naked) CCSBot::__MAKE_VHOOK(Update)(void)
{
__asm
{
@@ -326,6 +332,12 @@ void __declspec(naked) CCSBot::__MAKE_VHOOK(Update)(void)
#ifdef HOOK_GAMEDLL
+// NavAreaBuildPath hook
+bool NavAreaBuildPath__PathCost__wrapper(CNavArea *startArea, CNavArea *goalArea, const Vector *goalPos, PathCost &costFunc, CNavArea **closestArea)
+{
+ return NavAreaBuildPath(startArea, goalArea, goalPos, costFunc, closestArea);
+}
+
void CCSBot::Upkeep(void)
{
Upkeep_();
diff --git a/regamedll/dlls/bot/cs_bot_vision.cpp b/regamedll/dlls/bot/cs_bot_vision.cpp
index 452557df..a779b2e7 100644
--- a/regamedll/dlls/bot/cs_bot_vision.cpp
+++ b/regamedll/dlls/bot/cs_bot_vision.cpp
@@ -13,194 +13,274 @@ float StayOnLadderLine(CCSBot *me, const CNavLadder *ladder)
switch (faceDir)
{
case NORTH:
- return stiffness * (ladder->m_top.x - me->pev->origin.x);
+ return (stiffness * (ladder->m_top.x - me->pev->origin.x));
case EAST:
- return stiffness * (ladder->m_top.y - me->pev->origin.y);
+ return (stiffness * (ladder->m_top.y - me->pev->origin.y));
case SOUTH:
- return -stiffness * (ladder->m_top.x - me->pev->origin.x);
+ return (-stiffness * (ladder->m_top.x - me->pev->origin.x));
case WEST:
- return -stiffness * (ladder->m_top.y - me->pev->origin.y);
+ return (-stiffness * (ladder->m_top.y - me->pev->origin.y));
}
return 0.0f;
}
-void (*pCCSBot__UpdateLookAngles)(void);
+// Move actual view angles towards desired ones.
+// This is the only place v_angle is altered.
+// TODO: Make stiffness and turn rate constants timestep invariant.
/* <3d882c> ../cstrike/dlls/bot/cs_bot_vision.cpp:48 */
-void __declspec(naked) CCSBot::UpdateLookAngles(void)
+#ifndef HOOK_GAMEDLL
+void CCSBot::UpdateLookAngles(void)
{
- __asm
+ const float deltaT = g_flBotCommandInterval;
+ float maxAccel;
+ float stiffness;
+ float damping;
+
+ // springs are stiffer when attacking, so we can track and move between targets better
+ if (IsAttacking())
{
- jmp pCCSBot__UpdateLookAngles
+ stiffness = 300.0f;
+ damping = 30.0f;
+ maxAccel = 3000.0f;
+ }
+ else
+ {
+ stiffness = 200.0f;
+ damping = 25.0f;
+ maxAccel = 3000.0f;
}
- //float stiffness;
- //float damping;
+ // these may be overridden by ladder logic
+ float useYaw = m_lookYaw;
+ float usePitch = m_lookPitch;
- //if (IsAttacking())
- //{
- // damping = 30.0f;
- // stiffness = 300.0f;
- //}
- //else
- //{
- // damping = 25.0f;
- // stiffness = 200.0f;
- //}
+ // Ladders require precise movement, therefore we need to look at the
+ // ladder as we approach and ascend/descend it.
+ // If we are on a ladder, we need to look up or down to traverse it - override pitch in this case.
+ // If we're trying to break something, though, we actually need to look at it before we can
+ // look at the ladder
+ if (IsUsingLadder())
+ {
+ // set yaw to aim at ladder
+ Vector to = m_pathLadder->m_top - pev->origin;
+ float idealYaw = UTIL_VecToYaw(to);
- //float useYaw = m_lookYaw;
- //float usePitch = m_lookPitch;
+ NavDirType faceDir = m_pathLadder->m_dir;
- //const float deltaT = (long double)g_flBotCommandInterval;
- //const float maxAccel = 3000.0f;
- //const float lookAlongLadderRange = 100.0f;
- //const float ladderPitch = 60.0f;
+ if (m_pathLadderFaceIn)
+ {
+ faceDir = OppositeDirection(faceDir);
+ }
- //if (IsUsingLadder())
- //{
- // NavDirType faceDir = m_pathLadder->m_dir;
- // Vector to = m_pathLadder->m_top - pev->origin;
- // float idealYaw = UTIL_VecToYaw(to);
+ const float lookAlongLadderRange = 100.0f;
+ const float ladderPitch = 60.0f;
- // if (m_pathLadderFaceIn)
- // {
- // faceDir = OppositeDirection(faceDir);
- // }
+ // adjust pitch to look up/down ladder as we ascend/descend
+ switch (m_pathLadderState)
+ {
+ case APPROACH_ASCENDING_LADDER:
+ {
+ Vector to = m_goalPosition - pev->origin;
+ useYaw = idealYaw;
- // switch (m_pathLadderState)
- // {
- // case APPROACH_ASCENDING_LADDER:
- // {
- // Vector to = m_goalPosition - pev->origin;
- // if (to.IsLengthLessThan(lookAlongLadderRange))
- // usePitch = -ladderPitch;
- // useYaw = idealYaw;
- // break;
- // }
- // case APPROACH_DESCENDING_LADDER:
- // {
- // Vector to = m_goalPosition - pev->origin;
- // if (to.IsLengthLessThan(lookAlongLadderRange))
- // usePitch = ladderPitch;
- // useYaw = idealYaw;
- // break;
- // }
- // case FACE_ASCENDING_LADDER:
- // {
- // useYaw = idealYaw;
- // usePitch = -ladderPitch;
- // break;
- // }
- // case FACE_DESCENDING_LADDER:
- // {
- // useYaw = idealYaw;
- // usePitch = ladderPitch;
- // break;
- // }
- // case MOUNT_ASCENDING_LADDER:
- // case ASCEND_LADDER:
- // {
- // useYaw = DirectionToAngle(faceDir) + StayOnLadderLine(this, m_pathLadder);
- // usePitch = -ladderPitch;
- // break;
- // }
- // case MOUNT_DESCENDING_LADDER:
- // case DESCEND_LADDER:
- // {
- // useYaw = DirectionToAngle(faceDir) + StayOnLadderLine(this, m_pathLadder);
- // usePitch = ladderPitch;
- // break;
- // }
- // case DISMOUNT_ASCENDING_LADDER:
- // case DISMOUNT_DESCENDING_LADDER:
- // {
- // useYaw = DirectionToAngle(faceDir);
- // break;
- // }
- // }
- //}
+ if (to.IsLengthLessThan(lookAlongLadderRange))
+ usePitch = -ladderPitch;
+ break;
+ }
+ case APPROACH_DESCENDING_LADDER:
+ {
+ Vector to = m_goalPosition - pev->origin;
+ useYaw = idealYaw;
- //// if almost at target angle, snap to it
- //const float onTargetTolerance = 1.0f;
- //float angleDiff = NormalizeAngle(useYaw - pev->v_angle.y);
+ if (to.IsLengthLessThan(lookAlongLadderRange))
+ usePitch = ladderPitch;
+ break;
+ }
+ case FACE_ASCENDING_LADDER:
+ {
+ useYaw = idealYaw;
+ usePitch = -ladderPitch;
+ break;
+ }
+ case FACE_DESCENDING_LADDER:
+ {
+ useYaw = idealYaw;
+ usePitch = ladderPitch;
+ break;
+ }
+ case MOUNT_ASCENDING_LADDER:
+ case ASCEND_LADDER:
+ {
+ useYaw = DirectionToAngle(faceDir) + StayOnLadderLine(this, m_pathLadder);
+ usePitch = -ladderPitch;
+ break;
+ }
+ case MOUNT_DESCENDING_LADDER:
+ case DESCEND_LADDER:
+ {
+ useYaw = DirectionToAngle(faceDir) + StayOnLadderLine(this, m_pathLadder);
+ usePitch = ladderPitch;
+ break;
+ }
+ case DISMOUNT_ASCENDING_LADDER:
+ case DISMOUNT_DESCENDING_LADDER:
+ {
+ useYaw = DirectionToAngle(faceDir);
+ break;
+ }
+ }
+ }
- //if (angleDiff < onTargetTolerance && angleDiff > -onTargetTolerance)
- //{
- // m_lookYawVel = 0;
- // pev->v_angle.y = useYaw;
- //}
- //else
- //{
- // // simple angular spring/damper
- // long double accel = (long double)(angleDiff * stiffness - m_lookYawVel * damping);
- // //float_precision accel = (float_precision)(angleDiff * stiffness - m_lookYawVel * damping);
+ // Yaw
+ float angleDiff = NormalizeAngle(useYaw - pev->v_angle.y);
- // // limit rate
- // if (accel > maxAccel)
- // accel = maxAccel;
+ // if almost at target angle, snap to it
+ const float onTargetTolerance = 1.0f;
+ if (angleDiff < onTargetTolerance && angleDiff > -onTargetTolerance)
+ {
+ m_lookYawVel = 0.0f;
+ pev->v_angle.y = useYaw;
+ }
+ else
+ {
+ // simple angular spring/damper
+ float accel = stiffness * angleDiff - damping * m_lookYawVel;
- // else if (accel < -maxAccel)
- // accel = -maxAccel;
+ // limit rate
+ if (accel > maxAccel)
+ accel = maxAccel;
- // m_lookYawVel = m_lookYawVel + (deltaT * accel);
- // pev->v_angle.y += (deltaT * m_lookYawVel);
- //}
+ else if (accel < -maxAccel)
+ accel = -maxAccel;
- //angleDiff = NormalizeAngle(usePitch - pev->v_angle.x);
+ m_lookYawVel += deltaT * accel;
+ pev->v_angle.y += deltaT * m_lookYawVel;
+ }
- //// simple angular spring/damper
- //// double the stiffness since pitch is only +/- 90 and yaw is +/- 180
- //float accel = 2.0f * stiffness * angleDiff - damping * m_lookPitchVel;
+ // Pitch
+ // Actually, this is negative pitch.
+ angleDiff = usePitch - pev->v_angle.x;
- //if (accel > maxAccel)
- // accel = maxAccel;
+ angleDiff = NormalizeAngle(angleDiff);
- //else if (accel < -maxAccel)
- // accel = -maxAccel;
+ if (false && angleDiff < onTargetTolerance && angleDiff > -onTargetTolerance)
+ {
+ m_lookPitchVel = 0.0f;
+ pev->v_angle.x = usePitch;
+ }
+ else
+ {
+ // simple angular spring/damper
+ // double the stiffness since pitch is only +/- 90 and yaw is +/- 180
+ float accel = 2.0f * stiffness * angleDiff - damping * m_lookPitchVel;
- //m_lookPitchVel += (deltaT * accel);
- //pev->v_angle.x += (deltaT * m_lookPitchVel);
+ // limit rate
+ if (accel > maxAccel)
+ accel = maxAccel;
- //// limit range - avoid gimbal lock
- //if (pev->v_angle.x < -89.0f)
- // pev->v_angle.x = -89.0f;
- //else if (pev->v_angle.x > 89.0f)
- // pev->v_angle.x = 89.0f;
+ else if (accel < -maxAccel)
+ accel = -maxAccel;
- //pev->v_angle.z = 0.0f;
+ m_lookPitchVel += deltaT * accel;
+ pev->v_angle.x += deltaT * m_lookPitchVel;
+ }
+
+ // limit range - avoid gimbal lock
+ if (pev->v_angle.x < -89.0f)
+ pev->v_angle.x = -89.0f;
+ else if (pev->v_angle.x > 89.0f)
+ pev->v_angle.x = 89.0f;
+
+ pev->v_angle.z = 0.0f;
}
+#endif // HOOK_GAMEDLL
+
+// Return true if we can see the point
/* <3d8c91> ../cstrike/dlls/bot/cs_bot_vision.cpp:238 */
-NOBODY bool CCSBot::__MAKE_VHOOK(IsVisible)(const Vector *pos, bool testFOV) const
+bool CCSBot::__MAKE_VHOOK(IsVisible)(const Vector *pos, bool testFOV) const
{
-// {
-// const Vector *eye; // 248
-// class CCSBotManager *ctrl; // 251
-// TraceResult result; // 256
-// GetEyePosition(const class CCSBot *const this); // 248
-// GetEyePosition(const class CCSBot *const this); // 252
-// }
+ // we can't see anything if we're blind
+ if (IsBlind())
+ return false;
+
+ // is it in my general viewcone?
+ if (testFOV && !(const_cast(this)->FInViewCone(pos)))
+ return false;
+
+ // check line of sight against smoke
+ if (TheCSBots()->IsLineBlockedBySmoke(&GetEyePosition(), pos))
+ return false;
+
+ // check line of sight
+ // Must include CONTENTS_MONSTER to pick up all non-brush objects like barrels
+ TraceResult result;
+ UTIL_TraceLine(GetEyePosition(), *pos, ignore_monsters, ignore_glass, ENT(pev), &result);
+
+ if (result.flFraction != 1.0f)
+ return false;
+
+ return true;
}
+// Return true if we can see any part of the player
+// Check parts in order of importance. Return the first part seen in "visParts" if it is non-NULL.
+
/* <3d8d9b> ../cstrike/dlls/bot/cs_bot_vision.cpp:269 */
-NOBODY bool CCSBot::__MAKE_VHOOK(IsVisible)(CBasePlayer *player, bool testFOV, unsigned char *visParts) const
+bool CCSBot::__MAKE_VHOOK(IsVisible)(CBasePlayer *player, bool testFOV, unsigned char *visParts) const
{
-// {
-// float const topOfHead; // 271
-// float const standFeet; // 272
-// float const crouchFeet; // 273
-// unsigned char testVisParts; // 274
-// Vector spot; // 283
-// class Vector2D dir; // 297
-// class Vector2D perp; // 299
-// float const edgeOffset; // 300
-// Vector(Vector *const this,
-// float X,
-// float Y,
-// float Z); // 283
-// NormalizeInPlace(Vector2D *const this); // 298
-// }
+ Vector spot = player->pev->origin;
+ VisiblePartType testVisParts = NONE;
+
+ // finish chest check
+ if (IsVisible(&spot, testFOV))
+ testVisParts |= CHEST;
+
+ // check top of head
+ spot = spot + Vector(0, 0, 25.0f);
+
+ if (IsVisible(&spot, testFOV))
+ testVisParts |= HEAD;
+
+ // check feet
+ const float standFeet = 34.0f;
+ const float crouchFeet = 14.0f;
+
+ if (player->pev->flags & FL_DUCKING)
+ spot.z = player->pev->origin.z - crouchFeet;
+ else
+ spot.z = player->pev->origin.z - standFeet;
+
+ // check feet
+ if (IsVisible(&spot, testFOV))
+ testVisParts |= FEET;
+
+ // check "edges"
+ const float edgeOffset = 13.0f;
+ Vector2D dir = (player->pev->origin - pev->origin).Make2D();
+ dir.NormalizeInPlace();
+
+ Vector2D perp(-dir.y, dir.x);
+
+ spot = player->pev->origin + Vector(perp.x * edgeOffset, perp.y * edgeOffset, 0);
+
+ if (IsVisible(&spot, testFOV))
+ testVisParts |= LEFT_SIDE;
+
+ spot = player->pev->origin - Vector(perp.x * edgeOffset, perp.y * edgeOffset, 0);
+
+ if (IsVisible(&spot, testFOV))
+ testVisParts |= RIGHT_SIDE;
+
+ if (visParts != NULL)
+ *visParts = testVisParts;
+
+ if (testVisParts != NONE)
+ return true;
+
+ return false;
}
/* <3d8f9f> ../cstrike/dlls/bot/cs_bot_vision.cpp:302 */
@@ -222,6 +302,8 @@ void CCSBot::UpdateLookAt(void)
SetLookAngles(idealAngle.y, idealAngle.x);
}
+// Look at the given point in space for the given duration (-1 means forever)
+
/* <3d900c> ../cstrike/dlls/bot/cs_bot_vision.cpp:345 */
void CCSBot::SetLookAt(const char *desc, const Vector *pos, PriorityType pri, float duration, bool clearIfClose, float angleTolerance)
{
@@ -255,270 +337,711 @@ void CCSBot::SetLookAt(const char *desc, const Vector *pos, PriorityType pri, fl
m_lookAtDesc = desc;
}
+// Block all "look at" and "look around" behavior for given duration - just look ahead
+
/* <3d90a7> ../cstrike/dlls/bot/cs_bot_vision.cpp:383 */
-NOBODY void CCSBot::InhibitLookAround(float duration)
+void CCSBot::InhibitLookAround(float duration)
{
+ m_inhibitLookAroundTimestamp = gpGlobals->time + duration;
}
+// Update enounter spot timestamps, etc
+
/* <3d90d3> ../cstrike/dlls/bot/cs_bot_vision.cpp:392 */
-NOBODY void CCSBot::UpdatePeripheralVision(void)
+void CCSBot::UpdatePeripheralVision(void)
{
-// {
-// float const peripheralUpdateInterval; // 394
-// {
-// const class SpotOrder *spotOrder; // 403
-// Vector pos; // 404
-// {
-// const_iterator iter; // 406
-// end(list> *const this); // 406
-// operator++(_List_const_iterator *const this); // 406
-// {
-// const Vector *spotPos;// 410
-// }
-// }
-// }
-// }
+ // if we update at 10Hz, this ensures we test once every three
+ const float peripheralUpdateInterval = 0.29f;
+ if (gpGlobals->time - m_peripheralTimestamp < peripheralUpdateInterval)
+ return;
+
+ m_peripheralTimestamp = gpGlobals->time;
+
+ if (m_spotEncounter)
+ {
+ // check LOS to all spots in case we see them with our "peripheral vision"
+ const SpotOrder *spotOrder = NULL;
+ Vector pos;
+
+ for (SpotOrderList::const_iterator iter = m_spotEncounter->spotList.begin(); iter != m_spotEncounter->spotList.end(); ++iter)
+ {
+ spotOrder = &(*iter);
+
+ const Vector *spotPos = spotOrder->spot->GetPosition();
+
+ pos.x = spotPos->x;
+ pos.y = spotPos->y;
+ pos.z = spotPos->z + HalfHumanHeight;
+
+ if (!IsVisible(&pos, CHECK_FOV))
+ continue;
+
+ // can see hiding spot, remember when we saw it last
+ SetHidingSpotCheckTimestamp(spotOrder->spot);
+ }
+ }
}
+// Update the "looking around" behavior.
+
/* <3d91af> ../cstrike/dlls/bot/cs_bot_vision.cpp:429 */
-NOBODY void CCSBot::UpdateLookAround(bool updateNow)
+void CCSBot::UpdateLookAround(bool updateNow)
{
-// {
-// float const noiseStartleRange; // 439
-// float const recentThreatTime; // 456
-// {
-// Vector spot; // 442
-// Vector(Vector *const this,
-// const Vector &v); // 442
-// InhibitLookAround(CCSBot *const this,
-// float duration); // 448
-// }
-// IsLookingAtSpot(const class CCSBot *const this,
-// enum PriorityType pri); // 457
-// {
-// Vector spot; // 461
-// Vector(Vector *const this,
-// const Vector &v); // 461
-// ClearLookAt(CCSBot *const this); // 459
-// }
-// IsNotMoving(const class CCSBot *const this); // 481
-// {
-// int which; // 521
-// Vector spot; // 522
-// IsViewMoving(const class CCSBot *const this,
-// float angleVelThreshold); // 489
-// {
-// float range; // 491
-// }
-// GetZoomLevel(const class CCSBot *const this); // 497
-// ClearLookAt(CCSBot *const this); // 517
-// Vector(Vector *const this,
-// const Vector &v); // 522
-// }
-// IsLookingAtSpot(const class CCSBot *const this,
-// enum PriorityType pri); // 541
-// {
-// float asleep; // 550
-// Vector delta; // 558
-// float length; // 559
-// float adx; // 560
-// float ady; // 561
-// float t; // 562
-// float const leadCheckRange; // 570
-// class HidingSpot *dangerSpot; // 580
-// int dangerSpotCount; // 581
-// int dangerIndex; // 582
-// float const checkTime; // 584
-// const class SpotOrder *spotOrder; // 585
-// operator-(const Vector *const this,
-// const Vector &v); // 558
-// Length(const Vector *const this); // 559
-// {
-// iterator iter; // 586
-// end(list> *const this); // 586
-// operator++(_List_iterator *const this); // 586
-// }
-// {
-// int which; // 607
-// const Vector *checkSpot; // 608
-// Vector pos; // 610
-// operator+(const Vector *const this,
-// const Vector &v); // 610
-// }
-// }
-// }
+ // check if looking around has been inhibited
+ // Moved inhibit to allow high priority enemy lookats to still occur
+ if (gpGlobals->time < m_inhibitLookAroundTimestamp)
+ return;
+
+ const float recentThreatTime = 0.25f; // 1.0f;
+
+ // Unless we can hear them moving, in which case look towards the noise
+ if (!IsEnemyVisible())
+ {
+ const float noiseStartleRange = 1000.0f;
+ if (CanHearNearbyEnemyGunfire(noiseStartleRange))
+ {
+ Vector spot = m_noisePosition;
+ spot.z += HalfHumanHeight;
+
+ SetLookAt("Check dangerous noise", &spot, PRIORITY_HIGH, recentThreatTime);
+ InhibitLookAround(RANDOM_FLOAT(2.0f, 4.0f));
+
+ return;
+ }
+ }
+
+ // If we recently saw an enemy, look towards where we last saw them
+ if (!IsLookingAtSpot(PRIORITY_MEDIUM) && gpGlobals->time - m_lastSawEnemyTimestamp < recentThreatTime)
+ {
+ ClearLookAt();
+
+ Vector spot = m_lastEnemyPosition;
+
+ // find enemy position on the ground
+ if (GetSimpleGroundHeight(&m_lastEnemyPosition, &spot.z))
+ {
+ spot.z += HalfHumanHeight;
+ SetLookAt("Last Enemy Position", &spot, PRIORITY_MEDIUM, RANDOM_FLOAT(2.0f, 3.0f), true);
+ return;
+ }
+ }
+
+ // Look at nearby enemy noises
+ if (UpdateLookAtNoise())
+ return;
+
+ if (IsNotMoving())
+ {
+ // if we're sniping, zoom in to watch our approach points
+ if (IsUsingSniperRifle())
+ {
+ // low skill bots don't pre-zoom
+ if (GetProfile()->GetSkill() > 0.4f)
+ {
+ if (!IsViewMoving())
+ {
+ float range = ComputeWeaponSightRange();
+ AdjustZoom(range);
+ }
+ else
+ {
+ // zoom out
+ if (GetZoomLevel() != NO_ZOOM)
+ SecondaryAttack();
+ }
+ }
+ }
+
+ if (m_lastKnownArea == NULL)
+ return;
+
+ if (gpGlobals->time < m_lookAroundStateTimestamp)
+ return;
+
+ // if we're sniping, switch look-at spots less often
+ if (IsUsingSniperRifle())
+ m_lookAroundStateTimestamp = gpGlobals->time + RANDOM_FLOAT(5.0f, 10.0f);
+ else
+ m_lookAroundStateTimestamp = gpGlobals->time + RANDOM_FLOAT(1.0f, 2.0f);
+
+ if (m_approachPointCount == 0)
+ {
+ ClearLookAt();
+ return;
+ }
+
+ int which = RANDOM_LONG(0, m_approachPointCount - 1);
+ Vector spot = m_approachPoint[ which ];
+
+ // don't look at the floor, look roughly at chest level
+ // TODO: If this approach point is very near, this will cause us to aim up in the air if were crouching
+ spot.z += HalfHumanHeight;
+
+ SetLookAt("Approach Point (Hiding)", &spot, PRIORITY_LOW);
+
+ return;
+ }
+
+ // Glance at "encouter spots" as we move past them
+ if (m_spotEncounter)
+ {
+ // Check encounter spots
+ if (!IsSafe() && !IsLookingAtSpot(PRIORITY_LOW))
+ {
+ // allow a short time to look where we're going
+ if (gpGlobals->time < m_spotCheckTimestamp)
+ return;
+
+ // TODO: Use skill parameter instead of accuracy
+
+ // lower skills have exponentially longer delays
+ float_precision asleep = (1.0f - GetProfile()->GetSkill());
+ asleep *= asleep;
+ asleep *= asleep;
+
+ m_spotCheckTimestamp = gpGlobals->time + asleep * RANDOM_FLOAT(10.0f, 30.0f);
+
+ // figure out how far along the path segment we are
+ Vector delta = m_spotEncounter->path.to - m_spotEncounter->path.from;
+ float_precision length = delta.Length();
+ float adx = (float)abs(int64(delta.x));
+ float ady = (float)abs(int64(delta.y));
+ float_precision t;
+
+ if (adx > ady)
+ t = (pev->origin.x - m_spotEncounter->path.from.x) / delta.x;
+ else
+ t = (pev->origin.y - m_spotEncounter->path.from.y) / delta.y;
+
+ // advance parameter a bit so we "lead" our checks
+ const float leadCheckRange = 50.0f;
+ t += leadCheckRange / length;
+
+ if (t < 0.0f)
+ t = 0.0f;
+ else if (t > 1.0f)
+ t = 1.0f;
+
+ // collect the unchecked spots so far
+ #define MAX_DANGER_SPOTS 8
+ HidingSpot *dangerSpot[MAX_DANGER_SPOTS];
+ int dangerSpotCount = 0;
+ int dangerIndex = 0;
+
+ const float checkTime = 10.0f;
+ const SpotOrder *spotOrder;
+
+ for (SpotOrderList::iterator iter = m_spotEncounter->spotList.begin(); iter != m_spotEncounter->spotList.end(); ++iter)
+ {
+ spotOrder = &(*iter);
+
+ // if we have seen this spot recently, we don't need to look at it
+ if (gpGlobals->time - GetHidingSpotCheckTimestamp(spotOrder->spot) <= checkTime)
+ continue;
+
+ if (spotOrder->t > t)
+ break;
+
+ dangerSpot[ dangerIndex++ ] = spotOrder->spot;
+ if (dangerIndex >= MAX_DANGER_SPOTS)
+ dangerIndex = 0;
+ if (dangerSpotCount < MAX_DANGER_SPOTS)
+ ++dangerSpotCount;
+ }
+
+ if (dangerSpotCount)
+ {
+ // pick one of the spots at random
+ int which = RANDOM_LONG(0, dangerSpotCount - 1);
+
+ const Vector *checkSpot = dangerSpot[ which ]->GetPosition();
+
+ Vector pos = *checkSpot;
+ pos.z += HalfHumanHeight;
+
+ // glance at the spot for minimum time
+ SetLookAt("Encounter Spot", &pos, PRIORITY_LOW, 0, true, 10.0f);
+
+ // immediately mark it as "checked", so we don't check it again
+ // if we get distracted before we check it - that's the way it goes
+ SetHidingSpotCheckTimestamp(dangerSpot[which]);
+ }
+ }
+ }
}
+// "Bend" our line of sight around corners until we can "see" the point.
+
/* <3d9618> ../cstrike/dlls/bot/cs_bot_vision.cpp:628 */
-NOBODY bool CCSBot::BendLineOfSight(Vector *eye, const Vector *point, Vector *bend)
+bool CCSBot::BendLineOfSight(const Vector *eye, const Vector *point, Vector *bend) const
{
-// {
-// TraceResult result; // 631
-// Vector v; // 641
-// float startAngle; // 642
-// float length; // 643
-// float const angleInc; // 645
-// operator+(const Vector *const this,
-// const Vector &v); // 632
-// Length2D(const Vector *const this); // 643
-// operator-(const Vector *const this,
-// const Vector &v); // 641
-// {
-// float angle; // 646
-// {
-// int side; // 649
-// {
-// float actualAngle; // 651
-// float dx; // 653
-// float dy; // 654
-// Vector rotPoint; // 657
-// TraceResult result; // 660
-// Vector ray; // 667
-// float rayLength; // 668
-// float visibleLength; // 669
-// float const bendStepSize; // 672
-// operator+(const Vector *const this,
-// const Vector &v); // 661
-// operator-(const Vector *const this,
-// const Vector &v); // 667
-// NormalizeInPlace(Vector *const this); // 668
-// {
-// float bendLength; // 673
-// {
-// Vector rayPoint; // 676
-// Vector(Vector *const this,
-// float X,
-// float Y,
-// float Z); // 676
-// operator+(const Vector *const this,
-// const Vector &v); // 679
-// }
-// }
-// }
-// }
-// }
-// }
+ // if we can directly see the point, use it
+ TraceResult result;
+ UTIL_TraceLine(*eye, *point + Vector(0, 0, HalfHumanHeight), ignore_monsters, ENT(pev), &result);
+
+ if (result.flFraction == 1.0f && !result.fStartSolid)
+ {
+ // can directly see point, no bending needed
+ *bend = *point;
+ return true;
+ }
+
+ // "bend" our line of sight until we can see the approach point
+ Vector v = *point - *eye;
+ float startAngle = UTIL_VecToYaw(v);
+ float length = v.Length2D();
+ v.NormalizeInPlace();
+
+ float angleInc = 10.0f;
+ for (float angle = angleInc; angle <= 135.0f; angle += angleInc)
+ {
+ // check both sides at this angle offset
+ for (int side = 0; side < 2; ++side)
+ {
+ float actualAngle = (side) ? (startAngle + angle) : (startAngle - angle);
+
+ float dx = BotCOS(actualAngle);
+ float dy = BotSIN(actualAngle);
+
+ // compute rotated point ray endpoint
+ Vector rotPoint(eye->x + length * dx, eye->y + length * dy, point->z);
+
+ TraceResult result;
+ UTIL_TraceLine(*eye, rotPoint + Vector(0, 0, HalfHumanHeight), ignore_monsters, ENT(pev), &result);
+
+ // if this ray started in an obstacle, skip it
+ if (result.fStartSolid)
+ {
+ continue;
+ }
+
+ Vector ray = rotPoint - *eye;
+ float rayLength = ray.NormalizeInPlace();
+ float visibleLength = rayLength * result.flFraction;
+
+ // step along ray, checking if point is visible from ray point
+ const float bendStepSize = 50.0f;
+ for (float bendLength = bendStepSize; bendLength <= visibleLength; bendLength += bendStepSize)
+ {
+ // compute point along ray
+ Vector rayPoint = *eye + bendLength * ray;
+
+ // check if we can see approach point from this bend point
+ UTIL_TraceLine(rayPoint, *point + Vector(0, 0, HalfHumanHeight), ignore_monsters, ENT(pev), &result);
+
+ if (result.flFraction == 1.0f && !result.fStartSolid)
+ {
+ // target is visible from this bend point on the ray - use this point on the ray as our point
+
+ // keep "bent" point at correct height along line of sight
+ if (!GetGroundHeight(&rayPoint, &rayPoint.z))
+ {
+ rayPoint.z = point->z;
+ }
+
+ *bend = rayPoint;
+ return true;
+ }
+ }
+ }
+ }
+
+ *bend = *point;
+
+ // bending rays didn't help - still can't see the point
+ return false;
}
/* <3d99e8> ../cstrike/dlls/bot/cs_bot_vision.cpp:707 */
-NOBODY CBasePlayer *CCSBot::FindMostDangerousThreat(void)
+CBasePlayer *CCSBot::FindMostDangerousThreat(void)
{
-// {
-// class CloseInfo threat; // 715
-// int threatCount; // 716
-// float closeFriendRange; // 721
-// float closeHumanFriendRange; // 724
-// int i; // 726
-// int prevEnemies; // 835
-// int prevFriends; // 836
-// class PlaceRank placeRank; // 869
-// int locCount; // 870
-// class PlaceRank common; // 872
-// {
-// class CBaseEntity *entity; // 729
-// class CBasePlayer *player; // 744
-// int idx; // 792
-// Vector d; // 801
-// float distSq; // 802
-// FNullEnt(entvars_t *pev); // 734
-// {
-// int j; // 814
-// {
-// int k; // 822
-// }
-// }
-// entindex(CBaseEntity *const this); // 747
-// entindex(CBaseEntity *const this); // 747
-// {
-// TraceResult result; // 758
-// GetEyePosition(const class CCSBot *const this); // 759
-// {
-// int idx; // 763
-// Vector to; // 768
-// float rangeSq; // 769
-// entindex(CBaseEntity *const this); // 763
-// operator-(const Vector *const this,
-// const Vector &v); // 768
-// LengthSquared(const Vector *const this); // 769
-// }
-// }
-// entindex(CBaseEntity *const this); // 792
-// operator-(const Vector *const this,
-// const Vector &v); // 801
-// LengthSquared(const Vector *const this); // 802
-// }
-// {
-// float const recentTime; // 844
-// }
-// {
-// class CNavArea *area; // 879
-// unsigned int threatLoc; // 888
-// int j; // 893
-// }
-// {
-// int t; // 948
-// IsProtectedByShield(CBasePlayer *const this); // 949
-// }
-// }
+ // maximum number of simulataneously attendable threats
+ enum { MAX_THREATS = 16 };
+ struct CloseInfo
+ {
+ CBasePlayer *enemy;
+ float range;
+ }
+ threat[ MAX_THREATS ];
+ int threatCount = 0;
+
+ m_bomber = NULL;
+
+ m_closestVisibleFriend = NULL;
+ float closeFriendRange = 99999999999.9f;
+
+ m_closestVisibleHumanFriend = NULL;
+ float closeHumanFriendRange = 99999999999.9f;
+
+ int i;
+
+ {
+ for (i = 1; i <= gpGlobals->maxClients; ++i)
+ {
+ CBaseEntity *entity = UTIL_PlayerByIndex(i);
+
+ if (entity == NULL)
+ continue;
+
+ if (FNullEnt(entity->pev))
+ continue;
+
+ // is it a player?
+ if (!entity->IsPlayer())
+ continue;
+
+ CBasePlayer *player = static_cast(entity);
+
+ // ignore self
+ if (player->entindex() == entindex())
+ continue;
+
+ // is it alive?
+ if (!player->IsAlive())
+ continue;
+
+ // is it an enemy?
+ if (player->m_iTeam == m_iTeam)
+ {
+ TraceResult result;
+ UTIL_TraceLine(GetEyePosition(), player->pev->origin, ignore_monsters, ignore_glass, edict(), &result);
+ if (result.flFraction == 1.0f)
+ {
+ // update watch timestamp
+ int idx = player->entindex() - 1;
+ m_watchInfo[idx].timestamp = gpGlobals->time;
+ m_watchInfo[idx].isEnemy = false;
+
+ // keep track of our closest friend
+ Vector to = pev->origin - player->pev->origin;
+ float rangeSq = to.LengthSquared();
+ if (rangeSq < closeFriendRange)
+ {
+ m_closestVisibleFriend = player;
+ closeFriendRange = rangeSq;
+ }
+
+ // keep track of our closest human friend
+ if (!player->IsBot() && rangeSq < closeHumanFriendRange)
+ {
+ m_closestVisibleHumanFriend = player;
+ closeHumanFriendRange = rangeSq;
+ }
+ }
+
+ continue;
+ }
+
+ // check if this enemy is fully
+ if (!IsVisible(player, CHECK_FOV))
+ continue;
+
+ // update watch timestamp
+ int idx = player->entindex() - 1;
+ m_watchInfo[idx].timestamp = gpGlobals->time;
+ m_watchInfo[idx].isEnemy = true;
+
+ // note if we see the bomber
+ if (player->IsBombGuy())
+ {
+ m_bomber = player;
+ }
+
+ // keep track of all visible threats
+ Vector d = pev->origin - player->pev->origin;
+ float distSq = d.LengthSquared();
+
+ // maintain set of visible threats, sorted by increasing distance
+ if (threatCount == 0)
+ {
+ threat[0].enemy = player;
+ threat[0].range = distSq;
+ threatCount = 1;
+ }
+ else
+ {
+ // find insertion point
+ int j;
+ for (j = 0; j < threatCount; ++j)
+ {
+ if (distSq < threat[j].range)
+ break;
+ }
+
+
+ // shift lower half down a notch
+ for (int k = threatCount - 1; k >= j; --k)
+ threat[k + 1] = threat[k];
+
+ // insert threat into sorted list
+ threat[j].enemy = player;
+ threat[j].range = distSq;
+
+ if (threatCount < MAX_THREATS)
+ ++threatCount;
+ }
+ }
+ }
+ {
+ // track the maximum enemy and friend counts we've seen recently
+ int prevEnemies = m_nearbyEnemyCount;
+ int prevFriends = m_nearbyFriendCount;
+ m_nearbyEnemyCount = 0;
+ m_nearbyFriendCount = 0;
+
+ for (i = 0; i < MAX_CLIENTS; ++i)
+ {
+ if (m_watchInfo[i].timestamp <= 0.0f)
+ continue;
+
+ const float recentTime = 3.0f;
+ if (gpGlobals->time - m_watchInfo[i].timestamp < recentTime)
+ {
+ if (m_watchInfo[i].isEnemy)
+ ++m_nearbyEnemyCount;
+ else
+ ++m_nearbyFriendCount;
+ }
+ }
+
+ // note when we saw this batch of enemies
+ if (prevEnemies == 0 && m_nearbyEnemyCount > 0)
+ {
+ m_firstSawEnemyTimestamp = gpGlobals->time;
+ }
+
+ if (prevEnemies != m_nearbyEnemyCount || prevFriends != m_nearbyFriendCount)
+ {
+ PrintIfWatched("Nearby friends = %d, enemies = %d\n", m_nearbyFriendCount, m_nearbyEnemyCount);
+ }
+ }
+ {
+ // Track the place where we saw most of our enemies
+ struct PlaceRank
+ {
+ unsigned int place;
+ int count;
+ };
+ static PlaceRank placeRank[ MAX_PLACES_PER_MAP ];
+ int locCount = 0;
+
+ PlaceRank common;
+ common.place = 0;
+ common.count = 0;
+
+ for (i = 0; i < threatCount; ++i)
+ {
+ // find the area the player/bot is standing on
+ CNavArea *area;
+ CCSBot *bot = dynamic_cast(threat[i].enemy);
+ if (bot != NULL && bot->IsBot())
+ {
+ area = bot->GetLastKnownArea();
+ }
+ else
+ {
+ area = TheNavAreaGrid.GetNearestNavArea(&threat[i].enemy->pev->origin);
+ }
+
+ if (area == NULL)
+ continue;
+
+ unsigned int threatLoc = area->GetPlace();
+ if (!threatLoc)
+ continue;
+
+ // if place is already in set, increment count
+ int j;
+ for (j = 0; j < locCount; ++j)
+ {
+ if (placeRank[j].place == threatLoc)
+ break;
+ }
+
+ if (j == locCount)
+ {
+ // new place
+ if (locCount < MAX_PLACES_PER_MAP)
+ {
+ placeRank[ locCount ].place = threatLoc;
+ placeRank[ locCount ].count = 1;
+
+ if (common.count == 0)
+ common = placeRank[locCount];
+
+ ++locCount;
+ }
+ }
+ else
+ {
+ // others are in that place, increment
+ ++placeRank[j].count;
+
+ // keep track of the most common place
+ if (placeRank[j].count > common.count)
+ common = placeRank[j];
+ }
+ }
+
+ // remember most common place
+ m_enemyPlace = common.place;
+ }
+
+ {
+ if (threatCount == 0)
+ return NULL;
+
+ // otherwise, find the closest threat that without using shield
+ int t;
+ for (t = 0; t < threatCount; ++t)
+ {
+ if (!threat[t].enemy->IsProtectedByShield())
+ {
+ return threat[t].enemy;
+ }
+ }
+ }
+
+ // return closest threat
+ return threat[0].enemy;
}
+// Update our reaction time queue
+
/* <3d9f7d> ../cstrike/dlls/bot/cs_bot_vision.cpp:960 */
-NOBODY void CCSBot::UpdateReactionQueue(void)
+void CCSBot::UpdateReactionQueue(void)
{
-// {
-// class CBasePlayer *threat; // 967
-// int now; // 969
-// float reactionTime; // 994
-// float maxReactionTime; // 995
-// int reactionTimeSteps; // 1000
-// int i; // 1002
-// IsReloading(CBasePlayer *const this); // 975
-// IsProtectedByShield(CBasePlayer *const this); // 976
-// }
+ // zombies dont see any threats
+ if (cv_bot_zombie.value > 0.0f)
+ return;
+
+ // find biggest threat at this instant
+ CBasePlayer *threat = FindMostDangerousThreat();
+
+ int now = m_enemyQueueIndex;
+
+ // store a snapshot of its state at the end of the reaction time queue
+ if (threat != NULL)
+ {
+ m_enemyQueue[ now ].player = threat;
+ m_enemyQueue[ now ].isReloading = threat->IsReloading();
+ m_enemyQueue[ now ].isProtectedByShield = threat->IsProtectedByShield();
+ }
+ else
+ {
+ m_enemyQueue[ now ].player = NULL;
+ m_enemyQueue[ now ].isReloading = false;
+ m_enemyQueue[ now ].isProtectedByShield = false;
+ }
+
+ // queue is round-robin
+ ++m_enemyQueueIndex;
+ if (m_enemyQueueIndex >= MAX_ENEMY_QUEUE)
+ m_enemyQueueIndex = 0;
+
+ if (m_enemyQueueCount < MAX_ENEMY_QUEUE)
+ ++m_enemyQueueCount;
+
+ // clamp reaction time to enemy queue size
+ float reactionTime = GetProfile()->GetReactionTime();
+ float maxReactionTime = (MAX_ENEMY_QUEUE * g_flBotFullThinkInterval) - 0.01f;
+ if (reactionTime > maxReactionTime)
+ reactionTime = maxReactionTime;
+
+ // "rewind" time back to our reaction time
+ int reactionTimeSteps = (int)((reactionTime / g_flBotFullThinkInterval) + 0.5f);
+
+ int i = now - reactionTimeSteps;
+ if (i < 0)
+ i += MAX_ENEMY_QUEUE;
+
+ m_enemyQueueAttendIndex = (byte)i;
}
+// Return the most dangerous threat we are "conscious" of
+
/* <3da052> ../cstrike/dlls/bot/cs_bot_vision.cpp:1013 */
CBasePlayer *CCSBot::GetRecognizedEnemy(void)
{
if (m_enemyQueueAttendIndex >= m_enemyQueueCount)
return NULL;
- return (CBasePlayer *)((CBaseEntity *)m_enemyQueue[ m_enemyQueueAttendIndex ].player);
+ return (CBasePlayer *)m_enemyQueue[ m_enemyQueueAttendIndex ].player;
}
+// Return true if the enemy we are "conscious" of is reloading
+
/* <3da075> ../cstrike/dlls/bot/cs_bot_vision.cpp:1025 */
-NOBODY bool CCSBot::IsRecognizedEnemyReloading(void)
+bool CCSBot::IsRecognizedEnemyReloading(void)
{
+ if (m_enemyQueueAttendIndex >= m_enemyQueueCount)
+ return false;
+
+ return m_enemyQueue[ m_enemyQueueAttendIndex ].isReloading;
}
+// Return true if the enemy we are "conscious" of is hiding behind a shield
+
/* <3da09d> ../cstrike/dlls/bot/cs_bot_vision.cpp:1037 */
-NOBODY bool CCSBot::IsRecognizedEnemyProtectedByShield(void)
+bool CCSBot::IsRecognizedEnemyProtectedByShield(void)
{
+ if (m_enemyQueueAttendIndex >= m_enemyQueueCount)
+ return false;
+
+ return m_enemyQueue[ m_enemyQueueAttendIndex ].isProtectedByShield;
}
+// Return distance to closest enemy we are "conscious" of
+
/* <3da0c5> ../cstrike/dlls/bot/cs_bot_vision.cpp:1049 */
-NOBODY float CCSBot::GetRangeToNearestRecognizedEnemy(void)
+float CCSBot::GetRangeToNearestRecognizedEnemy(void)
{
-// {
-// const class CBasePlayer *enemy; // 1051
-// GetRecognizedEnemy(CCSBot *const this); // 1051
-// operator-(const Vector *const this,
-// const Vector &v); // 1054
-// Length(const Vector *const this); // 1054
-// }
+ const CBasePlayer *enemy = GetRecognizedEnemy();
+
+ if (enemy != NULL)
+ {
+ return (pev->origin - enemy->pev->origin).Length();
+ }
+
+ return 99999999.9f;
}
+// Blind the bot for the given duration
+
/* <3da170> ../cstrike/dlls/bot/cs_bot_vision.cpp:1063 */
-NOBODY void CCSBot::__MAKE_VHOOK(Blind)(float duration, float holdTime, float fadeTime, int alpha)
+void CCSBot::__MAKE_VHOOK(Blind)(float duration, float holdTime, float fadeTime, int alpha)
{
-// Say(BotChatterInterface *const this,
-// const char *phraseName,
-// float lifetime,
-// float delay); // 1091
+ // extend
+ CBasePlayer::Blind(duration, holdTime, fadeTime, alpha);
+
+ PrintIfWatched("I'm blind!\n");
+
+ if (RANDOM_FLOAT(0.0f, 100.0f) < 33.3f)
+ {
+ GetChatter()->Say("Blinded", 1.0f);
+ }
+
+ // decide which way to move while blind
+ m_blindMoveDir = static_cast(RANDOM_LONG(1, NUM_RELATIVE_DIRECTIONS - 1));
+
+ // if blinded while in combat - then spray and pray!
+ m_blindFire = (RANDOM_FLOAT(0.0f, 100.0f) < 10.0f) != 0;
+
+ // no longer safe
+ AdjustSafeTime();
}
#ifdef HOOK_GAMEDLL
+void (*pCCSBot__UpdateLookAngles)(void);
+void __declspec(naked) CCSBot::UpdateLookAngles(void)
+{
+ __asm
+ {
+ jmp pCCSBot__UpdateLookAngles
+ }
+}
+
void CCSBot::Blind(float duration, float holdTime, float fadeTime, int alpha)
{
Blind_(duration, holdTime, fadeTime, alpha);
@@ -528,6 +1051,7 @@ bool CCSBot::IsVisible(const Vector *pos, bool testFOV) const
{
return IsVisible_(pos, testFOV);
}
+
bool CCSBot::IsVisible(CBasePlayer *player, bool testFOV, unsigned char *visParts) const
{
return IsVisible_(player, testFOV, visParts);
diff --git a/regamedll/dlls/bot/cs_bot_weapon.cpp b/regamedll/dlls/bot/cs_bot_weapon.cpp
index 4f0d0e85..0e37e0ba 100644
--- a/regamedll/dlls/bot/cs_bot_weapon.cpp
+++ b/regamedll/dlls/bot/cs_bot_weapon.cpp
@@ -1,60 +1,156 @@
#include "precompiled.h"
+// Fire our active weapon towards our current enemy
+// NOTE: Aiming our weapon is handled in RunBotUpkeep()
+
/* <3eb434> ../cstrike/dlls/bot/cs_bot_weapon.cpp:17 */
-NOBODY void CCSBot::FireWeaponAtEnemy(void)
+void CCSBot::FireWeaponAtEnemy(void)
{
-// {
-// class CBasePlayer *enemy; // 20
-// IsUsingSniperRifle(const class CCSBot *const this); // 29
-// {
-// class Vector2D toAimSpot; // 47
-// float rangeToEnemy; // 48
-// float yaw; // 50
-// class Vector2D dir; // 51
-// float onTarget; // 53
-// float const halfSize; // 57
-// float const halfPI; // 60
-// float aimTolerance; // 61
-// {
-// class CCSBotManager *ctrl; // 65
-// bool doAttack; // 67
-// IsUsingKnife(const class CCSBot *const this); // 86
-// {
-// float const knifeRange; // 121
-// ForceRun(CCSBot *const this,
-// float duration); // 125
-// {
-// float const knifeStabChance; // 142
-// }
-// }
-// IsUsingPistol(const class CCSBot *const this); // 157
-// {
-// float const closePistolRange; // 160
-// StartRapidFire(CCSBot *const this); // 165
-// }
-// {
-// float const sprayRange; // 175
-// IsUsingMachinegun(const class CCSBot *const this); // 176
-// {
-// float const distantTargetRange; // 183
-// IsUsingSniperRifle(const class CCSBot *const this); // 184
-// }
-// }
-// }
-// NormalizeInPlace(Vector2D *const this); // 48
-// DotProduct(const class Vector2D &a,
-// const class Vector2D &b); // 53
-// IsUsingSniperRifle(const class CCSBot *const this); // 57
-// }
-// IsActiveWeaponReloading(const class CBot *const this); // 40
-// GetTimeSinceAcquiredCurrentEnemy(const class CCSBot *const this); // 33
-// GetSurpriseDelay(const class CCSBot *const this); // 34
-// ClearSurpriseDelay(CCSBot *const this); // 37
-// IsNotMoving(const class CCSBot *const this); // 29
-// StopRapidFire(CCSBot *const this); // 24
-// }
+ CBasePlayer *enemy = GetEnemy();
+ if (enemy == NULL)
+ {
+ StopRapidFire();
+ return;
+ }
+
+ if (IsUsingSniperRifle())
+ {
+ // if we're using a sniper rifle, don't fire until we are standing still, are zoomed in, and not rapidly moving our view
+ if (!IsNotMoving())
+ {
+ return;
+ }
+ }
+
+ if (gpGlobals->time > m_fireWeaponTimestamp && GetTimeSinceAcquiredCurrentEnemy() >= GetProfile()->GetAttackDelay() && GetTimeSinceAcquiredCurrentEnemy() >= GetSurpriseDelay())
+ {
+ ClearSurpriseDelay();
+
+ if (!(IsRecognizedEnemyProtectedByShield() && IsPlayerFacingMe(enemy)) // dont shoot at enemies behind shields
+ && !IsActiveWeaponReloading()
+ && !IsActiveWeaponClipEmpty()
+ && IsEnemyVisible())
+ {
+ // we have a clear shot - pull trigger if we are aiming at enemy
+ Vector2D toAimSpot = (m_aimSpot - pev->origin).Make2D();
+ float rangeToEnemy = toAimSpot.NormalizeInPlace();
+
+ const float_precision halfPI = (M_PI / 180.0f);
+ float_precision yaw = pev->v_angle[ YAW ] * halfPI;
+
+ Vector2D dir(cos(yaw), sin(yaw));
+ float_precision onTarget = DotProduct(toAimSpot, dir);
+
+ // aim more precisely with a sniper rifle
+ // because rifles' bullets spray, dont have to be very precise
+ const float_precision halfSize = (IsUsingSniperRifle()) ? HalfHumanWidth : 2.0f * HalfHumanWidth;
+
+ // aiming tolerance depends on how close the target is - closer targets subtend larger angles
+ float_precision aimTolerance = cos(atan(halfSize / rangeToEnemy));
+
+ if (onTarget > aimTolerance)
+ {
+ bool doAttack;
+
+ // if friendly fire is on, don't fire if a teammate is blocking our line of fire
+ if (TheCSBots()->AllowFriendlyFireDamage())
+ {
+ if (IsFriendInLineOfFire())
+ doAttack = false;
+ else
+ doAttack = true;
+ }
+ else
+ {
+ // fire freely
+ doAttack = true;
+ }
+
+ if (doAttack)
+ {
+ // if we are using a knife, only swing it if we're close
+ if (IsUsingKnife())
+ {
+ const float knifeRange = 75.0f; // 50.0f
+ if (rangeToEnemy < knifeRange)
+ {
+ // since we've given ourselves away - run!
+ ForceRun(5.0f);
+
+ // if our prey is facing away, backstab him!
+ if (!IsPlayerFacingMe(enemy))
+ {
+ SecondaryAttack();
+ }
+ else
+ {
+ // randomly choose primary and secondary attacks with knife
+ const float knifeStabChance = 33.3f;
+ if (RANDOM_FLOAT(0, 100) < knifeStabChance)
+ SecondaryAttack();
+ else
+ PrimaryAttack();
+ }
+ }
+ }
+ else
+ {
+ PrimaryAttack();
+ }
+ }
+
+ if (IsUsingPistol())
+ {
+ // high-skill bots fire their pistols quickly at close range
+ const float closePistolRange = 999999.9f;
+ if (GetProfile()->GetSkill() > 0.75f && rangeToEnemy < closePistolRange)
+ {
+ StartRapidFire();
+
+ // fire as fast as possible
+ m_fireWeaponTimestamp = 0.0f;
+ }
+ else
+ {
+ // fire somewhat quickly
+ m_fireWeaponTimestamp = RANDOM_FLOAT(0.15f, 0.4f);
+ }
+ }
+ // not using a pistol
+ else
+ {
+ const float sprayRange = 400.0f;
+ if (GetProfile()->GetSkill() < 0.5f || rangeToEnemy < sprayRange || IsUsingMachinegun())
+ {
+ // spray 'n pray if enemy is close, or we're not that good, or we're using the big machinegun
+ m_fireWeaponTimestamp = 0.0f;
+ }
+ else
+ {
+ const float distantTargetRange = 800.0f;
+ if (!IsUsingSniperRifle() && rangeToEnemy > distantTargetRange)
+ {
+ // if very far away, fire slowly for better accuracy
+ m_fireWeaponTimestamp = RANDOM_FLOAT(0.3f, 0.7f);
+ }
+ else
+ {
+ // fire short bursts for accuracy
+ m_fireWeaponTimestamp = RANDOM_FLOAT(0.15f, 0.5f); // 0.15f, 0.25f
+ }
+ }
+ }
+
+ // subtract system latency
+ m_fireWeaponTimestamp -= g_flBotFullThinkInterval;
+ m_fireWeaponTimestamp += gpGlobals->time;
+ }
+ }
+ }
}
+// Set the current aim offset using given accuracy (1.0 = perfect aim, 0.0f = terrible aim)
+
/* <3ea12d> ../cstrike/dlls/bot/cs_bot_weapon.cpp:210 */
void CCSBot::SetAimOffset(float accuracy)
{
@@ -96,6 +192,8 @@ void CCSBot::SetAimOffset(float accuracy)
m_aimOffsetTimestamp = gpGlobals->time + RANDOM_FLOAT(0.25, 1);
}
+// Wiggle aim error based on GetProfile()->GetSkill()
+
/* <3ea224> ../cstrike/dlls/bot/cs_bot_weapon.cpp:252 */
void CCSBot::UpdateAimOffset(void)
{
@@ -113,19 +211,65 @@ void CCSBot::UpdateAimOffset(void)
m_aimOffset.z += stiffness * d.z;
}
+// Change our zoom level to be appropriate for the given range.
+// Return true if the zoom level changed.
+
/* <3ea2b7> ../cstrike/dlls/bot/cs_bot_weapon.cpp:271 */
-NOBODY bool CCSBot::AdjustZoom(float range)
+bool CCSBot::AdjustZoom(float range)
{
-// IsUsingSniperRifle(const class CCSBot *const this); // 273
-// {
-// float const sniperZoomRange; // 275
-// float const sniperFarZoomRange; // 276
-// GetZoomLevel(const class CCSBot *const this); // 282
-// GetZoomLevel(const class CCSBot *const this); // 291
-// GetZoomLevel(const class CCSBot *const this); // 300
-// }
+ bool adjustZoom = false;
+
+ if (IsUsingSniperRifle())
+ {
+ // NOTE: This must be less than sniperMinRange in AttackState
+ const float sniperZoomRange = 300.0f; //150.0f
+ const float sniperFarZoomRange = 1500.0f;
+
+ // if range is too close, don't zoom
+ if (range <= sniperZoomRange)
+ {
+ // zoom out
+ if (GetZoomLevel() != NO_ZOOM)
+ {
+ adjustZoom = true;
+ }
+ }
+ else if (range < sniperFarZoomRange)
+ {
+ // maintain low zoom
+ if (GetZoomLevel() != LOW_ZOOM)
+ {
+ adjustZoom = true;
+ }
+ }
+ else
+ {
+ // maintain high zoom
+ if (GetZoomLevel() != HIGH_ZOOM)
+ {
+ adjustZoom = true;
+ }
+ }
+ }
+ else
+ {
+ // zoom out
+ if (GetZoomLevel() != NO_ZOOM)
+ {
+ adjustZoom = true;
+ }
+ }
+
+ if (adjustZoom)
+ {
+ SecondaryAttack();
+ }
+
+ return adjustZoom;
}
+// Return true if the given weapon is a sniper rifle
+
/* <3e9e2d> ../cstrike/dlls/bot/cs_bot_weapon.cpp:320 */
bool isSniperRifle(CBasePlayerItem *item)
{
@@ -135,45 +279,72 @@ bool isSniperRifle(CBasePlayerItem *item)
case WEAPON_SG550:
case WEAPON_AWP:
case WEAPON_G3SG1:
- break;
+ return true;
+
default:
return false;
}
-
- return true;
}
/* <3ea3ab> ../cstrike/dlls/bot/cs_bot_weapon.cpp:342 */
-bool CCSBot::IsUsingAWP(void)
+bool CCSBot::IsUsingAWP(void) const
{
- return (m_pActiveItem && m_pActiveItem->m_iId == WEAPON_AWP);
-}
+ CBasePlayerWeapon *weapon = GetActiveWeapon();
-/* <3ea3ce> ../cstrike/dlls/bot/cs_bot_weapon.cpp:357 */
-NOBODY bool CCSBot::DoesActiveWeaponHaveSilencer(void)
-{
-}
+ if (weapon != NULL && weapon->m_iId == WEAPON_AWP)
+ return true;
-/* <3ea3f1> ../cstrike/dlls/bot/cs_bot_weapon.cpp:375 */
-bool CCSBot::IsUsingSniperRifle(void)
-{
- if (m_pActiveItem)
- {
- return isSniperRifle(m_pActiveItem);
- }
return false;
}
-/* <3ea462> ../cstrike/dlls/bot/cs_bot_weapon.cpp:387 */
-NOBODY bool CCSBot::IsSniper(void)
+// Returns true if we are using a weapon with a removable silencer
+
+/* <3ea3ce> ../cstrike/dlls/bot/cs_bot_weapon.cpp:357 */
+bool CCSBot::DoesActiveWeaponHaveSilencer(void) const
{
-// {
-// int i; // 389
-// {
-// class CBasePlayerItem *item; // 391
-// isSniperRifle(CBasePlayerItem *item); // 393
-// }
-// }
+ CBasePlayerWeapon *weapon = GetActiveWeapon();
+
+ if (weapon == NULL)
+ return false;
+
+ if (weapon->m_iId == WEAPON_M4A1 || weapon->m_iId == WEAPON_USP)
+ return true;
+
+ return false;
+}
+
+// Return true if we are using a sniper rifle
+
+/* <3ea3f1> ../cstrike/dlls/bot/cs_bot_weapon.cpp:375 */
+bool CCSBot::IsUsingSniperRifle(void) const
+{
+ CBasePlayerWeapon *weapon = GetActiveWeapon();
+
+ if (weapon != NULL && isSniperRifle(weapon))
+ return true;
+
+ return false;
+}
+
+// Return true if we have a sniper rifle in our inventory
+
+/* <3ea462> ../cstrike/dlls/bot/cs_bot_weapon.cpp:387 */
+bool CCSBot::IsSniper(void) const
+{
+ for (int i = 0; i < MAX_ITEM_TYPES; ++i)
+ {
+ CBasePlayerItem *item = m_rgpPlayerItems[i];
+
+ while (item != NULL)
+ {
+ if (isSniperRifle(item))
+ return true;
+
+ item = item->m_pNext;
+ }
+ }
+
+ return false;
}
// Return true if we are actively sniping (moving to sniper spot or settled in)
@@ -187,144 +358,261 @@ bool CCSBot::IsSniping(void) const
return false;
}
+// Return true if we are using a shotgun
+
/* <3ea4e8> ../cstrike/dlls/bot/cs_bot_weapon.cpp:417 */
-bool CCSBot::IsUsingShotgun(void)
+bool CCSBot::IsUsingShotgun(void) const
{
- return (m_pActiveItem && (m_pActiveItem->m_iId == WEAPON_XM1014 || m_pActiveItem->m_iId == WEAPON_M3));
-}
+ CBasePlayerWeapon *weapon = GetActiveWeapon();
-/* <3ea50f> ../cstrike/dlls/bot/cs_bot_weapon.cpp:437 */
-bool CCSBot::IsUsingMachinegun(void)
-{
- return (m_pActiveItem && m_pActiveItem->m_iId == WEAPON_M249);
-}
+ if (weapon == NULL)
+ return false;
-/* <3ea532> ../cstrike/dlls/bot/cs_bot_weapon.cpp:449 */
-NOBODY bool CCSBot::IsPrimaryWeaponEmpty(void)
-{
-// {
-// class CBasePlayerWeapon *gun; // 451
-// }
-}
+ if (weapon->m_iId == WEAPON_XM1014 || weapon->m_iId == WEAPON_M3)
+ return true;
-/* <3ea578> ../cstrike/dlls/bot/cs_bot_weapon.cpp:467 */
-NOBODY bool CCSBot::IsPistolEmpty(void)
-{
-// {
-// class CBasePlayerWeapon *gun; // 469
-// }
-}
-
-/* <3ea5d9> ../cstrike/dlls/bot/cs_bot_weapon.cpp:485 */
-NOBODY bool CCSBot::DoEquip(CBasePlayerWeapon *gun)
-{
-// Start(IntervalTimer *const this); // 496
-}
-
-/* <3ea621> ../cstrike/dlls/bot/cs_bot_weapon.cpp:510 */
-NOBODY void CCSBot::EquipBestWeapon(bool mustEquip)
-{
-// {
-// class CCSBotManager *ctrl; // 523
-// class CBasePlayerWeapon *primary; // 525
-// GetElapsedTime(const class IntervalTimer *const this); // 513
-// {
-// int weaponClass; // 528
-// AllowShotguns(const class CCSBotManager *const this); // 530
-// DoEquip(CCSBot *const this,
-// class CBasePlayerWeapon *gun); // 538
-// }
-// DoEquip(CCSBot *const this,
-// class CBasePlayerWeapon *gun); // 545
-// EquipKnife(CCSBot *const this); // 550
-// }
-}
-
-/* <3ea7fe> ../cstrike/dlls/bot/cs_bot_weapon.cpp:557 */
-NOBODY void CCSBot::EquipPistol(void)
-{
-// {
-// class CCSBotManager *ctrl; // 563
-// GetElapsedTime(const class IntervalTimer *const this); // 560
-// IsUsingPistol(const class CCSBot *const this); // 566
-// DoEquip(CCSBot *const this,
-// class CBasePlayerWeapon *gun); // 567
-// }
-}
-
-/* <3ea91a> ../cstrike/dlls/bot/cs_bot_weapon.cpp:575 */
-NOBODY void CCSBot::EquipKnife(void)
-{
-// IsUsingKnife(const class CCSBot *const this); // 581
-// EquipKnife(CCSBot *const this); // 575
-}
-
-/* <3ea98b> ../cstrike/dlls/bot/cs_bot_weapon.cpp:589 */
-NOBODY bool CCSBot::HasGrenade(void)
-{
-}
-
-/* <3ea9ae> ../cstrike/dlls/bot/cs_bot_weapon.cpp:598 */
-NOBODY bool CCSBot::EquipGrenade(bool noSmoke)
-{
-// IsSniper(const class CCSBot *const this); // 601
-// IsUsingGrenade(const class CCSBot *const this); // 604
-// HasGrenade(const class CCSBot *const this); // 607
-}
-
-/* <3eaa8c> ../cstrike/dlls/bot/cs_bot_weapon.cpp:624 */
-bool CCSBot::IsUsingKnife(void)
-{
- CBasePlayerWeapon *gun = (CBasePlayerWeapon *)m_pActiveItem;
- return (gun && gun->m_iId == 29);
-}
-
-/* <3eaac2> ../cstrike/dlls/bot/cs_bot_weapon.cpp:638 */
-bool CCSBot::IsUsingPistol(void)
-{
- UNTESTED
-
- CBasePlayerWeapon *gun = (CBasePlayerWeapon *)m_pActiveItem;
- if (gun)
- {
- switch (gun->m_iId)
- {
- case WEAPON_USP:
- case WEAPON_GLOCK18:
- case WEAPON_P228:
- case WEAPON_DEAGLE:
- case WEAPON_ELITE:
- case WEAPON_FIVESEVEN:
- return true;
- default:
- break;
- }
-
- // TODO: check it, from the dwarf should be used function IsPistol
-// {
-// class CBasePlayerWeapon *gun; // 640
-// IsPistol(CBasePlayerWeapon *const this); // 642
-// }
- //return gun->IsPistol();
- }
return false;
}
-/* <3eab09> ../cstrike/dlls/bot/cs_bot_weapon.cpp:652 */
-bool CCSBot::IsUsingGrenade(void)
+// Returns true if using the big 'ol machinegun
+
+/* <3ea50f> ../cstrike/dlls/bot/cs_bot_weapon.cpp:437 */
+bool CCSBot::IsUsingMachinegun(void) const
{
- CBasePlayerWeapon *gun = (CBasePlayerWeapon *)m_pActiveItem;
- return (gun && (gun->m_iId == WEAPON_SMOKEGRENADE || gun->m_iId == WEAPON_FLASHBANG || gun->m_iId == WEAPON_HEGRENADE));
+ CBasePlayerWeapon *weapon = GetActiveWeapon();
+
+ if (weapon != NULL && weapon->m_iId == WEAPON_M249)
+ return true;
+
+ return false;
+}
+
+// Return true if primary weapon doesn't exist or is totally out of ammo
+
+/* <3ea532> ../cstrike/dlls/bot/cs_bot_weapon.cpp:449 */
+bool CCSBot::IsPrimaryWeaponEmpty(void) const
+{
+ CBasePlayerWeapon *weapon = static_cast(m_rgpPlayerItems[ PRIMARY_WEAPON_SLOT ]);
+
+ if (weapon == NULL)
+ return true;
+
+ // check if gun has any ammo left
+ if (HasAnyAmmo(weapon))
+ return false;
+
+ return true;
+}
+
+// Return true if pistol doesn't exist or is totally out of ammo
+
+/* <3ea578> ../cstrike/dlls/bot/cs_bot_weapon.cpp:467 */
+bool CCSBot::IsPistolEmpty(void) const
+{
+ CBasePlayerWeapon *weapon = static_cast(m_rgpPlayerItems[ PISTOL_SLOT ]);
+
+ if (weapon == NULL)
+ return true;
+
+ // check if gun has any ammo left
+ if (HasAnyAmmo(weapon))
+ {
+ return false;
+ }
+
+ return true;
+}
+
+// Equip the given item
+
+/* <3ea5d9> ../cstrike/dlls/bot/cs_bot_weapon.cpp:485 */
+bool CCSBot::DoEquip(CBasePlayerWeapon *gun)
+{
+ if (gun == NULL)
+ return false;
+
+ // check if weapon has any ammo left
+ if (!HasAnyAmmo(gun))
+ return false;
+
+ // equip it
+ SelectItem(STRING(gun->pev->classname));
+ m_equipTimer.Start();
+
+ return true;
+}
+
+// throttle how often equipping is allowed
+const float minEquipInterval = 5.0f;
+
+// Equip the best weapon we are carrying that has ammo
+
+/* <3ea621> ../cstrike/dlls/bot/cs_bot_weapon.cpp:510 */
+void CCSBot::EquipBestWeapon(bool mustEquip)
+{
+ // throttle how often equipping is allowed
+ if (!mustEquip && m_equipTimer.GetElapsedTime() < minEquipInterval)
+ return;
+
+ CCSBotManager *ctrl = TheCSBots();
+ CBasePlayerWeapon *primary = static_cast(m_rgpPlayerItems[ PRIMARY_WEAPON_SLOT ]);
+
+ if (primary != NULL)
+ {
+ WeaponClassType weaponClass = WeaponIDToWeaponClass(primary->m_iId);
+
+ if ((ctrl->AllowShotguns() && weaponClass == WEAPONCLASS_SHOTGUN)
+ || (ctrl->AllowMachineGuns() && weaponClass == WEAPONCLASS_MACHINEGUN)
+ || (ctrl->AllowRifles() && weaponClass == WEAPONCLASS_RIFLE)
+#ifndef REGAMEDLL_FIXES
+ // TODO: already is checked shotguns!
+ || (ctrl->AllowShotguns() && weaponClass == WEAPONCLASS_SHOTGUN)
+#endif // REGAMEDLL_FIXES
+ || (ctrl->AllowSnipers() && weaponClass == WEAPONCLASS_SNIPERRIFLE)
+ || (ctrl->AllowSubMachineGuns() && weaponClass == WEAPONCLASS_SUBMACHINEGUN)
+ || (ctrl->AllowTacticalShield() && primary->m_iId == WEAPON_SHIELDGUN))
+ {
+ if (DoEquip(primary))
+ return;
+ }
+ }
+
+ if (ctrl->AllowPistols())
+ {
+ if (DoEquip(static_cast(m_rgpPlayerItems[ PISTOL_SLOT ])))
+ return;
+ }
+
+ // always have a knife
+ EquipKnife();
+}
+
+// Equip our pistol
+
+/* <3ea7fe> ../cstrike/dlls/bot/cs_bot_weapon.cpp:557 */
+void CCSBot::EquipPistol(void)
+{
+ // throttle how often equipping is allowed
+ if (m_equipTimer.GetElapsedTime() < minEquipInterval)
+ return;
+
+ if (TheCSBots()->AllowPistols() && !IsUsingPistol())
+ {
+ CBasePlayerWeapon *pistol = static_cast(m_rgpPlayerItems[ PISTOL_SLOT ]);
+ DoEquip(pistol);
+ }
+}
+
+// Equip the knife
+
+/* <3ea91a> ../cstrike/dlls/bot/cs_bot_weapon.cpp:575 */
+void CCSBot::EquipKnife(void)
+{
+ if (!IsUsingKnife())
+ {
+ CBasePlayerWeapon *knife = static_cast(m_rgpPlayerItems[ KNIFE_SLOT ]);
+ if (knife != NULL)
+ {
+ SelectItem(STRING(knife->pev->classname));
+ }
+ }
+}
+
+// Return true if we have a grenade in our inventory
+
+/* <3ea98b> ../cstrike/dlls/bot/cs_bot_weapon.cpp:589 */
+bool CCSBot::HasGrenade(void) const
+{
+ CBasePlayerWeapon *grenade = static_cast(m_rgpPlayerItems[ GRENADE_SLOT ]);
+ return grenade != NULL;
+}
+
+// Equip a grenade, return false if we cant
+
+/* <3ea9ae> ../cstrike/dlls/bot/cs_bot_weapon.cpp:598 */
+bool CCSBot::EquipGrenade(bool noSmoke)
+{
+ // snipers don't use grenades
+ if (IsSniper())
+ return false;
+
+ if (IsUsingGrenade())
+ return true;
+
+ if (HasGrenade())
+ {
+ CBasePlayerWeapon *grenade = static_cast(m_rgpPlayerItems[ GRENADE_SLOT ]);
+
+ if (grenade != NULL)
+ {
+ if (noSmoke && grenade->m_iId == WEAPON_SMOKEGRENADE)
+ return false;
+
+ SelectItem(STRING(grenade->pev->classname));
+ return true;
+ }
+ }
+
+ return false;
+}
+
+// Returns true if we have knife equipped
+
+/* <3eaa8c> ../cstrike/dlls/bot/cs_bot_weapon.cpp:624 */
+bool CCSBot::IsUsingKnife(void) const
+{
+ CBasePlayerWeapon *weapon = GetActiveWeapon();
+
+ if (weapon != NULL && weapon->m_iId == WEAPON_KNIFE)
+ return true;
+
+ return false;
+}
+
+// Returns true if we have pistol equipped
+
+/* <3eaac2> ../cstrike/dlls/bot/cs_bot_weapon.cpp:638 */
+bool CCSBot::IsUsingPistol(void) const
+{
+ CBasePlayerWeapon *weapon = GetActiveWeapon();
+
+ if (weapon != NULL && weapon->IsPistol())
+ return true;
+
+ return false;
+}
+
+// Returns true if we have a grenade equipped
+
+/* <3eab09> ../cstrike/dlls/bot/cs_bot_weapon.cpp:652 */
+bool CCSBot::IsUsingGrenade(void) const
+{
+ CBasePlayerWeapon *weapon = GetActiveWeapon();
+
+ if (weapon == NULL)
+ return false;
+
+ if (weapon->m_iId == WEAPON_SMOKEGRENADE
+ || weapon->m_iId == WEAPON_FLASHBANG
+ || weapon->m_iId == WEAPON_HEGRENADE)
+ return true;
+
+ return false;
}
/* <3eab3f> ../cstrike/dlls/bot/cs_bot_weapon.cpp:672 */
-NOBODY bool CCSBot::IsUsingHEGrenade(void)
+bool CCSBot::IsUsingHEGrenade(void) const
{
-// {
-// class CBasePlayerWeapon *gun; // 674
-// }
+ CBasePlayerWeapon *weapon = GetActiveWeapon();
+
+ if (weapon != NULL && weapon->m_iId == WEAPON_HEGRENADE)
+ return true;
+
+ return false;
}
+// Begin the process of throwing the grenade
+
/* <3eab80> ../cstrike/dlls/bot/cs_bot_weapon.cpp:690 */
void CCSBot::ThrowGrenade(const Vector *target)
{
@@ -339,152 +627,322 @@ void CCSBot::ThrowGrenade(const Vector *target)
}
}
+// Find spot to throw grenade ahead of us and "around the corner" along our path
+
/* <3eac08> ../cstrike/dlls/bot/cs_bot_weapon.cpp:709 */
-NOBODY bool CCSBot::FindGrenadeTossPathTarget(const Vector *pos)
+bool CCSBot::FindGrenadeTossPathTarget(Vector *pos)
{
-// {
-// int i; // 715
-// Vector dir; // 726
-// float length; // 727
-// float const inc; // 729
-// Vector p; // 730
-// Vector visibleSpot; // 731
-// float const bufferRange; // 745
-// TraceResult result; // 747
-// Vector check; // 748
-// operator+(const Vector *const this,
-// const Vector &v); // 718
-// operator-(const Vector *const this,
-// const Vector &v); // 726
-// NormalizeInPlace(Vector *const this); // 727
-// Vector(Vector *const this,
-// const Vector &v); // 731
-// operator+(const Vector *const this,
-// const Vector &v); // 751
-// {
-// float range; // 756
-// }
-// operator+(const Vector *const this,
-// const Vector &v); // 764
-// {
-// float range; // 769
-// }
-// operator+(const Vector *const this,
-// const Vector &v); // 777
-// {
-// float range; // 782
-// }
-// operator+(const Vector *const this,
-// const Vector &v); // 790
-// {
-// float range; // 795
-// }
-// {
-// float t; // 732
-// operator*(float fl,
-// const Vector &v); // 734
-// operator+(const Vector *const this,
-// const Vector &v); // 734
-// }
-// }
+ if (!HasPath())
+ return false;
+
+ // find farthest point we can see on the path
+ int i;
+ for (i = m_pathIndex; i < m_pathLength; ++i)
+ {
+ if (!FVisible(m_path[i].pos + Vector(0, 0, HalfHumanHeight)))
+ break;
+ }
+
+ if (i == m_pathIndex)
+ return false;
+
+ // find exact spot where we lose sight
+ Vector dir = m_path[i].pos - m_path[i - 1].pos;
+ float length = dir.NormalizeInPlace();
+
+ const float inc = 25.0f;
+ Vector p;
+ Vector visibleSpot = m_path[i - 1].pos;
+ for (float t = 0.0f; t < length; t += inc)
+ {
+ p = m_path[i - 1].pos + t * dir;
+ p.z += HalfHumanHeight;
+
+ if (!FVisible(p))
+ break;
+
+ visibleSpot = p;
+ }
+
+ // massage the location a bit
+ visibleSpot.z += 10.0f;
+
+ const float bufferRange = 50.0f;
+ TraceResult result;
+ Vector check;
+
+ // check +X
+ check = visibleSpot + Vector(999.9f, 0, 0);
+ UTIL_TraceLine(visibleSpot, check, dont_ignore_monsters, ignore_glass, ENT(pev), &result);
+
+ if (result.flFraction < 1.0f)
+ {
+ float range = result.vecEndPos.x - visibleSpot.x;
+ if (range < bufferRange)
+ {
+ visibleSpot.x = result.vecEndPos.x - bufferRange;
+ }
+ }
+
+ // check -X
+ check = visibleSpot + Vector(-999.9f, 0, 0);
+ UTIL_TraceLine(visibleSpot, check, dont_ignore_monsters, ignore_glass, ENT(pev), &result);
+
+ if (result.flFraction < 1.0f)
+ {
+ float range = visibleSpot.x - result.vecEndPos.x;
+ if (range < bufferRange)
+ {
+ visibleSpot.x = result.vecEndPos.x + bufferRange;
+ }
+ }
+
+ // check +Y
+ check = visibleSpot + Vector(0, 999.9f, 0);
+ UTIL_TraceLine(visibleSpot, check, dont_ignore_monsters, ignore_glass, ENT(pev), &result);
+
+ if (result.flFraction < 1.0f)
+ {
+ float range = result.vecEndPos.y - visibleSpot.y;
+ if (range < bufferRange)
+ {
+ visibleSpot.y = result.vecEndPos.y - bufferRange;
+ }
+ }
+
+ // check -Y
+ check = visibleSpot + Vector(0, -999.9f, 0);
+ UTIL_TraceLine(visibleSpot, check, dont_ignore_monsters, ignore_glass, ENT(pev), &result);
+
+ if (result.flFraction < 1.0f)
+ {
+ float range = visibleSpot.y - result.vecEndPos.y;
+ if (range < bufferRange)
+ {
+ visibleSpot.y = result.vecEndPos.y + bufferRange;
+ }
+ }
+
+ *pos = visibleSpot;
+ return true;
}
+// Reload our weapon if we must
+
/* <3eaf22> ../cstrike/dlls/bot/cs_bot_weapon.cpp:810 */
-NOBODY void CCSBot::ReloadCheck(void)
+void CCSBot::ReloadCheck(void)
{
-// {
-// float const safeReloadWaitTime; // 812
-// float const reloadAmmoRatio; // 813
-// IsActiveWeaponReloading(const class CBot *const this); // 819
-// IsPistolEmpty(const class CCSBot *const this); // 827
-// IsUsingAWP(const class CCSBot *const this); // 848
-// GetNearbyEnemyCount(const class CCSBot *const this); // 854
-// {
-// float const hideChance; // 857
-// {
-// float const safeTime; // 861
-// GetTimeSinceLastSawEnemy(const class CCSBot *const this); // 862
-// {
-// const Vector *spot; // 865
-// }
-// }
-// }
-// GetTimeSinceLastSawEnemy(const class CCSBot *const this); // 835
-// IsPistol(CBasePlayerWeapon *const this); // 827
-// }
+ const float safeReloadWaitTime = 3.0f;
+ const float reloadAmmoRatio = 0.6f;
+
+ // don't bother to reload if there are no enemies left
+ if (GetEnemiesRemaining() == 0)
+ return;
+
+ if (IsDefusingBomb() || IsActiveWeaponReloading())
+ return;
+
+ if (IsActiveWeaponClipEmpty())
+ {
+ // high-skill players switch to pistol instead of reloading during combat
+ if (GetProfile()->GetSkill() > 0.5f && IsAttacking())
+ {
+ if (!GetActiveWeapon()->IsPistol() && !IsPistolEmpty())
+ {
+ // switch to pistol instead of reloading
+ EquipPistol();
+ return;
+ }
+ }
+ }
+ else if (GetTimeSinceLastSawEnemy() > safeReloadWaitTime && GetActiveWeaponAmmoRatio() <= reloadAmmoRatio)
+ {
+ // high-skill players use all their ammo and switch to pistol instead of reloading during combat
+ if (GetProfile()->GetSkill() > 0.5f && IsAttacking())
+ return;
+ }
+ else
+ {
+ // do not need to reload
+ return;
+ }
+
+ // don't reload the AWP until it is totally out of ammo
+ if (IsUsingAWP() && !IsActiveWeaponClipEmpty())
+ return;
+
+ Reload();
+
+ // move to cover to reload if there are enemies nearby
+ if (GetNearbyEnemyCount())
+ {
+ // avoid enemies while reloading (above 0.75 skill always hide to reload)
+ const float hideChance = 25.0f + 100.0f * GetProfile()->GetSkill();
+
+ if (!IsHiding() && RANDOM_FLOAT(0.0f, 100.0f) < hideChance)
+ {
+ const float safeTime = 5.0f;
+ if (GetTimeSinceLastSawEnemy() < safeTime)
+ {
+ PrintIfWatched("Retreating to a safe spot to reload!\n");
+ const Vector *spot = FindNearbyRetreatSpot(this, 1000.0f);
+ if (spot != NULL)
+ {
+ // ignore enemies for a second to give us time to hide
+ // reaching our hiding spot clears our disposition
+ IgnoreEnemies(10.0f);
+
+ Run();
+ StandUp();
+ Hide(spot, 0.0f);
+ }
+ }
+ }
+ }
}
+// Silence/unsilence our weapon if we must
+
/* <3eb0ac> ../cstrike/dlls/bot/cs_bot_weapon.cpp:885 */
-NOBODY void CCSBot::SilencerCheck(void)
+void CCSBot::SilencerCheck(void)
{
-// {
-// float const safeSilencerWaitTime; // 887
-// IsActiveWeaponReloading(const class CBot *const this); // 889
-// DoesActiveWeaponHaveSilencer(const class CCSBot *const this); // 892
-// GetNearbyEnemyCount(const class CCSBot *const this); // 896
-// {
-// bool isSilencerOn; // 899
-// class CBasePlayerWeapon *myGun; // 901
-// }
-// }
+ // longer than reload check because reloading should take precedence
+ const float safeSilencerWaitTime = 3.5f;
+
+ if (IsDefusingBomb() || IsActiveWeaponReloading() || IsAttacking())
+ return;
+
+ // M4A1 and USP are the only weapons with removable silencers
+ if (!DoesActiveWeaponHaveSilencer())
+ return;
+
+#ifdef REGAMEDLL_FIXES
+ if (GetTimeSinceLastSawEnemy() < safeSilencerWaitTime)
+ return;
+#endif // REGAMEDLL_FIXES
+
+ // don't touch the silencer if there are enemies nearby
+ if (GetNearbyEnemyCount() == 0)
+ {
+ CBasePlayerWeapon *myGun = GetActiveWeapon();
+ if (myGun == NULL)
+ return;
+
+ bool isSilencerOn = (myGun->m_iWeaponState & (WPNSTATE_M4A1_SILENCED | WPNSTATE_USP_SILENCED)) != 0;
+
+#ifndef REGAMEDLL_FIXES
+ if (isSilencerOn != GetProfile()->PrefersSilencer() && !HasShield())
+#else
+
+ if (myGun->m_flNextSecondaryAttack >= gpGlobals->time)
+ return;
+
+ // equip silencer if we want to and we don't have a shield.
+ if (isSilencerOn != (GetProfile()->PrefersSilencer() || GetProfile()->GetSkill() > 0.7f) && !HasShield())
+#endif // REGAMEDLL_FIXES
+ {
+ PrintIfWatched("%s silencer!\n", (isSilencerOn) ? "Unequipping" : "Equipping");
+ myGun->SecondaryAttack();
+ }
+ }
}
+// Invoked when in contact with a CWeaponBox
+
/* <3eb1a9> ../cstrike/dlls/bot/cs_bot_weapon.cpp:926 */
-NOBODY void CCSBot::__MAKE_VHOOK(OnTouchingWeapon)(CWeaponBox *box)
+void CCSBot::__MAKE_VHOOK(OnTouchingWeapon)(CWeaponBox *box)
{
-// {
-// class CBasePlayerItem *droppedGun; // 929
-// class CBasePlayerWeapon *myGun; // 934
-// float const safeTime; // 947
-// GetTimeSinceLastSawEnemy(const class CCSBot *const this); // 948
-// {
-// int i; // 952
-// {
-// int prefID; // 954
-// GetWeaponPreference(const class BotProfile *const this,
-// int i); // 954
-// }
-// }
-// }
+ CBasePlayerItem *droppedGun = dynamic_cast(box->m_rgpPlayerItems[ PRIMARY_WEAPON_SLOT ]);
+
+ // right now we only care about primary weapons on the ground
+ if (droppedGun != NULL)
+ {
+ CBasePlayerWeapon *myGun = dynamic_cast(m_rgpPlayerItems[ PRIMARY_WEAPON_SLOT ]);
+
+ // if the gun on the ground is the same one we have, dont bother
+ if (myGun != NULL && droppedGun->m_iId != myGun->m_iId)
+ {
+ // if we don't have a weapon preference, give up
+ if (GetProfile()->HasPrimaryPreference())
+ {
+ // don't change weapons if we've seen enemies recently
+ const float safeTime = 2.5f;
+ if (GetTimeSinceLastSawEnemy() >= safeTime)
+ {
+ // we have a primary weapon - drop it if the one on the ground is better
+ for (int i = 0; i < GetProfile()->GetWeaponPreferenceCount(); ++i)
+ {
+ int prefID = GetProfile()->GetWeaponPreference(i);
+
+ if (!IsPrimaryWeapon(prefID))
+ continue;
+
+ // if the gun we are using is more desirable, give up
+ if (prefID == myGun->m_iId)
+ break;
+
+ if (prefID == droppedGun->m_iId)
+ {
+ // the gun on the ground is better than the one we have - drop our gun
+ DropPrimary(this);
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
}
+// Return true if a friend is in our weapon's way
+// TODO: Check more rays for safety.
+
/* <3eb277> ../cstrike/dlls/bot/cs_bot_weapon.cpp:977 */
-NOBODY bool CCSBot::IsFriendInLineOfFire(void)
+bool CCSBot::IsFriendInLineOfFire(void)
{
-// {
-// Vector aimDir; // 981
-// TraceResult result; // 984
-// Vector target; // 985
-// operator+(const Vector *const this,
-// const Vector &v); // 980
-// operator*(float fl,
-// const Vector &v); // 985
-// operator+(const Vector *const this,
-// const Vector &v); // 985
-// {
-// class CBaseEntity *victim; // 990
-// Instance(edict_t *pent); // 990
-// }
-// }
+ UTIL_MakeVectors(pev->punchangle + pev->v_angle);
+
+ // compute the unit vector along our view
+ Vector aimDir = gpGlobals->v_forward;
+ Vector target = GetGunPosition();
+
+ // trace the bullet's path
+ TraceResult result;
+ UTIL_TraceLine(GetGunPosition(), target + 10000.0f * aimDir, dont_ignore_monsters, ignore_glass, ENT(pev), &result);
+
+ if (result.pHit != NULL)
+ {
+ CBaseEntity *victim = CBaseEntity::Instance(result.pHit);
+
+ if (victim != NULL && victim->IsPlayer() && victim->IsAlive())
+ {
+ CBasePlayer *player = static_cast(victim);
+
+ if (player->m_iTeam == m_iTeam)
+ return true;
+ }
+ }
+
+ return false;
}
+// Return line-of-sight distance to obstacle along weapon fire ray
+// TODO: Re-use this computation with IsFriendInLineOfFire()
+
/* <3eb84d> ../cstrike/dlls/bot/cs_bot_weapon.cpp:1009 */
-NOBODY float CCSBot::ComputeWeaponSightRange(void)
+float CCSBot::ComputeWeaponSightRange(void)
{
-// {
-// Vector aimDir; // 1013
-// TraceResult result; // 1016
-// Vector target; // 1017
-// operator+(const Vector *const this,
-// const Vector &v); // 1012
-// operator*(float fl,
-// const Vector &v); // 1017
-// operator+(const Vector *const this,
-// const Vector &v); // 1017
-// operator-(const Vector *const this,
-// const Vector &v); // 1020
-// Length(const Vector *const this); // 1020
-// }
+ UTIL_MakeVectors(pev->punchangle + pev->v_angle);
+
+ // compute the unit vector along our view
+ Vector aimDir = gpGlobals->v_forward;
+ Vector target = GetGunPosition();
+
+ // trace the bullet's path
+ TraceResult result;
+ UTIL_TraceLine(GetGunPosition(), target + 10000.0f * aimDir, dont_ignore_monsters, ignore_glass, ENT(pev), &result);
+
+ return (GetGunPosition() - result.vecEndPos).Length();
}
#ifdef HOOK_GAMEDLL
diff --git a/regamedll/dlls/bot/cs_gamestate.cpp b/regamedll/dlls/bot/cs_gamestate.cpp
index 05163147..1940cbe7 100644
--- a/regamedll/dlls/bot/cs_gamestate.cpp
+++ b/regamedll/dlls/bot/cs_gamestate.cpp
@@ -1,292 +1,702 @@
#include "precompiled.h"
-/* <3fca3c> ../cstrike/dlls/bot/cs_gamestate.cpp:13 */
-NOBODY CSGameState::CSGameState(void)
-{
-
-}
-
/* <3fcd6b> ../cstrike/dlls/bot/cs_gamestate.cpp:27 */
-NOBODY CSGameState::CSGameState(CCSBot *owner)
+CSGameState::CSGameState(CCSBot *owner)
{
-// IntervalTimer(IntervalTimer *const this); // 27
-// {
-// int i; // 41
-// }
-// IntervalTimer(IntervalTimer *const this); // 27
-// CountdownTimer(CountdownTimer *const this); // 27
+ m_owner = owner;
+ m_isRoundOver = false;
+ m_bombState = MOVING;
+
+ m_lastSawBomber.Invalidate();
+ m_lastSawLooseBomb.Invalidate();
+ m_validateInterval.Invalidate();
+ m_isPlantedBombPosKnown = false;
+ m_plantedBombsite = UNKNOWN;
+
+ m_bombsiteCount = 0;
+ m_bombsiteSearchIndex = 0;
+
+ for (int i = 0; i < MAX_HOSTAGES; ++i)
+ {
+ HostageInfo *info = &m_hostage[i];
+
+ info->hostage = NULL;
+ info->knownPos = Vector(0, 0, 0);
+ info->isValid = false;
+ info->isAlive = false;
+ info->isFree = true;
+ }
}
+// Reset at round start
+
/* <3fd4f4> ../cstrike/dlls/bot/cs_gamestate.cpp:55 */
-NOBODY void CSGameState::Reset(void)
+void CSGameState::Reset(void)
{
-// {
-// class CCSBotManager *ctrl; // 66
-// int i; // 69
-// Invalidate(IntervalTimer *const this); // 61
-// Invalidate(IntervalTimer *const this); // 62
-// {
-// int swap; // 81
-// int rnd; // 82
-// }
-// }
+ int i;
+ CCSBotManager *ctrl = TheCSBots();
+
+ m_isRoundOver = false;
+
+ // bomb
+ m_bombState = MOVING;
+ m_lastSawBomber.Invalidate();
+ m_lastSawLooseBomb.Invalidate();
+ m_bombsiteCount = ctrl->GetZoneCount();
+
+ m_isPlantedBombPosKnown = false;
+ m_plantedBombsite = UNKNOWN;
+
+ for (i = 0; i < m_bombsiteCount; ++i)
+ {
+ m_isBombsiteClear[i] = false;
+ m_bombsiteSearchOrder[i] = i;
+ }
+
+ // shuffle the bombsite search order
+ // allows T's to plant at random site, and TEAM_CT's to search in a random order
+ // NOTE: VS6 std::random_shuffle() doesn't work well with an array of two elements (most maps)
+ for (i = 0; i < m_bombsiteCount; ++i)
+ {
+ int swap = m_bombsiteSearchOrder[i];
+ int rnd = RANDOM_LONG(i, m_bombsiteCount - 1);
+
+ m_bombsiteSearchOrder[i] = m_bombsiteSearchOrder[rnd];
+ m_bombsiteSearchOrder[rnd] = swap;
+ }
+
+ m_bombsiteSearchIndex = 0;
+ InitializeHostageInfo();
}
+// Update game state based on events we have received
+
/* <3fce67> ../cstrike/dlls/bot/cs_gamestate.cpp:97 */
-NOBODY void CSGameState::OnEvent(GameEventType event, CBaseEntity *entity, CBaseEntity *other)
+void CSGameState::OnEvent(GameEventType event, CBaseEntity *entity, CBaseEntity *other)
{
-// SetBombState(CSGameState *const this,
-// enum BombState state); // 104
-// UpdatePlantedBomb(CSGameState *const this,
-// const Vector *pos); // 109
-// SetBombState(CSGameState *const this,
-// enum BombState state); // 117
-// SetBombState(CSGameState *const this,
-// enum BombState state); // 124
+ switch (event)
+ {
+ case EVENT_BOMB_PLANTED:
+ SetBombState(PLANTED);
+ if (m_owner->m_iTeam == TERRORIST && other != NULL)
+ {
+ UpdatePlantedBomb(&other->pev->origin);
+ }
+ break;
+ case EVENT_BOMB_DEFUSED:
+ SetBombState(DEFUSED);
+ break;
+ case EVENT_BOMB_EXPLODED:
+ SetBombState(EXPLODED);
+ break;
+ case EVENT_ALL_HOSTAGES_RESCUED:
+ m_allHostagesRescued = true;
+ break;
+ case EVENT_TERRORISTS_WIN:
+ case EVENT_CTS_WIN:
+ case EVENT_ROUND_DRAW:
+ m_isRoundOver = true;
+ break;
+ default:
+ break;
+ }
}
+// True if round has been won or lost (but not yet reset)
+
/* <3fcf9c> ../cstrike/dlls/bot/cs_gamestate.cpp:144 */
-NOBODY bool CSGameState::IsRoundOver(void) const
+bool CSGameState::IsRoundOver(void) const
{
+ return m_isRoundOver;
}
/* <3fcfc6> ../cstrike/dlls/bot/cs_gamestate.cpp:150 */
-NOBODY void CSGameState::SetBombState(BombState state)
+void CSGameState::SetBombState(BombState state)
{
+ // if state changed, reset "last seen" timestamps
+ if (m_bombState != state)
+ {
+ m_bombState = state;
+ }
}
/* <3fcff2> ../cstrike/dlls/bot/cs_gamestate.cpp:160 */
-NOBODY void CSGameState::UpdateLooseBomb(const Vector *pos)
+void CSGameState::UpdateLooseBomb(const Vector *pos)
{
-// SetBombState(CSGameState *const this,
-// enum BombState state); // 166
-// Reset(IntervalTimer *const this); // 163
+ m_looseBombPos = *pos;
+ m_lastSawLooseBomb.Reset();
+
+ // we saw the loose bomb, update our state
+ SetBombState(LOOSE);
}
/* <3fd06e> ../cstrike/dlls/bot/cs_gamestate.cpp:170 */
-NOBODY float CSGameState::TimeSinceLastSawLooseBomb(void) const
+float CSGameState::TimeSinceLastSawLooseBomb(void) const
{
-// GetElapsedTime(const class IntervalTimer *const this); // 172
+ return m_lastSawLooseBomb.GetElapsedTime();
}
/* <3fd0f4> ../cstrike/dlls/bot/cs_gamestate.cpp:176 */
-NOBODY bool CSGameState::IsLooseBombLocationKnown(void) const
+bool CSGameState::IsLooseBombLocationKnown(void) const
{
-// HasStarted(const class IntervalTimer *const this); // 181
+ if (m_bombState != LOOSE)
+ return false;
+
+ return (m_lastSawLooseBomb.HasStarted()) ? true : false;
}
/* <3fd135> ../cstrike/dlls/bot/cs_gamestate.cpp:185 */
-NOBODY void CSGameState::UpdateBomber(const Vector *pos)
+void CSGameState::UpdateBomber(const Vector *pos)
{
-// Reset(IntervalTimer *const this); // 188
-// SetBombState(CSGameState *const this,
-// enum BombState state); // 191
+ m_bomberPos = *pos;
+ m_lastSawBomber.Reset();
+
+ // we saw the bomber, update our state
+ SetBombState(MOVING);
}
/* <3fd1b1> ../cstrike/dlls/bot/cs_gamestate.cpp:195 */
-NOBODY float CSGameState::TimeSinceLastSawBomber(void) const
+float CSGameState::TimeSinceLastSawBomber(void) const
{
-// GetElapsedTime(const class IntervalTimer *const this); // 197
+ return m_lastSawBomber.GetElapsedTime();
}
/* <3fd237> ../cstrike/dlls/bot/cs_gamestate.cpp:201 */
-NOBODY bool CSGameState::IsPlantedBombLocationKnown(void) const
+bool CSGameState::IsPlantedBombLocationKnown(void) const
{
+ if (m_bombState != PLANTED)
+ return false;
+
+ return m_isPlantedBombPosKnown;
}
+// Return the zone index of the planted bombsite, or UNKNOWN
+
/* <3fd25a> ../cstrike/dlls/bot/cs_gamestate.cpp:213 */
-NOBODY int CSGameState::GetPlantedBombsite(void) const
+int CSGameState::GetPlantedBombsite(void) const
{
+ if (m_bombState != PLANTED)
+ return UNKNOWN;
+
+ return m_plantedBombsite;
}
+// Return true if we are currently in the bombsite where the bomb is planted
+
/* <3fd284> ../cstrike/dlls/bot/cs_gamestate.cpp:225 */
-NOBODY bool CSGameState::IsAtPlantedBombsite(void) const
+bool CSGameState::IsAtPlantedBombsite(void) const
{
-// {
-// class CCSBotManager *ctrl; // 230
-// const class Zone *zone; // 231
-// }
+ if (m_bombState != PLANTED)
+ return false;
+
+ CCSBotManager *ctrl = TheCSBots();
+ const CCSBotManager::Zone *zone = ctrl->GetClosestZone(&m_owner->pev->origin);
+
+ if (zone != NULL)
+ {
+ return (m_plantedBombsite == zone->m_index);
+ }
+
+ return false;
}
+// Return the zone index of the next bombsite to search
+
/* <3fd2d2> ../cstrike/dlls/bot/cs_gamestate.cpp:246 */
-NOBODY int CSGameState::GetNextBombsiteToSearch(void)
+int CSGameState::GetNextBombsiteToSearch(void)
{
-// {
-// int i; // 251
-// {
-// int z; // 256
-// }
-// }
+ if (m_bombsiteCount <= 0)
+ return 0;
+
+ int i;
+ // return next non-cleared bombsite index
+ for (i = m_bombsiteSearchIndex; i < m_bombsiteCount; ++i)
+ {
+ int z = m_bombsiteSearchOrder[i];
+ if (!m_isBombsiteClear[z])
+ {
+ m_bombsiteSearchIndex = i;
+ return z;
+ }
+ }
+
+ // all the bombsites are clear, someone must have been mistaken - start search over
+ for (i = 0; i < m_bombsiteCount; ++i)
+ {
+ m_isBombsiteClear[i] = false;
+ }
+
+ m_bombsiteSearchIndex = 0;
+ return GetNextBombsiteToSearch();
}
+// Returns position of bomb in its various states (moving, loose, planted),
+// or NULL if we don't know where the bomb is
+
/* <3fd32c> ../cstrike/dlls/bot/cs_gamestate.cpp:277 */
-NOBODY const Vector *CSGameState::GetBombPosition(void) const
+const Vector *CSGameState::GetBombPosition(void) const
{
-// HasStarted(const class IntervalTimer *const this); // 283
+ switch (m_bombState)
+ {
+ case MOVING:
+ {
+ if (!m_lastSawBomber.HasStarted())
+ return NULL;
+
+ return &m_bomberPos;
+ }
+ case LOOSE:
+ {
+ if (IsLooseBombLocationKnown())
+ return &m_looseBombPos;
+
+ return NULL;
+ }
+ case PLANTED:
+ {
+ if (IsPlantedBombLocationKnown())
+ return &m_plantedBombPos;
+
+ return NULL;
+ }
+ }
+
+ return NULL;
}
+// We see the planted bomb at 'pos'
+
/* <3fd373> ../cstrike/dlls/bot/cs_gamestate.cpp:313 */
-NOBODY void CSGameState::UpdatePlantedBomb(const Vector *pos)
+void CSGameState::UpdatePlantedBomb(const Vector *pos)
{
-// {
-// class CCSBotManager *ctrl; // 315
-// const class Zone *zone; // 316
-// SetBombState(CSGameState *const this,
-// enum BombState state); // 330
-// }
+ CCSBotManager *ctrl = TheCSBots();
+ const CCSBotManager::Zone *zone = ctrl->GetClosestZone(pos);
+
+ if (zone == NULL)
+ {
+ CONSOLE_ECHO("ERROR: Bomb planted outside of a zone!\n");
+ m_plantedBombsite = UNKNOWN;
+ }
+ else
+ {
+ m_plantedBombsite = zone->m_index;
+ }
+
+ m_plantedBombPos = *pos;
+ m_isPlantedBombPosKnown = true;
+ SetBombState(PLANTED);
}
+// Someone told us where the bomb is planted
+
/* <3fd3dd> ../cstrike/dlls/bot/cs_gamestate.cpp:337 */
-NOBODY void CSGameState::MarkBombsiteAsPlanted(int zoneIndex)
+void CSGameState::MarkBombsiteAsPlanted(int zoneIndex)
{
-// SetBombState(CSGameState *const this,
-// enum BombState state); // 340
+ m_plantedBombsite = zoneIndex;
+ SetBombState(PLANTED);
}
+// Someone told us a bombsite is clear
+
/* <3fd43a> ../cstrike/dlls/bot/cs_gamestate.cpp:347 */
-NOBODY void CSGameState::ClearBombsite(int zoneIndex)
+void CSGameState::ClearBombsite(int zoneIndex)
{
+ if (zoneIndex >= 0 && zoneIndex < m_bombsiteCount)
+ m_isBombsiteClear[zoneIndex] = true;
}
/* <3fd475> ../cstrike/dlls/bot/cs_gamestate.cpp:354 */
-NOBODY bool CSGameState::IsBombsiteClear(int zoneIndex) const
+bool CSGameState::IsBombsiteClear(int zoneIndex) const
{
+ if (zoneIndex >= 0 && zoneIndex < m_bombsiteCount)
+ return m_isBombsiteClear[zoneIndex];
+
+ return false;
}
/* <3fd4b0> ../cstrike/dlls/bot/cs_gamestate.cpp:367 */
-NOBODY void CSGameState::InitializeHostageInfo(void)
+void CSGameState::InitializeHostageInfo(void)
{
-// {
-// class CBaseEntity *hostage; // 373
-// }
+ m_hostageCount = 0;
+ m_allHostagesRescued = 0;
+ m_haveSomeHostagesBeenTaken = 0;
+
+ CBaseEntity *hostage = NULL;
+ while ((hostage = UTIL_FindEntityByClassname(hostage, "hostage_entity")) != NULL)
+ {
+ if (m_hostageCount >= MAX_HOSTAGES)
+ break;
+
+ if (hostage->pev->takedamage != DAMAGE_YES)
+ continue;
+
+ m_hostage[m_hostageCount].hostage = static_cast(hostage);
+ m_hostage[m_hostageCount].knownPos = hostage->pev->origin;
+ m_hostage[m_hostageCount].isValid = true;
+ m_hostage[m_hostageCount].isAlive = true;
+ m_hostage[m_hostageCount].isFree = true;
+ ++m_hostageCount;
+ }
}
+// Return the closest free and live hostage
+// If we are a CT this information is perfect.
+// Otherwise, this is based on our individual memory of the game state.
+// If NULL is returned, we don't think there are any hostages left, or we dont know where they are.
+// NOTE: a T can remember a hostage who has died. knowPos will be filled in, but NULL will be
+// returned, since CHostages get deleted when they die.
+
/* <3fd5ab> ../cstrike/dlls/bot/cs_gamestate.cpp:398 */
-NOBODY CHostage *CSGameState::GetNearestFreeHostage(Vector *knowPos)
+CHostage *CSGameState::GetNearestFreeHostage(Vector *knowPos) const
{
-// {
-// class CNavArea *startArea; // 403
-// class CHostage *close; // 407
-// const Vector *closePos; // 408
-// float closeDistance; // 409
-// {
-// int i; // 411
-// {
-// const Vector *hostagePos; // 413
-// class CNavArea *hostageArea; // 435
-// {
-// class ShortestPathCost pc; // 438
-// float travelDistance; // 439
-// NavAreaTravelDistance(CNavArea *startArea,
-// class CNavArea *endArea,
-// class ShortestPathCost &costFunc); // 439
-// }
-// IsValid(CHostage *const this); // 418
-// IsFollowingSomeone(CHostage *const this); // 421
-// }
-// }
-// }
+ if (m_owner == NULL)
+ return NULL;
+
+ CNavArea *startArea = m_owner->GetLastKnownArea();
+
+ if (startArea == NULL)
+ return NULL;
+
+ CHostage *close = NULL;
+ const Vector *closePos = NULL;
+ float closeDistance = 9999999999.9f;
+
+ for (int i = 0; i < m_hostageCount; ++i)
+ {
+ CHostage *hostage = m_hostage[i].hostage;
+ const Vector *hostagePos = NULL;
+
+ if (m_owner->m_iTeam == CT)
+ {
+ // we know exactly where the hostages are, and if they are alive
+ if (!m_hostage[i].hostage || !m_hostage[i].hostage->IsValid())
+ continue;
+
+ if (m_hostage[i].hostage->IsFollowingSomeone())
+ continue;
+
+ hostagePos = &hostage->pev->origin;
+ }
+ else
+ {
+ // use our memory of where we think the hostages are
+ if (m_hostage[i].isValid == false)
+ continue;
+
+ hostagePos = &m_hostage[i].knownPos;
+ }
+
+ CNavArea *hostageArea = TheNavAreaGrid.GetNearestNavArea(hostagePos);
+
+ if (hostageArea != NULL)
+ {
+ ShortestPathCost pc;
+ float travelDistance = NavAreaTravelDistance(startArea, hostageArea, pc);
+
+ if (travelDistance >= 0.0f && travelDistance < closeDistance)
+ {
+ closePos = hostagePos;
+ closeDistance = travelDistance;
+ close = hostage;
+ }
+ }
+ }
+
+ // return where we think the hostage is
+ if (knowPos != NULL && closePos != NULL)
+ {
+ knowPos = const_cast(closePos);
+ }
+
+ return close;
}
+// Return the location of a "free" hostage, or NULL if we dont know of any
+
/* <3fdbd3> ../cstrike/dlls/bot/cs_gamestate.cpp:461 */
-NOBODY const Vector *CSGameState::GetRandomFreeHostagePosition(void)
+const Vector *CSGameState::GetRandomFreeHostagePosition(void)
{
-// {
-// const Vector *freePos; // 466
-// int freeCount; // 467
-// {
-// int i; // 469
-// {
-// const class HostageInfo *info; // 471
-// IsFollowingSomeone(CHostage *const this); // 480
-// }
-// }
-// }
+ // TODO: use static?
+ const Vector *freePos[MAX_HOSTAGES];
+ int freeCount = 0;
+
+ if (m_owner == NULL)
+ return NULL;
+
+ for (int i = 0; i < m_hostageCount; ++i)
+ {
+ const HostageInfo *info = &m_hostage[i];
+ const Vector *hostagePos = NULL;
+
+ if (m_owner->m_iTeam == CT)
+ {
+ // we know exactly where the hostages are, and if they are alive
+ if (!info->hostage || !info->hostage->IsAlive())
+ continue;
+
+ // escorted hostages are not "free"
+ if (info->hostage->IsFollowingSomeone())
+ continue;
+
+ freePos[ freeCount++ ] = &info->hostage->pev->origin;
+ }
+ else
+ {
+ // use our memory of where we think the hostages are
+ if (info->isValid == false)
+ continue;
+
+ freePos[ freeCount++ ] = &info->knownPos;
+ }
+ }
+
+ if (freeCount)
+ {
+ return freePos[RANDOM_LONG(0, freeCount - 1)];
+ }
+
+ return NULL;
}
+// If we can see any of the positions where we think a hostage is, validate it
+// Return status of any changes (a hostage died or was moved)
+
/* <3fdcd2> ../cstrike/dlls/bot/cs_gamestate.cpp:509 */
-NOBODY unsigned char CSGameState::ValidateHostagePositions(void)
+CSGameState::ValidateStatusType CSGameState::ValidateHostagePositions(void)
{
-// {
-// float const validateInterval; // 515
-// TraceResult result; // 520
-// unsigned char status; // 521
-// int i; // 523
-// int startValidCount; // 524
-// int endValidCount; // 605
-// IsElapsed(const class CountdownTimer *const this); // 512
-// Start(CountdownTimer *const this,
-// float duration); // 516
-// {
-// class HostageInfo *info; // 531
-// {
-// float const tolerance; // 594
-// IsValid(CHostage *const this); // 576
-// IsFollowingSomeone(CHostage *const this); // 586
-// operator-(const Vector *const this,
-// const Vector &v); // 595
-// IsLengthGreaterThan(const Vector *const this,
-// float length); // 595
-// }
-// IsFollowingSomeone(CHostage *const this); // 541
-// }
-// }
+ // limit how often we validate
+ if (!m_validateInterval.IsElapsed())
+ return NO_CHANGE;
+
+ const float validateInterval = 0.5f;
+ m_validateInterval.Start(validateInterval);
+
+ // check the status of hostages
+ ValidateStatusType status = NO_CHANGE;
+
+ int i;
+ int startValidCount = 0;
+ for (i = 0; i < m_hostageCount; ++i)
+ {
+ if (m_hostage[i].isValid)
+ ++startValidCount;
+ }
+
+ for (i = 0; i < m_hostageCount; ++i)
+ {
+ HostageInfo *info = &m_hostage[i];
+
+ if (!info->hostage)
+ continue;
+
+ // if we can see a hostage, update our knowledge of it
+ if (m_owner->IsVisible(&info->hostage->pev->origin, CHECK_FOV))
+ {
+ if (info->hostage->pev->takedamage == DAMAGE_YES)
+ {
+ // live hostage
+ // if hostage is being escorted by a CT, we don't "see" it, we see the CT
+ if (info->hostage->IsFollowingSomeone())
+ {
+ info->isValid = false;
+ }
+ else
+ {
+ info->knownPos = info->hostage->pev->origin;
+ info->isValid = true;
+ }
+ }
+ else
+ {
+ // dead hostage
+ // if we thought it was alive, this is news to us
+ if (info->isAlive)
+ status |= HOSTAGE_DIED;
+
+ info->isAlive = false;
+ info->isValid = false;
+ }
+
+ continue;
+ }
+
+ // if we dont know where this hostage is, nothing to validate
+ if (!info->isValid)
+ continue;
+
+ // can't directly see this hostage
+ // check line of sight to where we think this hostage is, to see if we noticed that is has moved
+ if (m_owner->IsVisible(&info->knownPos, CHECK_FOV))
+ {
+ // we can see where we thought the hostage was - verify it is still there and alive
+ if (info->hostage->pev->takedamage != DAMAGE_YES)
+ {
+ // since we have line of sight to an invalid hostage, it must be dead
+ // discovered that hostage has been killed
+ status |= HOSTAGE_DIED;
+
+ info->isAlive = false;
+ info->isValid = false;
+ continue;
+ }
+
+ if (info->hostage->IsFollowingSomeone())
+ {
+ // discovered the hostage has been taken
+ status |= HOSTAGE_GONE;
+ info->isValid = false;
+ continue;
+ }
+
+ const float tolerance = 50.0f;
+ if ((info->hostage->pev->origin - info->knownPos).IsLengthGreaterThan(tolerance))
+ {
+ // discovered that hostage has been moved
+ status |= HOSTAGE_GONE;
+ info->isValid = false;
+ continue;
+ }
+ }
+ }
+
+ int endValidCount = 0;
+ for (i = 0; i < m_hostageCount; ++i)
+ {
+ if (m_hostage[i].isValid)
+ ++endValidCount;
+ }
+
+ if (endValidCount == 0 && startValidCount > 0)
+ {
+ // we discovered all the hostages are gone
+ status &= ~HOSTAGE_GONE;
+ status |= HOSTAGES_ALL_GONE;
+ }
+
+ return status;
}
+// Return the nearest visible free hostage
+// Since we can actually see any hostage we return, we know its actual position
+
/* <3fdef7> ../cstrike/dlls/bot/cs_gamestate.cpp:626 */
-NOBODY CHostage *CSGameState::GetNearestVisibleFreeHostage(void)
+CHostage *CSGameState::GetNearestVisibleFreeHostage(void) const
{
-// {
-// class CHostage *close; // 628
-// float closeRangeSq; // 629
-// float rangeSq; // 630
-// Vector pos; // 632
-// {
-// int i; // 634
-// {
-// const class HostageInfo *info; // 636
-// IsFollowingSomeone(CHostage *const this); // 643
-// operator+(const Vector *const this,
-// const Vector &v); // 647
-// operator-(const Vector *const this,
-// const Vector &v); // 648
-// LengthSquared(const Vector *const this); // 648
-// }
-// }
-// }
+ CHostage *close = NULL;
+ float closeRangeSq = 999999999.9f;
+ float rangeSq;
+
+ Vector pos;
+
+ for (int i = 0; i < m_hostageCount; ++i)
+ {
+ const HostageInfo *info = &m_hostage[i];
+
+ if (!info->hostage)
+ continue;
+
+ // if the hostage is dead or rescued, its not free
+ if (info->hostage->pev->takedamage != DAMAGE_YES)
+ continue;
+
+ // if this hostage is following someone, its not free
+ if (info->hostage->IsFollowingSomeone())
+ continue;
+
+ // TODO: Use travel distance here
+ pos = info->hostage->pev->origin + Vector(0, 0, HumanHeight * 0.75f);
+ rangeSq = (pos - m_owner->pev->origin).LengthSquared();
+
+ if (rangeSq < closeRangeSq)
+ {
+ if (!m_owner->IsVisible(&pos))
+ continue;
+
+ close = info->hostage;
+ closeRangeSq = rangeSq;
+ }
+ }
+
+ return close;
}
+// Return true if there are no free hostages
+
/* <3fe064> ../cstrike/dlls/bot/cs_gamestate.cpp:668 */
-NOBODY bool CSGameState::AreAllHostagesBeingRescued(void)
+bool CSGameState::AreAllHostagesBeingRescued(void) const
{
-// {
-// bool isAllDead; // 674
-// {
-// int i; // 676
-// {
-// const class HostageInfo *info; // 678
-// IsValid(CHostage *const this); // 683
-// IsFollowingSomeone(CHostage *const this); // 685
-// }
-// }
-// }
+ // if the hostages have all been rescued, they are not being rescued any longer
+ if (m_allHostagesRescued)
+ return false;
+
+ bool isAllDead = true;
+
+ for (int i = 0; i < m_hostageCount; ++i)
+ {
+ const HostageInfo *info = &m_hostage[i];
+
+ if (m_owner->m_iTeam == CT)
+ {
+ // CT's have perfect knowledge via their radar
+ if (info->hostage != NULL && info->hostage->IsValid())
+ {
+ if (!info->hostage->IsFollowingSomeone())
+ return false;
+
+ isAllDead = false;
+ }
+ }
+ else
+ {
+ if (info->isValid && info->isAlive)
+ return false;
+
+ if (info->isAlive)
+ isAllDead = false;
+ }
+ }
+
+ // if all of the remaining hostages are dead, they arent being rescued
+ if (isAllDead)
+ return false;
+
+ return true;
}
+// All hostages have been rescued or are dead
+
/* <3fe148> ../cstrike/dlls/bot/cs_gamestate.cpp:712 */
-NOBODY bool CSGameState::AreAllHostagesGone(void)
+bool CSGameState::AreAllHostagesGone(void) const
{
-// {
-// int i; // 718
-// {
-// const class HostageInfo *info; // 720
-// }
-// }
+ if (m_allHostagesRescued)
+ return true;
+
+ // do we know that all the hostages are dead
+ for (int i = 0; i < m_hostageCount; ++i)
+ {
+ const HostageInfo *info = &m_hostage[i];
+
+ if (m_owner->m_iTeam == CT)
+ {
+ // CT's have perfect knowledge via their radar
+ if (info->hostage->IsAlive())// == DAMAGE_YES)
+ return false;
+ }
+ else
+ {
+ if (info->isValid && info->isAlive)
+ return false;
+ }
+ }
+
+ return true;
}
+// Someone told us all the hostages are gone
+
/* <3fe1a2> ../cstrike/dlls/bot/cs_gamestate.cpp:742 */
-NOBODY void CSGameState::AllHostagesGone(void)
+void CSGameState::AllHostagesGone(void)
{
-// {
-// int i; // 744
-// }
+ for (int i = 0; i < m_hostageCount; ++i)
+ m_hostage[i].isValid = false;
}
diff --git a/regamedll/dlls/bot/cs_gamestate.h b/regamedll/dlls/bot/cs_gamestate.h
index 5f79f940..45529041 100644
--- a/regamedll/dlls/bot/cs_gamestate.h
+++ b/regamedll/dlls/bot/cs_gamestate.h
@@ -33,29 +33,19 @@
#endif
class CCSBot;
-//class CHostage;
+// This class represents the game state as known by a particular bot
class CSGameState
{
public:
- CSGameState(void);
+ CSGameState() {};
CSGameState(CCSBot *owner);
- struct HostageInfo
- {
- CHostage *hostage;
- Vector knownPos;
- bool isValid;
- bool isAlive;
- bool isFree;
- };/* size: 20, cachelines: 1, members: 5 */
-
- NOBODY void Reset(void);
- // Event handling
- NOBODY void OnEvent(GameEventType event, CBaseEntity *entity, CBaseEntity *other);
- // true if round has been won or lost (but not yet reset)
- NOBODY bool IsRoundOver(void) const;
+ void Reset(void);
+ void OnEvent(GameEventType event, CBaseEntity *entity, CBaseEntity *other); // Event handling
+ bool IsRoundOver(void) const; // true if round has been won or lost (but not yet reset)
+ // bomb defuse scenario
enum BombState
{
MOVING, // being carried by a Terrorist
@@ -64,106 +54,101 @@ public:
DEFUSED, // the bomb has been defused
EXPLODED, // the bomb has exploded
};
- bool IsBombMoving(void) const
- {
- return (m_bombState == MOVING);
- }
- bool IsBombLoose(void) const
- {
- return (m_bombState == LOOSE);
- }
- bool IsBombPlanted(void) const
- {
- return (m_bombState == PLANTED);
- }
- bool IsBombDefused(void) const
- {
- return (m_bombState == DEFUSED);
- }
- bool IsBombExploded(void) const
- {
- return (m_bombState == EXPLODED);
- }
- // we see the loose bomb
- NOBODY void UpdateLooseBomb(const Vector *pos);
- // how long has is been since we saw the loose bomb
- NOBODY float TimeSinceLastSawLooseBomb(void) const;
- // do we know where the loose bomb is
- NOBODY bool IsLooseBombLocationKnown(void) const;
- // we see the bomber
- NOBODY void UpdateBomber(const Vector *pos);
- // how long has is been since we saw the bomber
- NOBODY float TimeSinceLastSawBomber(void) const;
- // we see the planted bomb
- NOBODY void UpdatePlantedBomb(const Vector *pos);
- // do we know where the bomb was planted
- NOBODY bool IsPlantedBombLocationKnown(void) const;
- // mark bombsite as the location of the planted bomb
- NOBODY void MarkBombsiteAsPlanted(int zoneIndex);
- enum { UNKNOWN = -1 };
- // return the zone index of the planted bombsite, or UNKNOWN
- NOBODY int GetPlantedBombsite(void) const;
- // return true if we are currently in the bombsite where the bomb is planted
- NOBODY bool IsAtPlantedBombsite(void) const;
- // return the zone index of the next bombsite to search
- NOBODY int GetNextBombsiteToSearch(void);
- // return true if given bombsite has been cleared
- NOBODY bool IsBombsiteClear(int zoneIndex) const;
- // mark bombsite as clear
- NOBODY void ClearBombsite(int zoneIndex);
- // return where we think the bomb is, or NULL if we don't know
- NOBODY const Vector *GetBombPosition(void) const;
+ bool IsBombMoving(void) const { return (m_bombState == MOVING); }
+ bool IsBombLoose(void) const { return (m_bombState == LOOSE); }
+ bool IsBombPlanted(void) const { return (m_bombState == PLANTED); }
+ bool IsBombDefused(void) const { return (m_bombState == DEFUSED); }
+ bool IsBombExploded(void) const { return (m_bombState == EXPLODED); }
+
+ void UpdateLooseBomb(const Vector *pos); // we see the loose bomb
+ float TimeSinceLastSawLooseBomb(void) const; // how long has is been since we saw the loose bomb
+ bool IsLooseBombLocationKnown(void) const; // do we know where the loose bomb is
- NOBODY CHostage *GetNearestFreeHostage(Vector *knowPos);
- NOBODY const Vector *GetRandomFreeHostagePosition(void);
- NOBODY bool AreAllHostagesBeingRescued(void);
- NOBODY bool AreAllHostagesGone(void);
- NOBODY void AllHostagesGone(void);
- bool HaveSomeHostagesBeenTaken(void)
- {
- return m_haveSomeHostagesBeenTaken;
- }
- void HostageWasTaken(void)
- {
- m_haveSomeHostagesBeenTaken = true;
- }
- NOBODY CHostage *GetNearestVisibleFreeHostage(void);
- NOBODY unsigned char ValidateHostagePositions(void);
- NOBODY void SetBombState(BombState state);
- BombState GetBombState(void)
- {
- return m_bombState;
- }
- CBaseEntity *GetNearestHostage(void)
- {
- UNTESTED
- // TODO: Not implemented
+ void UpdateBomber(const Vector *pos); // we see the bomber
+ float TimeSinceLastSawBomber(void) const; // how long has is been since we saw the bomber
- //CHostage *pHostage = g_pHostages->GetClosestHostage(m_owner->pev->origin);
- //return GetClassPtr((CHostage *)pHostage->pev);
- }
- NOBODY void InitializeHostageInfo(void);
+ void UpdatePlantedBomb(const Vector *pos); // we see the planted bomb
+ bool IsPlantedBombLocationKnown(void) const; // do we know where the bomb was planted
+ void MarkBombsiteAsPlanted(int zoneIndex); // mark bombsite as the location of the planted bomb
+
+ enum { UNKNOWN = -1 };
+ int GetPlantedBombsite(void) const; // return the zone index of the planted bombsite, or UNKNOWN
+ bool IsAtPlantedBombsite(void) const; // return true if we are currently in the bombsite where the bomb is planted
+
+ int GetNextBombsiteToSearch(void); // return the zone index of the next bombsite to search
+ bool IsBombsiteClear(int zoneIndex) const; // return true if given bombsite has been cleared
+ void ClearBombsite(int zoneIndex); // mark bombsite as clear
+
+ const Vector *GetBombPosition(void) const; // return where we think the bomb is, or NULL if we don't know
+
+ // hostage rescue scenario
+ CHostage *GetNearestFreeHostage(Vector *knowPos = NULL) const; // return the closest free hostage, and where we think it is (knowPos)
+ const Vector *GetRandomFreeHostagePosition(void);
+ bool AreAllHostagesBeingRescued(void) const; // return true if there are no free hostages
+ bool AreAllHostagesGone(void) const; // all hostages have been rescued or are dead
+ void AllHostagesGone(void); // someone told us all the hostages are gone
+ bool HaveSomeHostagesBeenTaken(void) const { return m_haveSomeHostagesBeenTaken; } // return true if one or more hostages have been moved by the CT's
+ void HostageWasTaken(void) { m_haveSomeHostagesBeenTaken = true; } // someone told us a CT is talking to a hostage
+
+ CHostage *GetNearestVisibleFreeHostage(void) const;
+
+ // hostage rescue scenario
+ enum ValidateStatusType:uint8
+ {
+ NO_CHANGE = 0x00,
+ HOSTAGE_DIED = 0x01,
+ HOSTAGE_GONE = 0x02,
+ HOSTAGES_ALL_GONE = 0x04
+ };
+ ValidateStatusType ValidateHostagePositions(void); // update our knowledge with what we currently see - returns bitflag events
+
+#ifndef HOOK_GAMEDLL
private:
- CCSBot *m_owner;
- bool m_isRoundOver;
- BombState m_bombState;
+#endif // HOOK_GAMEDLL
+
+ CCSBot *m_owner; // who owns this gamestate
+ bool m_isRoundOver; // true if round is over, but no yet reset
+
+ // bomb defuse scenario
+ void SetBombState(BombState state);
+ BombState GetBombState(void) { return m_bombState; }
+
+ BombState m_bombState; // what we think the bomb is doing
+
IntervalTimer m_lastSawBomber;
Vector m_bomberPos;
+
IntervalTimer m_lastSawLooseBomb;
Vector m_looseBombPos;
- bool m_isBombsiteClear[4];
- int m_bombsiteSearchOrder[4];
+
+ bool m_isBombsiteClear[4]; // corresponds to zone indices in CCSBotManager
+ int m_bombsiteSearchOrder[4]; // randomized order of bombsites to search
int m_bombsiteCount;
- int m_bombsiteSearchIndex;
- int m_plantedBombsite;
- bool m_isPlantedBombPosKnown;
+ int m_bombsiteSearchIndex; // the next step in the search
+
+ int m_plantedBombsite; // zone index of the bombsite where the planted bomb is
+
+ bool m_isPlantedBombPosKnown; // if true, we know the exact location of the bomb
Vector m_plantedBombPos;
- struct HostageInfo m_hostage[12];
- int m_hostageCount;
+
+ // hostage rescue scenario
+ struct HostageInfo
+ {
+ CHostage *hostage;
+ Vector knownPos;
+ bool isValid;
+ bool isAlive;
+ bool isFree; // not being escorted by a CT
+ }
+ m_hostage[ MAX_HOSTAGES ];
+ int m_hostageCount; // number of hostages left in map
CountdownTimer m_validateInterval;
- bool m_allHostagesRescued;
- bool m_haveSomeHostagesBeenTaken;
+ NOXREF CBaseEntity *GetNearestHostage(void) const; // return the closest live hostage
+ void InitializeHostageInfo(void); // initialize our knowledge of the number and location of hostages
+
+ bool m_allHostagesRescued; // if true, so every hostages been is rescued
+ bool m_haveSomeHostagesBeenTaken; // true if a hostage has been moved by a CT (and we've seen it)
};/* size: 348, cachelines: 6, members: 19 */
diff --git a/regamedll/dlls/bot/states/cs_bot_attack.cpp b/regamedll/dlls/bot/states/cs_bot_attack.cpp
index 21297bcc..0e7bf412 100644
--- a/regamedll/dlls/bot/states/cs_bot_attack.cpp
+++ b/regamedll/dlls/bot/states/cs_bot_attack.cpp
@@ -1,7 +1,7 @@
#include "precompiled.h"
/* <519735> ../cstrike/dlls/bot/states/cs_bot_attack.cpp:16 */
-NOBODY void AttackState::OnEnter(CCSBot *me)
+NOBODY void AttackState::__MAKE_VHOOK(OnEnter)(CCSBot *me)
{
// {
// class CBasePlayer *enemy; // 18
@@ -43,7 +43,7 @@ NOBODY void AttackState::StopAttacking(CCSBot *me)
}
/* <51997e> ../cstrike/dlls/bot/states/cs_bot_attack.cpp:152 */
-NOBODY void AttackState::OnUpdate(CCSBot *me)
+NOBODY void AttackState::__MAKE_VHOOK(OnUpdate)(CCSBot *me)
{
// {
// class CBasePlayerWeapon *weapon; // 161
@@ -149,7 +149,7 @@ NOBODY void AttackState::OnUpdate(CCSBot *me)
}
/* <5198d4> ../cstrike/dlls/bot/states/cs_bot_attack.cpp:578 */
-NOBODY void AttackState::OnExit(CCSBot *me)
+NOBODY void AttackState::__MAKE_VHOOK(OnExit)(CCSBot *me)
{
// ForgetNoise(CCSBot *const this); // 585
// PopPostureContext(CBot *const this); // 589
@@ -157,3 +157,22 @@ NOBODY void AttackState::OnExit(CCSBot *me)
// StopRapidFire(CCSBot *const this); // 597
// ClearSurpriseDelay(CCSBot *const this); // 598
}
+
+#ifdef HOOK_GAMEDLL
+
+void AttackState::OnEnter(CCSBot *me)
+{
+ OnEnter_(me);
+}
+
+void AttackState::OnUpdate(CCSBot *me)
+{
+ OnUpdate_(me);
+}
+
+void AttackState::OnExit(CCSBot *me)
+{
+ OnExit_(me);
+}
+
+#endif // HOOK_GAMEDLL
\ No newline at end of file
diff --git a/regamedll/dlls/bot/states/cs_bot_buy.cpp b/regamedll/dlls/bot/states/cs_bot_buy.cpp
index e17479b3..b049eaae 100644
--- a/regamedll/dlls/bot/states/cs_bot_buy.cpp
+++ b/regamedll/dlls/bot/states/cs_bot_buy.cpp
@@ -6,7 +6,7 @@ NOBODY bool HasDefaultPistol(CCSBot *me)
}
/* <5299e4> ../cstrike/dlls/bot/states/cs_bot_buy.cpp:37 */
-NOBODY void BuyState::OnEnter(CCSBot *me)
+NOBODY void BuyState::__MAKE_VHOOK(OnEnter)(CCSBot *me)
{
// {
// class CCSBotManager *ctrl; // 48
@@ -27,7 +27,7 @@ NOBODY inline WeaponType GetWeaponType(const char *alias)
}
/* <529753> ../cstrike/dlls/bot/states/cs_bot_buy.cpp:241 */
-NOBODY void BuyState::OnUpdate(CCSBot *me)
+NOBODY void BuyState::__MAKE_VHOOK(OnUpdate)(CCSBot *me)
{
// {
// bool inBuyZone; // 273
@@ -84,6 +84,25 @@ NOBODY void BuyState::OnUpdate(CCSBot *me)
}
/* <5296f1> ../cstrike/dlls/bot/states/cs_bot_buy.cpp:529 */
-NOBODY void BuyState::OnExit(CCSBot *me)
+NOBODY void BuyState::__MAKE_VHOOK(OnExit)(CCSBot *me)
{
}
+
+#ifdef HOOK_GAMEDLL
+
+void BuyState::OnEnter(CCSBot *me)
+{
+ OnEnter_(me);
+}
+
+void BuyState::OnUpdate(CCSBot *me)
+{
+ OnUpdate_(me);
+}
+
+void BuyState::OnExit(CCSBot *me)
+{
+ OnExit_(me);
+}
+
+#endif // HOOK_GAMEDLL
diff --git a/regamedll/dlls/bot/states/cs_bot_defuse_bomb.cpp b/regamedll/dlls/bot/states/cs_bot_defuse_bomb.cpp
index 47d86d46..7f2a3f26 100644
--- a/regamedll/dlls/bot/states/cs_bot_defuse_bomb.cpp
+++ b/regamedll/dlls/bot/states/cs_bot_defuse_bomb.cpp
@@ -1,7 +1,7 @@
#include "precompiled.h"
/* <539f0e> ../cstrike/dlls/bot/states/cs_bot_defuse_bomb.cpp:16 */
-NOBODY void DefuseBombState::OnEnter(CCSBot *me)
+NOBODY void DefuseBombState::__MAKE_VHOOK(OnEnter)(CCSBot *me)
{
// Say(BotChatterInterface *const this,
// const char *phraseName,
@@ -10,7 +10,7 @@ NOBODY void DefuseBombState::OnEnter(CCSBot *me)
}
/* <539eac> ../cstrike/dlls/bot/states/cs_bot_defuse_bomb.cpp:27 */
-NOBODY void DefuseBombState::OnUpdate(CCSBot *me)
+NOBODY void DefuseBombState::__MAKE_VHOOK(OnUpdate)(CCSBot *me)
{
// {
// const Vector *bombPos; // 29
@@ -19,10 +19,29 @@ NOBODY void DefuseBombState::OnUpdate(CCSBot *me)
}
/* <539e36> ../cstrike/dlls/bot/states/cs_bot_defuse_bomb.cpp:73 */
-NOBODY void DefuseBombState::OnExit(CCSBot *me)
+NOBODY void DefuseBombState::__MAKE_VHOOK(OnExit)(CCSBot *me)
{
// SetTask(CCSBot *const this,
// enum TaskType task,
// class CBaseEntity *entity); // 77
// ClearLookAt(CCSBot *const this); // 79
}
+
+#ifdef HOOK_GAMEDLL
+
+void DefuseBombState::OnEnter(CCSBot *me)
+{
+ OnEnter_(me);
+}
+
+void DefuseBombState::OnUpdate(CCSBot *me)
+{
+ OnUpdate_(me);
+}
+
+void DefuseBombState::OnExit(CCSBot *me)
+{
+ OnExit_(me);
+}
+
+#endif // HOOK_GAMEDLL
diff --git a/regamedll/dlls/bot/states/cs_bot_escape_from_bomb.cpp b/regamedll/dlls/bot/states/cs_bot_escape_from_bomb.cpp
index 612d0ca7..b55b5cbe 100644
--- a/regamedll/dlls/bot/states/cs_bot_escape_from_bomb.cpp
+++ b/regamedll/dlls/bot/states/cs_bot_escape_from_bomb.cpp
@@ -1,13 +1,13 @@
#include "precompiled.h"
/* <5499ae> ../cstrike/dlls/bot/states/cs_bot_escape_from_bomb.cpp:16 */
-NOBODY void EscapeFromBombState::OnEnter(CCSBot *me)
+NOBODY void EscapeFromBombState::__MAKE_VHOOK(OnEnter)(CCSBot *me)
{
// DestroyPath(CCSBot *const this); // 20
}
/* <549be9> ../cstrike/dlls/bot/states/cs_bot_escape_from_bomb.cpp:28 */
-NOBODY void EscapeFromBombState::OnUpdate(CCSBot *me)
+NOBODY void EscapeFromBombState::__MAKE_VHOOK(OnUpdate)(CCSBot *me)
{
// {
// const Vector *bombPos; // 30
@@ -21,6 +21,25 @@ NOBODY void EscapeFromBombState::OnUpdate(CCSBot *me)
}
/* <549976> ../cstrike/dlls/bot/states/cs_bot_escape_from_bomb.cpp:60 */
-NOBODY void EscapeFromBombState::OnExit(CCSBot *me)
+NOBODY void EscapeFromBombState::__MAKE_VHOOK(OnExit)(CCSBot *me)
{
}
+
+#ifdef HOOK_GAMEDLL
+
+void EscapeFromBombState::OnEnter(CCSBot *me)
+{
+ OnEnter_(me);
+}
+
+void EscapeFromBombState::OnUpdate(CCSBot *me)
+{
+ OnUpdate_(me);
+}
+
+void EscapeFromBombState::OnExit(CCSBot *me)
+{
+ OnExit_(me);
+}
+
+#endif // HOOK_GAMEDLL
diff --git a/regamedll/dlls/bot/states/cs_bot_fetch_bomb.cpp b/regamedll/dlls/bot/states/cs_bot_fetch_bomb.cpp
index 427b3a7a..32324115 100644
--- a/regamedll/dlls/bot/states/cs_bot_fetch_bomb.cpp
+++ b/regamedll/dlls/bot/states/cs_bot_fetch_bomb.cpp
@@ -1,13 +1,13 @@
#include "precompiled.h"
/* <5587b3> ../cstrike/dlls/bot/states/cs_bot_fetch_bomb.cpp:17 */
-NOBODY void FetchBombState::OnEnter(CCSBot *me)
+NOBODY void FetchBombState::__MAKE_VHOOK(OnEnter)(CCSBot *me)
{
// DestroyPath(CCSBot *const this); // 19
}
/* <5587fa> ../cstrike/dlls/bot/states/cs_bot_fetch_bomb.cpp:26 */
-NOBODY void FetchBombState::OnUpdate(CCSBot *me)
+NOBODY void FetchBombState::__MAKE_VHOOK(OnUpdate)(CCSBot *me)
{
// {
// class CCSBotManager *ctrl; // 28
@@ -15,3 +15,17 @@ NOBODY void FetchBombState::OnUpdate(CCSBot *me)
// GetLooseBomb(CCSBotManager *const this); // 30
// }
}
+
+#ifdef HOOK_GAMEDLL
+
+void FetchBombState::OnEnter(CCSBot *me)
+{
+ OnEnter_(me);
+}
+
+void FetchBombState::OnUpdate(CCSBot *me)
+{
+ OnUpdate_(me);
+}
+
+#endif // HOOK_GAMEDLL
diff --git a/regamedll/dlls/bot/states/cs_bot_follow.cpp b/regamedll/dlls/bot/states/cs_bot_follow.cpp
index 805ff6d3..f337fa37 100644
--- a/regamedll/dlls/bot/states/cs_bot_follow.cpp
+++ b/regamedll/dlls/bot/states/cs_bot_follow.cpp
@@ -1,7 +1,7 @@
#include "precompiled.h"
/* <56918b> ../cstrike/dlls/bot/states/cs_bot_follow.cpp:16 */
-NOBODY void FollowState::OnEnter(CCSBot *me)
+NOBODY void FollowState::__MAKE_VHOOK(OnEnter)(CCSBot *me)
{
// DestroyPath(CCSBot *const this); // 20
// Invalidate(CountdownTimer *const this); // 33
@@ -27,7 +27,7 @@ NOBODY void FollowState::ComputeLeaderMotionState(float leaderSpeed)
}
/* <569368> ../cstrike/dlls/bot/states/cs_bot_follow.cpp:164 */
-NOBODY void FollowState::OnUpdate(CCSBot *me)
+NOBODY void FollowState::__MAKE_VHOOK(OnUpdate)(CCSBot *me)
{
// {
// float leaderSpeed; // 194
@@ -98,6 +98,25 @@ NOBODY void FollowState::OnUpdate(CCSBot *me)
}
/* <569231> ../cstrike/dlls/bot/states/cs_bot_follow.cpp:353 */
-NOBODY void FollowState::OnExit(CCSBot *me)
+NOBODY void FollowState::__MAKE_VHOOK(OnExit)(CCSBot *me)
{
}
+
+#ifdef HOOK_GAMEDLL
+
+void FollowState::OnEnter(CCSBot *me)
+{
+ OnEnter_(me);
+}
+
+void FollowState::OnUpdate(CCSBot *me)
+{
+ OnUpdate_(me);
+}
+
+void FollowState::OnExit(CCSBot *me)
+{
+ OnExit_(me);
+}
+
+#endif // HOOK_GAMEDLL
diff --git a/regamedll/dlls/bot/states/cs_bot_hide.cpp b/regamedll/dlls/bot/states/cs_bot_hide.cpp
index 4ee84e11..c1641ded 100644
--- a/regamedll/dlls/bot/states/cs_bot_hide.cpp
+++ b/regamedll/dlls/bot/states/cs_bot_hide.cpp
@@ -1,13 +1,13 @@
#include "precompiled.h"
/* <57c261> ../cstrike/dlls/bot/states/cs_bot_hide.cpp:22 */
-NOBODY void HideState::OnEnter(CCSBot *me)
+NOBODY void HideState::__MAKE_VHOOK(OnEnter)(CCSBot *me)
{
// GetFollowLeader(CCSBot *const this); // 50
}
/* <57c35e> ../cstrike/dlls/bot/states/cs_bot_hide.cpp:59 */
-NOBODY void HideState::OnUpdate(CCSBot *me)
+NOBODY void HideState::__MAKE_VHOOK(OnUpdate)(CCSBot *me)
{
// {
// class CCSBotManager *ctrl; // 61
@@ -110,7 +110,7 @@ NOBODY void HideState::OnUpdate(CCSBot *me)
}
/* <57c2c8> ../cstrike/dlls/bot/states/cs_bot_hide.cpp:450 */
-NOBODY void HideState::OnExit(CCSBot *me)
+NOBODY void HideState::__MAKE_VHOOK(OnExit)(CCSBot *me)
{
// ClearLookAt(CCSBot *const this); // 456
// ClearApproachPoints(CCSBot *const this); // 457
@@ -118,3 +118,22 @@ NOBODY void HideState::OnExit(CCSBot *me)
// OnExit(HideState *const this,
// class CCSBot *me); // 450
}
+
+#ifdef HOOK_GAMEDLL
+
+void HideState::OnEnter(CCSBot *me)
+{
+ OnEnter_(me);
+}
+
+void HideState::OnUpdate(CCSBot *me)
+{
+ OnUpdate_(me);
+}
+
+void HideState::OnExit(CCSBot *me)
+{
+ OnExit_(me);
+}
+
+#endif // HOOK_GAMEDLL
diff --git a/regamedll/dlls/bot/states/cs_bot_hunt.cpp b/regamedll/dlls/bot/states/cs_bot_hunt.cpp
index 1392a52c..8d6ff436 100644
--- a/regamedll/dlls/bot/states/cs_bot_hunt.cpp
+++ b/regamedll/dlls/bot/states/cs_bot_hunt.cpp
@@ -1,7 +1,7 @@
#include "precompiled.h"
/* <58e6e0> ../cstrike/dlls/bot/states/cs_bot_hunt.cpp:18 */
-NOBODY void HuntState::OnEnter(CCSBot *me)
+NOBODY void HuntState::__MAKE_VHOOK(OnEnter)(CCSBot *me)
{
// SetTask(CCSBot *const this,
// enum TaskType task,
@@ -10,7 +10,7 @@ NOBODY void HuntState::OnEnter(CCSBot *me)
}
/* <58e452> ../cstrike/dlls/bot/states/cs_bot_hunt.cpp:38 */
-NOBODY void HuntState::OnUpdate(CCSBot *me)
+NOBODY void HuntState::__MAKE_VHOOK(OnUpdate)(CCSBot *me)
{
// {
// class CCSBotManager *ctrl; // 40
@@ -58,6 +58,25 @@ NOBODY void HuntState::OnUpdate(CCSBot *me)
}
/* <58e418> ../cstrike/dlls/bot/states/cs_bot_hunt.cpp:211 */
-NOBODY void HuntState::OnExit(CCSBot *me)
+NOBODY void HuntState::__MAKE_VHOOK(OnExit)(CCSBot *me)
{
}
+
+#ifdef HOOK_GAMEDLL
+
+void HuntState::OnEnter(CCSBot *me)
+{
+ OnEnter_(me);
+}
+
+void HuntState::OnUpdate(CCSBot *me)
+{
+ OnUpdate_(me);
+}
+
+void HuntState::OnExit(CCSBot *me)
+{
+ OnExit_(me);
+}
+
+#endif // HOOK_GAMEDLL
\ No newline at end of file
diff --git a/regamedll/dlls/bot/states/cs_bot_idle.cpp b/regamedll/dlls/bot/states/cs_bot_idle.cpp
index cb3dde89..09049d3f 100644
--- a/regamedll/dlls/bot/states/cs_bot_idle.cpp
+++ b/regamedll/dlls/bot/states/cs_bot_idle.cpp
@@ -1,7 +1,7 @@
#include "precompiled.h"
/* <5a12ee> ../cstrike/dlls/bot/states/cs_bot_idle.cpp:26 */
-NOBODY void IdleState::OnEnter(CCSBot *me)
+NOBODY void IdleState::__MAKE_VHOOK(OnEnter)(CCSBot *me)
{
// DestroyPath(CCSBot *const this); // 28
// SetTask(CCSBot *const this,
@@ -10,7 +10,7 @@ NOBODY void IdleState::OnEnter(CCSBot *me)
}
/* <5a0c66> ../cstrike/dlls/bot/states/cs_bot_idle.cpp:46 */
-NOBODY void IdleState::OnUpdate(CCSBot *me)
+NOBODY void IdleState::__MAKE_VHOOK(OnUpdate)(CCSBot *me)
{
// {
// class CCSBotManager *ctrl; // 59
@@ -154,3 +154,17 @@ NOBODY void IdleState::OnUpdate(CCSBot *me)
// }
// }
}
+
+#ifdef HOOK_GAMEDLL
+
+void IdleState::OnEnter(CCSBot *me)
+{
+ OnEnter_(me);
+}
+
+void IdleState::OnUpdate(CCSBot *me)
+{
+ OnUpdate_(me);
+}
+
+#endif // HOOK_GAMEDLL
diff --git a/regamedll/dlls/bot/states/cs_bot_investigate_noise.cpp b/regamedll/dlls/bot/states/cs_bot_investigate_noise.cpp
index d0a18891..cde90b77 100644
--- a/regamedll/dlls/bot/states/cs_bot_investigate_noise.cpp
+++ b/regamedll/dlls/bot/states/cs_bot_investigate_noise.cpp
@@ -7,14 +7,14 @@ NOBODY void InvestigateNoiseState::AttendCurrentNoise(CCSBot *me)
}
/* <5b2f37> ../cstrike/dlls/bot/states/cs_bot_investigate_noise.cpp:38 */
-NOBODY void InvestigateNoiseState::OnEnter(CCSBot *me)
+NOBODY void InvestigateNoiseState::__MAKE_VHOOK(OnEnter)(CCSBot *me)
{
// AttendCurrentNoise(InvestigateNoiseState *const this,
// class CCSBot *me); // 40
}
/* <5b2fa2> ../cstrike/dlls/bot/states/cs_bot_investigate_noise.cpp:47 */
-NOBODY void InvestigateNoiseState::OnUpdate(CCSBot *me)
+NOBODY void InvestigateNoiseState::__MAKE_VHOOK(OnUpdate)(CCSBot *me)
{
// {
// float newNoiseDist; // 50
@@ -40,6 +40,25 @@ NOBODY void InvestigateNoiseState::OnUpdate(CCSBot *me)
}
/* <5b2e95> ../cstrike/dlls/bot/states/cs_bot_investigate_noise.cpp:129 */
-NOBODY void InvestigateNoiseState::OnExit(CCSBot *me)
+NOBODY void InvestigateNoiseState::__MAKE_VHOOK(OnExit)(CCSBot *me)
{
}
+
+#ifdef HOOK_GAMEDLL
+
+void InvestigateNoiseState::OnEnter(CCSBot *me)
+{
+ OnEnter_(me);
+}
+
+void InvestigateNoiseState::OnUpdate(CCSBot *me)
+{
+ OnUpdate_(me);
+}
+
+void InvestigateNoiseState::OnExit(CCSBot *me)
+{
+ OnExit_(me);
+}
+
+#endif // HOOK_GAMEDLL
diff --git a/regamedll/dlls/bot/states/cs_bot_move_to.cpp b/regamedll/dlls/bot/states/cs_bot_move_to.cpp
index d9de1f39..f2d3a928 100644
--- a/regamedll/dlls/bot/states/cs_bot_move_to.cpp
+++ b/regamedll/dlls/bot/states/cs_bot_move_to.cpp
@@ -1,7 +1,7 @@
#include "precompiled.h"
/* <5c4e91> ../cstrike/dlls/bot/states/cs_bot_move_to.cpp:21 */
-NOBODY void MoveToState::OnEnter(CCSBot *me)
+NOBODY void MoveToState::__MAKE_VHOOK(OnEnter)(CCSBot *me)
{
// {
// enum RouteType route; // 30
@@ -9,7 +9,7 @@ NOBODY void MoveToState::OnEnter(CCSBot *me)
}
/* <5c4edf> ../cstrike/dlls/bot/states/cs_bot_move_to.cpp:55 */
-NOBODY void MoveToState::OnUpdate(CCSBot *me)
+NOBODY void MoveToState::__MAKE_VHOOK(OnUpdate)(CCSBot *me)
{
// {
// class CCSBotManager *ctrl; // 76
@@ -82,6 +82,25 @@ NOBODY void MoveToState::OnUpdate(CCSBot *me)
}
/* <5c4e54> ../cstrike/dlls/bot/states/cs_bot_move_to.cpp:320 */
-NOBODY void MoveToState::OnExit(CCSBot *me)
+NOBODY void MoveToState::__MAKE_VHOOK(OnExit)(CCSBot *me)
{
}
+
+#ifdef HOOK_GAMEDLL
+
+void MoveToState::OnEnter(CCSBot *me)
+{
+ OnEnter_(me);
+}
+
+void MoveToState::OnUpdate(CCSBot *me)
+{
+ OnUpdate_(me);
+}
+
+void MoveToState::OnExit(CCSBot *me)
+{
+ OnExit_(me);
+}
+
+#endif // HOOK_GAMEDLL
diff --git a/regamedll/dlls/bot/states/cs_bot_plant_bomb.cpp b/regamedll/dlls/bot/states/cs_bot_plant_bomb.cpp
index 81439a77..45e122dd 100644
--- a/regamedll/dlls/bot/states/cs_bot_plant_bomb.cpp
+++ b/regamedll/dlls/bot/states/cs_bot_plant_bomb.cpp
@@ -1,35 +1,79 @@
#include "precompiled.h"
+// Plant the bomb.
+
/* <5d4160> ../cstrike/dlls/bot/states/cs_bot_plant_bomb.cpp:17 */
-NOBODY void PlantBombState::OnEnter(CCSBot *me)
+void PlantBombState::__MAKE_VHOOK(OnEnter)(CCSBot *me)
{
-// {
-// float yaw; // 25
-// class Vector2D dir; // 26
-// Vector down; // 28
-// GetFeetZ(const class CCSBot *const this); // 28
-// Vector(Vector *const this,
-// float X,
-// float Y,
-// float Z); // 28
-// }
+ me->Crouch();
+ me->SetDisposition(CCSBot::SELF_DEFENSE);
+
+ float yaw = me->pev->v_angle.y;
+ Vector2D dir(BotCOS(yaw), BotSIN(yaw));
+
+ Vector down(me->pev->origin.x + 10.0f * dir.x, me->pev->origin.y + 10.0f * dir.y, me->GetFeetZ());
+ me->SetLookAt("Plant bomb on floor", &down, PRIORITY_HIGH);
}
+// Plant the bomb.
+
/* <5d40d0> ../cstrike/dlls/bot/states/cs_bot_plant_bomb.cpp:36 */
-NOBODY void PlantBombState::OnUpdate(CCSBot *me)
+void PlantBombState::__MAKE_VHOOK(OnUpdate)(CCSBot *me)
{
-// {
-// class CBasePlayerWeapon *gun; // 38
-// bool holdingC4; // 39
-// float const timeout; // 59
-// SetTask(CCSBot *const this,
-// enum TaskType task,
-// class CBaseEntity *entity); // 54
-// }
+ CBasePlayerWeapon *gun = me->GetActiveWeapon();
+ bool holdingC4 = false;
+ if (gun != NULL)
+ {
+ if (FStrEq(STRING(gun->pev->classname), "weapon_c4"))
+ holdingC4 = true;
+ }
+
+ // if we aren't holding the C4, grab it, otherwise plant it
+ if (holdingC4)
+ me->PrimaryAttack();
+ else
+ me->SelectItem("weapon_c4");
+
+ // if we no longer have the C4, we've successfully planted
+ if (!me->IsCarryingBomb())
+ {
+ // move to a hiding spot and watch the bomb
+ me->SetTask(CCSBot::GUARD_TICKING_BOMB);
+ me->Hide();
+ }
+
+ // if we time out, it's because we slipped into a non-plantable area
+ const float timeout = 5.0f;
+ if (gpGlobals->time - me->GetStateTimestamp() > timeout)
+ me->Idle();
}
/* <5d4088> ../cstrike/dlls/bot/states/cs_bot_plant_bomb.cpp:65 */
-NOBODY void PlantBombState::OnExit(CCSBot *me)
+void PlantBombState::__MAKE_VHOOK(OnExit)(CCSBot *me)
{
-// ClearLookAt(CCSBot *const this); // 72
+ // equip our rifle (in case we were interrupted while holding C4)
+ me->EquipBestWeapon();
+ me->StandUp();
+ me->ResetStuckMonitor();
+ me->SetDisposition(CCSBot::ENGAGE_AND_INVESTIGATE);
+ me->ClearLookAt();
}
+
+#ifdef HOOK_GAMEDLL
+
+void PlantBombState::OnEnter(CCSBot *me)
+{
+ OnEnter_(me);
+}
+
+void PlantBombState::OnUpdate(CCSBot *me)
+{
+ OnUpdate_(me);
+}
+
+void PlantBombState::OnExit(CCSBot *me)
+{
+ OnExit_(me);
+}
+
+#endif // HOOK_GAMEDLL
diff --git a/regamedll/dlls/bot/states/cs_bot_use_entity.cpp b/regamedll/dlls/bot/states/cs_bot_use_entity.cpp
index 5e97f6a4..d63c953b 100644
--- a/regamedll/dlls/bot/states/cs_bot_use_entity.cpp
+++ b/regamedll/dlls/bot/states/cs_bot_use_entity.cpp
@@ -1,26 +1,68 @@
#include "precompiled.h"
+// Face the entity and "use" it
+// NOTE: This state assumes we are standing in range of the entity to be used, with no obstructions.
+
/* <5e3017> ../cstrike/dlls/bot/states/cs_bot_use_entity.cpp:17 */
-NOBODY void UseEntityState::OnEnter(CCSBot *me)
+void UseEntityState::__MAKE_VHOOK(OnEnter)(CCSBot *me)
{
+ ;
}
/* <5e308c> ../cstrike/dlls/bot/states/cs_bot_use_entity.cpp:21 */
-NOBODY void UseEntityState::OnUpdate(CCSBot *me)
+void UseEntityState::__MAKE_VHOOK(OnUpdate)(CCSBot *me)
{
-// {
-// float const useTimeout; // 25
-// Vector pos; // 33
-// {
-// class CCSBotManager *ctrl; // 39
-// }
-// }
-// OnUpdate(UseEntityState *const this,
-// class CCSBot *me); // 21
+ // in the very rare situation where two or more bots "used" a hostage at the same time,
+ // one bot will fail and needs to time out of this state
+ const float useTimeout = 5.0f;
+ if (me->GetStateTimestamp() - gpGlobals->time > useTimeout)
+ {
+ me->Idle();
+ return;
+ }
+
+ // look at the entity
+ Vector pos = m_entity->pev->origin + Vector(0, 0, HumanHeight * 0.5f);
+ me->SetLookAt("Use entity", &pos, PRIORITY_HIGH);
+
+ // if we are looking at the entity, "use" it and exit
+ if (me->IsLookingAtPosition(&pos))
+ {
+ if (TheCSBots()->GetScenario() == CCSBotManager::SCENARIO_RESCUE_HOSTAGES
+ && me->m_iTeam == CT
+ && me->GetTask() == CCSBot::COLLECT_HOSTAGES)
+ {
+ // we are collecting a hostage, assume we were successful - the update check will correct us if we weren't
+ me->IncreaseHostageEscortCount();
+ }
+
+ me->UseEnvironment();
+ me->Idle();
+ }
}
/* <5e304a> ../cstrike/dlls/bot/states/cs_bot_use_entity.cpp:54 */
-NOBODY void UseEntityState::OnExit(CCSBot *me)
+void UseEntityState::__MAKE_VHOOK(OnExit)(CCSBot *me)
{
-// ClearLookAt(CCSBot *const this); // 56
+ me->ClearLookAt();
+ me->ResetStuckMonitor();
}
+
+#ifdef HOOK_GAMEDLL
+
+void UseEntityState::OnEnter(CCSBot *me)
+{
+ OnEnter_(me);
+}
+
+void UseEntityState::OnUpdate(CCSBot *me)
+{
+ OnUpdate_(me);
+}
+
+void UseEntityState::OnExit(CCSBot *me)
+{
+ OnExit_(me);
+}
+
+#endif // HOOK_GAMEDLL
\ No newline at end of file
diff --git a/regamedll/dlls/career_tasks.cpp b/regamedll/dlls/career_tasks.cpp
index dba9f903..a263f55f 100644
--- a/regamedll/dlls/career_tasks.cpp
+++ b/regamedll/dlls/career_tasks.cpp
@@ -184,17 +184,12 @@ void CCareerTask::OnWeaponKill(int weaponId, int weaponClassId, bool headshot, b
while ((hostageEntity = UTIL_FindEntityByClassname(hostageEntity, "hostage_entity")) != NULL)
{
- CHostage *hostage = (CHostage *)hostageEntity;
-
- if (!hostage || hostage->pev->takedamage != DAMAGE_YES)
+ if (hostageEntity->pev->takedamage != DAMAGE_YES)
continue;
- if (hostage->m_improv)
- {
- if (!hostage->IsFollowingSomeone())
- continue;
- }
- else if (!hostage->m_hTargetEnt || hostage->m_State != CHostage::FOLLOW)
+ CHostage *hostage = static_cast(hostageEntity);
+
+ if (!hostage->IsFollowingSomeone())
continue;
if (hostage->IsValid() && hostage->m_target == pAttacker)
@@ -274,19 +269,10 @@ void CCareerTask::__MAKE_VHOOK(OnEvent)(GameEventType event, CBasePlayer *pVicti
if (hostageEntity->pev->takedamage != DAMAGE_YES)
continue;
- CHostage *hostage = reinterpret_cast(hostageEntity);
+ CHostage *hostage = static_cast(hostageEntity);
- if (hostage->m_improv)
- {
- if (!hostage->IsFollowingSomeone())
- {
- continue;
- }
- }
- else if (hostage->m_hTargetEnt == NULL || hostage->m_State != CHostage::FOLLOW)
- {
+ if (!hostage->IsFollowingSomeone())
continue;
- }
if (hostage->IsValid() && hostage->m_target == pAttacker)
++hostages_;
diff --git a/regamedll/dlls/career_tasks.h b/regamedll/dlls/career_tasks.h
index 02605d5a..671ca0bc 100644
--- a/regamedll/dlls/career_tasks.h
+++ b/regamedll/dlls/career_tasks.h
@@ -43,10 +43,7 @@ public:
public:
virtual void OnEvent(GameEventType event, CBasePlayer *pAttacker, CBasePlayer *pVictim);
virtual void Reset(void);
- virtual bool IsTaskCompletableThisRound(void)
- {
- return true;
- }
+ virtual bool IsTaskCompletableThisRound(void) { return true; }
#ifdef HOOK_GAMEDLL
@@ -61,26 +58,13 @@ public:
void OnWeaponKill(int weaponId, int weaponClassId, bool headshot, bool killerHasShield, CBasePlayer *pAttacker, CBasePlayer *pVictim);
void OnWeaponInjury(int weaponId, int weaponClassId, bool attackerHasShield, CBasePlayer *pAttacker);
- bool IsComplete(void)
- {
- return m_isComplete;
- }
- const char *GetTaskName(void)
- {
- return m_name;
- }
- int GetWeaponId(void)
- {
- return m_weaponId;
- }
- int GetWeaponClassId(void)
- {
- return m_weaponClassId;
- }
- bool IsValidFor(CBasePlayer *pPlayer)
- {
- return true;
- }
+ bool IsComplete(void) { return m_isComplete;}
+ const char *GetTaskName(void) { return m_name; }
+
+ int GetWeaponId(void) { return m_weaponId; }
+ int GetWeaponClassId(void) { return m_weaponClassId; }
+
+ bool IsValidFor(CBasePlayer *pPlayer) { return true; }
void SendPartialNotification(void);
private:
@@ -102,10 +86,37 @@ private:
};/* size: 44, cachelines: 1, members: 15 */
-typedef std::list CareerTaskList;
-
+typedef std::STD_LIST CareerTaskList;
typedef CareerTaskList::iterator CareerTaskListIt;
+typedef CCareerTask *(*TaskFactoryFunction)(const char *taskName, GameEventType event, const char *weaponName, int eventCount, bool mustLive, bool crossRounds, int nextId, bool isComplete);
+
+/* <1ef56d> ../cstrike/dlls/career_tasks.cpp:139 */
+class CPreventDefuseTask: public CCareerTask
+{
+public:
+ CPreventDefuseTask(const char *taskName, GameEventType event, const char *weaponName, int n, bool mustLive, bool crossRounds, int id, bool isComplete);
+public:
+ virtual void OnEvent(GameEventType event, CBasePlayer *pAttacker, CBasePlayer *pVictim);
+ virtual void Reset(void);
+ virtual bool IsTaskCompletableThisRound(void) { return m_bombPlantedThisRound && !m_defuseStartedThisRound; }
+
+#ifdef HOOK_GAMEDLL
+
+ void OnEvent_(GameEventType event, CBasePlayer *pAttacker, CBasePlayer *pVictim);
+ void Reset_(void);
+
+#endif // HOOK_GAMEDLL
+
+public:
+ static CCareerTask *NewTask(const char *taskName, GameEventType event, const char *weaponName, int n, bool mustLive, bool crossRounds, int id, bool isComplete);
+
+protected:
+ bool m_bombPlantedThisRound;
+ bool m_defuseStartedThisRound;
+
+};/* size: 48, cachelines: 1, members: 3 */
+
/* <1efed1> ../cstrike/dlls/career_tasks.cpp:636 */
class CCareerTaskManager
{
@@ -128,32 +139,15 @@ public:
bool AreAllTasksComplete(void);
int GetNumRemainingTasks(void);
float GetRoundElapsedTime(void);
- int GetTaskTime(void)
- {
- return m_taskTime;
- }
+ int GetTaskTime(void) { return m_taskTime; }
void SetFinishedTaskTime(int val);
- int GetFinishedTaskTime(void)
- {
- return m_finishedTaskTime;
- }
- int GetFinishedTaskRound(void)
- {
- return m_finishedTaskRound;
- }
- CareerTaskList *GetTasks(void)
- {
- return &m_tasks;
- }
+ int GetFinishedTaskTime(void) { return m_finishedTaskTime; }
+ int GetFinishedTaskRound(void) { return m_finishedTaskRound; }
+ CareerTaskList *GetTasks(void) { return &m_tasks; }
void LatchRoundEndMessage(void);
void UnlatchRoundEndMessage(void);
private:
-
-#if defined(_WIN32) && defined(HOOK_GAMEDLL)
- int unknown_padding1;
-#endif // HOOK_GAMEDLL
-
CareerTaskList m_tasks;
int m_nextId;
@@ -167,8 +161,6 @@ private:
};/* size: 36, cachelines: 1, members: 8 */
-typedef CCareerTask *(*TaskFactoryFunction)(const char *taskName, GameEventType event, const char *weaponName, int eventCount, bool mustLive, bool crossRounds, int nextId, bool isComplete);
-
struct TaskInfo
{
const char *taskName;
@@ -177,35 +169,6 @@ struct TaskInfo
};/* size: 12, cachelines: 1, members: 3 */
-/* <1ef56d> ../cstrike/dlls/career_tasks.cpp:139 */
-class CPreventDefuseTask: public CCareerTask
-{
-public:
- CPreventDefuseTask(const char *taskName, GameEventType event, const char *weaponName, int n, bool mustLive, bool crossRounds, int id, bool isComplete);
-public:
- virtual void OnEvent(GameEventType event, CBasePlayer *pAttacker, CBasePlayer *pVictim);
- virtual void Reset(void);
- virtual bool IsTaskCompletableThisRound(void)
- {
- return m_bombPlantedThisRound && !m_defuseStartedThisRound;
- }
-
-#ifdef HOOK_GAMEDLL
-
- void OnEvent_(GameEventType event, CBasePlayer *pAttacker, CBasePlayer *pVictim);
- void Reset_(void);
-
-#endif // HOOK_GAMEDLL
-
-public:
- static CCareerTask *NewTask(const char *taskName, GameEventType event, const char *weaponName, int n, bool mustLive, bool crossRounds, int id, bool isComplete);
-
-protected:
- bool m_bombPlantedThisRound;
- bool m_defuseStartedThisRound;
-
-};/* size: 48, cachelines: 1, members: 3 */
-
#ifdef HOOK_GAMEDLL
#define TheCareerTasks (*pTheCareerTasks)
diff --git a/regamedll/dlls/cbase.h b/regamedll/dlls/cbase.h
index ed453522..66d8d5fd 100644
--- a/regamedll/dlls/cbase.h
+++ b/regamedll/dlls/cbase.h
@@ -277,7 +277,7 @@ public:
operator int();
operator CBaseEntity*();
- operator CBasePlayer*() { return (CBasePlayer *)GET_PRIVATE(Get()); } // custom
+ operator CBasePlayer*() { return static_cast(GET_PRIVATE(Get())); } // custom
CBaseEntity *operator=(CBaseEntity *pEntity);
CBaseEntity *operator->();
diff --git a/regamedll/dlls/client.cpp b/regamedll/dlls/client.cpp
index 52b6ed1d..534b1b47 100644
--- a/regamedll/dlls/client.cpp
+++ b/regamedll/dlls/client.cpp
@@ -711,6 +711,7 @@ void Host_Say(edict_t *pEntity, int teamonly)
char *pszConsoleFormat = NULL;
bool consoleUsesPlaceName = false;
+ // team only
if (teamonly)
{
if (UTIL_IsGame("czero") && (player->m_iTeam == CT || player->m_iTeam == TERRORIST))
@@ -773,6 +774,7 @@ void Host_Say(edict_t *pEntity, int teamonly)
pszConsoleFormat = "(Spectator) %s : %s";
}
}
+ // everyone
else
{
if (bSenderDead)
@@ -2006,14 +2008,17 @@ BOOL HandleMenu_ChooseTeam(CBasePlayer *player, int slot)
break;
case MENU_SLOT_TEAM_VIP:
{
- if (mp->m_iMapHasVIPSafetyZone != MAP_HAVE_VIP_SAFETYZONE_YES || player->m_iTeam != CT)
+ if (mp->m_iMapHasVIPSafetyZone == MAP_HAVE_VIP_SAFETYZONE_YES && player->m_iTeam == CT)
+ {
+ mp->AddToVIPQueue(player);
+ CLIENT_COMMAND(ENT(player->pev), "slot10\n");
+ return TRUE;
+ }
+ else
{
return FALSE;
}
-
- mp->AddToVIPQueue(player);
- CLIENT_COMMAND(ENT(player->pev), "slot10\n");
- return TRUE;
+ break;
}
case MENU_SLOT_TEAM_RANDOM:
{
@@ -2198,6 +2203,7 @@ BOOL HandleMenu_ChooseTeam(CBasePlayer *player, int slot)
}
}
+ // If we already died and changed teams once, deny
if (player->m_bTeamChanged)
{
if (player->pev->deadflag != DEAD_NO)
@@ -4504,6 +4510,20 @@ void ClientPrecache(void)
PRECACHE_GENERIC("sprites/scope_arc_sw.tga");
m_usResetDecals = g_engfuncs.pfnPrecacheEvent(1, "events/decal_reset.sc");
+
+ /*Vector temp = g_vecZero;
+ ENGINE_FORCE_UNMODIFIED(force_exactfile, (float *)&temp, (float *)&temp, "sprites/scope_arc.tga");
+ ENGINE_FORCE_UNMODIFIED(force_exactfile, (float *)&temp, (float *)&temp, "sprites/scope_arc_nw.tga");
+ ENGINE_FORCE_UNMODIFIED(force_exactfile, (float *)&temp, (float *)&temp, "sprites/scope_arc_ne.tga");
+ ENGINE_FORCE_UNMODIFIED(force_exactfile, (float *)&temp, (float *)&temp, "sprites/scope_arc_sw.tga");
+
+
+ PRECACHE_GENERIC("sprites/scope_arc.tga");
+ PRECACHE_GENERIC("sprites/scope_arc_nw.tga");
+ PRECACHE_GENERIC("sprites/scope_arc_ne.tga");
+ PRECACHE_GENERIC("sprites/scope_arc_sw.tga");
+
+ m_usResetDecals = g_engfuncs.pfnPrecacheEvent(1, "events/decal_reset.sc");*/
}
/* <4a6e5> ../cstrike/dlls/client.cpp:4996 */
diff --git a/regamedll/dlls/combat.cpp b/regamedll/dlls/combat.cpp
index 3cae8f3b..61ce3694 100644
--- a/regamedll/dlls/combat.cpp
+++ b/regamedll/dlls/combat.cpp
@@ -362,7 +362,7 @@ Activity CBaseMonster::__MAKE_VHOOK(GetDeathActivity)(void)
}
// can we perform the prescribed death?
- if (LookupActivity(deathActivity) == ACTIVITY_NOT_AVAILABLE)
+ if (LookupActivity(deathActivity) == ACT_INVALID)
{
// no! did we fail to perform a directional death?
if (fTriedDirection)
@@ -384,7 +384,7 @@ Activity CBaseMonster::__MAKE_VHOOK(GetDeathActivity)(void)
}
}
- if (LookupActivity(deathActivity) == ACTIVITY_NOT_AVAILABLE)
+ if (LookupActivity(deathActivity) == ACT_INVALID)
{
// if we're still invalid, simple is our only option.
deathActivity = ACT_DIESIMPLE;
@@ -458,7 +458,7 @@ NOXREF Activity CBaseMonster::GetSmallFlinchActivity(void)
}
// do we have a sequence for the ideal activity?
- if (LookupActivity(flinchActivity) == ACTIVITY_NOT_AVAILABLE)
+ if (LookupActivity(flinchActivity) == ACT_INVALID)
{
flinchActivity = ACT_SMALL_FLINCH;
}
diff --git a/regamedll/dlls/gamerules.cpp b/regamedll/dlls/gamerules.cpp
index 64ba8abe..5d17dba6 100644
--- a/regamedll/dlls/gamerules.cpp
+++ b/regamedll/dlls/gamerules.cpp
@@ -38,8 +38,10 @@ BOOL CGameRules::__MAKE_VHOOK(CanHaveAmmo)(CBasePlayer *pPlayer, const char *psz
/* ../cstrike/dlls/gamerules.cpp:59 */
edict_t *CGameRules::__MAKE_VHOOK(GetPlayerSpawnSpot)(CBasePlayer *pPlayer)
{
+ // gat valid spawn point
edict_t *pentSpawnSpot = EntSelectSpawnPoint(pPlayer);
+ // Move the player to the place it said.
#ifndef PLAY_GAMEDLL
pPlayer->pev->origin = VARS(pentSpawnSpot)->origin + Vector(0, 0, 1);
#else
diff --git a/regamedll/dlls/gamerules.h b/regamedll/dlls/gamerules.h
index 0300d6f9..e526e959 100644
--- a/regamedll/dlls/gamerules.h
+++ b/regamedll/dlls/gamerules.h
@@ -64,6 +64,9 @@
#define MAX_MOTD_LENGTH 1536 // (MAX_MOTD_CHUNK * 4)
// custom enum
+#define WINNER_NONE 0
+#define WINNER_DRAW 1
+
enum
{
WINSTATUS_CTS = 1,
@@ -187,10 +190,7 @@ public:
return FALSE;
}
virtual BOOL IsCoOp(void) = 0;
- virtual const char *GetGameDescription(void)
- {
- return "Counter-Strike";
- }
+ virtual const char *GetGameDescription(void) { return "Counter-Strike"; } // this is the game name that gets seen in the server browser
virtual BOOL ClientConnected(edict_t *pEntity, const char *pszName, const char *pszAddress, char *szRejectReason) = 0;
virtual void InitHUD(CBasePlayer *pl) = 0;
virtual void ClientDisconnected(edict_t *pClient) = 0;
@@ -473,6 +473,8 @@ public:
virtual void CleanUpMap(void);
virtual void RestartRound(void);
+
+ // check if the scenario has been won/lost
virtual void CheckWinConditions(void);
virtual void RemoveGuns(void);
virtual void GiveC4(void);
diff --git a/regamedll/dlls/ggrenade.cpp b/regamedll/dlls/ggrenade.cpp
index ac3a36ff..058a1d0c 100644
--- a/regamedll/dlls/ggrenade.cpp
+++ b/regamedll/dlls/ggrenade.cpp
@@ -130,6 +130,7 @@ void CGrenade::Explode2(TraceResult *pTrace, int bitsDamageType)
m_bJustBlew = true;
mp->CheckWinConditions();
+ // Pull out of the wall a bit
if (pTrace->flFraction != 1.0f)
{
pev->origin = pTrace->vecEndPos + (pTrace->vecPlaneNormal * (pev->dmg - 24) * 0.6);
@@ -177,6 +178,7 @@ void CGrenade::Explode2(TraceResult *pTrace, int bitsDamageType)
WRITE_BYTE(17);
MESSAGE_END();
+ // Sound! for everyone
EMIT_SOUND(ENT(pev), CHAN_WEAPON, "weapons/c4_explode1.wav", VOL_NORM, 0.25);
CSoundEnt::InsertSound(bits_SOUND_COMBAT, pev->origin, NORMAL_EXPLOSION_VOLUME, 3);
@@ -198,14 +200,16 @@ void CGrenade::Explode2(TraceResult *pTrace, int bitsDamageType)
}
// tell director about it
+ // send director message, that something important happed here
MESSAGE_BEGIN(MSG_SPEC, SVC_DIRECTOR);
WRITE_BYTE(9); // command length in bytes
- WRITE_BYTE(DRC_CMD_EVENT); // explode event
+ WRITE_BYTE(DRC_CMD_EVENT); // bomb explode
WRITE_SHORT(ENTINDEX(edict())); // index number of primary entity
WRITE_SHORT(0); // index number of secondary entity
WRITE_LONG(15 | DRC_FLAG_FINAL); // eventflags (priority and flags)
MESSAGE_END();
+ // Decal!
if (RANDOM_FLOAT(0, 1) < 0.5)
UTIL_DecalTrace(pTrace, DECAL_SCORCH1);
else
@@ -984,6 +988,7 @@ void CGrenade::__MAKE_VHOOK(Use)(CBaseEntity *pActivator, CBaseEntity *pCaller,
CBasePlayer *player = GetClassPtr((CBasePlayer *)pActivator->pev);
+ // For CTs to defuse the c4
if (player->m_iTeam != CT)
{
return;
@@ -991,16 +996,18 @@ void CGrenade::__MAKE_VHOOK(Use)(CBaseEntity *pActivator, CBaseEntity *pCaller,
if (m_bStartDefuse)
{
- m_fNextDefuse = gpGlobals->time + 0.5;
+ m_fNextDefuse = gpGlobals->time + 0.5f;
return;
}
+ // freeze the player in place while defusing
SET_CLIENT_MAXSPEED(player->edict(), 1);
if (TheBots != NULL)
{
TheBots->OnEvent(EVENT_BOMB_DEFUSING, pActivator);
}
+
if (g_pGameRules->IsCareer())
{
if (TheCareerTasks != NULL)
@@ -1011,14 +1018,12 @@ void CGrenade::__MAKE_VHOOK(Use)(CBaseEntity *pActivator, CBaseEntity *pCaller,
if (player->m_bHasDefuser)
{
- UTIL_LogPrintf
- (
- "\"%s<%i><%s>\" triggered \"Begin_Bomb_Defuse_With_Kit\"\n",
+ UTIL_LogPrintf("\"%s<%i><%s>\" triggered \"Begin_Bomb_Defuse_With_Kit\"\n",
STRING(player->pev->netname),
GETPLAYERUSERID(player->edict()),
- GETPLAYERAUTHID(player->edict())
- );
+ GETPLAYERAUTHID(player->edict()));
+ // TODO show messages on clients on event
ClientPrint(player->pev, HUD_PRINTCENTER, "#Defusing_Bomb_With_Defuse_Kit");
EMIT_SOUND(ENT(player->pev), CHAN_ITEM, "weapons/c4_disarm.wav", VOL_NORM, ATTN_NORM);
@@ -1027,6 +1032,8 @@ void CGrenade::__MAKE_VHOOK(Use)(CBaseEntity *pActivator, CBaseEntity *pCaller,
m_bStartDefuse = true;
m_flDefuseCountDown = gpGlobals->time + 5;
m_fNextDefuse = gpGlobals->time + 0.5;
+
+ // start the progress bar
player->SetProgressBarTime(5);
}
else
@@ -1036,6 +1043,7 @@ void CGrenade::__MAKE_VHOOK(Use)(CBaseEntity *pActivator, CBaseEntity *pCaller,
GETPLAYERUSERID(player->edict()),
GETPLAYERAUTHID(player->edict()));
+ // TODO show messages on clients on event
ClientPrint(player->pev, HUD_PRINTCENTER, "#Defusing_Bomb_Without_Defuse_Kit");
EMIT_SOUND(ENT(player->pev), CHAN_ITEM, "weapons/c4_disarm.wav", VOL_NORM, ATTN_NORM);
@@ -1044,6 +1052,8 @@ void CGrenade::__MAKE_VHOOK(Use)(CBaseEntity *pActivator, CBaseEntity *pCaller,
m_bStartDefuse = true;
m_flDefuseCountDown = gpGlobals->time + 10;
m_fNextDefuse = gpGlobals->time + 0.5;
+
+ // start the progress bar
player->SetProgressBarTime(10);
}
}
@@ -1208,14 +1218,17 @@ void CGrenade::C4Think(void)
AnnounceFlashInterval(20);
break;
}
+
++m_iCurWave;
}
if (gpGlobals->time >= m_flNextBeep)
{
- m_flNextBeep = gpGlobals->time + 1.4;
+ m_flNextBeep = gpGlobals->time + 1.4f;
EMIT_SOUND(ENT(pev), CHAN_VOICE, m_sBeepName, VOL_NORM, m_fAttenu);
+ // let the bots hear the bomb beeping
+ // BOTPORT: Emit beep events at same time as client effects
if (TheBots != NULL)
{
TheBots->OnEvent(EVENT_BOMB_BEEP, this);
@@ -1238,6 +1251,7 @@ void CGrenade::C4Think(void)
MESSAGE_END();
}
+ // If the timer has expired ! blow this bomb up!
if (gpGlobals->time >= m_flC4Blow)
{
if (TheBots != NULL)
@@ -1260,7 +1274,7 @@ void CGrenade::C4Think(void)
}
CBasePlayer *pBombOwner = (CBasePlayer *)CBaseEntity::Instance(pev->owner);
- if (pBombOwner)
+ if (pBombOwner != NULL)
{
pBombOwner->pev->frags += 3;
}
@@ -1276,14 +1290,17 @@ void CGrenade::C4Think(void)
SetThink(&CGrenade::Detonate2);
}
- if (m_bStartDefuse)
+ // if the defusing process has started
+ if (m_bStartDefuse && m_pBombDefuser != NULL)
{
- CBasePlayer *pPlayer = (CBasePlayer *)((CBaseEntity *)m_pBombDefuser);
+ CBasePlayer *pPlayer = (CBasePlayer *)m_pBombDefuser;
- if (pPlayer != NULL && gpGlobals->time < m_flDefuseCountDown)
+ // if the defusing process has not ended yet
+ if (gpGlobals->time < m_flDefuseCountDown)
{
int iOnGround = ((m_pBombDefuser->pev->flags & FL_ONGROUND) == FL_ONGROUND);
+ // if the bomb defuser has stopped defusing the bomb
if (gpGlobals->time > m_fNextDefuse || !iOnGround)
{
if (!iOnGround)
@@ -1291,92 +1308,95 @@ void CGrenade::C4Think(void)
ClientPrint(m_pBombDefuser->pev, HUD_PRINTCENTER, "#C4_Defuse_Must_Be_On_Ground");
}
+ // release the player from being frozen
pPlayer->ResetMaxSpeed();
pPlayer->m_bIsDefusing = false;
- pPlayer->SetProgressBarTime(0);
+ // cancel the progress bar
+ pPlayer->SetProgressBarTime(0);
m_pBombDefuser = NULL;
m_bStartDefuse = false;
m_flDefuseCountDown = 0;
+ // tell the bots someone has aborted defusing
if (TheBots != NULL)
{
TheBots->OnEvent(EVENT_BOMB_DEFUSE_ABORTED);
}
}
}
+ // if the defuse process has ended, kill the c4
+ else if (m_pBombDefuser->pev->deadflag == DEAD_NO)
+ {
+ Broadcast("BOMBDEF");
+
+ if (TheBots != NULL)
+ {
+ TheBots->OnEvent(EVENT_BOMB_DEFUSED, (CBaseEntity *)m_pBombDefuser);
+ }
+
+ MESSAGE_BEGIN(MSG_SPEC, SVC_DIRECTOR);
+ WRITE_BYTE(9);
+ WRITE_BYTE(DRC_CMD_EVENT);
+ WRITE_SHORT(ENTINDEX(m_pBombDefuser->edict()));
+ WRITE_SHORT(0);
+ WRITE_LONG(15 | DRC_FLAG_FINAL | DRC_FLAG_FACEPLAYER | DRC_FLAG_DRAMATIC);
+ MESSAGE_END();
+
+ UTIL_LogPrintf("\"%s<%i><%s>\" triggered \"Defused_The_Bomb\"\n",
+ STRING(m_pBombDefuser->pev->netname),
+ GETPLAYERUSERID(m_pBombDefuser->edict()),
+ GETPLAYERAUTHID(m_pBombDefuser->edict()));
+
+ UTIL_EmitAmbientSound(ENT(pev), pev->origin, "weapons/c4_beep5.wav", 0, ATTN_NONE, SND_STOP, 0);
+ EMIT_SOUND(ENT(m_pBombDefuser->pev), CHAN_WEAPON, "weapons/c4_disarmed.wav", VOL_NORM, ATTN_NORM);
+ UTIL_Remove(this);
+
+ m_bJustBlew = true;
+
+ // release the player from being frozen
+ pPlayer->ResetMaxSpeed();
+ pPlayer->m_bIsDefusing = false;
+
+ MESSAGE_BEGIN(MSG_ALL, gmsgScenarioIcon);
+ WRITE_BYTE(0);
+ MESSAGE_END();
+
+ if (g_pGameRules->IsCareer() && !pPlayer->IsBot())
+ {
+ if (TheCareerTasks != NULL)
+ {
+ TheCareerTasks->HandleEvent(EVENT_BOMB_DEFUSED, pPlayer);
+ }
+ }
+
+ g_pGameRules->m_bBombDefused = true;
+ g_pGameRules->CheckWinConditions();
+
+ // give the defuser credit for defusing the bomb
+ m_pBombDefuser->pev->frags += 3;
+
+ MESSAGE_BEGIN(MSG_ALL, gmsgBombPickup);
+ MESSAGE_END();
+
+ g_pGameRules->m_bBombDropped = FALSE;
+ m_pBombDefuser = NULL;
+ m_bStartDefuse = false;
+ }
else
{
- if (pPlayer != NULL && m_pBombDefuser->pev->deadflag == DEAD_NO)
+ // if it gets here then the previouse defuser has taken off or been killed
+ // release the player from being frozen
+ pPlayer->ResetMaxSpeed();
+ pPlayer->m_bIsDefusing = false;
+
+ m_bStartDefuse = false;
+ m_pBombDefuser = NULL;
+
+ // tell the bots someone has aborted defusing
+ if (TheBots != NULL)
{
- Broadcast("BOMBDEF");
-
- if (TheBots != NULL)
- {
- TheBots->OnEvent(EVENT_BOMB_DEFUSED, (CBaseEntity *)m_pBombDefuser);
- }
-
- MESSAGE_BEGIN(MSG_SPEC, SVC_DIRECTOR);
- WRITE_BYTE(9);
- WRITE_BYTE(DRC_CMD_EVENT);
- WRITE_SHORT(ENTINDEX(m_pBombDefuser->edict()));
- WRITE_SHORT(0);
- WRITE_LONG(15 | DRC_FLAG_FINAL | DRC_FLAG_FACEPLAYER | DRC_FLAG_DRAMATIC);
- MESSAGE_END();
-
- UTIL_LogPrintf("\"%s<%i><%s>\" triggered \"Defused_The_Bomb\"\n",
- STRING(m_pBombDefuser->pev->netname),
- GETPLAYERUSERID(m_pBombDefuser->edict()),
- GETPLAYERAUTHID(m_pBombDefuser->edict()));
-
- UTIL_EmitAmbientSound(ENT(pev), pev->origin, "weapons/c4_beep5.wav", 0, ATTN_NONE, SND_STOP, 0);
- EMIT_SOUND(ENT(m_pBombDefuser->pev), CHAN_WEAPON, "weapons/c4_disarmed.wav", VOL_NORM, ATTN_NORM);
- UTIL_Remove(this);
-
- m_bJustBlew = true;
-
- pPlayer->ResetMaxSpeed();
- pPlayer->m_bIsDefusing = false;
-
- MESSAGE_BEGIN(MSG_ALL, gmsgScenarioIcon);
- WRITE_BYTE(0);
- MESSAGE_END();
-
- if (g_pGameRules->IsCareer() && !pPlayer->IsBot())
- {
- if (TheCareerTasks != NULL)
- {
- TheCareerTasks->HandleEvent(EVENT_BOMB_DEFUSED, pPlayer);
- }
- }
-
- g_pGameRules->m_bBombDefused = true;
- g_pGameRules->CheckWinConditions();
-
- m_pBombDefuser->pev->frags += 3;
-
- MESSAGE_BEGIN(MSG_ALL, gmsgBombPickup);
- MESSAGE_END();
-
- g_pGameRules->m_bBombDropped = FALSE;
- m_pBombDefuser = NULL;
- m_bStartDefuse = false;
- }
- else
- {
- if (pPlayer != NULL)
- {
- pPlayer->ResetMaxSpeed();
- pPlayer->m_bIsDefusing = false;
- }
-
- m_bStartDefuse = false;
- m_pBombDefuser = NULL;
-
- if (TheBots != NULL)
- {
- TheBots->OnEvent(EVENT_BOMB_DEFUSE_ABORTED);
- }
+ TheBots->OnEvent(EVENT_BOMB_DEFUSE_ABORTED);
}
}
}
diff --git a/regamedll/dlls/hostage/hostage.cpp b/regamedll/dlls/hostage/hostage.cpp
index 2d1895ed..201a3c05 100644
--- a/regamedll/dlls/hostage/hostage.cpp
+++ b/regamedll/dlls/hostage/hostage.cpp
@@ -253,17 +253,13 @@ void CHostage::IdleThink(void)
if (m_improv != NULL)
{
- if (IsFollowingSomeone())
- {
+ if (m_improv->IsFollowing())
player = (CBasePlayer *)m_improv->GetFollowLeader();
- }
}
else
- {
player = GetClassPtr((CBasePlayer *)m_hTargetEnt->pev);
- }
- if (!player || player->m_iTeam == CT)
+ if (player == NULL || player->m_iTeam == CT)
{
if (!g_pGameRules->m_bMapHasRescueZone)
{
@@ -924,18 +920,7 @@ void CHostage::DoFollow(void)
}
else if (pev->takedamage == DAMAGE_YES)
{
- if (m_improv != NULL)
- {
- if (IsFollowingSomeone())
- {
- if (!m_bStuck && flDistToDest > 200)
- {
- m_bStuck = TRUE;
- m_flStuckTime = gpGlobals->time;
- }
- }
- }
- else if (m_hTargetEnt != NULL && m_State == FOLLOW)
+ if (IsFollowingSomeone())
{
if (!m_bStuck && flDistToDest > 200)
{
@@ -1498,7 +1483,6 @@ bool CHostageManager::IsNearbyHostageJumping(CHostageImprov *improv)
{
for (int i = 0; i < m_hostageCount; i++)
{
- const float closeRange = 500.0f;
const CHostageImprov *other = m_hostage[i]->m_improv;
if (other == NULL)
@@ -1506,7 +1490,8 @@ bool CHostageManager::IsNearbyHostageJumping(CHostageImprov *improv)
if (!other->IsAlive() || other == improv)
continue;
-
+
+ const float closeRange = 500.0f;
if (!(improv->GetCentroid() - other->GetCentroid()).IsLengthGreaterThan(closeRange) && other->IsJumping())
{
return true;
diff --git a/regamedll/dlls/hostage/hostage.h b/regamedll/dlls/hostage/hostage.h
index b88cf6a1..dcf80add 100644
--- a/regamedll/dlls/hostage/hostage.h
+++ b/regamedll/dlls/hostage/hostage.h
@@ -95,13 +95,15 @@ extern int g_iHostageNumber;
extern cvar_t cv_hostage_debug;
extern cvar_t cv_hostage_stop;
+// A Counter-Strike Hostage Simple
+
/* <4858e5> ../cstrike/dlls/hostage/hostage.h:32 */
class CHostage: public CBaseMonster
{
public:
virtual void Spawn(void);
virtual void Precache(void);
- virtual int ObjectCaps(void);
+ virtual int ObjectCaps(void); // make hostage "useable"
virtual int Classify(void)
{
return CLASS_HUMAN_PASSIVE;
@@ -152,22 +154,34 @@ public:
void Wiggle(void);
void PreThink(void);
+ // queries
bool IsFollowingSomeone(void)
{
- return m_improv->IsFollowing();
+ return IsFollowing();
}
- CBaseEntity *GetLeader(void)
+ CBaseEntity *GetLeader(void) // return our leader, or NULL
{
if (m_improv != NULL)
{
return m_improv->GetFollowLeader();
}
- return NULL;
+ return m_hTargetEnt;
}
- bool IsFollowing(const CBaseEntity *entity)
+ bool IsFollowing(const CBaseEntity *entity = NULL)
{
- return (entity == m_hTargetEnt && m_State == FOLLOW);
+ if (m_improv != NULL)
+ {
+ return m_improv->IsFollowing();
+ }
+
+ if (entity == NULL && m_hTargetEnt == NULL || (entity != NULL && m_hTargetEnt != entity))
+ return false;
+
+ if (m_State != FOLLOW)
+ return false;
+
+ return true;
}
bool IsValid(void)
{
@@ -187,24 +201,6 @@ public:
}
public:
- enum state
- {
- FOLLOW = 0,
- STAND,
- DUCK,
- SCARED,
- IDLE,
- FOLLOWPATH,
- };
-
- enum ModelType
- {
- REGULAR_GUY = 0,
- OLD_GUY,
- BLACK_GUY,
- GOOFY_GUY,
- };
-
int m_Activity;
BOOL m_bTouched;
BOOL m_bRescueMe;
@@ -214,7 +210,8 @@ public:
int m_iModel;
int m_iSkin;
float m_flNextRadarTime;
- state m_State;
+ enum state { FOLLOW, STAND, DUCK, SCARED, IDLE, FOLLOWPATH }
+ m_State;
Vector m_vStart;
Vector m_vStartAngles;
Vector m_vPathToFollow[20];
@@ -235,7 +232,9 @@ public:
BOOL m_bStuck;
float m_flStuckTime;
CHostageImprov *m_improv;
- ModelType m_whichModel;
+
+ enum ModelType { REGULAR_GUY, OLD_GUY, BLACK_GUY, GOOFY_GUY }
+ m_whichModel;
};/* size: 1988, cachelines: 32, members: 32 */
@@ -294,6 +293,25 @@ public:
bool IsNearbyHostageTalking(CHostageImprov *improv);
bool IsNearbyHostageJumping(CHostageImprov *improv);
void OnEvent(GameEventType event, CBaseEntity *entity, CBaseEntity *other);
+
+ // Iterate over all active hostages in the game, invoking functor on each.
+ // If functor returns false, stop iteration and return false.
+ template
+ inline bool ForEachHostage(Functor &func) const
+ {
+ for (int i = 0; i < m_hostageCount; i++)
+ {
+ CHostage *hostage = m_hostage[i];
+
+ if (hostage == NULL || hostage->pev->deadflag == DEAD_DEAD)
+ continue;
+
+ if (func(hostage) == false)
+ return false;
+ }
+
+ return true;
+ }
inline CHostage *GetClosestHostage(const Vector &pos, float *resultRange = NULL)
{
float range;
@@ -317,23 +335,6 @@ public:
return close;
}
- template
- bool ForEachHostage(T &func) const
- {
- for (int i = 0; i < m_hostageCount; i++)
- {
- CHostage *pHostage = m_hostage[ i ];
-
- if (pHostage->pev->deadflag == DEAD_DEAD)
- continue;
-
- if (func(pHostage) == false)
- return false;
- }
-
- return true;
- }
-
private:
CHostage *m_hostage[ MAX_HOSTAGES ];
int m_hostageCount;
@@ -341,43 +342,18 @@ private:
};/* size: 5680, cachelines: 89, members: 3 */
-
-///* <470134> ../cstrike/dlls/hostage/hostage.h:293 */
-//inline void CHostageManager::ForEachHostage(KeepPersonalSpace &func)
-//{
-//// {
-//// int i; // 295
-//// }
-//}
-//
-///* <46fbe8> ../cstrike/dlls/hostage/hostage.h:293 */
-//inline void CHostageManager::ForEachHostage(CheckAhead &func)
-//{
-//// {
-//// int i; // 295
-//// }
-//}
-//
-///* <46fb04> ../cstrike/dlls/hostage/hostage.h:293 */
-//inline void CHostageManager::ForEachHostage(CheckWayFunctor &func)
-//{
-//// {
-//// int i; // 295
-//// }
-//}
-
#ifdef HOOK_GAMEDLL
// linked object
C_DLLEXPORT void hostage_entity(entvars_t *pev);
C_DLLEXPORT void monster_scientist(entvars_t *pev);
+// refs
+extern void (CBaseEntity::*pCHostage__IdleThink)(void);
+
#endif // HOOK_GAMEDLL
void Hostage_RegisterCVars(void);
void InstallHostageManager(void);
-// refs
-extern void (CBaseEntity::*pCHostage__IdleThink)(void);
-
#endif // HOSTAGE_H
diff --git a/regamedll/dlls/hostage/hostage_improv.cpp b/regamedll/dlls/hostage/hostage_improv.cpp
index 6732619b..13e9a49a 100644
--- a/regamedll/dlls/hostage/hostage_improv.cpp
+++ b/regamedll/dlls/hostage/hostage_improv.cpp
@@ -275,7 +275,7 @@ void CHostageImprov::FaceOutwards(void)
float farthestRange = 0.0f;
int farthest = 0;
- Vector corner[] =
+ static Vector corner[] =
{
Vector(-1000, 1000, 0),
Vector(1000, 1000, 0),
@@ -935,7 +935,7 @@ void CHostageImprov::UpdatePosition(float deltaT)
while (yaw < -180.0f)
yaw += 360.0f;
-
+
while (pitch > 180.0f)
pitch -= 360.0f;
@@ -1536,7 +1536,7 @@ CBasePlayer *CHostageImprov::GetClosestVisiblePlayer(int team)
for (int i = 0; i < m_visiblePlayerCount; i++)
{
- CBasePlayer *player = (CBasePlayer *)((CBaseEntity *)m_visiblePlayer[i]);
+ CBasePlayer *player = (CBasePlayer *)m_visiblePlayer[i];
if (player == NULL || (team > 0 && player->m_iTeam != team))
continue;
@@ -1784,6 +1784,8 @@ void CHostageImprov::Wave(void)
m_animateState.AddSequence(this, ACT_WAVE);
}
+// Invoked when an improv fails to reach a MoveTo goal
+
/* <474938> ../cstrike/dlls/hostage/hostage_improv.cpp:2375 */
void CHostageImprov::__MAKE_VHOOK(OnMoveToFailure)(const Vector &goal, MoveToFailureType reason)
{
@@ -1798,12 +1800,6 @@ void CHostageImprov::__MAKE_VHOOK(OnMoveToFailure)(const Vector &goal, MoveToFai
/* <4763d7> ../cstrike/dlls/hostage/hostage_improv.cpp:2391 */
void CHostageImprov::Wiggle(void)
{
- Vector dir;
- Vector lat;
-
- const float force = 15.0f;
- const float minStuckJumpTime = 0.5f;
-
// for wiggling
if (m_wiggleTimer.IsElapsed())
{
@@ -1811,45 +1807,34 @@ void CHostageImprov::Wiggle(void)
m_wiggleTimer.Start(RANDOM_FLOAT(0.3, 0.5));
}
- lat.x = BotCOS(m_moveAngle);
- lat.y = BotSIN(m_moveAngle);
- lat.z = 0;
+ const float force = 15.0f;
+ Vector dir(BotCOS(m_moveAngle), BotSIN(m_moveAngle), 0.0f);
+ Vector lat(-dir.y, dir.x, 0.0f);
switch (m_wiggleDirection)
{
case FORWARD:
- dir.x = lat.x;
- dir.y = lat.y;
-
ApplyForce(dir * force);
break;
- case RIGHT:
- dir.x = -lat.y;
- dir.y = lat.x;
-
- ApplyForce(dir * -force);
- break;
case BACKWARD:
- dir.x = lat.x;
- dir.y = lat.y;
-
ApplyForce(dir * -force);
break;
case LEFT:
- dir.x = -lat.y;
- dir.y = lat.x;
-
- ApplyForce(dir * force);
+ ApplyForce(lat * force);
+ break;
+ case RIGHT:
+ ApplyForce(lat * -force);
break;
default:
break;
}
+ const float minStuckJumpTime = 0.5f;
if (m_follower.GetStuckDuration() > minStuckJumpTime && m_wiggleJumpTimer.IsElapsed())
{
if (Jump())
{
- m_wiggleJumpTimer.Start(RANDOM_FLOAT(0.75, 1.2));
+ m_wiggleJumpTimer.Start(RANDOM_FLOAT(0.75f, 1.2f));
}
}
}
diff --git a/regamedll/dlls/hostage/hostage_improv.h b/regamedll/dlls/hostage/hostage_improv.h
index 633497ee..e0420f4e 100644
--- a/regamedll/dlls/hostage/hostage_improv.h
+++ b/regamedll/dlls/hostage/hostage_improv.h
@@ -38,21 +38,21 @@
class CHostage;
enum HostageChatterType;
+// A Counter-Strike Hostage improved
class CHostageImprov: public CImprov
{
public:
CHostageImprov(CBaseEntity *entity);
~CHostageImprov(void) {};
- virtual void OnMoveToSuccess(const Vector &goal)
- {
- m_behavior.OnMoveToSuccess(goal);
- }
+ // invoked when an improv reaches its MoveTo goal
+ virtual void OnMoveToSuccess(const Vector &goal) { m_behavior.OnMoveToSuccess(goal); }
+
+ // invoked when an improv fails to reach a MoveTo goal
virtual void OnMoveToFailure(const Vector &goal, MoveToFailureType reason);
virtual void OnInjury(float amount)
{
m_behavior.OnInjury(amount);
-
m_lastInjuryTimer.Start();
Frighten(TERRIFIED);
}
@@ -63,122 +63,58 @@ public:
virtual void FaceTo(const Vector &goal);
virtual void ClearFaceTo(void);
virtual bool IsAtMoveGoal(float error = 20.0f) const;
- virtual bool HasLookAt(void) const
- {
- return m_isLookingAt;
- }
- virtual bool HasFaceTo(void) const
- {
- return m_isFacingTo;
- }
+ virtual bool HasLookAt(void) const { return m_isLookingAt; }
+ virtual bool HasFaceTo(void) const { return m_isFacingTo; }
virtual bool IsAtFaceGoal(void) const;
virtual bool IsFriendInTheWay(const Vector &goalPos) const;
virtual bool IsFriendInTheWay(CBaseEntity *myFriend, const Vector &goalPos) const;
- virtual void MoveForward(void)
- {
- m_moveFlags |= IN_FORWARD;
- }
- virtual void MoveBackward(void)
- {
- m_moveFlags |= IN_BACK;
- }
- virtual void StrafeLeft(void)
- {
- m_moveFlags |= IN_MOVELEFT;
- }
- virtual void StrafeRight(void)
- {
- m_moveFlags |= IN_MOVERIGHT;
- }
+ virtual void MoveForward(void) { m_moveFlags |= IN_FORWARD; }
+ virtual void MoveBackward(void) { m_moveFlags |= IN_BACK; }
+ virtual void StrafeLeft(void) { m_moveFlags |= IN_MOVELEFT; }
+ virtual void StrafeRight(void) { m_moveFlags |= IN_MOVERIGHT; }
#define HOSTAGE_MUST_JUMP true
virtual bool Jump(void);
virtual void Crouch(void);
virtual void StandUp(void);
- virtual void TrackPath(const Vector &pathGoal, float deltaT);
+ virtual void TrackPath(const Vector &pathGoal, float deltaT); // move along path by following "pathGoal"
virtual void StartLadder(const CNavLadder *ladder, NavTraverseType how, const Vector *approachPos, const Vector *departPos);
virtual bool TraverseLadder(const CNavLadder *ladder, NavTraverseType how, const Vector *approachPos, const Vector *departPos, float deltaT);
virtual bool GetSimpleGroundHeightWithFloor(const Vector *pos, float *height, Vector *normal = NULL);
virtual void Run(void);
virtual void Walk(void);
virtual void Stop(void);
- virtual float GetMoveAngle(void) const
- {
- return m_moveAngle;
- }
- virtual float GetFaceAngle(void) const
- {
- return m_moveAngle;
- }
+ virtual float GetMoveAngle(void) const { return m_moveAngle; }
+ virtual float GetFaceAngle(void) const { return m_moveAngle; }
virtual const Vector &GetFeet(void) const;
virtual const Vector &GetCentroid(void) const;
virtual const Vector &GetEyes(void) const;
- virtual bool IsRunning(void) const
- {
- return (m_moveType == Running);
- }
- virtual bool IsWalking(void) const
- {
- return (m_moveType == Walking);
- }
- virtual bool IsStopped(void) const
- {
- return (m_moveType == Stopped);
- }
- virtual bool IsCrouching(void) const
- {
- return m_isCrouching;
- }
- virtual bool IsJumping(void) const
- {
- return (m_jumpTimer.IsElapsed() == false);
- }
- virtual bool IsUsingLadder(void) const
- {
- return false;
- }
+ virtual bool IsRunning(void) const { return (m_moveType == Running); }
+ virtual bool IsWalking(void) const { return (m_moveType == Walking); }
+ virtual bool IsStopped(void) const { return (m_moveType == Stopped); }
+ virtual bool IsCrouching(void) const { return m_isCrouching; }
+ virtual bool IsJumping(void) const { return (m_jumpTimer.IsElapsed() == false); }
+ virtual bool IsUsingLadder(void) const { return false; }
virtual bool IsOnGround(void) const;
virtual bool IsMoving(void) const;
- virtual bool CanRun(void) const
- {
- return true;
- }
- virtual bool CanCrouch(void) const
- {
- return true;
- }
- virtual bool CanJump(void) const
- {
- return true;
- }
- virtual bool IsVisible(const Vector &pos, bool testFOV = false) const;
+ virtual bool CanRun(void) const { return true; }
+ virtual bool CanCrouch(void) const { return true; }
+ virtual bool CanJump(void) const { return true; }
+ virtual bool IsVisible(const Vector &pos, bool testFOV = false) const; // return true if hostage can see position
virtual bool IsPlayerLookingAtMe(CBasePlayer *other, float cosTolerance = 0.95f) const;
virtual CBasePlayer *IsAnyPlayerLookingAtMe(int team = 0, float cosTolerance = 0.95f) const;
virtual CBasePlayer *GetClosestPlayerByTravelDistance(int team = 0, float *range = NULL) const;
- virtual CNavArea *GetLastKnownArea(void) const
- {
- return m_lastKnownArea;
- }
+ virtual CNavArea *GetLastKnownArea(void) const { return m_lastKnownArea; }
virtual void OnUpdate(float deltaT);
virtual void OnUpkeep(float deltaT);
virtual void OnReset(void);
virtual void OnGameEvent(GameEventType event, CBaseEntity *entity = NULL, CBaseEntity *other = NULL);
- virtual void OnTouch(CBaseEntity *other);
+ virtual void OnTouch(CBaseEntity *other); // in contact with "other"
#ifdef HOOK_GAMEDLL
- void OnMoveToSuccess_(const Vector &goal)
- {
- //if (m_behavior.IsState(NULL))
- // IImprovEvent::OnMoveToSuccess(goal);
- }
void OnMoveToFailure_(const Vector &goal, MoveToFailureType reason);
- void OnInjury_(float amount)
- {
- //m_behavior.Update();
- //m_lastInjuryTimer.Start();
- }
bool IsAlive_(void) const;
void MoveTo_(const Vector &goal);
void LookAt_(const Vector &target);
@@ -217,27 +153,13 @@ public:
#endif // HOOK_GAMEDLL
public:
- enum MoveType
- {
- Stopped = 0,
- Walking,
- Running,
- };
-
- enum ScareType
- {
- NERVOUS = 0,
- SCARED,
- TERRIFIED,
- };
+ enum MoveType { Stopped, Walking, Running };
+ enum ScareType { NERVOUS, SCARED, TERRIFIED };
void FaceOutwards(void);
bool IsFriendInTheWay(void) const;
void SetKnownGoodPosition(const Vector &pos);
- const Vector &GetKnownGoodPosition(void) const
- {
- return m_knownGoodPos;
- }
+ const Vector &GetKnownGoodPosition(void) const { return m_knownGoodPos; }
void ResetToKnownGoodPosition(void);
void ResetJump(void)
{
@@ -253,7 +175,7 @@ public:
m_hasJumpedIntoAir = true;
}
}
- void ApplyForce(Vector force);
+ void ApplyForce(Vector force); // apply a force to the hostage
#ifdef PLAY_GAMEDLL
void ApplyForce2(float_precision x, float_precision y)
{
@@ -261,62 +183,32 @@ public:
m_vel.y += y;
}
#endif // PLAY_GAMEDLL
- const Vector GetActualVelocity(void) const
- {
- return m_actualVel;
- }
- void SetMoveLimit(MoveType limit)
- {
- m_moveLimit = limit;
- }
- MoveType GetMoveLimit(void) const
- {
- return m_moveLimit;
- }
- CNavPath *GetPath(void)
- {
- return &m_path;
- }
+ const Vector GetActualVelocity(void) const { return m_actualVel; }
+ void SetMoveLimit(MoveType limit) { m_moveLimit = limit; }
+ MoveType GetMoveLimit(void) const { return m_moveLimit; }
+ CNavPath *GetPath(void) { return &m_path; }
CNavPathFollower *GetPathFollower(void);
- void Idle(void)
- {
- m_behavior.SetState(&m_idleState);
- }
- bool IsIdle(void) const
- {
- return m_behavior.IsState(&m_idleState);
- }
- void Follow(CBasePlayer *leader)
- {
- m_followState.SetLeader(leader);
- m_behavior.SetState(&m_followState);
- }
- bool IsFollowing(const CBaseEntity *leader = NULL) const
- {
- return m_behavior.IsState(&m_followState);
- }
- void Escape(void)
- {
- m_behavior.SetState(&m_escapeState);
- }
- bool IsEscaping(void) const
- {
- return m_behavior.IsState(&m_escapeState);
- }
- void Retreat(void)
- {
- m_behavior.SetState(&m_retreatState);
- }
- bool IsRetreating(void) const
- {
- return m_behavior.IsState(&m_retreatState);
- }
+
+ // hostage states
+ // stand idle
+ void Idle(void) { m_behavior.SetState(&m_idleState); }
+ bool IsIdle(void) const { return m_behavior.IsState(&m_idleState); }
+
+ // begin following "leader"
+ void Follow(CBasePlayer *leader) { m_followState.SetLeader(leader); m_behavior.SetState(&m_followState); }
+ bool IsFollowing(const CBaseEntity *leader = NULL) const { return m_behavior.IsState(&m_followState); }
+
+ // Escape
+ void Escape(void) { m_behavior.SetState(&m_escapeState); }
+ bool IsEscaping(void) const { return m_behavior.IsState(&m_escapeState); }
+
+ // Retreat
+ void Retreat(void) { m_behavior.SetState(&m_retreatState); }
+ bool IsRetreating(void) const { return m_behavior.IsState(&m_retreatState); }
+
bool IsAtHome(void) const;
bool CanSeeRescueZone(void) const;
- CBaseEntity *GetFollowLeader(void) const
- {
- return m_followState.GetLeader();
- }
+ CBaseEntity *GetFollowLeader(void) const { return m_followState.GetLeader(); }
CBasePlayer *GetClosestVisiblePlayer(int team);
float GetTimeSinceLastSawPlayer(int team);
float GetTimeSinceLastInjury(void);
@@ -324,25 +216,13 @@ public:
bool IsTerroristNearby(void);
void Frighten(ScareType scare);
bool IsScared(void) const;
- ScareType GetScareIntensity(void) const
- {
- return m_scareIntensity;
- }
- bool IsIgnoringTerrorists(void) const
- {
- m_ignoreTerroristTimer.IsElapsed();
- }
- float GetAggression(void) const
- {
- return m_aggression;
- }
+ ScareType GetScareIntensity(void) const { return m_scareIntensity; }
+ bool IsIgnoringTerrorists(void) const { m_ignoreTerroristTimer.IsElapsed(); }
+ float GetAggression(void) const { return m_aggression; }
void Chatter(HostageChatterType sayType, bool mustSpeak = true);
void DelayedChatter(float delayTime, HostageChatterType sayType, bool mustSpeak = false);
NOXREF void UpdateDelayedChatter(void);
- bool IsTalking(void) const
- {
- return m_talkingTimer.IsElapsed();
- }
+ bool IsTalking(void) const { return m_talkingTimer.IsElapsed(); }
void UpdateGrenadeReactions(void);
void Afraid(void);
void Wave(void);
@@ -352,20 +232,14 @@ public:
void Flinch(Activity activity);
void UpdateIdleActivity(Activity activity, Activity fidget);
void UpdateStationaryAnimation(void);
- CHostage *GetEntity(void) const
- {
- return m_hostage;
- }
+ CHostage *GetEntity(void) const { return m_hostage; }
void CheckForNearbyTerrorists(void);
void UpdatePosition(float);
void MoveTowards(const Vector &pos, float deltaT);
- bool FaceTowards(const Vector &target, float deltaT);
+ bool FaceTowards(const Vector &target, float deltaT); // rotate body to face towards "target"
float GetSpeed(void);
- void SetMoveAngle(float angle)
- {
- m_moveAngle = angle;
- }
- void Wiggle(void);
+ void SetMoveAngle(float angle) { m_moveAngle = angle; }
+ void Wiggle(void); // attempt to wiggle-out of begin stuck
void ClearPath(void);
#define HOSTAGE_ONLY_JUMP_DOWN true
@@ -378,7 +252,7 @@ public:
private:
CHostage *m_hostage;
- CNavArea *m_lastKnownArea;
+ CNavArea *m_lastKnownArea; // last area we were in
mutable Vector m_centroid;
mutable Vector m_eye;
HostageStateMachine m_behavior;
@@ -423,25 +297,27 @@ private:
bool m_isLookingAt;
Vector m_faceGoal;
bool m_isFacingTo;
- CNavPath m_path;
+ CNavPath m_path; // current path to follow
CNavPathFollower m_follower;
Vector m_lastPosition;
MoveType m_moveType;
MoveType m_moveLimit;
- bool m_isCrouching;
+ bool m_isCrouching; // true if hostage is crouching
CountdownTimer m_minCrouchTimer;
float m_moveAngle;
NavRelativeDirType m_wiggleDirection;
- CountdownTimer m_wiggleTimer;
+
+ CountdownTimer m_wiggleTimer; // for wiggling
CountdownTimer m_wiggleJumpTimer;
CountdownTimer m_inhibitObstacleAvoidance;
- CountdownTimer m_jumpTimer;
+ CountdownTimer m_jumpTimer; // if zero, we can jump
+
bool m_hasJumped;
bool m_hasJumpedIntoAir;
Vector m_jumpTarget;
CountdownTimer m_clearPathTimer;
bool m_traversingLadder;
- EHANDLE m_visiblePlayer[32];
+ EHANDLE m_visiblePlayer[ MAX_CLIENTS ];
int m_visiblePlayerCount;
CountdownTimer m_visionTimer;
@@ -475,6 +351,9 @@ public:
}; /* size: 20, cachelines: 1, members: 3 */
+// Functor used with NavAreaBuildPath() for building Hostage paths.
+// Once we hook up crouching and ladders, this can be removed and ShortestPathCost() can be used instead.
+
/* <46f426> ../cstrike/dlls/hostage/hostage_improv.h:400 */
class HostagePathCost
{
@@ -496,9 +375,12 @@ public:
const float ladderCost = 10.0f;
return ladder->m_length * ladderCost + fromArea->GetCostSoFar();
}
-
- dist = (*area->GetCenter() - *fromArea->GetCenter()).Length();
- float cost = fromArea->GetCostSoFar() + dist;
+ else
+ {
+ dist = (*area->GetCenter() - *fromArea->GetCenter()).Length();
+ }
+
+ float cost = dist + fromArea->GetCostSoFar();
// if this is a "crouch" area, add penalty
if (area->GetAttributes() & NAV_CROUCH)
@@ -594,12 +476,8 @@ public:
CheckAhead(const CHostageImprov *me)
{
m_me = me;
-
+ m_dir = Vector(BotCOS(me->GetMoveAngle()), BotSIN(me->GetMoveAngle()), 0.0f);
m_isBlocked = false;
-
- m_dir.x = BotCOS(me->GetMoveAngle());
- m_dir.y = BotSIN(me->GetMoveAngle());
- m_dir.z = 0;
}
/* <47046f> ../cstrike/dlls/hostage/hostage_improv.cpp:525 */
bool operator()(CBaseEntity *entity)
diff --git a/regamedll/dlls/hostage/hostage_states.h b/regamedll/dlls/hostage/hostage_states.h
index 1eadc644..73a0673d 100644
--- a/regamedll/dlls/hostage/hostage_states.h
+++ b/regamedll/dlls/hostage/hostage_states.h
@@ -79,24 +79,11 @@ public:
virtual void OnEnter(CHostageImprov *improv);
virtual void OnUpdate(CHostageImprov *improv);
virtual void OnExit(CHostageImprov *improv);
- virtual const char *GetName(void) const
- {
- return "Idle";
- }
+ virtual const char *GetName(void) const { return "Idle"; }
virtual void UpdateStationaryAnimation(CHostageImprov *improv);
- virtual void OnMoveToSuccess(const Vector &goal)
- {
- m_moveState = MoveDone;
- }
- virtual void OnMoveToFailure(const Vector &goal, MoveToFailureType reason)
- {
- m_moveState = MoveFailed;
- }
- virtual void OnInjury(float amount = -1.0f)
- {
- m_fleeTimer.Invalidate();
- m_mustFlee = true;
- }
+ virtual void OnMoveToSuccess(const Vector &goal) { m_moveState = MoveDone; }
+ virtual void OnMoveToFailure(const Vector &goal, MoveToFailureType reason) { m_moveState = MoveFailed; }
+ virtual void OnInjury(float amount = -1.0f) { m_fleeTimer.Invalidate(); m_mustFlee = true; }
#ifdef HOOK_GAMEDLL
@@ -137,10 +124,7 @@ public:
virtual void OnEnter(CHostageImprov *improv);
virtual void OnUpdate(CHostageImprov *improv);
virtual void OnExit(CHostageImprov *improv);
- virtual const char *GetName(void) const
- {
- return "Escape:ToCover";
- }
+ virtual const char *GetName(void) const { return "Escape:ToCover"; }
virtual void OnMoveToFailure(const Vector &goal, MoveToFailureType reason);
#ifdef HOOK_GAMEDLL
@@ -153,10 +137,7 @@ public:
#endif // HOOK_GAMEDLL
public:
- void SetRescueGoal(const Vector &rescueGoal)
- {
- m_rescueGoal = rescueGoal;
- }
+ void SetRescueGoal(const Vector &rescueGoal) { m_rescueGoal = rescueGoal; }
private:
Vector m_rescueGoal;
@@ -174,10 +155,7 @@ public:
virtual void OnEnter(CHostageImprov *improv);
virtual void OnUpdate(CHostageImprov *improv);
virtual void OnExit(CHostageImprov *improv);
- virtual const char *GetName(void) const
- {
- return "Escape:LookAround";
- }
+ virtual const char *GetName(void) const { return "Escape:LookAround"; }
#ifdef HOOK_GAMEDLL
@@ -201,14 +179,8 @@ public:
virtual void OnEnter(CHostageImprov *improv);
virtual void OnUpdate(CHostageImprov *improv);
virtual void OnExit(CHostageImprov *improv);
- virtual const char *GetName(void) const
- {
- return "Escape";
- }
- virtual void OnMoveToFailure(const Vector &goal, MoveToFailureType reason)
- {
- m_behavior.OnMoveToFailure(goal, reason);
- }
+ virtual const char *GetName(void) const { return "Escape"; }
+ virtual void OnMoveToFailure(const Vector &goal, MoveToFailureType reason) { m_behavior.OnMoveToFailure(goal, reason); }
#ifdef HOOK_GAMEDLL
@@ -219,14 +191,8 @@ public:
#endif // HOOK_GAMEDLL
public:
- void ToCover(void)
- {
- m_behavior.SetState(&m_toCoverState);
- }
- void LookAround(void)
- {
- m_behavior.SetState(&m_lookAroundState);
- }
+ void ToCover(void) { m_behavior.SetState(&m_toCoverState); }
+ void LookAround(void) { m_behavior.SetState(&m_lookAroundState); }
private:
HostageEscapeToCoverState m_toCoverState;
@@ -246,20 +212,13 @@ public:
virtual void OnEnter(CHostageImprov *improv);
virtual void OnUpdate(CHostageImprov *improv);
virtual void OnExit(CHostageImprov *improv);
- virtual const char *GetName(void) const
- {
- return "Retreat";
- }
+ virtual const char *GetName(void) const { return "Retreat"; }
#ifdef HOOK_GAMEDLL
void OnEnter_(CHostageImprov *improv);
void OnUpdate_(CHostageImprov *improv);
void OnExit_(CHostageImprov *improv);
- const char *GetName_(void) const
- {
- return GetName();
- }
#endif // HOOK_GAMEDLL
@@ -274,10 +233,7 @@ public:
virtual void OnEnter(CHostageImprov *improv);
virtual void OnUpdate(CHostageImprov *improv);
virtual void OnExit(CHostageImprov *improv);
- virtual const char *GetName(void) const
- {
- return "Follow";
- }
+ virtual const char *GetName(void) const { return "Follow"; }
virtual void UpdateStationaryAnimation(CHostageImprov *improv);
#ifdef HOOK_GAMEDLL
@@ -290,14 +246,8 @@ public:
#endif // HOOK_GAMEDLL
public:
- void SetLeader(CBaseEntity *leader)
- {
- m_leader = leader;
- }
- CBaseEntity *GetLeader(void) const
- {
- return m_leader;
- }
+ void SetLeader(CBaseEntity *leader) { m_leader = leader; }
+ CBaseEntity *GetLeader(void) const { return m_leader; }
private:
mutable EHANDLE m_leader;
@@ -321,10 +271,7 @@ public:
virtual void OnEnter(CHostageImprov *improv);
virtual void OnUpdate(CHostageImprov *improv);
virtual void OnExit(CHostageImprov *improv);
- virtual const char *GetName(void) const
- {
- return "Animate";
- }
+ virtual const char *GetName(void) const { return "Animate"; }
#ifdef HOOK_GAMEDLL
@@ -340,8 +287,7 @@ public:
int seqID;
float holdTime;
float rate;
-
- };/* size: 12, cachelines: 1, members: 3 */
+ };
enum PerformanceType
{
diff --git a/regamedll/dlls/hostage/states/hostage_follow.cpp b/regamedll/dlls/hostage/states/hostage_follow.cpp
index 53545fae..02d849e2 100644
--- a/regamedll/dlls/hostage/states/hostage_follow.cpp
+++ b/regamedll/dlls/hostage/states/hostage_follow.cpp
@@ -137,7 +137,7 @@ void HostageFollowState::__MAKE_VHOOK(OnUpdate)(CHostageImprov *improv)
bool makeWay = false;
const float cosTolerance = 0.99f;
- if (improv->IsPlayerLookingAtMe((CBasePlayer *)((CBaseEntity *)m_leader), cosTolerance))
+ if (improv->IsPlayerLookingAtMe((CBasePlayer *)m_leader, cosTolerance))
{
if (!m_makeWayTimer.HasStarted())
{
diff --git a/regamedll/dlls/multiplay_gamerules.cpp b/regamedll/dlls/multiplay_gamerules.cpp
index 5dcfd968..4febf01f 100644
--- a/regamedll/dlls/multiplay_gamerules.cpp
+++ b/regamedll/dlls/multiplay_gamerules.cpp
@@ -448,7 +448,7 @@ CHalfLifeMultiplay::CHalfLifeMultiplay(void)
m_iAccountCT = 0;
m_iAccountTerrorist = 0;
m_iHostagesRescued = 0;
- m_iRoundWinStatus = 0;
+ m_iRoundWinStatus = WINNER_NONE;
m_iNumCTWins = 0;
m_iNumTerroristWins = 0;
m_pVIP = NULL;
@@ -949,7 +949,7 @@ void CHalfLifeMultiplay::QueueCareerRoundEndMenu(float tmDelay, int iWinStatus)
{
numHostagesInMap++;
- CHostage *pHostage = reinterpret_cast(hostage);
+ CHostage *pHostage = static_cast(hostage);
if (pHostage->pev->takedamage != DAMAGE_YES)
{
@@ -958,17 +958,8 @@ void CHalfLifeMultiplay::QueueCareerRoundEndMenu(float tmDelay, int iWinStatus)
CBasePlayer *pLeader = NULL;
- if (pHostage->m_improv != NULL)
- {
- if (pHostage->IsFollowingSomeone())
- {
- pLeader = reinterpret_cast(pHostage->GetLeader());
- }
- }
- else if (pHostage->m_hTargetEnt != NULL && pHostage->m_State == CHostage::FOLLOW)
- {
- pLeader = (CBasePlayer *)((CBaseEntity *)pHostage->m_hTargetEnt);
- }
+ if (pHostage->IsFollowingSomeone())
+ pLeader = static_cast(pHostage->GetLeader());
if (pLeader == NULL)
{
@@ -1042,7 +1033,7 @@ void CHalfLifeMultiplay::__MAKE_VHOOK(CheckWinConditions)(void)
#endif // REGAMEDLL_ADD
// If a winner has already been determined and game of started.. then get the heck out of here
- if (m_bFirstConnected && m_iRoundWinStatus != 0)
+ if (m_bFirstConnected && m_iRoundWinStatus != WINNER_NONE)
{
return;
}
@@ -2091,7 +2082,7 @@ void CHalfLifeMultiplay::__MAKE_VHOOK(RestartRound)(void)
m_iAccountTerrorist = m_iAccountCT = 0;
m_iHostagesRescued = 0;
m_iHostagesTouched = 0;
- m_iRoundWinStatus = 0;
+ m_iRoundWinStatus = WINNER_NONE;
m_bTargetBombed = m_bBombDefused = false;
m_bLevelInitialized = false;
m_bCompleteReset = false;
@@ -3000,7 +2991,7 @@ void CHalfLifeMultiplay::CheckRestartRound(void)
bool CHalfLifeMultiplay::HasRoundTimeExpired(void)
{
// We haven't completed other objectives, so go for this!.
- if (TimeRemaining() > 0 || m_iRoundWinStatus != 0)
+ if (TimeRemaining() > 0 || m_iRoundWinStatus != WINNER_NONE)
{
return false;
}
diff --git a/regamedll/dlls/player.h b/regamedll/dlls/player.h
index f646a8a9..b2a16488 100644
--- a/regamedll/dlls/player.h
+++ b/regamedll/dlls/player.h
@@ -463,10 +463,7 @@ public:
virtual void Precache(void);
virtual int Save(CSave &save);
virtual int Restore(CRestore &restore);
- virtual int ObjectCaps(void)
- {
- return (CBaseMonster::ObjectCaps() & ~FCAP_ACROSS_TRANSITION);
- }
+ virtual int ObjectCaps(void) { return (CBaseMonster::ObjectCaps() & ~FCAP_ACROSS_TRANSITION); }
virtual int Classify(void);
virtual void TraceAttack(entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType);
virtual int TakeDamage(entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType);
@@ -477,60 +474,30 @@ public:
virtual BOOL AddPlayerItem(CBasePlayerItem *pItem);
virtual BOOL RemovePlayerItem(CBasePlayerItem *pItem);
virtual int GiveAmmo(int iAmount, char *szName, int iMax);
- virtual void StartSneaking(void)
- {
- m_tSneaking = gpGlobals->time - 1;
- }
- virtual void StopSneaking(void)
- {
- m_tSneaking = gpGlobals->time + 30;
- }
- virtual BOOL IsSneaking(void)
- {
- return m_tSneaking <= gpGlobals->time;
- }
- virtual BOOL IsAlive(void)
- {
- return (pev->deadflag == DEAD_NO && pev->health > 0.0f);
- }
- virtual BOOL IsPlayer(void)
- {
- return (pev->flags & FL_SPECTATOR) != FL_SPECTATOR;
- }
- virtual BOOL IsNetClient(void)
- {
- return TRUE;
- }
+ virtual void StartSneaking(void) { m_tSneaking = gpGlobals->time - 1; }
+ virtual void StopSneaking(void) { m_tSneaking = gpGlobals->time + 30; }
+ virtual BOOL IsSneaking(void) { return m_tSneaking <= gpGlobals->time; }
+ virtual BOOL IsAlive(void) { return (pev->deadflag == DEAD_NO && pev->health > 0.0f); }
+ virtual BOOL IsPlayer(void) { return (pev->flags & FL_SPECTATOR) != FL_SPECTATOR; }
+ virtual BOOL IsNetClient(void) { return TRUE; }
virtual const char *TeamID(void);
virtual BOOL FBecomeProne(void);
- virtual Vector BodyTarget(const Vector &posSrc)
- {
- return Center() + pev->view_ofs * RANDOM_FLOAT(0.5, 1.1);
- }
+ virtual Vector BodyTarget(const Vector &posSrc) { return Center() + pev->view_ofs * RANDOM_FLOAT(0.5, 1.1); }
virtual int Illumination(void);
- virtual BOOL ShouldFadeOnDeath(void)
- {
- return FALSE;
- }
+ virtual BOOL ShouldFadeOnDeath(void) { return FALSE; }
virtual void ResetMaxSpeed(void);
virtual void Jump(void);
virtual void Duck(void);
virtual void PreThink(void);
virtual void PostThink(void);
virtual Vector GetGunPosition(void);
- virtual BOOL IsBot(void)
- {
- return FALSE;
- }
+ virtual BOOL IsBot(void) { return FALSE; }
virtual void UpdateClientData(void);
virtual void ImpulseCommands(void);
virtual void RoundRespawn(void);
virtual Vector GetAutoaimVector(float flDelta);
virtual void Blind(float flUntilTime, float flHoldTime, float flFadeTime, int iAlpha);
- virtual void OnTouchingWeapon(CWeaponBox *pWeapon)
- {
- ;
- }
+ virtual void OnTouchingWeapon(CWeaponBox *pWeapon) { }
#ifdef HOOK_GAMEDLL
@@ -573,10 +540,7 @@ public:
void Observer_SetMode(int iMode);
void Observer_CheckTarget(void);
void Observer_CheckProperties(void);
- int IsObserver(void)
- {
- return pev->iuser1;
- }
+ int IsObserver(void) { return pev->iuser1; }
NOXREF void PlantC4(void);
void Radio(const char *msg_id, const char *msg_verbose = NULL, short pitch = 100, bool showIcon = true);
CBasePlayer *GetNextRadioRecipient(CBasePlayer *pStartPlayer);
@@ -623,10 +587,7 @@ public:
void UpdatePlayerSound(void);
void DeathSound(void);
void SetAnimation(PLAYER_ANIM playerAnim);
- NOXREF void SetWeaponAnimType(const char *szExtention)
- {
- Q_strcpy(m_szAnimExtention, szExtention);
- }
+ NOXREF void SetWeaponAnimType(const char *szExtention) { Q_strcpy(m_szAnimExtention, szExtention); }
void CheatImpulseCommands(int iImpulse);
void StartDeathCam(void);
void StartObserver(Vector vecPosition, Vector vecViewAngle);
@@ -685,10 +646,7 @@ public:
void SendWeatherInfo(void);
void UpdateShieldCrosshair(bool draw);
bool HasShield(void);
- bool IsProtectedByShield(void)
- {
- return HasShield() && m_bShieldDrawn;
- }
+ bool IsProtectedByShield(void) { return HasShield() && m_bShieldDrawn; }
void RemoveShield(void);
void DropShield(bool bDeploy = true);
void GiveShield(bool bDeploy = true);
@@ -696,27 +654,17 @@ public:
bool SelectSpawnSpot(const char *pEntClassName, CBaseEntity* &pSpot);
bool IsReloading(void)
{
- if (m_pActiveItem != NULL && ((CBasePlayerWeapon *)m_pActiveItem)->m_fInReload)
+ CBasePlayerWeapon *weapon = static_cast(m_pActiveItem);
+
+ if (weapon != NULL && weapon->m_fInReload)
return true;
return false;
}
- bool IsBlind(void)
- {
- return (m_blindUntilTime > gpGlobals->time);
- }
- bool IsAutoFollowAllowed(void)
- {
- return (gpGlobals->time > m_allowAutoFollowTime);
- }
- void InhibitAutoFollow(float duration)
- {
- m_allowAutoFollowTime = duration;
- }
- void AllowAutoFollow(void)
- {
- m_allowAutoFollowTime = 0;
- }
+ bool IsBlind(void) const { return (m_blindUntilTime > gpGlobals->time); }
+ bool IsAutoFollowAllowed(void) const { return (gpGlobals->time > m_allowAutoFollowTime); }
+ void InhibitAutoFollow(float duration) { m_allowAutoFollowTime = gpGlobals->time + duration; }
+ void AllowAutoFollow(void) { m_allowAutoFollowTime = 0; }
void ClearAutoBuyData(void);
void AddAutoBuyData(const char *str);
void AutoBuy(void);
@@ -744,15 +692,9 @@ public:
void RebuyNightVision(void);
void RebuyArmor(void);
void UpdateLocation(bool forceUpdate = false);
- void SetObserverAutoDirector(bool val)
- {
- m_bObserverAutoDirector = val;
- }
+ void SetObserverAutoDirector(bool val) { m_bObserverAutoDirector = val; }
bool IsObservingPlayer(CBasePlayer *pPlayer);
- bool CanSwitchObserverModes(void)
- {
- return m_canSwitchObserverModes;
- }
+ bool CanSwitchObserverModes(void) const { return m_canSwitchObserverModes; }
NOXREF void Intense(void)
{
//m_musicState = INTENSE;
diff --git a/regamedll/dlls/triggers.cpp b/regamedll/dlls/triggers.cpp
index ca5b8c3f..b4fc68fb 100644
--- a/regamedll/dlls/triggers.cpp
+++ b/regamedll/dlls/triggers.cpp
@@ -2271,7 +2271,7 @@ void CTriggerCamera::FollowTarget(void)
if (m_hPlayer->IsAlive())
{
SET_VIEW(m_hPlayer->edict(), m_hPlayer->edict());
- ((CBasePlayer *)((CBaseEntity *)m_hPlayer))->EnableControl(TRUE);
+ ((CBasePlayer *)m_hPlayer)->EnableControl(TRUE);
}
SUB_UseTargets(this, USE_TOGGLE, 0);
diff --git a/regamedll/dlls/tutor_cs_tutor.cpp b/regamedll/dlls/tutor_cs_tutor.cpp
index 4f534643..c91457c3 100644
--- a/regamedll/dlls/tutor_cs_tutor.cpp
+++ b/regamedll/dlls/tutor_cs_tutor.cpp
@@ -701,7 +701,7 @@ void CCSTutor::ProcessShownDeathsForEvent(TutorMessageEvent *event)
return;
}
- for (int i = 0; i < ARRAYSIZE(m_playerDeathInfo); i++)
+ for (int i = 0; i < ARRAYSIZE(m_playerDeathInfo); ++i)
{
if (m_playerDeathInfo[i].m_event == event)
{
@@ -1071,7 +1071,7 @@ void CCSTutor::ClearEventList(void)
/* <213289> ../cstrike/dlls/tutor_cs_tutor.cpp:1175 */
void CCSTutor::DeleteEvent(TutorMessageEvent *event)
{
- for (int i = 0; i < ARRAYSIZE(m_playerDeathInfo); i++)
+ for (int i = 0; i < ARRAYSIZE(m_playerDeathInfo); ++i)
{
if (m_playerDeathInfo[i].m_event == event)
{
@@ -1409,7 +1409,7 @@ void CCSTutor::HandleWeaponFired(CBaseEntity *entity, CBaseEntity *other)
if (localPlayer != NULL && localPlayer->IsAlive())
{
- CBasePlayer *player = reinterpret_cast(entity);
+ CBasePlayer *player = static_cast(entity);
if (player != NULL && player == localPlayer)
{
@@ -1425,7 +1425,7 @@ void CCSTutor::HandleWeaponFiredOnEmpty(CBaseEntity *entity, CBaseEntity *other)
if (localPlayer != NULL)
{
- CBasePlayer *player = reinterpret_cast(entity);
+ CBasePlayer *player = static_cast(entity);
if (player != NULL && player->IsPlayer() && player == localPlayer)
{
@@ -1449,7 +1449,7 @@ void CCSTutor::HandleWeaponFiredOnEmpty(CBaseEntity *entity, CBaseEntity *other)
/* <213817> ../cstrike/dlls/tutor_cs_tutor.cpp:1654 */
void CCSTutor::HandleWeaponReloaded(CBaseEntity *entity, CBaseEntity *other)
{
- CBasePlayer *player = reinterpret_cast(entity);
+ CBasePlayer *player = static_cast(entity);
if (player != NULL && player->IsPlayer() && player == UTIL_GetLocalPlayer())
{
@@ -1467,8 +1467,8 @@ void CCSTutor::HandlePlayerDied(CBaseEntity *entity, CBaseEntity *other)
return;
}
- CBasePlayer *victim = reinterpret_cast(entity);
- CBasePlayer *attacker = reinterpret_cast(other);
+ CBasePlayer *victim = static_cast(entity);
+ CBasePlayer *attacker = static_cast(other);
if (victim != NULL && !victim->IsPlayer())
{
@@ -1711,8 +1711,8 @@ void CCSTutor::HandlePlayerTookDamage(CBaseEntity *entity, CBaseEntity *other)
if (localPlayer != NULL)
{
- CBasePlayer *victim = reinterpret_cast(entity);
- CBasePlayer *attacker = reinterpret_cast(other);
+ CBasePlayer *victim = static_cast(entity);
+ CBasePlayer *attacker = static_cast(other);
if (victim != NULL && !victim->IsPlayer())
{
@@ -1742,7 +1742,7 @@ void CCSTutor::HandlePlayerBlindedByFlashbang(CBaseEntity *entity, CBaseEntity *
if (localPlayer != NULL)
{
- CBasePlayer *player = reinterpret_cast(entity);
+ CBasePlayer *player = static_cast(entity);
if (player != NULL && player->IsPlayer() && player == localPlayer)
{
@@ -1754,7 +1754,7 @@ void CCSTutor::HandlePlayerBlindedByFlashbang(CBaseEntity *entity, CBaseEntity *
/* <213ab7> ../cstrike/dlls/tutor_cs_tutor.cpp:2008 */
void CCSTutor::HandlePlayerSpawned(CBaseEntity *entity, CBaseEntity *other)
{
- CBasePlayer *player = reinterpret_cast(entity);
+ CBasePlayer *player = static_cast(entity);
if (player->IsPlayer() && player == UTIL_GetLocalPlayer())
{
@@ -1767,7 +1767,7 @@ void CCSTutor::HandlePlayerSpawned(CBaseEntity *entity, CBaseEntity *other)
/* <21868e> ../cstrike/dlls/tutor_cs_tutor.cpp:2033 */
NOXREF void CCSTutor::HandleClientCorpseSpawned(CBaseEntity *entity, CBaseEntity *other)
{
- CBasePlayer *player = reinterpret_cast(entity);
+ CBasePlayer *player = static_cast(entity);
if (player == NULL || !player->IsPlayer())
{
@@ -1850,7 +1850,7 @@ void CCSTutor::HandleBombDefused(CBaseEntity *entity, CBaseEntity *other)
if (localPlayer != NULL)
{
- CBasePlayer *defuser = reinterpret_cast(entity);
+ CBasePlayer *defuser = static_cast(entity);
if (defuser != NULL && defuser->IsPlayer() && defuser == localPlayer)
{
@@ -1881,7 +1881,7 @@ void CCSTutor::HandleBombDefusing(CBaseEntity *entity, CBaseEntity *other)
if (localPlayer != NULL)
{
- CBasePlayer *player = reinterpret_cast(entity);
+ CBasePlayer *player = static_cast(entity);
if (player != NULL && player->IsPlayer() && player == localPlayer && !player->m_bHasDefuser)
{
@@ -1962,7 +1962,7 @@ void CCSTutor::HandleBeingShotAt(CBaseEntity *entity, CBaseEntity *other)
if (localPlayer != NULL)
{
- CBasePlayer *player = reinterpret_cast(entity);
+ CBasePlayer *player = static_cast(entity);
if (player != NULL && player->IsPlayer() && player == localPlayer && localPlayer->IsAlive())
{
@@ -1978,7 +1978,7 @@ void CCSTutor::HandleHostageUsed(CBaseEntity *entity, CBaseEntity *other)
if (localPlayer != NULL)
{
- CBasePlayer *activator = reinterpret_cast(entity);
+ CBasePlayer *activator = static_cast(entity);
if (activator != NULL && activator->IsPlayer())
{
@@ -2013,7 +2013,7 @@ void CCSTutor::HandleHostageRescued(CBaseEntity *entity, CBaseEntity *other)
if (localPlayer != NULL)
{
- CBasePlayer *rescuer = reinterpret_cast(entity);
+ CBasePlayer *rescuer = static_cast(entity);
if (rescuer != NULL && rescuer->IsPlayer())
{
@@ -2060,7 +2060,7 @@ void CCSTutor::HandleHostageDamaged(CBaseEntity *entity, CBaseEntity *other)
if (localPlayer != NULL)
{
- CBasePlayer *attacker = reinterpret_cast(other);
+ CBasePlayer *attacker = static_cast(other);
if (entity != NULL && attacker != NULL && attacker->IsPlayer() && localPlayer == attacker)
{
@@ -2078,7 +2078,7 @@ void CCSTutor::HandleHostageKilled(CBaseEntity *entity, CBaseEntity *other)
{
CheckForAllHostagesDead();
- CBasePlayer *attacker = reinterpret_cast(other);
+ CBasePlayer *attacker = static_cast(other);
if (entity != NULL && attacker != NULL && attacker->IsPlayer())
{
@@ -2141,7 +2141,7 @@ void CCSTutor::HandleDeathCameraStart(CBaseEntity *entity, CBaseEntity *other)
if (localPlayer != NULL)
{
- CBasePlayer *player = reinterpret_cast(entity);
+ CBasePlayer *player = static_cast(entity);
if (player != NULL && player->IsPlayer() && player == localPlayer)
{
@@ -2362,9 +2362,9 @@ void CCSTutor::GetNumPlayersAliveOnTeams(int &numT, int &numCT)
numT = 0;
numCT = 0;
- for (int i = 1; i <= gpGlobals->maxClients; i++)
+ for (int i = 1; i <= gpGlobals->maxClients; ++i)
{
- CBasePlayer *player = reinterpret_cast(UTIL_PlayerByIndex(i));
+ CBasePlayer *player = static_cast(UTIL_PlayerByIndex(i));
if (player == NULL || !player->IsAlive())
{
@@ -2481,9 +2481,9 @@ void CCSTutor::CheckForBombViewable(void)
{
CBasePlayer *bombCarrier = NULL;
- for (int i = 1; i <= gpGlobals->maxClients; i++)
+ for (int i = 1; i <= gpGlobals->maxClients; ++i)
{
- CBasePlayer *player = reinterpret_cast(UTIL_PlayerByIndex(i));
+ CBasePlayer *player = static_cast(UTIL_PlayerByIndex(i));
if (player && player->m_bHasC4)
{
@@ -2683,9 +2683,7 @@ void CCSTutor::CheckForHostageViewable(void)
CBasePlayer *localPlayer = UTIL_GetLocalPlayer();
if (localPlayer == NULL)
- {
return;
- }
CBaseEntity *hostageEntity = NULL;
bool sawFirst = false;
@@ -2693,21 +2691,12 @@ void CCSTutor::CheckForHostageViewable(void)
while ((hostageEntity = UTIL_FindEntityByClassname(hostageEntity, "hostage_entity")) != NULL)
{
bool validHostage = false;
- CHostage *hostage = reinterpret_cast(hostageEntity);
+ CHostage *hostage = static_cast(hostageEntity);
if (hostage->pev->takedamage == DAMAGE_YES)
{
- if (hostage->m_improv != NULL)
- {
- if (!hostage->IsFollowingSomeone())
- {
- validHostage = true;
- }
- }
- else if (hostage->m_hTargetEnt == NULL || hostage->m_State != CHostage::FOLLOW)
- {
+ if (!hostage->IsFollowingSomeone())
validHostage = true;
- }
}
if (hostage->IsValid() && validHostage && IsEntityInViewOfPlayer(hostage, localPlayer) && !sawFirst)
@@ -2813,15 +2802,7 @@ bool CCSTutor::CheckForAllHostagesFollowingSomeone(void)
{
if (hostage->pev->takedamage == DAMAGE_YES)
{
- if (hostage->m_improv != NULL)
- {
- if (!hostage->IsFollowingSomeone())
- {
- foundUnusedOne = true;
- break;
- }
- }
- else if (hostage->m_hTargetEnt == NULL || hostage->m_State != CHostage::FOLLOW)
+ if (!hostage->IsFollowingSomeone())
{
foundUnusedOne = true;
break;
@@ -3098,7 +3079,7 @@ void CCSTutor::CheckExamineMessages(float time)
return;
}
- for (int i = 0; i < TUTOR_NUM_MESSAGES; i++)
+ for (int i = 0; i < TUTOR_NUM_MESSAGES; ++i)
{
//bool sawOne = false;
@@ -3160,48 +3141,33 @@ void CCSTutor::CheckExamineMessages(float time)
if (i == YOU_SEE_FRIEND)
{
- CBasePlayer *player = reinterpret_cast(entity);
+ CBasePlayer *player = static_cast(entity);
if (player->IsPlayer() && player->IsAlive() && player->m_iTeam == localPlayer->m_iTeam)
- {
validEntity = true;
- }
}
else if (i == YOU_SEE_ENEMY)
{
- CBasePlayer *player = reinterpret_cast(entity);
+ CBasePlayer *player = static_cast(entity);
if (player->IsPlayer() && player->IsAlive() && player->m_iTeam == localPlayer->m_iTeam)
{
if ((player->m_iTeam != CT || localPlayer->m_iTeam == TERRORIST) && (player->m_iTeam != TERRORIST || localPlayer->m_iTeam == CT))
- {
validEntity = true;
- }
}
}
else if (i == YOU_SEE_HOSTAGE_CT_EXAMINE)
{
- CHostage *hostage = reinterpret_cast(entity);
+ CHostage *hostage = static_cast(entity);
if (entity->pev->takedamage == DAMAGE_YES)
{
- if (hostage->m_improv != NULL)
- {
- if (!hostage->IsFollowingSomeone())
- {
- validEntity = true;
- }
- }
- else if (hostage->m_hTargetEnt == NULL || hostage->m_State != CHostage::FOLLOW)
- {
+ if (!hostage->IsFollowingSomeone())
validEntity = true;
- }
}
if (!hostage->IsValid() || !validEntity)
- {
continue;
- }
}
if (validEntity)
@@ -3291,7 +3257,7 @@ bool CCSTutor::IsBombMap(void)
/* <216d35> ../cstrike/dlls/tutor_cs_tutor.cpp:3781 */
void CCSTutor::ResetPlayerDeathInfo(void)
{
- for (int i = 0; i < ARRAYSIZE(m_playerDeathInfo); i++)
+ for (int i = 0; i < ARRAYSIZE(m_playerDeathInfo); ++i)
{
m_playerDeathInfo[i].m_hasBeenShown = false;
m_playerDeathInfo[i].m_event = NULL;
@@ -3309,9 +3275,9 @@ void CCSTutor::ConstructRecentDeathsList(TeamName team, char *buf, int buflen, T
char scratch[32];
buf[0] = '\0';
- for (int i = 1; i <= gpGlobals->maxClients; i++)
+ for (int i = 1; i <= gpGlobals->maxClients; ++i)
{
- CBasePlayer *pPlayer = reinterpret_cast(UTIL_PlayerByIndex(i));
+ CBasePlayer *pPlayer = static_cast(UTIL_PlayerByIndex(i));
if (pPlayer == NULL)
continue;
@@ -3334,7 +3300,7 @@ void CCSTutor::ConstructRecentDeathsList(TeamName team, char *buf, int buflen, T
/* <216dc2> ../cstrike/dlls/tutor_cs_tutor.cpp:3853 */
void CCSTutor::TransferDeathEvents(TutorMessageEvent *oldEvent, TutorMessageEvent *newEvent)
{
- for (int i = 0; i < ARRAYSIZE(m_playerDeathInfo); i++)
+ for (int i = 0; i < ARRAYSIZE(m_playerDeathInfo); ++i)
{
if (m_playerDeathInfo[i].m_event == oldEvent)
{
diff --git a/regamedll/dlls/weapons.cpp b/regamedll/dlls/weapons.cpp
index d3efb25a..30b71b8b 100644
--- a/regamedll/dlls/weapons.cpp
+++ b/regamedll/dlls/weapons.cpp
@@ -587,7 +587,7 @@ void CBasePlayerItem::CheckRespawn(void)
}
}
-// Respawn- this item is already in the world, but it is
+// Respawn - this item is already in the world, but it is
// invisible and intangible. Make it visible and tangible.
/* <1d1e09> ../cstrike/dlls/weapons.cpp:616 */
@@ -620,6 +620,9 @@ CBaseEntity *CBasePlayerItem::__MAKE_VHOOK(Respawn)(void)
return pNewWeapon;
}
+// whats going on here is that if the player drops this weapon, they shouldn't take it back themselves
+// for a little while. But if they throw it at someone else, the other player should get it immediately.
+
/* <1d26f0> ../cstrike/dlls/weapons.cpp:642 */
void CBasePlayerItem::DefaultTouch(CBaseEntity *pOther)
{
@@ -629,7 +632,7 @@ void CBasePlayerItem::DefaultTouch(CBaseEntity *pOther)
return;
}
- CBasePlayer *pPlayer = reinterpret_cast(pOther);
+ CBasePlayer *pPlayer = static_cast(pOther);
if (pPlayer->m_bIsVIP
&& m_iId != WEAPON_USP
@@ -789,6 +792,8 @@ void CBasePlayerWeapon::KickBack(float up_base, float lateral_base, float up_mod
/* <1d242e> ../cstrike/dlls/weapons.cpp:792 */
void CBasePlayerWeapon::FireRemaining(int &shotsFired, float &shootTime, BOOL bIsGlock)
{
+ float nexttime = 0.1f;
+
m_iClip--;
if (m_iClip < 0)
@@ -831,16 +836,15 @@ void CBasePlayerWeapon::FireRemaining(int &shotsFired, float &shootTime, BOOL bI
m_pPlayer->pev->effects |= EF_MUZZLEFLASH;
m_pPlayer->SetAnimation(PLAYER_ATTACK1);
- shotsFired++;
- float nexttime = 0;
+ shotsFired++;
if (shotsFired != 3)
{
- nexttime = gpGlobals->time + 0.1f;
+ shootTime = gpGlobals->time + nexttime;
}
-
- shootTime = nexttime;
+ else
+ shootTime = 0;
}
/* <1d389e> ../cstrike/dlls/weapons.cpp:876 */
@@ -911,6 +915,8 @@ void CBasePlayerWeapon::__MAKE_VHOOK(ItemPostFrame)(void)
FireRemaining(m_iFamasShotsFired, m_flFamasShoot, FALSE);
}
+ // Return zoom level back to previous zoom level before we fired a shot.
+ // This is used only for the AWP and Scout
if (m_flNextPrimaryAttack <= UTIL_WeaponTimeBase())
{
if (m_pPlayer->m_bResumeZoom)
@@ -920,6 +926,7 @@ void CBasePlayerWeapon::__MAKE_VHOOK(ItemPostFrame)(void)
if (m_pPlayer->m_iFOV == m_pPlayer->m_iLastZoom)
{
+ // return the fade level in zoom.
m_pPlayer->m_bResumeZoom = false;
}
}
@@ -978,6 +985,8 @@ void CBasePlayerWeapon::__MAKE_VHOOK(ItemPostFrame)(void)
m_pPlayer->TabulateAmmo();
+ // Can't shoot during the freeze period
+ // Always allow firing in single player
if ((m_pPlayer->m_bCanShoot && g_pGameRules->IsMultiplayer() && !g_pGameRules->IsFreezePeriod() && !m_pPlayer->m_bIsDefusing) || !g_pGameRules->IsMultiplayer())
{
PrimaryAttack();
@@ -985,6 +994,7 @@ void CBasePlayerWeapon::__MAKE_VHOOK(ItemPostFrame)(void)
}
else if ((m_pPlayer->pev->button & IN_RELOAD) && iMaxClip() != WEAPON_NOCLIP && !m_fInReload && m_flNextPrimaryAttack < UTIL_WeaponTimeBase())
{
+ // reload when reload is pressed, or if no buttons are down and weapon is empty.
if (m_flFamasShoot == 0 && m_flGlock18Shoot == 0)
{
if (!(m_iWeaponState & WPNSTATE_SHIELD_DRAWN))
@@ -997,6 +1007,9 @@ void CBasePlayerWeapon::__MAKE_VHOOK(ItemPostFrame)(void)
else if (!(usableButtons & (IN_ATTACK | IN_ATTACK2)))
{
// no fire buttons down
+
+ // The following code prevents the player from tapping the firebutton repeatedly
+ // to simulate full auto and retaining the single shot accuracy of single fire
if (m_bDelayFire)
{
m_bDelayFire = false;
@@ -1011,16 +1024,19 @@ void CBasePlayerWeapon::__MAKE_VHOOK(ItemPostFrame)(void)
m_fFireOnEmpty = FALSE;
- if (m_iId != WEAPON_USP && m_iId != WEAPON_GLOCK18 && m_iId != WEAPON_P228 && m_iId != WEAPON_DEAGLE && m_iId != WEAPON_ELITE && m_iId != WEAPON_FIVESEVEN)
+ // if it's a pistol then set the shots fired to 0 after the player releases a button
+ if (IsSecondaryWeapon(m_iId))
+ {
+ m_iShotsFired = 0;
+ }
+ else
{
if (m_iShotsFired > 0 && m_flDecreaseShotsFired < gpGlobals->time)
{
+ m_flDecreaseShotsFired = gpGlobals->time + 0.0225f;
m_iShotsFired--;
- m_flDecreaseShotsFired = gpGlobals->time + 0.0225;
}
}
- else
- m_iShotsFired = 0;
if (!IsUseable() && m_flNextPrimaryAttack < UTIL_WeaponTimeBase())
{
diff --git a/regamedll/dlls/weapons.h b/regamedll/dlls/weapons.h
index d580145e..54c46357 100644
--- a/regamedll/dlls/weapons.h
+++ b/regamedll/dlls/weapons.h
@@ -489,10 +489,7 @@ public:
float GetNextAttackDelay(float delay);
float GetNextAttackDelay2(float delay);
bool HasSecondaryAttack(void);
- BOOL IsPistol(void)
- {
- return FALSE;
- }
+ BOOL IsPistol(void) { return (m_iId == WEAPON_USP || m_iId == WEAPON_GLOCK18 || m_iId == WEAPON_P228 || m_iId == WEAPON_DEAGLE || m_iId == WEAPON_ELITE || m_iId == WEAPON_FIVESEVEN); }
void SetPlayerShieldAnim(void);
void ResetPlayerShieldAnim(void);
bool ShieldSecondaryFire(int iUpAnim, int iDownAnim);
@@ -523,8 +520,8 @@ public:
int m_iShotsFired;
Vector m_vVecAiming;
string_t model_name;
- float m_flGlock18Shoot;
- int m_iGlock18ShotsFired;
+ float m_flGlock18Shoot; // time to shoot the remaining bullets of the glock18 burst fire
+ int m_iGlock18ShotsFired; // used to keep track of the shots fired during the Glock18 burst fire mode.
float m_flFamasShoot;
int m_iFamasShotsFired;
float m_fBurstSpread;
@@ -2224,7 +2221,7 @@ extern int giAmmoIndex;
extern short g_sModelIndexRadio;
extern MULTIDAMAGE gMultiDamage;
-void FindHullIntersection(Vector &vecSrc, TraceResult &tr, float *mins, float *maxs, edict_t *pEntity);
+void FindHullIntersection(const Vector &vecSrc, TraceResult &tr, float *mins, float *maxs, edict_t *pEntity);
void AnnounceFlashInterval(float interval, float offset = 0);
int MaxAmmoCarry(int iszName);
diff --git a/regamedll/dlls/weapontype.cpp b/regamedll/dlls/weapontype.cpp
index e060153c..54eb7caa 100644
--- a/regamedll/dlls/weapontype.cpp
+++ b/regamedll/dlls/weapontype.cpp
@@ -7,41 +7,41 @@
AutoBuyInfoStruct g_autoBuyInfo[] =
{
- { (AutoBuyClassType)(AUTOBUYCLASS_PRIMARY | AUTOBUYCLASS_RIFLE), "galil", "weapon_galil" },
- { (AutoBuyClassType)(AUTOBUYCLASS_PRIMARY | AUTOBUYCLASS_RIFLE), "ak47", "weapon_ak47" },
- { (AutoBuyClassType)(AUTOBUYCLASS_PRIMARY | AUTOBUYCLASS_SNIPERRIFLE), "scout", "weapon_scout" },
- { (AutoBuyClassType)(AUTOBUYCLASS_PRIMARY | AUTOBUYCLASS_RIFLE), "sg552", "weapon_sg552" },
- { (AutoBuyClassType)(AUTOBUYCLASS_PRIMARY | AUTOBUYCLASS_SNIPERRIFLE), "awp", "weapon_awp" },
- { (AutoBuyClassType)(AUTOBUYCLASS_PRIMARY | AUTOBUYCLASS_SNIPERRIFLE), "g3sg1", "weapon_g3sg1" },
- { (AutoBuyClassType)(AUTOBUYCLASS_PRIMARY | AUTOBUYCLASS_RIFLE), "famas", "weapon_famas" },
- { (AutoBuyClassType)(AUTOBUYCLASS_PRIMARY | AUTOBUYCLASS_RIFLE), "m4a1", "weapon_m4a1" },
- { (AutoBuyClassType)(AUTOBUYCLASS_PRIMARY | AUTOBUYCLASS_RIFLE), "aug", "weapon_aug" },
- { (AutoBuyClassType)(AUTOBUYCLASS_PRIMARY | AUTOBUYCLASS_SNIPERRIFLE), "sg550", "weapon_sg550" },
- { (AutoBuyClassType)(AUTOBUYCLASS_SECONDARY | AUTOBUYCLASS_PISTOL), "glock", "weapon_glock18" },
- { (AutoBuyClassType)(AUTOBUYCLASS_SECONDARY | AUTOBUYCLASS_PISTOL), "usp", "weapon_usp" },
- { (AutoBuyClassType)(AUTOBUYCLASS_SECONDARY | AUTOBUYCLASS_PISTOL), "p228", "weapon_p228" },
- { (AutoBuyClassType)(AUTOBUYCLASS_SECONDARY | AUTOBUYCLASS_PISTOL), "deagle", "weapon_deagle" },
- { (AutoBuyClassType)(AUTOBUYCLASS_SECONDARY | AUTOBUYCLASS_PISTOL), "elites", "weapon_elite" },
- { (AutoBuyClassType)(AUTOBUYCLASS_SECONDARY | AUTOBUYCLASS_PISTOL), "fn57", "weapon_fiveseven" },
- { (AutoBuyClassType)(AUTOBUYCLASS_PRIMARY | AUTOBUYCLASS_SHOTGUN), "m3", "weapon_m3" },
- { (AutoBuyClassType)(AUTOBUYCLASS_PRIMARY | AUTOBUYCLASS_SHOTGUN), "xm1014", "weapon_xm1014" },
- { (AutoBuyClassType)(AUTOBUYCLASS_PRIMARY | AUTOBUYCLASS_SMG), "mac10", "weapon_mac10" },
- { (AutoBuyClassType)(AUTOBUYCLASS_PRIMARY | AUTOBUYCLASS_SMG), "tmp", "weapon_tmp" },
- { (AutoBuyClassType)(AUTOBUYCLASS_PRIMARY | AUTOBUYCLASS_SMG), "mp5", "weapon_mp5navy" },
- { (AutoBuyClassType)(AUTOBUYCLASS_PRIMARY | AUTOBUYCLASS_SMG), "ump45", "weapon_ump45" },
- { (AutoBuyClassType)(AUTOBUYCLASS_PRIMARY | AUTOBUYCLASS_SMG), "p90", "weapon_p90" },
- { (AutoBuyClassType)(AUTOBUYCLASS_PRIMARY | AUTOBUYCLASS_MACHINEGUN), "m249", "weapon_m249" },
- { (AutoBuyClassType)(AUTOBUYCLASS_PRIMARY | AUTOBUYCLASS_AMMO), "primammo", "primammo" },
- { (AutoBuyClassType)(AUTOBUYCLASS_SECONDARY | AUTOBUYCLASS_AMMO), "secammo", "secammo" },
- { (AutoBuyClassType)(AUTOBUYCLASS_ARMOR), "vest", "item_kevlar" },
- { (AutoBuyClassType)(AUTOBUYCLASS_ARMOR), "vesthelm", "item_assaultsuit" },
- { (AutoBuyClassType)(AUTOBUYCLASS_GRENADE), "flash", "weapon_flashbang" },
- { (AutoBuyClassType)(AUTOBUYCLASS_GRENADE), "hegren", "weapon_hegrenade" },
- { (AutoBuyClassType)(AUTOBUYCLASS_GRENADE), "sgren", "weapon_smokegrenade"},
- { (AutoBuyClassType)(AUTOBUYCLASS_NIGHTVISION), "nvgs", "nvgs" },
- { (AutoBuyClassType)(AUTOBUYCLASS_DEFUSER), "defuser", "defuser" },
- { (AutoBuyClassType)(AUTOBUYCLASS_PRIMARY | AUTOBUYCLASS_SHIELD), "shield", "shield" },
- { (AutoBuyClassType)0, NULL, NULL }
+ { AUTOBUYCLASS_PRIMARY|AUTOBUYCLASS_RIFLE, "galil", "weapon_galil" },
+ { AUTOBUYCLASS_PRIMARY|AUTOBUYCLASS_RIFLE, "ak47", "weapon_ak47" },
+ { AUTOBUYCLASS_PRIMARY|AUTOBUYCLASS_SNIPERRIFLE, "scout", "weapon_scout" },
+ { AUTOBUYCLASS_PRIMARY|AUTOBUYCLASS_RIFLE, "sg552", "weapon_sg552" },
+ { AUTOBUYCLASS_PRIMARY|AUTOBUYCLASS_SNIPERRIFLE, "awp", "weapon_awp" },
+ { AUTOBUYCLASS_PRIMARY|AUTOBUYCLASS_SNIPERRIFLE, "g3sg1", "weapon_g3sg1" },
+ { AUTOBUYCLASS_PRIMARY|AUTOBUYCLASS_RIFLE, "famas", "weapon_famas" },
+ { AUTOBUYCLASS_PRIMARY|AUTOBUYCLASS_RIFLE, "m4a1", "weapon_m4a1" },
+ { AUTOBUYCLASS_PRIMARY|AUTOBUYCLASS_RIFLE, "aug", "weapon_aug" },
+ { AUTOBUYCLASS_PRIMARY|AUTOBUYCLASS_SNIPERRIFLE, "sg550", "weapon_sg550" },
+ { AUTOBUYCLASS_SECONDARY|AUTOBUYCLASS_PISTOL, "glock", "weapon_glock18" },
+ { AUTOBUYCLASS_SECONDARY|AUTOBUYCLASS_PISTOL, "usp", "weapon_usp" },
+ { AUTOBUYCLASS_SECONDARY|AUTOBUYCLASS_PISTOL, "p228", "weapon_p228" },
+ { AUTOBUYCLASS_SECONDARY|AUTOBUYCLASS_PISTOL, "deagle", "weapon_deagle" },
+ { AUTOBUYCLASS_SECONDARY|AUTOBUYCLASS_PISTOL, "elites", "weapon_elite" },
+ { AUTOBUYCLASS_SECONDARY|AUTOBUYCLASS_PISTOL, "fn57", "weapon_fiveseven" },
+ { AUTOBUYCLASS_PRIMARY|AUTOBUYCLASS_SHOTGUN, "m3", "weapon_m3" },
+ { AUTOBUYCLASS_PRIMARY|AUTOBUYCLASS_SHOTGUN, "xm1014", "weapon_xm1014" },
+ { AUTOBUYCLASS_PRIMARY|AUTOBUYCLASS_SMG, "mac10", "weapon_mac10" },
+ { AUTOBUYCLASS_PRIMARY|AUTOBUYCLASS_SMG, "tmp", "weapon_tmp" },
+ { AUTOBUYCLASS_PRIMARY|AUTOBUYCLASS_SMG, "mp5", "weapon_mp5navy" },
+ { AUTOBUYCLASS_PRIMARY|AUTOBUYCLASS_SMG, "ump45", "weapon_ump45" },
+ { AUTOBUYCLASS_PRIMARY|AUTOBUYCLASS_SMG, "p90", "weapon_p90" },
+ { AUTOBUYCLASS_PRIMARY|AUTOBUYCLASS_MACHINEGUN, "m249", "weapon_m249" },
+ { AUTOBUYCLASS_PRIMARY|AUTOBUYCLASS_AMMO, "primammo", "primammo" },
+ { AUTOBUYCLASS_SECONDARY|AUTOBUYCLASS_AMMO, "secammo", "secammo" },
+ { AUTOBUYCLASS_ARMOR, "vest", "item_kevlar" },
+ { AUTOBUYCLASS_ARMOR, "vesthelm", "item_assaultsuit" },
+ { AUTOBUYCLASS_GRENADE, "flash", "weapon_flashbang" },
+ { AUTOBUYCLASS_GRENADE, "hegren", "weapon_hegrenade" },
+ { AUTOBUYCLASS_GRENADE, "sgren", "weapon_smokegrenade"},
+ { AUTOBUYCLASS_NIGHTVISION, "nvgs", "nvgs" },
+ { AUTOBUYCLASS_DEFUSER, "defuser", "defuser" },
+ { AUTOBUYCLASS_PRIMARY|AUTOBUYCLASS_SHIELD, "shield", "shield" },
+ { AUTOBUYCLASS_NONE, NULL, NULL }
};
WeaponAliasInfo weaponAliasInfo[] =
@@ -225,12 +225,14 @@ WeaponInfoStruct weaponInfo[27];
#endif // HOOK_GAMEDLL
+// Given an alias, return the associated weapon ID
+
/* <22cd2a> ../cstrike/dlls/weapontype.cpp:208 */
WeaponIdType AliasToWeaponID(const char *alias)
{
if (alias != NULL)
{
- for (int i = 0; weaponAliasInfo[i].alias != NULL; i++)
+ for (int i = 0; weaponAliasInfo[i].alias != NULL; ++i)
{
if (!Q_stricmp(weaponAliasInfo[i].alias, alias))
return weaponAliasInfo[i].id;
@@ -259,6 +261,8 @@ const char *BuyAliasToWeaponID(const char *alias, WeaponIdType &id)
return NULL;
}
+// Given a weapon ID, return its alias
+
/* <22cd03> ../cstrike/dlls/weapontype.cpp:246 */
const char *WeaponIDToAlias(int id)
{
@@ -292,6 +296,8 @@ WeaponClassType WeaponIDToWeaponClass(int id)
return AliasToWeaponClass(WeaponIDToAlias(id));
}
+// Return true if given weapon ID is a primary weapon
+
/* <22cee3> ../cstrike/dlls/weapontype.cpp:285 */
bool IsPrimaryWeapon(int id)
{
@@ -324,6 +330,8 @@ bool IsPrimaryWeapon(int id)
return false;
}
+// Return true if given weapon ID is a secondary weapon
+
/* <22cf19> ../cstrike/dlls/weapontype.cpp:318 */
NOXREF bool IsSecondaryWeapon(int id)
{
diff --git a/regamedll/dlls/weapontype.h b/regamedll/dlls/weapontype.h
index 49ba93f8..19ad8533 100644
--- a/regamedll/dlls/weapontype.h
+++ b/regamedll/dlls/weapontype.h
@@ -70,6 +70,7 @@ enum WeaponIdType
enum AutoBuyClassType
{
+ AUTOBUYCLASS_NONE = 0,
AUTOBUYCLASS_PRIMARY = (1 << 0),
AUTOBUYCLASS_SECONDARY = (1 << 1),
AUTOBUYCLASS_AMMO = (1 << 2),
diff --git a/regamedll/dlls/wpn_shared/wpn_awp.cpp b/regamedll/dlls/wpn_shared/wpn_awp.cpp
index 1f89e28a..0392d8dd 100644
--- a/regamedll/dlls/wpn_shared/wpn_awp.cpp
+++ b/regamedll/dlls/wpn_shared/wpn_awp.cpp
@@ -129,6 +129,7 @@ void CAWP::AWPFire(float flSpread, float flCycleTime, BOOL fUseAutoAim)
m_pPlayer->m_iFOV = DEFAULT_FOV;
m_pPlayer->pev->fov = DEFAULT_FOV;
}
+ // If we are not zoomed in, the bullet diverts more.
else
{
flSpread += 0.08;
@@ -224,7 +225,11 @@ void CAWP::__MAKE_VHOOK(WeaponIdle)(void)
/* <23fa86> ../cstrike/dlls/wpn_shared/wpn_awp.cpp:283 */
float CAWP::__MAKE_VHOOK(GetMaxSpeed)(void)
{
- return m_pPlayer->m_iFOV == DEFAULT_FOV ? AWP_MAX_SPEED : AWP_MAX_SPEED_ZOOM;
+ if (m_pPlayer->m_iFOV == DEFAULT_FOV)
+ return AWP_MAX_SPEED;
+
+ // Slower speed when zoomed in.
+ return AWP_MAX_SPEED_ZOOM;
}
#ifdef HOOK_GAMEDLL
diff --git a/regamedll/dlls/wpn_shared/wpn_c4.cpp b/regamedll/dlls/wpn_shared/wpn_c4.cpp
index 3347381f..7ac30205 100644
--- a/regamedll/dlls/wpn_shared/wpn_c4.cpp
+++ b/regamedll/dlls/wpn_shared/wpn_c4.cpp
@@ -79,7 +79,7 @@ BOOL CC4::__MAKE_VHOOK(Deploy)(void)
void CC4::__MAKE_VHOOK(Holster)(int skiplocal)
{
m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 0.5;
- m_bStartedArming = false;
+ m_bStartedArming = false; // stop arming sequence
if (!m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType])
{
@@ -98,15 +98,14 @@ void CC4::__MAKE_VHOOK(Holster)(int skiplocal)
void CC4::__MAKE_VHOOK(PrimaryAttack)(void)
{
BOOL PlaceBomb;
- int inBombZone, onGround;
if (m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 0)
{
return;
}
- inBombZone = (m_pPlayer->m_signals.GetState() & SIGNAL_BOMB) == SIGNAL_BOMB;
- onGround = (m_pPlayer->pev->flags & FL_ONGROUND) == FL_ONGROUND;
+ int inBombZone = (m_pPlayer->m_signals.GetState() & SIGNAL_BOMB) == SIGNAL_BOMB;
+ int onGround = (m_pPlayer->pev->flags & FL_ONGROUND) == FL_ONGROUND;
PlaceBomb = (onGround && inBombZone);
if (!m_bStartedArming)
@@ -121,7 +120,7 @@ void CC4::__MAKE_VHOOK(PrimaryAttack)(void)
if (!onGround)
{
ClientPrint(m_pPlayer->pev, HUD_PRINTCENTER, "#C4_Plant_Must_Be_On_Ground");
- m_flNextPrimaryAttack = GetNextAttackDelay(1);
+ m_flNextPrimaryAttack = GetNextAttackDelay(1.0);
return;
}
@@ -129,8 +128,10 @@ void CC4::__MAKE_VHOOK(PrimaryAttack)(void)
m_bBombPlacedAnimation = false;
m_fArmedTime = gpGlobals->time + C4_ARMING_ON_TIME;
+ // player "arming bomb" animation
SendWeaponAnim(C4_ARM, UseDecrement() != FALSE);
+ // freeze the player in place while planting
SET_CLIENT_MAXSPEED(m_pPlayer->edict(), 1.0);
m_pPlayer->SetAnimation(PLAYER_ATTACK1);
@@ -186,21 +187,24 @@ void CC4::__MAKE_VHOOK(PrimaryAttack)(void)
TheCareerTasks->HandleEvent(EVENT_BOMB_PLANTED, m_pPlayer);
}
- UTIL_LogPrintf
- (
- "\"%s<%i><%s>\" triggered \"Planted_The_Bomb\"\n",
+ UTIL_LogPrintf("\"%s<%i><%s>\" triggered \"Planted_The_Bomb\"\n",
STRING(m_pPlayer->pev->netname),
GETPLAYERUSERID(m_pPlayer->edict()),
- GETPLAYERAUTHID(m_pPlayer->edict())
- );
+ GETPLAYERAUTHID(m_pPlayer->edict()));
g_pGameRules->m_bBombDropped = FALSE;
+
+ // Play the plant sound.
EMIT_SOUND(edict(), CHAN_WEAPON, "weapons/c4_plant.wav", VOL_NORM, ATTN_NORM);
+ // hide the backpack in Terrorist's models.
m_pPlayer->pev->body = 0;
- m_pPlayer->ResetMaxSpeed();
- m_pPlayer->SetBombIcon(FALSE);
+ // release the player from being frozen
+ m_pPlayer->ResetMaxSpeed();
+
+ // No more c4!
+ m_pPlayer->SetBombIcon(FALSE);
m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType]--;
if (!m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType])
@@ -214,9 +218,11 @@ void CC4::__MAKE_VHOOK(PrimaryAttack)(void)
{
if (m_fArmedTime - 0.75 <= gpGlobals->time && !m_bBombPlacedAnimation)
{
+ // call the c4 Placement animation
m_bBombPlacedAnimation = true;
-
SendWeaponAnim(C4_DROP, UseDecrement() != FALSE);
+
+ // player "place" animation
m_pPlayer->SetAnimation(PLAYER_HOLDBOMB);
}
}
@@ -231,11 +237,17 @@ void CC4::__MAKE_VHOOK(PrimaryAttack)(void)
m_bStartedArming = false;
m_flNextPrimaryAttack = GetNextAttackDelay(1.5);
+ // release the player from being frozen, we've somehow left the bomb zone
m_pPlayer->ResetMaxSpeed();
m_pPlayer->SetProgressBarTime(0);
m_pPlayer->SetAnimation(PLAYER_HOLDBOMB);
- SendWeaponAnim(m_bBombPlacedAnimation ? C4_DRAW : C4_IDLE1, UseDecrement() != FALSE);
+ // this means the placement animation is canceled
+ if (m_bBombPlacedAnimation)
+ SendWeaponAnim(C4_DRAW, UseDecrement() != FALSE);
+ else
+ SendWeaponAnim(C4_IDLE1, UseDecrement() != FALSE);
+
return;
}
}
@@ -249,13 +261,20 @@ void CC4::__MAKE_VHOOK(WeaponIdle)(void)
{
if (m_bStartedArming)
{
+ // if the player releases the attack button cancel the arming sequence
m_bStartedArming = false;
+ // release the player from being frozen
m_pPlayer->ResetMaxSpeed();
+
m_flNextPrimaryAttack = GetNextAttackDelay(1.0);
m_pPlayer->SetProgressBarTime(0);
- SendWeaponAnim(m_bBombPlacedAnimation ? C4_DRAW : C4_IDLE1, UseDecrement() != FALSE);
+ // this means the placement animation is canceled
+ if (m_bBombPlacedAnimation)
+ SendWeaponAnim(C4_DRAW, UseDecrement() != FALSE);
+ else
+ SendWeaponAnim(C4_IDLE1, UseDecrement() != FALSE);
}
if (m_flTimeWeaponIdle <= UTIL_WeaponTimeBase())
diff --git a/regamedll/dlls/wpn_shared/wpn_glock18.cpp b/regamedll/dlls/wpn_shared/wpn_glock18.cpp
index 60668bd3..7e4a0982 100644
--- a/regamedll/dlls/wpn_shared/wpn_glock18.cpp
+++ b/regamedll/dlls/wpn_shared/wpn_glock18.cpp
@@ -175,6 +175,7 @@ void CGLOCK18::GLOCK18Fire(float flSpread, float flCycleTime, BOOL bFireBurst)
if (m_flLastFire)
{
+ // Mark the time of this shot and determine the accuracy modifier based on the last shot fired...
m_flAccuracy -= (0.325 - (gpGlobals->time - m_flLastFire)) * 0.275;
if (m_flAccuracy > 0.9)
@@ -208,10 +209,13 @@ void CGLOCK18::GLOCK18Fire(float flSpread, float flCycleTime, BOOL bFireBurst)
m_iClip--;
m_pPlayer->pev->effects |= EF_MUZZLEFLASH;
+
+ // player "shoot" animation
m_pPlayer->SetAnimation(PLAYER_ATTACK1);
UTIL_MakeVectors(m_pPlayer->pev->v_angle + m_pPlayer->pev->punchangle);
+ // non-silenced
m_pPlayer->m_iWeaponVolume = NORMAL_GUN_VOLUME;
m_pPlayer->m_iWeaponFlash = NORMAL_GUN_FLASH;
@@ -233,6 +237,7 @@ void CGLOCK18::GLOCK18Fire(float flSpread, float flCycleTime, BOOL bFireBurst)
if (!m_iClip && m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 0)
{
+ // HEV suit - indicate out of ammo condition
m_pPlayer->SetSuitUpdate("!HEV_AMO0", FALSE, FALSE);
}
@@ -240,6 +245,7 @@ void CGLOCK18::GLOCK18Fire(float flSpread, float flCycleTime, BOOL bFireBurst)
if (bFireBurst)
{
+ // Fire off the next two rounds
m_iGlock18ShotsFired++;
m_flGlock18Shoot = gpGlobals->time + 0.1;
}
@@ -294,6 +300,7 @@ void CGLOCK18::__MAKE_VHOOK(WeaponIdle)(void)
SendWeaponAnim(GLOCK18_SHIELD_IDLE, UseDecrement() != FALSE);
}
}
+ // only idle if the slid isn't back
else if (m_iClip)
{
flRand = RANDOM_FLOAT(0, 1);
diff --git a/regamedll/dlls/wpn_shared/wpn_knife.cpp b/regamedll/dlls/wpn_shared/wpn_knife.cpp
index 2e8f6016..66a56999 100644
--- a/regamedll/dlls/wpn_shared/wpn_knife.cpp
+++ b/regamedll/dlls/wpn_shared/wpn_knife.cpp
@@ -93,35 +93,26 @@ NOXREF void CKnife::WeaponAnimation(int iAnimation)
flag = 0;
#endif // CLIENT_WEAPONS
- PLAYBACK_EVENT_FULL
- (
- flag,
- m_pPlayer->edict(),
- m_usKnife,
- 0,
- (float *)&g_vecZero,
- (float *)&g_vecZero,
- 0,
- 0,
- iAnimation,
- 2, // param noxref
- 3, // param noxref
- 4 // param noxref
- );
+ PLAYBACK_EVENT_FULL(flag, m_pPlayer->edict(), m_usKnife,
+ 0.0, (float *)&g_vecZero, (float *)&g_vecZero,
+ 0.0,
+ 0.0,
+ iAnimation, 2, 3, 4);
}
/* <26f852> ../cstrike/dlls/wpn_shared/wpn_knife.cpp:140 */
-void FindHullIntersection(Vector &vecSrc, TraceResult &tr, float *mins, float *maxs, edict_t *pEntity)
+void FindHullIntersection(const Vector &vecSrc, TraceResult &tr, float *mins, float *maxs, edict_t *pEntity)
{
int i, j, k;
float distance;
float *minmaxs[2] = { mins, maxs };
TraceResult tmpTrace;
- Vector vecHullEnd, vecEnd;
+ Vector vecHullEnd = tr.vecEndPos;
+ Vector vecEnd;
distance = 1e6f;
- vecHullEnd = vecSrc + ((tr.vecEndPos - vecSrc) * 2);
+ vecHullEnd = vecSrc + ((vecHullEnd - vecSrc) * 2);
UTIL_TraceLine(vecSrc, vecHullEnd, dont_ignore_monsters, pEntity, &tmpTrace);
if (tmpTrace.flFraction < 1.0f)
@@ -130,11 +121,11 @@ void FindHullIntersection(Vector &vecSrc, TraceResult &tr, float *mins, float *m
return;
}
- for (i = 0; i < 2; i++)
+ for (i = 0; i < 2; ++i)
{
- for (j = 0; j < 2; j++)
+ for (j = 0; j < 2; ++j)
{
- for (k = 0; k < 2; k++)
+ for (k = 0; k < 2; ++k)
{
vecEnd.x = vecHullEnd.x + minmaxs[i][0];
vecEnd.y = vecHullEnd.y + minmaxs[j][1];
@@ -326,10 +317,10 @@ int CKnife::Swing(int fFirst)
SendWeaponAnim(KNIFE_SHIELD_ATTACKHIT, UseDecrement() != FALSE);
m_flNextPrimaryAttack = GetNextAttackDelay(1.0);
- m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 1.2;
+ m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 1.2f;
}
- m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 2.0;
+ m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 2.0f;
// play wiff or swish sound
if (RANDOM_LONG(0, 1))
@@ -355,17 +346,17 @@ int CKnife::Swing(int fFirst)
}
m_flNextPrimaryAttack = GetNextAttackDelay(0.4);
- m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 0.5;
+ m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 0.5f;
}
else
{
SendWeaponAnim(KNIFE_SHIELD_ATTACKHIT, UseDecrement() != FALSE);
m_flNextPrimaryAttack = GetNextAttackDelay(1.0);
- m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 1.2;
+ m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 1.2f;
}
- m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 2.0;
+ m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 2.0f;
// play thwack, smack, or dong sound
float flVol = 1.0f;
@@ -378,7 +369,7 @@ int CKnife::Swing(int fFirst)
m_pPlayer->SetAnimation(PLAYER_ATTACK1);
ClearMultiDamage();
- if (m_flNextPrimaryAttack + 0.4 < UTIL_WeaponTimeBase())
+ if (m_flNextPrimaryAttack + 0.4f < UTIL_WeaponTimeBase())
pEntity->TraceAttack(m_pPlayer->pev, 20, gpGlobals->v_forward, &tr, (DMG_NEVERGIB | DMG_BULLET));
else
pEntity->TraceAttack(m_pPlayer->pev, 15, gpGlobals->v_forward, &tr, (DMG_NEVERGIB | DMG_BULLET));
@@ -429,7 +420,7 @@ int CKnife::Swing(int fFirst)
m_trHit = tr;
SetThink(&CKnife::Smack);
- pev->nextthink = UTIL_WeaponTimeBase() + 0.2;
+ pev->nextthink = UTIL_WeaponTimeBase() + 0.2f;
m_pPlayer->m_iWeaponVolume = (int)(flVol * KNIFE_WALLHIT_VOLUME);
ResetPlayerShieldAnim();
diff --git a/regamedll/engine/common.h b/regamedll/engine/common.h
index b7e5717f..0ce575f8 100644
--- a/regamedll/engine/common.h
+++ b/regamedll/engine/common.h
@@ -115,6 +115,7 @@ typedef struct incomingtransfer_s
//#define Q_strtoull strtoull
//#define Q_FileNameCmp FileNameCmp
#define Q_vsnprintf _vsnprintf
+#define Q_vsnwprintf _vsnwprintf
#else // Q_functions
void Q_strcpy(char *dest, const char *src);
int Q_strlen(const char *str);
diff --git a/regamedll/game_shared/bot/bot.cpp b/regamedll/game_shared/bot/bot.cpp
index 9ff6d645..07bd07e5 100644
--- a/regamedll/game_shared/bot/bot.cpp
+++ b/regamedll/game_shared/bot/bot.cpp
@@ -11,6 +11,7 @@ float g_flBotCommandInterval = 1.0 / 30.0;
// full AI only 10 times per second
float g_flBotFullThinkInterval = 1.0 / 10.0;
+// Nasty Hack. See client.cpp/ClientCommand()
const char *BotArgs[4] = { NULL };
bool UseBotArgs = false;
@@ -25,14 +26,24 @@ bool UseBotArgs;
#endif // HOOK_GAMEDLL
/* <48fed0> ../game_shared/bot/bot.cpp:28 */
-NOBODY CBot::CBot(void)
+CBot::CBot(void)
{
-// CBasePlayer(CBasePlayer *const this); // 28
-// {
-// unsigned int nextID; // 34
-// }
+ // the profile will be attached after this instance is constructed
+ m_profile = NULL;
+
+ // assign this bot a unique ID
+ static unsigned int nextID = 1;
+
+ // wraparound (highly unlikely)
+ if (nextID == 0)
+ ++nextID;
+
+ m_id = nextID++;
+ m_postureStackIndex = 0;
}
+// Prepare bot for action
+
/* <48f6ef> ../game_shared/bot/bot.cpp:50 */
bool CBot::__MAKE_VHOOK(Initialize)(const BotProfile *profile)
{
@@ -41,18 +52,40 @@ bool CBot::__MAKE_VHOOK(Initialize)(const BotProfile *profile)
}
/* <48fbbd> ../game_shared/bot/bot.cpp:57 */
-NOBODY void CBot::__MAKE_VHOOK(Spawn)(void)
+void CBot::__MAKE_VHOOK(Spawn)(void)
{
-// ResetCommand(CBot *const this); // 80
+ // Let CBasePlayer set some things up
+ CBasePlayer::Spawn();
+
+ // Make sure everyone knows we are a bot
+ pev->flags |= (FL_CLIENT | FL_FAKECLIENT);
+
+ // Bots use their own thinking mechanism
+ SetThink(NULL);
+ pev->nextthink = -1;
+
+ m_flNextBotThink = gpGlobals->time + g_flBotCommandInterval;
+ m_flNextFullBotThink = gpGlobals->time + g_flBotFullThinkInterval;
+ m_flPreviousCommandTime = gpGlobals->time;
+
+ m_isRunning = true;
+ m_isCrouching = false;
+ m_postureStackIndex = 0;
+
+ m_jumpTimestamp = 0.0f;
+
+ // Command interface variable initialization
+ ResetCommand();
+
+ // Allow derived classes to setup at spawn time
+ SpawnBot();
}
/* <48fa37> ../game_shared/bot/bot.cpp:88 */
-NOBODY Vector CBot::__MAKE_VHOOK(GetAutoaimVector)(float flDelta)
+Vector CBot::__MAKE_VHOOK(GetAutoaimVector)(float flDelta)
{
-// operator+(const Vector *const this,
-// const Vector &v); // 90
-// Vector(Vector *const this,
-// const Vector &v); // 92
+ UTIL_MakeVectors(pev->v_angle + pev->punchangle);
+ return gpGlobals->v_forward;
}
/* <48ffa8> ../game_shared/bot/bot.cpp:97 */
@@ -76,77 +109,125 @@ void CBot::BotThink(void)
}
/* <48f723> ../game_shared/bot/bot.cpp:119 */
-NOBODY void CBot::__MAKE_VHOOK(MoveForward)(void)
+void CBot::__MAKE_VHOOK(MoveForward)(void)
{
-// GetMoveSpeed(CBot *const this); // 121
+ m_forwardSpeed = GetMoveSpeed();
+ m_buttonFlags |= IN_FORWARD;
+
+ // make mutually exclusive
+ m_buttonFlags &= ~IN_BACK;
}
/* <48f761> ../game_shared/bot/bot.cpp:130 */
-NOBODY void CBot::__MAKE_VHOOK(MoveBackward)(void)
+void CBot::__MAKE_VHOOK(MoveBackward)(void)
{
-// GetMoveSpeed(CBot *const this); // 132
+ m_forwardSpeed = -GetMoveSpeed();
+ m_buttonFlags |= IN_BACK;
+
+ // make mutually exclusive
+ m_buttonFlags &= ~IN_FORWARD;
}
/* <48f79f> ../game_shared/bot/bot.cpp:140 */
-NOBODY void CBot::__MAKE_VHOOK(StrafeLeft)(void)
+void CBot::__MAKE_VHOOK(StrafeLeft)(void)
{
-// GetMoveSpeed(CBot *const this); // 142
+ m_strafeSpeed = -GetMoveSpeed();
+ m_buttonFlags |= IN_MOVELEFT;
+
+ // make mutually exclusive
+ m_buttonFlags &= ~IN_MOVERIGHT;
}
/* <48f7dd> ../game_shared/bot/bot.cpp:150 */
-NOBODY void CBot::__MAKE_VHOOK(StrafeRight)(void)
+void CBot::__MAKE_VHOOK(StrafeRight)(void)
{
-// GetMoveSpeed(CBot *const this); // 152
+ m_strafeSpeed = GetMoveSpeed();
+ m_buttonFlags |= IN_MOVERIGHT;
+
+ // make mutually exclusive
+ m_buttonFlags &= ~IN_MOVELEFT;
}
/* <48fe00> ../game_shared/bot/bot.cpp:160 */
-NOBODY bool CBot::__MAKE_VHOOK(Jump)(bool mustJump)
+bool CBot::__MAKE_VHOOK(Jump)(bool mustJump)
{
-// {
-// float const sanityInterval; // 173
-// IsJumping(CBot *const this); // 162
-// {
-// float const minJumpInterval; // 167
-// }
-// }
-// Jump(CBot *const this,
-// bool mustJump); // 160
+ if (IsJumping() || IsCrouching())
+ return false;
+
+ if (!mustJump)
+ {
+ const float minJumpInterval = 0.9f; // 1.5f;
+ if (gpGlobals->time - m_jumpTimestamp < minJumpInterval)
+ return false;
+ }
+
+ // still need sanity check for jumping frequency
+ const float sanityInterval = 0.3f;
+ if (gpGlobals->time - m_jumpTimestamp < sanityInterval)
+ return false;
+
+ // jump
+ m_buttonFlags |= IN_JUMP;
+ m_jumpTimestamp = gpGlobals->time;
+ return true;
}
+// Zero any MoveForward(), Jump(), etc
+
/* <48f81b> ../game_shared/bot/bot.cpp:187 */
-NOBODY void CBot::__MAKE_VHOOK(ClearMovement)(void)
+void CBot::__MAKE_VHOOK(ClearMovement)(void)
{
-// ResetCommand(CBot *const this); // 189
+ ResetCommand();
}
+// Returns true if we are in the midst of a jump
+
/* <48ffe7> ../game_shared/bot/bot.cpp:196 */
-NOBODY bool CBot::IsJumping(void)
+bool CBot::IsJumping(void)
{
+ // if long time after last jump, we can't be jumping
+ if (gpGlobals->time - m_jumpTimestamp > 3.0f)
+ return false;
+
+ // if we just jumped, we're still jumping
+ if (gpGlobals->time - m_jumpTimestamp < 1.0f)
+ return true;
+
+ // a little after our jump, we're jumping until we hit the ground
+ if (pev->flags & FL_ONGROUND)
+ return false;
+
+ return true;
}
/* <48f859> ../game_shared/bot/bot.cpp:214 */
-NOBODY void CBot::__MAKE_VHOOK(Crouch)(void)
+void CBot::__MAKE_VHOOK(Crouch)(void)
{
+ m_isCrouching = true;
}
/* <48f87f> ../game_shared/bot/bot.cpp:220 */
-NOBODY void CBot::__MAKE_VHOOK(StandUp)(void)
+void CBot::__MAKE_VHOOK(StandUp)(void)
{
+ m_isCrouching = false;
}
/* <48f8a5> ../game_shared/bot/bot.cpp:227 */
-NOBODY void CBot::__MAKE_VHOOK(UseEnvironment)(void)
+void CBot::__MAKE_VHOOK(UseEnvironment)(void)
{
+ m_buttonFlags |= IN_USE;
}
/* <48f8cb> ../game_shared/bot/bot.cpp:234 */
-NOBODY void CBot::__MAKE_VHOOK(PrimaryAttack)(void)
+void CBot::__MAKE_VHOOK(PrimaryAttack)(void)
{
+ m_buttonFlags |= IN_ATTACK;
}
/* <48f8f1> ../game_shared/bot/bot.cpp:240 */
-NOBODY void CBot::__MAKE_VHOOK(ClearPrimaryAttack)(void)
+void CBot::__MAKE_VHOOK(ClearPrimaryAttack)(void)
{
+ m_buttonFlags &= ~IN_ATTACK;
}
/* <48f917> ../game_shared/bot/bot.cpp:246 */
@@ -159,40 +240,68 @@ void CBot::__MAKE_VHOOK(TogglePrimaryAttack)(void)
}
/* <48f93d> ../game_shared/bot/bot.cpp:260 */
-NOBODY void CBot::__MAKE_VHOOK(SecondaryAttack)(void)
+void CBot::__MAKE_VHOOK(SecondaryAttack)(void)
{
+ m_buttonFlags |= IN_ATTACK2;
}
/* <48f963> ../game_shared/bot/bot.cpp:266 */
-NOBODY void CBot::__MAKE_VHOOK(Reload)(void)
+void CBot::__MAKE_VHOOK(Reload)(void)
{
+ m_buttonFlags |= IN_RELOAD;
}
+// Returns ratio of ammo left to max ammo (1 = full clip, 0 = empty)
+
/* <490008> ../game_shared/bot/bot.cpp:275 */
-NOBODY float CBot::GetActiveWeaponAmmoRatio(void) const
+float CBot::GetActiveWeaponAmmoRatio(void) const
{
-// {
-// class CBasePlayerWeapon *gun; // 277
-// iMaxClip(CBasePlayerItem *const this); // 286
-// }
+ CBasePlayerWeapon *weapon = GetActiveWeapon();
+
+ if (!weapon)
+ return 0.0f;
+
+ // weapons with no ammo are always full
+ if (weapon->m_iClip < 0)
+ return 1.0f;
+
+ return (float)weapon->m_iClip / (float)weapon->iMaxClip();
}
+// Return true if active weapon has an empty clip
+
/* <490058> ../game_shared/bot/bot.cpp:293 */
-NOBODY bool CBot::IsActiveWeaponClipEmpty(void) const
+bool CBot::IsActiveWeaponClipEmpty(void) const
{
-// {
-// class CBasePlayerWeapon *gun; // 295
-// }
+ CBasePlayerWeapon *weapon = GetActiveWeapon();
+
+ if (weapon != NULL && weapon->m_iClip == 0)
+ return true;
+
+ return false;
}
+// Return true if active weapon has no ammo at all
+
/* <490096> ../game_shared/bot/bot.cpp:307 */
-NOBODY bool CBot::IsActiveWeaponOutOfAmmo(void) const
+bool CBot::IsActiveWeaponOutOfAmmo(void) const
{
-// {
-// class CBasePlayerWeapon *gun; // 309
-// }
+ CBasePlayerWeapon *gun = GetActiveWeapon();
+
+ if (gun == NULL)
+ return true;
+
+ if (gun->m_iClip < 0)
+ return false;
+
+ if (gun->m_iClip == 0 && m_rgAmmo[ gun->m_iPrimaryAmmoType ] <= 0)
+ return true;
+
+ return false;
}
+// Return true if looking thru weapon's scope
+
/* <4900d4> ../game_shared/bot/bot.cpp:327 */
bool CBot::IsUsingScope(void) const
{
@@ -252,6 +361,8 @@ byte CBot::ThrottledMsec(void) const
return (byte)iNewMsec;
}
+// Do a "client command" - useful for invoking menu choices, etc.
+
/* <49016e> ../game_shared/bot/bot.cpp:389 */
void CBot::ClientCommand(const char *cmd, const char *arg1, const char *arg2, const char *arg3)
{
@@ -265,48 +376,94 @@ void CBot::ClientCommand(const char *cmd, const char *arg1, const char *arg2, co
UseBotArgs = false;
}
+// Returns TRUE if given entity is our enemy
+
/* <4901ac> ../game_shared/bot/bot.cpp:410 */
-NOBODY bool CBot::IsEnemy(CBaseEntity *ent) const
+bool CBot::IsEnemy(CBaseEntity *ent) const
{
-// {
-// class CBasePlayer *player; // 420
-// }
-// IsEnemy(const class CBot *const this,
-// class CBaseEntity *ent); // 410
+ // only Players (real and AI) can be enemies
+ if (!ent->IsPlayer())
+ return false;
+
+ // corpses are no threat
+ if (!ent->IsAlive())
+ return false;
+
+ CBasePlayer *player = static_cast(ent);
+
+ // if they are on our team, they are our friends
+ if (player->m_iTeam == m_iTeam)
+ return false;
+
+ // yep, we hate 'em
+ return true;
}
+// Return number of enemies left alive
+
/* <49021a> ../game_shared/bot/bot.cpp:434 */
-NOBODY int CBot::GetEnemiesRemaining(void) const
+int CBot::GetEnemiesRemaining(void) const
{
-// {
-// int count; // 436
-// {
-// int i; // 438
-// {
-// class CBaseEntity *player; // 440
-// FNullEnt(entvars_t *pev); // 445
-// IsEnemy(const class CBot *const this,
-// class CBaseEntity *ent); // 451
-// }
-// }
-// }
+ int count = 0;
+
+ for (int i = 1; i <= gpGlobals->maxClients; ++i)
+ {
+ CBaseEntity *player = UTIL_PlayerByIndex(i);
+
+ if (player == NULL)
+ continue;
+
+ if (FNullEnt(player->pev))
+ continue;
+
+ if (FStrEq(STRING(player->pev->netname), ""))
+ continue;
+
+ if (!IsEnemy(player))
+ continue;
+
+ if (!player->IsAlive())
+ continue;
+
+ count++;
+ }
+
+ return count;
}
+// Return number of friends left alive
+
/* <490338> ../game_shared/bot/bot.cpp:467 */
-NOBODY int CBot::GetFriendsRemaining(void) const
+int CBot::GetFriendsRemaining(void) const
{
-// {
-// int count; // 469
-// {
-// int i; // 471
-// {
-// class CBaseEntity *player; // 473
-// FNullEnt(entvars_t *pev); // 478
-// IsEnemy(const class CBot *const this,
-// class CBaseEntity *ent); // 484
-// }
-// }
-// }
+ int count = 0;
+
+ for (int i = 1; i <= gpGlobals->maxClients; ++i)
+ {
+ CBaseEntity *player = UTIL_PlayerByIndex(i);
+
+ if (player == NULL)
+ continue;
+
+ if (FNullEnt(player->pev))
+ continue;
+
+ if (FStrEq(STRING(player->pev->netname), ""))
+ continue;
+
+ if (IsEnemy(player))
+ continue;
+
+ if (!player->IsAlive())
+ continue;
+
+ if (player == static_cast(const_cast(this)))
+ continue;
+
+ count++;
+ }
+
+ return count;
}
/* <490489> ../game_shared/bot/bot.cpp:503 */
@@ -332,6 +489,7 @@ bool CBot::IsLocalPlayerWatchingMe(void) const
return true;
}
}
+
return false;
}
@@ -417,7 +575,7 @@ bool ActiveGrenade::IsValid(void) const
}
/* <490710> ../game_shared/bot/bot.cpp:622 */
-NOXREF const Vector *ActiveGrenade::GetPosition(void) const
+const Vector *ActiveGrenade::GetPosition(void) const
{
return &m_entity->pev->origin;
}
diff --git a/regamedll/game_shared/bot/bot.h b/regamedll/game_shared/bot/bot.h
index f176a235..29c10a84 100644
--- a/regamedll/game_shared/bot/bot.h
+++ b/regamedll/game_shared/bot/bot.h
@@ -50,6 +50,8 @@ extern bool UseBotArgs;
class BotProfile;
+extern bool AreBotsAllowed();
+
/* <36c175> ../game_shared/bot/bot.h:36 */
template
T *CreateBot(const BotProfile *profile)
@@ -88,7 +90,7 @@ public:
// constructor initializes all values to zero
CBot(void);
- NOBODY virtual void Spawn(void);
+ virtual void Spawn(void);
// invoked when injured by something
virtual int TakeDamage(entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType)
@@ -100,15 +102,12 @@ public:
{
CBasePlayer::Killed(pevAttacker, iGib);
}
- NOBODY virtual void Think(void) {};
- virtual BOOL IsBot(void)
- {
- return true;
- }
- NOBODY virtual Vector GetAutoaimVector(float flDelta);
+ virtual void Think(void) {};
+ virtual BOOL IsBot(void) { return true; }
+ virtual Vector GetAutoaimVector(float flDelta);
// invoked when in contact with a CWeaponBox
- NOBODY virtual void OnTouchingWeapon(CWeaponBox *box) {}
- NOBODY virtual bool Initialize(const BotProfile *profile);
+ virtual void OnTouchingWeapon(CWeaponBox *box) {}
+ virtual bool Initialize(const BotProfile *profile);
virtual void SpawnBot(void) = 0;
@@ -118,28 +117,29 @@ public:
// heavyweight algorithms, invoked less often
virtual void Update(void) = 0;
- NOBODY virtual void Run(void);
- NOBODY virtual void Walk(void);
- NOBODY virtual void Crouch(void);
- NOBODY virtual void StandUp(void);
- NOBODY virtual void MoveForward(void);
- NOBODY virtual void MoveBackward(void);
- NOBODY virtual void StrafeLeft(void);
- NOBODY virtual void StrafeRight(void);
+ virtual void Run(void);
+ virtual void Walk(void);
+ virtual void Crouch(void);
+ virtual void StandUp(void);
+ virtual void MoveForward(void);
+ virtual void MoveBackward(void);
+ virtual void StrafeLeft(void);
+ virtual void StrafeRight(void);
// returns true if jump was started
- NOBODY virtual bool Jump(bool mustJump = false);
+ #define MUST_JUMP true
+ virtual bool Jump(bool mustJump = false);
// zero any MoveForward(), Jump(), etc
- NOBODY virtual void ClearMovement(void);
+ virtual void ClearMovement(void);
// Weapon interface
- NOBODY virtual void UseEnvironment(void);
- NOBODY virtual void PrimaryAttack(void);
- NOBODY virtual void ClearPrimaryAttack(void);
+ virtual void UseEnvironment(void);
+ virtual void PrimaryAttack(void);
+ virtual void ClearPrimaryAttack(void);
virtual void TogglePrimaryAttack(void);
- NOBODY virtual void SecondaryAttack(void);
- NOBODY virtual void Reload(void);
+ virtual void SecondaryAttack(void);
+ virtual void Reload(void);
// invoked when event occurs in the game (some events have NULL entities)
virtual void OnEvent(GameEventType event, CBaseEntity *entity = NULL, CBaseEntity *other = NULL) {};
@@ -150,7 +150,7 @@ public:
// return true if we can see any part of the player
virtual bool IsVisible(CBasePlayer *player, bool testFOV = false, unsigned char *visParts = NULL) const = 0;
- enum VisiblePartType
+ enum VisiblePartType:uint8
{
NONE = 0x00,
CHEST = 0x01,
@@ -164,12 +164,12 @@ public:
virtual bool IsEnemyPartVisible(VisiblePartType part) const = 0;
// return true if player is facing towards us
- NOBODY virtual bool IsPlayerFacingMe(CBasePlayer *other) const;
+ virtual bool IsPlayerFacingMe(CBasePlayer *other) const;
// returns true if other player is pointing right at us
- NOBODY virtual bool IsPlayerLookingAtMe(CBasePlayer *other) const;
+ virtual bool IsPlayerLookingAtMe(CBasePlayer *other) const;
virtual void ExecuteCommand(void);
- NOBODY virtual void SetModel(const char *modelName);
+ virtual void SetModel(const char *modelName);
#ifdef HOOK_GAMEDLL
@@ -189,45 +189,36 @@ public:
void ClearPrimaryAttack_(void);
void TogglePrimaryAttack_(void);
void SecondaryAttack_(void);
+ bool IsPlayerFacingMe_(CBasePlayer *other) const;
+ bool IsPlayerLookingAtMe_(CBasePlayer *other) const;
void Reload_(void);
void ExecuteCommand_(void);
+ void SetModel_(const char *modelName);
#endif // HOOK_GAMEDLL
public:
- unsigned int GetID(void) const
- {
- return m_id;
- }
- bool IsRunning(void) const
- {
- return m_isRunning;
- }
- bool IsCrouching(void) const
- {
- return m_isCrouching;
- }
+ unsigned int GetID(void) const { return m_id; }
+ bool IsRunning(void) const { return m_isRunning; }
+ bool IsCrouching(void) const { return m_isCrouching; }
// push the current posture context onto the top of the stack
void PushPostureContext(void);
// restore the posture context to the next context on the stack
void PopPostureContext(void);
- NOBODY bool IsJumping(void);
+ bool IsJumping(void);
// return time last jump began
- float GetJumpTimestamp(void) const
- {
- return m_jumpTimestamp;
- }
+ float GetJumpTimestamp(void) const { return m_jumpTimestamp; }
// returns ratio of ammo left to max ammo (1 = full clip, 0 = empty)
- NOBODY float GetActiveWeaponAmmoRatio(void) const;
+ float GetActiveWeaponAmmoRatio(void) const;
// return true if active weapon has any empty clip
- NOBODY bool IsActiveWeaponClipEmpty(void) const;
+ bool IsActiveWeaponClipEmpty(void) const;
// return true if active weapon has no ammo at all
- NOBODY bool IsActiveWeaponOutOfAmmo(void) const;
+ bool IsActiveWeaponOutOfAmmo(void) const;
// is the weapon in the middle of a reload
bool IsActiveWeaponReloading(void) const;
@@ -242,13 +233,13 @@ public:
bool IsUsingScope(void) const;
// returns TRUE if given entity is our enemy
- NOBODY bool IsEnemy(CBaseEntity *ent) const;
+ bool IsEnemy(CBaseEntity *ent) const;
// return number of enemies left alive
- NOBODY int GetEnemiesRemaining(void) const;
+ int GetEnemiesRemaining(void) const;
// return number of friends left alive
- NOBODY int GetFriendsRemaining(void) const;
+ int GetFriendsRemaining(void) const;
// return true if local player is observing this bot
bool IsLocalPlayerWatchingMe(void) const;
@@ -260,18 +251,13 @@ public:
void PrintIfWatched(char *format,...) const;
void BotThink(void);
- bool IsNetClient(void) const
- {
- return false;
- }
+ bool IsNetClient(void) const { return false; }
int Save(CSave &save) const;
int Restore(CRestore &restor) const;
// return our personality profile
- const BotProfile *GetProfile(void) const
- {
- return m_profile;
- }
+ const BotProfile *GetProfile(void) const { return m_profile; }
+
#ifndef HOOK_GAMEDLL
protected:
#endif // HOOK_GAMEDLL
@@ -280,8 +266,8 @@ protected:
// the "personality" profile of this bot
const BotProfile *m_profile;
-private:
+private:
void ResetCommand(void);
byte ThrottledMsec(void) const;
@@ -329,7 +315,7 @@ private:
};/* size: 2564, cachelines: 41, members: 15 */
/* <48f61d> ../game_shared/bot/bot.h:253 */
-inline void CBot::SetModel(const char *modelName)
+inline void CBot::__MAKE_VHOOK(SetModel)(const char *modelName)
{
SET_CLIENT_KEY_VALUE(entindex(), GET_INFO_BUFFER(edict()), "model", (char *)modelName);
}
@@ -364,11 +350,11 @@ inline CBasePlayerWeapon *CBot::GetActiveWeapon(void) const
/* <5c4d70> ../game_shared/bot/bot.h:287 */
inline bool CBot::IsActiveWeaponReloading(void) const
{
- CBasePlayerWeapon *gun = GetActiveWeapon();
- if (gun == NULL)
+ CBasePlayerWeapon *weapon = GetActiveWeapon();
+ if (weapon == NULL)
return false;
- return (gun->m_fInReload || gun->m_fInSpecialReload) != 0;
+ return (weapon->m_fInReload || weapon->m_fInSpecialReload) != 0;
}
/* <3c5c5c> ../game_shared/bot/bot.h:297 */
@@ -392,6 +378,7 @@ inline void CBot::PushPostureContext(void)
PrintIfWatched("PushPostureContext() overflow error!\n");
return;
}
+
m_postureStack[m_postureStackIndex].isRunning = m_isRunning;
m_postureStack[m_postureStackIndex].isCrouching = m_isCrouching;
++m_postureStackIndex;
@@ -416,7 +403,7 @@ inline void CBot::PopPostureContext(void)
}
/* <48fae3> ../game_shared/bot/bot.h:340 */
-inline bool CBot::IsPlayerFacingMe(CBasePlayer *other) const
+inline bool CBot::__MAKE_VHOOK(IsPlayerFacingMe)(CBasePlayer *other) const
{
Vector toOther = other->pev->origin - pev->origin;
UTIL_MakeVectors(other->pev->v_angle + other->pev->punchangle);
@@ -424,11 +411,12 @@ inline bool CBot::IsPlayerFacingMe(CBasePlayer *other) const
if (otherDir.x * toOther.x + otherDir.y * toOther.y < 0.0f)
return true;
+
return false;
}
/* <48fbfc> ../game_shared/bot/bot.h:355 */
-inline bool CBot::IsPlayerLookingAtMe(CBasePlayer *other) const
+inline bool CBot::__MAKE_VHOOK(IsPlayerLookingAtMe)(CBasePlayer *other) const
{
Vector toOther = other->pev->origin - pev->origin;
toOther.NormalizeInPlace();
@@ -443,6 +431,7 @@ inline bool CBot::IsPlayerLookingAtMe(CBasePlayer *other) const
if (IsVisible(&vec))
return true;
}
+
return false;
}
@@ -451,6 +440,21 @@ inline bool CBot::IsPlayerLookingAtMe(CBasePlayer *other) const
typedef bool (CBot::*IS_VISIBLE_VECTOR)(const Vector *, bool) const;
typedef bool (CBot::*IS_VISIBLE_CBASE_PLAYER)(CBasePlayer *, bool, unsigned char *) const;
+inline bool CBot::IsPlayerFacingMe(CBasePlayer *other) const
+{
+ return IsPlayerFacingMe_(other);
+}
+
+inline bool CBot::IsPlayerLookingAtMe(CBasePlayer *other) const
+{
+ return IsPlayerLookingAtMe_(other);
+}
+
+inline void CBot::SetModel(const char *modelName)
+{
+ SetModel_(modelName);
+}
+
#endif // HOOK_GAMEDLL
#endif // BOT_H
diff --git a/regamedll/game_shared/bot/bot_constants.h b/regamedll/game_shared/bot/bot_constants.h
index e0d54339..66eb0a3d 100644
--- a/regamedll/game_shared/bot/bot_constants.h
+++ b/regamedll/game_shared/bot/bot_constants.h
@@ -32,11 +32,15 @@
#pragma once
#endif
+// We'll define our own version of this, because everyone else does.
+// This needs to stay in sync with MAX_CLIENTS, but there's no header with the #define.
#define BOT_MAX_CLIENTS 32
+// version number is MAJOR.MINOR
#define BOT_VERSION_MAJOR 1
#define BOT_VERSION_MINOR 50
+// Difficulty levels
enum BotDifficultyType
{
BOT_EASY = 0,
@@ -47,22 +51,12 @@ enum BotDifficultyType
NUM_DIFFICULTY_LEVELS
};
-#ifdef DEFINE_DIFFICULTY_NAMES
+#ifdef HOOK_GAMEDLL
-char *BotDifficultyName[] =
-{
- "EASY",
- "NORMAL",
- "HARD",
- "EXPERT",
+#define BotDifficultyName (*pBotDifficultyName)
- NULL
-};
+#endif // HOOK_GAMEDLL
-#else
-
-extern char *BotDifficultyName[];
-
-#endif // DEFINE_DIFFICULTY_NAMES
+extern char *BotDifficultyName[5];
#endif // BOT_CONSTANTS_H
diff --git a/regamedll/game_shared/bot/bot_profile.cpp b/regamedll/game_shared/bot/bot_profile.cpp
index f0cc01c1..7b19cac4 100644
--- a/regamedll/game_shared/bot/bot_profile.cpp
+++ b/regamedll/game_shared/bot/bot_profile.cpp
@@ -8,45 +8,74 @@
BotProfileManager *TheBotProfiles = NULL;
+char *BotDifficultyName[] =
+{
+ "EASY", "NORMAL", "HARD", "EXPERT", NULL
+};
+
#else // HOOK_GAMEDLL
BotProfileManager *TheBotProfiles;
+char *BotDifficultyName[5];
#endif // HOOK_GAMEDLL
+// Generates a filename-decorated skin name
+
/* <4a693f> ../game_shared/bot/bot_profile.cpp:52 */
-NOBODY const char *GetDecoratedSkinName(const char *name, const char *filename)
+const char *GetDecoratedSkinName(const char *name, const char *filename)
{
-// {
-// int const BufLen; // 57
-// char buf; // 59
-// }
+ const int BufLen = MAX_PATH + 64;
+ static char buf[BufLen];
+ Q_snprintf(buf, BufLen, "%s/%s", filename, name);
+ return buf;
}
/* <4a7a99> ../game_shared/bot/bot_profile.cpp:65 */
-NOBODY const char *BotProfile::GetWeaponPreferenceAsString(int i) const
+const char *BotProfile::GetWeaponPreferenceAsString(int i) const
{
+ if (i < 0 || i >= m_weaponPreferenceCount)
+ return NULL;
+
+ return WeaponIDToAlias(m_weaponPreference[i]);
}
+// Return true if this profile has a primary weapon preference
+
/* <4a7acd> ../game_shared/bot/bot_profile.cpp:78 */
-NOBODY bool BotProfile::HasPrimaryPreference(void) const
+bool BotProfile::HasPrimaryPreference(void) const
{
-// {
-// int i; // 80
-// {
-// int weaponClass; // 82
-// }
-// }
+ for (int i = 0; i < m_weaponPreferenceCount; ++i)
+ {
+ int weaponClass = AliasToWeaponClass(WeaponIDToAlias(m_weaponPreference[i]));
+
+ if (weaponClass == WEAPONCLASS_SUBMACHINEGUN ||
+ weaponClass == WEAPONCLASS_SHOTGUN ||
+ weaponClass == WEAPONCLASS_MACHINEGUN ||
+ weaponClass == WEAPONCLASS_RIFLE ||
+ weaponClass == WEAPONCLASS_SNIPERRIFLE)
+ return true;
+ }
+
+ return false;
}
+// Return true if this profile has a pistol weapon preference
+
/* <4a7b22> ../game_shared/bot/bot_profile.cpp:99 */
-NOBODY bool BotProfile::HasPistolPreference(void) const
+bool BotProfile::HasPistolPreference(void) const
{
-// {
-// int i; // 101
-// }
+ for (int i = 0; i < m_weaponPreferenceCount; ++i)
+ {
+ if (AliasToWeaponClass(WeaponIDToAlias(m_weaponPreference[i])) == WEAPONCLASS_PISTOL)
+ return true;
+ }
+
+ return false;
}
+// Return true if this profile is valid for the specified team
+
/* <4a7b5e> ../game_shared/bot/bot_profile.cpp:112 */
bool BotProfile::IsValidForTeam(BotProfileTeamType team) const
{
@@ -54,132 +83,462 @@ bool BotProfile::IsValidForTeam(BotProfileTeamType team) const
}
/* <4a7bb2> ../game_shared/bot/bot_profile.cpp:122 */
-NOBODY BotProfileManager::BotProfileManager(void)
+BotProfileManager::BotProfileManager(void)
{
-// list(list> *const this); // 122
-// vector(vector> *const this); // 122
-// {
-// int i; // 125
-// }
+ m_nextSkin = 0;
+ for (int i = 0; i < NumCustomSkins; ++i)
+ {
+ m_skins[i] = NULL;
+ m_skinFilenames[i] = NULL;
+ m_skinModelnames[i] = NULL;
+ }
}
+// Load the bot profile database
+
/* <4a8acb> ../game_shared/bot/bot_profile.cpp:137 */
-NOBODY void BotProfileManager::Init(const char *filename, unsigned int *checksum)
+void BotProfileManager::Init(const char *filename, unsigned int *checksum)
{
-// {
-// int dataLength; // 139
-// char *dataPointer; // 140
-// const char *dataFile; // 141
-// BotProfileList templateList; // 159
-// class BotProfile defaultProfile; // 161
-// ComputeSimpleChecksum(const unsigned char *dataPointer,
-// int dataLength); // 155
-// BotProfile(BotProfile *const this); // 161
-// list(list> *const this); // 159
-// {
-// char *token; // 172
-// bool isDefault; // 174
-// bool isTemplate; // 175
-// bool isCustomSkin; // 176
-// class BotProfile *profile; // 270
-// bool isFirstWeaponPref; // 348
-// {
-// int const BufLen; // 180
-// char skinName; // 181
-// const char *decoratedName; // 236
-// bool skinExists; // 237
-// GetDecoratedSkinName(const char *name,
-// const char *filename); // 236
-// GetCustomSkinIndex(BotProfileManager *const this,
-// const char *name,
-// const char *filename); // 237
-// CloneString(const char *str); // 241
-// CloneString(const char *str); // 244
-// }
-// {
-// const class BotProfile *inherit; // 287
-// {
-// char *c; // 292
-// strchr(char *__s,
-// int __c); // 292
-// {
-// iterator iter; // 297
-// operator++(_List_iterator *const this); // 297
-// }
-// Inherit(BotProfile *const this,
-// const class BotProfile *parent,
-// const class BotProfile *baseline); // 314
-// }
-// }
-// {
-// char attributeName; // 366
-// {
-// char *c; // 474
-// strchr(char *__s,
-// int __c); // 474
-// {
-// int i; // 478
-// }
-// }
-// atof(const char *__nptr); // 464
-// atof(const char *__nptr); // 453
-// atoi(const char *__nptr); // 424
-// atoi(const char *__nptr); // 420
-// atof(const char *__nptr); // 416
-// atoi(const char *__nptr); // 407
-// GetCustomSkinIndex(BotProfileManager *const this,
-// const char *name,
-// const char *filename); // 411
-// atof(const char *__nptr); // 403
-// atof(const char *__nptr); // 399
-// }
-// BotProfile(BotProfile *const this); // 278
-// CloneString(const char *str); // 334
-// push_back(list> *const this,
-// const value_type &__x); // 514
-// push_back(list> *const this,
-// const value_type &__x); // 519
-// }
-// ~list(list> *const this,
-// int const __in_chrg); // 159
-// {
-// iterator iter; // 527
-// operator++(_List_iterator *const this); // 527
-// }
-// ~list(list> *const this,
-// int const __in_chrg); // 159
-// }
+ int dataLength;
+ char *dataPointer = (char *)LOAD_FILE_FOR_ME(const_cast(filename), &dataLength);
+ const char *dataFile = dataPointer;
+
+ if (dataFile == NULL)
+ {
+ if (UTIL_IsGame("czero"))
+ {
+ CONSOLE_ECHO("WARNING: Cannot access bot profile database '%s'\n", filename);
+ }
+
+ return;
+ }
+
+ // compute simple checksum
+ if (checksum)
+ {
+ *checksum = ComputeSimpleChecksum((const unsigned char *)dataPointer, dataLength);
+ }
+
+ // keep list of templates used for inheritance
+ BotProfileList templateList;
+ BotProfile defaultProfile;
+
+ // Parse the BotProfile.db into BotProfile instances
+ while (true)
+ {
+ dataFile = SharedParse(dataFile);
+ if (!dataFile)
+ break;
+
+ char *token = SharedGetToken();
+
+ bool isDefault = (!Q_stricmp(token, "Default"));
+ bool isTemplate = (!Q_stricmp(token, "Template"));
+ bool isCustomSkin = (!Q_stricmp(token, "Skin"));
+
+ if (isCustomSkin)
+ {
+ const int BufLen = 64;
+ char skinName[BufLen];
+
+ // get skin name
+ dataFile = SharedParse(dataFile);
+ if (!dataFile)
+ {
+ CONSOLE_ECHO("Error parsing %s - expected skin name\n", filename);
+ FREE_FILE(dataPointer);
+ return;
+ }
+
+ token = SharedGetToken();
+ Q_snprintf(skinName, BufLen, "%s", token);
+
+ // get attribute name
+ dataFile = SharedParse(dataFile);
+ if (!dataFile)
+ {
+ CONSOLE_ECHO("Error parsing %s - expected 'Model'\n", filename);
+ FREE_FILE(dataPointer);
+ return;
+ }
+
+ token = SharedGetToken();
+ if (Q_stricmp("Model", token))
+ {
+ CONSOLE_ECHO("Error parsing %s - expected 'Model'\n", filename);
+ FREE_FILE(dataPointer);
+ return;
+ }
+
+ // eat '='
+ dataFile = SharedParse(dataFile);
+ if (!dataFile)
+ {
+ CONSOLE_ECHO("Error parsing %s - expected '='\n", filename);
+ FREE_FILE(dataPointer);
+ return;
+ }
+
+ token = SharedGetToken();
+ if (Q_strcmp("=", token))
+ {
+ CONSOLE_ECHO("Error parsing %s - expected '='\n", filename);
+ FREE_FILE(dataPointer);
+ return;
+ }
+
+ // get attribute value
+ dataFile = SharedParse(dataFile);
+ if (!dataFile)
+ {
+ CONSOLE_ECHO("Error parsing %s - expected attribute value\n", filename);
+ FREE_FILE(dataPointer);
+ return;
+ }
+
+ token = SharedGetToken();
+
+ const char *decoratedName = GetDecoratedSkinName(skinName, filename);
+ bool skinExists = GetCustomSkinIndex(decoratedName) > 0;
+ if (m_nextSkin < NumCustomSkins && !skinExists)
+ {
+ // decorate the name
+ m_skins[ m_nextSkin ] = CloneString(decoratedName);
+
+ // construct the model filename
+ m_skinModelnames[ m_nextSkin ] = CloneString(token);
+ m_skinFilenames[ m_nextSkin ] = new char[ Q_strlen(token) * 2 + Q_strlen("models/player//.mdl") + 1 ];
+ Q_sprintf(m_skinFilenames[ m_nextSkin ], "models/player/%s/%s.mdl", token, token);
+ ++m_nextSkin;
+ }
+
+ // eat 'End'
+ dataFile = SharedParse(dataFile);
+ if (!dataFile)
+ {
+ CONSOLE_ECHO("Error parsing %s - expected 'End'\n", filename);
+ FREE_FILE(dataPointer);
+ return;
+ }
+
+ token = SharedGetToken();
+ if (Q_strcmp("End", token))
+ {
+ CONSOLE_ECHO("Error parsing %s - expected 'End'\n", filename);
+ FREE_FILE(dataPointer);
+ return;
+ }
+
+ // it's just a custom skin - no need to do inheritance on a bot profile, etc.
+ continue;
+ }
+
+ // encountered a new profile
+ BotProfile *profile;
+ if (isDefault)
+ {
+ profile = &defaultProfile;
+ }
+ else
+ {
+ profile = new BotProfile;
+ // always inherit from Default
+ *profile = defaultProfile;
+ }
+
+ // do inheritance in order of appearance
+ if (!isTemplate && !isDefault)
+ {
+ const BotProfile *inherit = NULL;
+
+ // template names are separated by "+"
+ while (true)
+ {
+ char *c = Q_strchr(token, '+');
+ if (c)
+ *c = '\000';
+
+ // find the given template name
+ for (BotProfileList::iterator iter = templateList.begin(); iter != templateList.end(); ++iter)
+ {
+ if (!Q_stricmp((*iter)->GetName(), token))
+ {
+ inherit = *iter;
+ break;
+ }
+ }
+
+ if (inherit == NULL)
+ {
+ CONSOLE_ECHO("Error parsing '%s' - invalid template reference '%s'\n", filename, token);
+ FREE_FILE(dataPointer);
+ return;
+ }
+
+ // inherit the data
+ profile->Inherit(inherit, &defaultProfile);
+
+ if (c == NULL)
+ break;
+
+ token = c + 1;
+ }
+ }
+
+ // get name of this profile
+ if (!isDefault)
+ {
+ dataFile = SharedParse(dataFile);
+ if (!dataFile)
+ {
+ CONSOLE_ECHO("Error parsing '%s' - expected name\n", filename);
+ FREE_FILE(dataPointer);
+ return;
+ }
+
+ profile->m_name = CloneString(SharedGetToken());
+
+ // HACK HACK
+ // Until we have a generalized means of storing bot preferences, we're going to hardcode the bot's
+ // preference towards silencers based on his name.
+ if (profile->m_name[0] % 2)
+ {
+ profile->m_prefersSilencer = true;
+ }
+ }
+
+ // read attributes for this profile
+ bool isFirstWeaponPref = true;
+ while (true)
+ {
+ // get next token
+ dataFile = SharedParse(dataFile);
+ if (!dataFile)
+ {
+ CONSOLE_ECHO("Error parsing %s - expected 'End'\n", filename);
+ FREE_FILE(dataPointer);
+ return;
+ }
+
+ token = SharedGetToken();
+
+ // check for End delimiter
+ if (!Q_stricmp(token, "End"))
+ break;
+
+ // found attribute name - keep it
+ char attributeName[64];
+ Q_strcpy(attributeName, token);
+
+ // eat '='
+ dataFile = SharedParse(dataFile);
+ if (!dataFile)
+ {
+ CONSOLE_ECHO("Error parsing %s - expected '='\n", filename);
+ FREE_FILE(dataPointer);
+ return;
+ }
+
+ token = SharedGetToken();
+ if (Q_strcmp("=", token))
+ {
+ CONSOLE_ECHO("Error parsing %s - expected '='\n", filename);
+ FREE_FILE(dataPointer);
+ return;
+ }
+
+ // get attribute value
+ dataFile = SharedParse(dataFile);
+ if (!dataFile)
+ {
+ CONSOLE_ECHO("Error parsing %s - expected attribute value\n", filename);
+ FREE_FILE(dataPointer);
+ return;
+ }
+
+ token = SharedGetToken();
+
+ // store value in appropriate attribute
+ if (!Q_stricmp("Aggression", attributeName))
+ {
+ profile->m_aggression = Q_atof(token) / 100.0f;
+ }
+ else if (!Q_stricmp("Skill", attributeName))
+ {
+ profile->m_skill = Q_atof(token) / 100.0f;
+ }
+ else if (!Q_stricmp("Skin", attributeName))
+ {
+ profile->m_skin = Q_atoi(token);
+
+ if (profile->m_skin == 0)
+ {
+ // Q_atoi() failed - try to look up a custom skin by name
+ profile->m_skin = GetCustomSkinIndex(token, filename);
+ }
+ }
+ else if (!Q_stricmp("Teamwork", attributeName))
+ {
+ profile->m_teamwork = Q_atof(token) / 100.0f;
+ }
+ else if (!Q_stricmp("Cost", attributeName))
+ {
+ profile->m_cost = Q_atoi(token);
+ }
+ else if (!Q_stricmp("VoicePitch", attributeName))
+ {
+ profile->m_voicePitch = Q_atoi(token);
+ }
+ else if (!Q_stricmp("VoiceBank", attributeName))
+ {
+ profile->m_voiceBank = FindVoiceBankIndex(token);
+ }
+ else if (!Q_stricmp("WeaponPreference", attributeName))
+ {
+ // weapon preferences override parent prefs
+ if (isFirstWeaponPref)
+ {
+ isFirstWeaponPref = false;
+ profile->m_weaponPreferenceCount = 0;
+ }
+
+ if (!Q_stricmp(token, "none"))
+ {
+ profile->m_weaponPreferenceCount = 0;
+ }
+ else
+ {
+ if (profile->m_weaponPreferenceCount < BotProfile::MAX_WEAPON_PREFS)
+ {
+ profile->m_weaponPreference[ profile->m_weaponPreferenceCount++ ] = AliasToWeaponID(token);
+ }
+ }
+ }
+ else if (!Q_stricmp("ReactionTime", attributeName))
+ {
+ profile->m_reactionTime = Q_atof(token);
+
+#ifndef GAMEUI_EXPORTS
+ // subtract off latency due to "think" update rate.
+ // In GameUI, we don't really care.
+ profile->m_reactionTime -= g_flBotFullThinkInterval;
+#endif // GAMEUI_EXPORTS
+
+ }
+ else if (!Q_stricmp("AttackDelay", attributeName))
+ {
+ profile->m_attackDelay = Q_atof(token);
+ }
+ else if (!Q_stricmp("Difficulty", attributeName))
+ {
+ // override inheritance
+ profile->m_difficultyFlags = 0;
+
+ // parse bit flags
+ while (true)
+ {
+ char *c = Q_strchr(token, '+');
+ if (c)
+ *c = '\000';
+
+ for (int i = 0; i < NUM_DIFFICULTY_LEVELS; ++i)
+ {
+ if (!Q_stricmp(BotDifficultyName[i], token))
+ profile->m_difficultyFlags |= (1 << i);
+ }
+
+ if (c == NULL)
+ break;
+
+ token = c + 1;
+ }
+ }
+ else if (!Q_stricmp("Team", attributeName))
+ {
+ if (!Q_stricmp(token, "T"))
+ {
+ profile->m_teams = BOT_TEAM_T;
+ }
+ else if (!Q_stricmp(token, "CT"))
+ {
+ profile->m_teams = BOT_TEAM_CT;
+ }
+ else
+ {
+ profile->m_teams = BOT_TEAM_ANY;
+ }
+ }
+ else
+ {
+ CONSOLE_ECHO("Error parsing %s - unknown attribute '%s'\n", filename, attributeName);
+ }
+ }
+
+ if (!isDefault)
+ {
+ if (isTemplate)
+ {
+ // add to template list
+ templateList.push_back(profile);
+ }
+ else
+ {
+ // add profile to the master list
+ m_profileList.push_back(profile);
+ }
+ }
+ }
+
+ FREE_FILE(dataPointer);
+
+ // free the templates
+ for (BotProfileList::iterator iter = templateList.begin(); iter != templateList.end(); ++iter)
+ delete *iter;
}
/* <4a7dfd> ../game_shared/bot/bot_profile.cpp:532 */
-NOBODY BotProfileManager::~BotProfileManager(void)
+BotProfileManager::~BotProfileManager(void)
{
-// {
-// iterator it; // 536
-// begin(vector> *const this); // 537
-// end(vector> *const this); // 537
-// operator++(__normal_iterator> > *const this); // 537
-// clear(vector> *const this); // 541
-// }
-// ~vector(vector> *const this,
-// int const __in_chrg); // 532
-// ~list(list> *const this,
-// int const __in_chrg); // 532
+ Reset();
+
+ for (VoiceBankList::iterator it = m_voiceBanks.begin(); it != m_voiceBanks.end(); ++it)
+ delete[] *it;
+
+ m_voiceBanks.clear();
}
+// Free all bot profiles
+
/* <4a7c76> ../game_shared/bot/bot_profile.cpp:548 */
-NOBODY void BotProfileManager::Reset(void)
+void BotProfileManager::Reset(void)
{
-// clear(list> *const this); // 553
-// {
-// iterator iter; // 550
-// operator++(_List_iterator *const this); // 550
-// }
-// {
-// int i; // 555
-// }
+ for (BotProfileList::iterator iter = m_profileList.begin(); iter != m_profileList.end(); ++iter)
+ delete *iter;
+
+ m_profileList.clear();
+
+ for (int i = 0; i < NumCustomSkins; ++i)
+ {
+ if (m_skins[i])
+ {
+ delete[] m_skins[i];
+ m_skins[i] = NULL;
+ }
+ if (m_skinFilenames[i])
+ {
+ delete[] m_skinFilenames[i];
+ m_skinFilenames[i] = NULL;
+ }
+ if (m_skinModelnames[i])
+ {
+ delete[] m_skinModelnames[i];
+ m_skinModelnames[i] = NULL;
+ }
+ }
}
+// Returns custom skin name at a particular index
+
/* <4a7fdf> ../game_shared/bot/bot_profile.cpp:579 */
const char *BotProfileManager::GetCustomSkin(int index)
{
@@ -191,6 +550,8 @@ const char *BotProfileManager::GetCustomSkin(int index)
return m_skins[ index - FirstCustomSkin ];
}
+// Returns custom skin filename at a particular index
+
/* <4a8019> ../game_shared/bot/bot_profile.cpp:593 */
const char *BotProfileManager::GetCustomSkinFname(int index)
{
@@ -202,6 +563,8 @@ const char *BotProfileManager::GetCustomSkinFname(int index)
return m_skinFilenames[ index - FirstCustomSkin ];
}
+// Returns custom skin modelname at a particular index
+
/* <4a8053> ../game_shared/bot/bot_profile.cpp:607 */
const char *BotProfileManager::GetCustomSkinModelname(int index)
{
@@ -213,37 +576,55 @@ const char *BotProfileManager::GetCustomSkinModelname(int index)
return m_skinModelnames[ index - FirstCustomSkin ];
}
+// Looks up a custom skin index by filename-decorated name (will decorate the name if filename is given)
+
/* <4a80db> ../game_shared/bot/bot_profile.cpp:621 */
-NOBODY int BotProfileManager::GetCustomSkinIndex(const char *name, const char *filename)
+int BotProfileManager::GetCustomSkinIndex(const char *name, const char *filename)
{
-// {
-// const char *skinName; // 623
-// GetDecoratedSkinName(const char *name,
-// const char *filename); // 626
-// {
-// int i; // 629
-// }
-// }
+ const char *skinName = name;
+ if (filename)
+ {
+ skinName = GetDecoratedSkinName(name, filename);
+ }
+
+ for (int i = 0; i < NumCustomSkins; ++i)
+ {
+ if (m_skins[i])
+ {
+ if (!Q_stricmp(skinName, m_skins[i]))
+ {
+ return FirstCustomSkin + i;
+ }
+ }
+ }
+
+ return 0;
}
+// return index of the (custom) bot phrase db, inserting it if needed
+
/* <4a8916> ../game_shared/bot/bot_profile.cpp:647 */
-NOBODY int BotProfileManager::FindVoiceBankIndex(const char *filename)
+int BotProfileManager::FindVoiceBankIndex(const char *filename)
{
-// {
-// int index; // 649
-// const_iterator it; // 651
-// begin(vector> *const this); // 652
-// end(vector> *const this); // 652
-// operator++(__normal_iterator> > *const this); // 652
-// CloneString(const char *str); // 660
-// push_back(vector> *const this,
-// const value_type &__x); // 660
-// }
+ int index = 0;
+ for (VoiceBankList::const_iterator it = m_voiceBanks.begin(); it != m_voiceBanks.end(); ++it, ++index)
+ {
+ if (!Q_stricmp(filename, *it))
+ {
+ return index;
+ }
+ }
+
+ m_voiceBanks.push_back(CloneString(filename));
+ return index;
}
+// Return random unused profile that matches the given difficulty level
+
/* <4a8177> ../game_shared/bot/bot_profile.cpp:669 */
const BotProfile *BotProfileManager::GetRandomProfile(BotDifficultyType difficulty, BotProfileTeamType team) const
{
+#ifdef RANDOM_LONG
BotProfileList::const_iterator iter;
// count up valid profiles
@@ -274,4 +655,8 @@ const BotProfile *BotProfileManager::GetRandomProfile(BotDifficultyType difficul
}
return NULL;
+#else
+ // we don't need random profiles when we're not in the game dll
+ return NULL;
+#endif // RANDOM_LONG
}
diff --git a/regamedll/game_shared/bot/bot_profile.h b/regamedll/game_shared/bot/bot_profile.h
index 9d1192c1..b2944486 100644
--- a/regamedll/game_shared/bot/bot_profile.h
+++ b/regamedll/game_shared/bot/bot_profile.h
@@ -83,71 +83,27 @@ public:
m_voiceBank = 0;
m_prefersSilencer = false;
}
-
- const char *GetName(void) const
- {
- return m_name;
- }
- float GetAggression(void) const
- {
- return m_aggression;
- }
- float GetSkill(void) const
- {
- return m_skill;
- }
- float GetTeamwork(void) const
- {
- return m_teamwork;
- }
- int GetWeaponPreference(int i)
- {
- return m_weaponPreference[i];
- }
- NOBODY const char *GetWeaponPreferenceAsString(int i) const;
- int GetWeaponPreferenceCount(void) const
- {
- return m_weaponPreferenceCount;
- }
-
- NOBODY bool HasPrimaryPreference(void) const;
- NOBODY bool HasPistolPreference(void) const;
-
- int GetCost(void) const
- {
- return m_cost;
- }
- int GetSkin(void) const
- {
- return m_skin;
- }
- NOBODY bool IsDifficulty(BotDifficultyType diff) const;
- int GetVoicePitch(void) const
- {
- return m_voicePitch;
- }
- float GetReactionTime(void) const
- {
- return m_reactionTime;
- }
- float GetAttackDelay(void) const
- {
- return m_attackDelay;
- }
- int GetVoiceBank(void) const
- {
- return m_voiceBank;
- }
+ const char *GetName(void) const { return m_name; }
+ float GetAggression(void) const { return m_aggression; }
+ float GetSkill(void) const { return m_skill; }
+ float GetTeamwork(void) const { return m_teamwork; }
+ int GetWeaponPreference(int i) const { return m_weaponPreference[i]; }
+ const char *GetWeaponPreferenceAsString(int i) const;
+ int GetWeaponPreferenceCount(void) const { return m_weaponPreferenceCount; }
+ bool HasPrimaryPreference(void) const;
+ bool HasPistolPreference(void) const;
+ int GetCost(void) const { return m_cost; }
+ int GetSkin(void) const { return m_skin; }
+ bool IsDifficulty(BotDifficultyType diff) const;
+ int GetVoicePitch(void) const { return m_voicePitch; }
+ float GetReactionTime(void) const { return m_reactionTime; }
+ float GetAttackDelay(void) const { return m_attackDelay; }
+ int GetVoiceBank(void) const { return m_voiceBank; }
bool IsValidForTeam(BotProfileTeamType team) const;
- bool PrefersSilencer(void) const
- {
- return m_prefersSilencer;
- }
- // TODO: it func private
- NOBODY void Inherit(const BotProfile *parent, const BotProfile *baseline);
+ bool PrefersSilencer(void) const { return m_prefersSilencer; }
private:
-
+ void Inherit(const BotProfile *parent, const BotProfile *baseline);
friend class BotProfileManager;
char *m_name;
@@ -223,7 +179,7 @@ inline void BotProfile::Inherit(const BotProfile *parent, const BotProfile *base
m_voiceBank = parent->m_voiceBank;
}
-typedef std::list BotProfileList;
+typedef std::STD_LIST BotProfileList;
/* <36a051> ../game_shared/bot/bot_profile.h:180 */
class BotProfileManager
@@ -238,8 +194,10 @@ public:
const BotProfile *GetProfile(const char *name, BotProfileTeamType team) const
{
for (BotProfileList::const_iterator iter = m_profileList.begin(); iter != m_profileList.end(); ++iter)
+ {
if (!Q_stricmp(name, (*iter)->GetName()) && (*iter)->IsValidForTeam(team))
return *iter;
+ }
return NULL;
}
@@ -254,7 +212,7 @@ public:
const char *GetCustomSkinFname(int index);
int GetCustomSkinIndex(const char *name, const char *filename = NULL);
- typedef std::vector VoiceBankList;
+ typedef std::STD_VECTOR VoiceBankList;
const VoiceBankList *GetVoiceBanks() const
{
@@ -263,11 +221,6 @@ public:
int FindVoiceBankIndex(const char *filename);
protected:
-
-#if defined(_WIN32) && defined(HOOK_GAMEDLL)
- int unknown_padding1;
-#endif // HOOK_GAMEDLL
-
BotProfileList m_profileList;
VoiceBankList m_voiceBanks;
diff --git a/regamedll/game_shared/bot/bot_util.cpp b/regamedll/game_shared/bot/bot_util.cpp
index 44c37e21..0f1968a1 100644
--- a/regamedll/game_shared/bot/bot_util.cpp
+++ b/regamedll/game_shared/bot/bot_util.cpp
@@ -144,7 +144,7 @@ int UTIL_HumansInGame(bool ignoreSpectators)
}
/* <4ad507> ../game_shared/bot/bot_util.cpp:174 */
-NOBODY int UTIL_HumansOnTeam(int teamID, bool isAlive)
+int UTIL_HumansOnTeam(int teamID, bool isAlive)
{
int iCount = 0;
for (int iIndex = 1; iIndex <= gpGlobals->maxClients; ++iIndex)
@@ -178,7 +178,7 @@ NOBODY int UTIL_HumansOnTeam(int teamID, bool isAlive)
}
/* <4ad5db> ../game_shared/bot/bot_util.cpp:210 */
-NOBODY int UTIL_BotsInGame(void)
+int UTIL_BotsInGame(void)
{
int iCount = 0;
@@ -265,7 +265,7 @@ bool UTIL_KickBotFromTeam(TeamName kickTeam)
}
/* <4ad7ad> ../game_shared/bot/bot_util.cpp:305 */
-NOBODY bool UTIL_IsTeamAllBots(int team)
+bool UTIL_IsTeamAllBots(int team)
{
int botCount = 0;
for (int i = 1; i <= gpGlobals->maxClients; ++i)
@@ -330,7 +330,7 @@ NOBODY bool UTIL_IsTeamAllBots(int team)
// If 'distance' is non-NULL, the distance to the closest player is returned in it.
/* <4ad86a> ../game_shared/bot/bot_util.cpp:343 */
-NOBODY /*extern*/ CBasePlayer *UTIL_GetClosestPlayer(const Vector *pos, int team, float *distance)
+/*extern*/ CBasePlayer *UTIL_GetClosestPlayer(const Vector *pos, int team, float *distance)
{
CBasePlayer *closePlayer = NULL;
float closeDistSq = 1.0e12f; // 999999999999.9f
@@ -388,7 +388,7 @@ void UTIL_ConstructBotNetName(char *name, int nameLength, const BotProfile *prof
}
/* <4adb6c> ../game_shared/bot/bot_util.cpp:440 */
-NOBODY bool UTIL_IsVisibleToTeam(const Vector &spot, int team, float maxRange)
+bool UTIL_IsVisibleToTeam(const Vector &spot, int team, float maxRange)
{
for (int i = 1; i <= gpGlobals->maxClients; ++i)
{
@@ -432,26 +432,26 @@ CBasePlayer *UTIL_GetLocalPlayer(void)
}
/* <4adcab> ../game_shared/bot/bot_util.cpp:491 */
-NOBODY Vector UTIL_ComputeOrigin(entvars_t *pevVars)
+NOXREF Vector UTIL_ComputeOrigin(entvars_t *pevVars)
{
- if ((pevVars->origin.x == 0.0) && (pevVars->origin.y == 0.0) && (pevVars->origin.z == 0.0))
- return (pevVars->absmax + pevVars->absmin) *0.5;
+ if (pevVars->origin.x == 0.0f && pevVars->origin.y == 0.0f && pevVars->origin.z == 0.0f)
+ return (pevVars->absmax + pevVars->absmin) * 0.5f;
else
return pevVars->origin;
}
-NOBODY Vector UTIL_ComputeOrigin(CBaseEntity *pEntity)
+NOXREF Vector UTIL_ComputeOrigin(CBaseEntity *pEntity)
{
return UTIL_ComputeOrigin(pEntity->pev);
}
-NOBODY Vector UTIL_ComputeOrigin(edict_t *pentEdict)
+NOXREF Vector UTIL_ComputeOrigin(edict_t *pentEdict)
{
return UTIL_ComputeOrigin(VARS(pentEdict));
}
/* <4adf8a> ../game_shared/bot/bot_util.cpp:513 */
-NOBODY void UTIL_DrawBeamFromEnt(int iIndex, Vector vecEnd, int iLifetime, byte bRed, byte bGreen, byte bBlue)
+NOXREF void UTIL_DrawBeamFromEnt(int iIndex, Vector vecEnd, int iLifetime, byte bRed, byte bGreen, byte bBlue)
{
MESSAGE_BEGIN(MSG_PVS, SVC_TEMPENTITY, vecEnd);
WRITE_BYTE(TE_BEAMENTPOINT);
@@ -474,7 +474,7 @@ NOBODY void UTIL_DrawBeamFromEnt(int iIndex, Vector vecEnd, int iLifetime, byte
}
/* <4ae02e> ../game_shared/bot/bot_util.cpp:537 */
-NOBODY void UTIL_DrawBeamPoints(Vector vecStart, Vector vecEnd, int iLifetime, byte bRed, byte bGreen, byte bBlue)
+void UTIL_DrawBeamPoints(Vector vecStart, Vector vecEnd, int iLifetime, byte bRed, byte bGreen, byte bBlue)
{
MESSAGE_BEGIN(MSG_PVS, SVC_TEMPENTITY, vecStart);
WRITE_BYTE(TE_BEAMPOINTS);
@@ -585,8 +585,8 @@ bool IsGameEventAudible(GameEventType event, CBaseEntity *entity, CBaseEntity *o
switch (event)
{
- /// TODO: Check weapon type (knives are pretty quiet)
- /// TODO: Use actual volume, account for silencers, etc.
+ // TODO: Check weapon type (knives are pretty quiet)
+ // TODO: Use actual volume, account for silencers, etc.
case EVENT_WEAPON_FIRED:
{
if (player->m_pActiveItem == NULL)
diff --git a/regamedll/game_shared/bot/bot_util.h b/regamedll/game_shared/bot/bot_util.h
index 805f8bca..0be21454 100644
--- a/regamedll/game_shared/bot/bot_util.h
+++ b/regamedll/game_shared/bot/bot_util.h
@@ -45,10 +45,7 @@ class BotProfile;
enum PriorityType
{
- PRIORITY_LOW,
- PRIORITY_MEDIUM,
- PRIORITY_HIGH,
- PRIORITY_UNINTERRUPTABLE
+ PRIORITY_LOW, PRIORITY_MEDIUM, PRIORITY_HIGH, PRIORITY_UNINTERRUPTABLE
};
// Simple class for tracking intervals of game time
@@ -97,7 +94,8 @@ public:
{
return (gpGlobals->time - m_timestamp > duration) ? true : false;
}
-/*private:*/
+
+private:
float m_timestamp;
};/* size: 4, cachelines: 1, members: 1 */
@@ -179,12 +177,14 @@ inline bool IsIntersecting2D(const Vector &startA, const Vector &endA, const Vec
// parallel
return false;
}
+
float numS = (startA.y - startB.y) * (endB.x - startB.x) - (startA.x - startB.x) * (endB.y - startB.y);
if (numS == 0.0f)
{
// coincident
return true;
}
+
float numT = (startA.y - startB.y) * (endA.x - startA.x) - (startA.x - startB.x) * (endA.y - startA.y);
float s = numS / denom;
if (s < 0.0f || s > 1.0f)
@@ -192,6 +192,7 @@ inline bool IsIntersecting2D(const Vector &startA, const Vector &endA, const Vec
// intersection is not within line segment of startA to endA
return false;
}
+
float t = numT / denom;
if (t < 0.0f || t > 1.0f)
{
@@ -214,7 +215,7 @@ inline bool IsIntersecting2D(const Vector &startA, const Vector &endA, const Vec
template
bool ForEachPlayer(Functor &func)
{
- for (int i = 1; i <= gpGlobals->maxClients; i++)
+ for (int i = 1; i <= gpGlobals->maxClients; ++i)
{
CBasePlayer *player = static_cast(UTIL_PlayerByIndex(i));
if (!IsEntityValid((CBaseEntity *)player))
@@ -247,38 +248,106 @@ inline bool IsZombieGame(void)
#define s_iBeamSprite (*ps_iBeamSprite)
#define cosTable (*pcosTable)
+#define cv_bot_traceview (*pcv_bot_traceview)
+#define cv_bot_stop (*pcv_bot_stop)
+#define cv_bot_show_nav (*pcv_bot_show_nav)
+#define cv_bot_show_danger (*pcv_bot_show_danger)
+#define cv_bot_nav_edit (*pcv_bot_nav_edit)
+#define cv_bot_nav_zdraw (*pcv_bot_nav_zdraw)
+#define cv_bot_walk (*pcv_bot_walk)
+#define cv_bot_difficulty (*pcv_bot_difficulty)
+#define cv_bot_debug (*pcv_bot_debug)
+#define cv_bot_quicksave (*pcv_bot_quicksave)
+#define cv_bot_quota (*pcv_bot_quota)
+#define cv_bot_quota_match (*pcv_bot_quota_match)
+#define cv_bot_prefix (*pcv_bot_prefix)
+#define cv_bot_allow_rogues (*pcv_bot_allow_rogues)
+#define cv_bot_allow_pistols (*pcv_bot_allow_pistols)
+#define cv_bot_allow_shotguns (*pcv_bot_allow_shotguns)
+#define cv_bot_allow_sub_machine_guns (*pcv_bot_allow_sub_machine_guns)
+#define cv_bot_allow_rifles (*pcv_bot_allow_rifles)
+#define cv_bot_allow_machine_guns (*pcv_bot_allow_machine_guns)
+#define cv_bot_allow_grenades (*pcv_bot_allow_grenades)
+#define cv_bot_allow_snipers (*pcv_bot_allow_snipers)
+#define cv_bot_allow_shield (*pcv_bot_allow_shield)
+#define cv_bot_join_team (*pcv_bot_join_team)
+#define cv_bot_join_after_player (*pcv_bot_join_after_player)
+#define cv_bot_auto_vacate (*pcv_bot_auto_vacate)
+#define cv_bot_zombie (*pcv_bot_zombie)
+#define cv_bot_defer_to_human (*pcv_bot_defer_to_human)
+#define cv_bot_chatter (*pcv_bot_chatter)
+#define cv_bot_profile_db (*pcv_bot_profile_db)
+
#endif // HOOK_GAMEDLL
extern short s_iBeamSprite;
extern float cosTable[COS_TABLE_SIZE];
+extern cvar_t cv_bot_traceview;
+extern cvar_t cv_bot_stop;
+extern cvar_t cv_bot_show_nav;
+extern cvar_t cv_bot_show_danger;
+extern cvar_t cv_bot_nav_edit;
+extern cvar_t cv_bot_nav_zdraw;
+extern cvar_t cv_bot_walk;
+extern cvar_t cv_bot_difficulty;
+extern cvar_t cv_bot_debug;
+extern cvar_t cv_bot_quicksave;
+extern cvar_t cv_bot_quota;
+extern cvar_t cv_bot_quota_match;
+extern cvar_t cv_bot_prefix;
+extern cvar_t cv_bot_allow_rogues;
+extern cvar_t cv_bot_allow_pistols;
+extern cvar_t cv_bot_allow_shotguns;
+extern cvar_t cv_bot_allow_sub_machine_guns;
+extern cvar_t cv_bot_allow_rifles;
+extern cvar_t cv_bot_allow_machine_guns;
+extern cvar_t cv_bot_allow_grenades;
+extern cvar_t cv_bot_allow_snipers;
+extern cvar_t cv_bot_allow_shield;
+extern cvar_t cv_bot_join_team;
+extern cvar_t cv_bot_join_after_player;
+extern cvar_t cv_bot_auto_vacate;
+extern cvar_t cv_bot_zombie;
+extern cvar_t cv_bot_defer_to_human;
+extern cvar_t cv_bot_chatter;
+extern cvar_t cv_bot_profile_db;
+
+#define IS_ALIVE true
+int UTIL_HumansOnTeam(int teamID, bool isAlive = false);
+
+#define IGNORE_SPECTATORS true
+int UTIL_HumansInGame(bool ignoreSpectators = false);
+
bool UTIL_IsNameTaken(const char *name, bool ignoreHumans = false);
int UTIL_ClientsInGame(void);
int UTIL_ActivePlayersInGame(void);
-int UTIL_HumansInGame(bool ignoreSpectators);
-NOBODY int UTIL_HumansOnTeam(int teamID, bool isAlive = false);
-NOBODY int UTIL_BotsInGame(void);
+int UTIL_BotsInGame(void);
bool UTIL_KickBotFromTeam(TeamName kickTeam);
-NOBODY bool UTIL_IsTeamAllBots(int team);
+bool UTIL_IsTeamAllBots(int team);
CBasePlayer *UTIL_GetClosestPlayer(const Vector *pos, float *distance = NULL);
-NOBODY CBasePlayer *UTIL_GetClosestPlayer(const Vector *pos, int team, float *distance = NULL);
+CBasePlayer *UTIL_GetClosestPlayer(const Vector *pos, int team, float *distance = NULL);
const char *UTIL_GetBotPrefix();
void UTIL_ConstructBotNetName(char *name, int nameLength, const BotProfile *profile);
-NOBODY bool UTIL_IsVisibleToTeam(const Vector &spot, int team, float maxRange = -1.0f);
+bool UTIL_IsVisibleToTeam(const Vector &spot, int team, float maxRange = -1.0f);
CBasePlayer *UTIL_GetLocalPlayer(void);
-NOBODY Vector UTIL_ComputeOrigin(entvars_t *pevVars);
-NOBODY Vector UTIL_ComputeOrigin(CBaseEntity *pEntity);
-NOBODY Vector UTIL_ComputeOrigin(edict_t *pentEdict);
-NOBODY void UTIL_DrawBeamFromEnt(int iIndex, Vector vecEnd, int iLifetime, byte bRed, byte bGreen, byte bBlue);
-NOBODY void UTIL_DrawBeamPoints(Vector vecStart, Vector vecEnd, int iLifetime, byte bRed, byte bGreen, byte bBlue);
+NOXREF Vector UTIL_ComputeOrigin(entvars_t *pevVars);
+NOXREF Vector UTIL_ComputeOrigin(CBaseEntity *pEntity);
+NOXREF Vector UTIL_ComputeOrigin(edict_t *pentEdict);
+NOXREF void UTIL_DrawBeamFromEnt(int iIndex, Vector vecEnd, int iLifetime, byte bRed, byte bGreen, byte bBlue);
+void UTIL_DrawBeamPoints(Vector vecStart, Vector vecEnd, int iLifetime, byte bRed, byte bGreen, byte bBlue);
+
+// Echos text to the console, and prints it on the client's screen. This is NOT tied to the developer cvar.
+// If you are adding debugging output in cstrike, use UTIL_DPrintf() (debug.h) instead.
void CONSOLE_ECHO(char *pszMsg, ...);
void CONSOLE_ECHO_LOGGED(char *pszMsg, ...);
+
void BotPrecache(void);
void InitBotTrig(void);
float BotCOS(float angle);
float BotSIN(float angle);
bool IsGameEventAudible(enum GameEventType event, CBaseEntity *entity, CBaseEntity *other, float *range, PriorityType *priority, bool *isHostile);
-NOBODY void HintMessageToAllPlayers(const char *message);
+void HintMessageToAllPlayers(const char *message);
#ifdef HOOK_GAMEDLL
diff --git a/regamedll/game_shared/bot/nav.h b/regamedll/game_shared/bot/nav.h
index 2066d1d9..5296df5a 100644
--- a/regamedll/game_shared/bot/nav.h
+++ b/regamedll/game_shared/bot/nav.h
@@ -36,7 +36,7 @@
#pragma warning(disable : 4530)
// to help identify nav files
-#define NAV_MAGIC_NUMBER 0xFEEDFACE
+#define NAV_MAGIC_NUMBER 0xFEEDFACE
// A place is a named group of navigation areas
typedef unsigned int Place;
@@ -47,6 +47,7 @@ typedef unsigned int Place;
#define WALK_THRU_DOORS 0x01
#define WALK_THRU_BREAKABLES 0x02
+#define WALK_THRU_EVERYTHING (WALK_THRU_DOORS | WALK_THRU_BREAKABLES)
//class CNavArea;
//class CNavNode;
@@ -141,24 +142,13 @@ struct Extent
Vector lo;
Vector hi;
- UNTESTED float SizeX(void) const
- {
- return hi.x - lo.x;
- }
- UNTESTED float SizeY(void) const
- {
- return hi.y - lo.y;
- }
- UNTESTED float SizeZ(void) const
- {
- return hi.z - lo.z;
- }
- UNTESTED float Area(void) const
- {
- return SizeX() * SizeY();
- }
+ float SizeX(void) const { return hi.x - lo.x; }
+ float SizeY(void) const { return hi.y - lo.y;}
+ float SizeZ(void) const { return hi.z - lo.z; }
+ float Area(void) const { return SizeX() * SizeY(); }
+
// return true if 'pos' is inside of this extent
- UNTESTED bool Contains(const Vector *pos) const
+ bool Contains(const Vector *pos) const
{
return (pos->x >= lo.x && pos->x <= hi.x &&
pos->y >= lo.y && pos->y <= hi.y &&
@@ -236,12 +226,12 @@ inline void AddDirectionVector(Vector *v, NavDirType dir, float amount)
case NORTH:
v->y -= amount;
return;
- case EAST:
- v->x += amount;
- return;
case SOUTH:
v->y += amount;
return;
+ case EAST:
+ v->x += amount;
+ return;
case WEST:
v->x -= amount;
return;
@@ -267,7 +257,7 @@ inline float DirectionToAngle(NavDirType dir)
}
/* <3d8335> ../game_shared/bot/nav.h:202 */
-inline NavDirType AngleToDirection(float angle)
+inline NavDirType AngleToDirection(float_precision angle)
{
while (angle < 0.0f)
angle += 360.0f;
@@ -327,6 +317,13 @@ inline void SnapToGrid(float *value)
*value = c * GenerationStepSize;
}
+// custom
+inline float SnapToGrid(float v)
+{
+ int c = v / GenerationStepSize;
+ return c;
+}
+
/* <14ea2f> ../game_shared/bot/nav.h:251 */
inline float_precision NormalizeAngle(float_precision angle)
{
@@ -368,7 +365,7 @@ inline float AngleDifference(float a, float b)
/* <38cac9> ../game_shared/bot/nav.h:288 */
inline bool AnglesAreEqual(float a, float b, float tolerance = 5.0f)
{
- if (abs(AngleDifference(a, b)) < tolerance)
+ if (abs(int64(AngleDifference(a, b))) < tolerance)
return true;
return false;
diff --git a/regamedll/game_shared/bot/nav_area.cpp b/regamedll/game_shared/bot/nav_area.cpp
index 6fc860b8..672a4aad 100644
--- a/regamedll/game_shared/bot/nav_area.cpp
+++ b/regamedll/game_shared/bot/nav_area.cpp
@@ -3631,7 +3631,7 @@ int CNavArea::GetPlayerCount(int teamID, CBasePlayer *ignore) const
if (!player->IsAlive())
continue;
- if (teamID == 0 || player->m_iTeam == teamID)
+ if (teamID == UNASSIGNED || player->m_iTeam == teamID)
if (Contains(&player->pev->origin))
++count;
}
@@ -3697,7 +3697,7 @@ void CNavArea::DrawConnectedAreas(void)
if (player == NULL)
return;
- CCSBotManager *ctrl = static_cast(TheBots);
+ CCSBotManager *ctrl = TheCSBots();
const float maxRange = 500.0f;
// draw self
@@ -3868,10 +3868,9 @@ public:
{
m_initialPlace = area->GetPlace();
}
-
bool operator()(CNavArea *area)
{
- CCSBotManager *ctrl = static_cast(TheBots);
+ CCSBotManager *ctrl = TheCSBots();
if (area->GetPlace() != m_initialPlace)
return false;
@@ -3891,8 +3890,7 @@ private:
/* <4d76ef> ../game_shared/bot/nav_area.cpp:4002 */
void EditNavAreas(NavEditCmdType cmd)
{
- CCSBotManager *ctrl = static_cast(TheBots);
-
+ CCSBotManager *ctrl = TheCSBots();
CBasePlayer *player = UTIL_GetLocalPlayer();
if (player == NULL)
return;
@@ -3912,7 +3910,6 @@ void EditNavAreas(NavEditCmdType cmd)
lastDrawTimestamp = drawTimestamp;
}
-
const float maxRange = 1000.0f;
int beamTime = 1;
@@ -4034,7 +4031,7 @@ void EditNavAreas(NavEditCmdType cmd)
// find the area the player is pointing at
CNavArea *area = TheNavAreaGrid.GetNearestNavArea(&result.vecEndPos);
- if (area)
+ if (area != NULL)
{
// if area changed, print its ID
if (area != lastSelectedArea)
@@ -4048,10 +4045,10 @@ void EditNavAreas(NavEditCmdType cmd)
if (area->GetPlace())
{
const char *name = TheBotPhrases->IDToName(area->GetPlace());
- if (name)
- strcpy(locName, name);
+ if (name != NULL)
+ Q_strcpy(locName, name);
else
- strcpy(locName, "ERROR");
+ Q_strcpy(locName, "ERROR");
}
else
{
@@ -4064,14 +4061,14 @@ void EditNavAreas(NavEditCmdType cmd)
}
else
{
- sprintf(attrib, "%s%s%s%s",
+ Q_sprintf(attrib, "%s%s%s%s",
(area->GetAttributes() & NAV_CROUCH) ? "CROUCH " : "",
(area->GetAttributes() & NAV_JUMP) ? "JUMP " : "",
(area->GetAttributes() & NAV_PRECISE) ? "PRECISE " : "",
(area->GetAttributes() & NAV_NO_JUMP) ? "NO_JUMP " : "");
}
- sprintf(buffer, "Area #%d %s %s\n", area->GetID(), locName, attrib);
+ Q_sprintf(buffer, "Area #%d %s %s\n", area->GetID(), locName, attrib);
UTIL_SayTextAll(buffer, player);
// do "place painting"
@@ -4255,7 +4252,7 @@ void EditNavAreas(NavEditCmdType cmd)
connected += markedArea->GetAdjacentCount(WEST);
char buffer[80];
- sprintf(buffer, "Marked Area is connected to %d other Areas\n", connected);
+ Q_sprintf(buffer, "Marked Area is connected to %d other Areas\n", connected);
UTIL_SayTextAll(buffer, player);
}
break;
@@ -4302,7 +4299,7 @@ void EditNavAreas(NavEditCmdType cmd)
}
char buffer[80];
- sprintf(buffer, "Marked Area is connected to %d other Areas - there are %d total unnamed areas\n", connected, totalUnnamedAreas);
+ Q_sprintf(buffer, "Marked Area is connected to %d other Areas - there are %d total unnamed areas\n", connected, totalUnnamedAreas);
UTIL_SayTextAll(buffer, player);
}
}
diff --git a/regamedll/game_shared/bot/nav_area.h b/regamedll/game_shared/bot/nav_area.h
index fcd3d045..e9e3274a 100644
--- a/regamedll/game_shared/bot/nav_area.h
+++ b/regamedll/game_shared/bot/nav_area.h
@@ -125,7 +125,6 @@ enum LadderDirectionType
NUM_LADDER_DIRECTIONS
};
-
/* <4c2fda> ../game_shared/bot/nav_area.h:63 */
class CNavLadder
{
@@ -232,10 +231,12 @@ public:
}
static void ChangeMasterMarker(void)
{
- IMPL(m_masterMarker)++;
+ ++IMPL(m_masterMarker);
}
+#ifndef HOOK_GAMEDLL
private:
+#endif // HOOK_GAMEDLL
friend void DestroyHidingSpots(void);
Vector m_pos;
@@ -243,9 +244,6 @@ private:
unsigned int m_marker;
unsigned char m_flags;
-#ifdef HOOK_GAMEDLL
-public:
-#endif // HOOK_GAMEDLL
static unsigned int IMPL(m_nextID);
static unsigned int IMPL(m_masterMarker);
@@ -303,77 +301,45 @@ public:
void Load(SteamFile *file, unsigned int version);
NavErrorType PostLoad(void);
- unsigned int GetID(void) const
- {
- return m_id;
- }
- void SetAttributes(unsigned char bits)
- {
- m_attributeFlags = bits;
- }
- unsigned char GetAttributes(void) const
- {
- return m_attributeFlags;
- }
- void SetPlace(Place place) // set place descriptor
- {
- m_place = place;
- }
- Place GetPlace(void) const // get place descriptor
- {
- return m_place;
- }
+ unsigned int GetID(void) const { return m_id; }
+ void SetAttributes(unsigned char bits) { m_attributeFlags = bits; }
+ unsigned char GetAttributes(void) const { return m_attributeFlags; }
+ void SetPlace(Place place) { m_place = place; } // set place descriptor
+ Place GetPlace(void) const { return m_place; } // get place descriptor
- bool IsOverlapping(const Vector *pos) const; // return true if 'pos' is within 2D extents of area
- bool IsOverlapping(const CNavArea *area) const; // return true if 'area' overlaps our 2D extents
- bool IsOverlappingX(const CNavArea *area) const; // return true if 'area' overlaps our X extent
- bool IsOverlappingY(const CNavArea *area) const; // return true if 'area' overlaps our Y extent
- int GetPlayerCount(int teamID = 0, CBasePlayer *ignore = NULL) const; // return number of players with given teamID in this area (teamID == 0 means any/all)
- float GetZ(const Vector *pos) const; // return Z of area at (x,y) of 'pos'
- float GetZ(float x, float y) const; // return Z of area at (x,y) of 'pos'
- bool Contains(const Vector *pos) const; // return true if given point is on or above this area, but no others
- bool IsCoplanar(const CNavArea *area) const; // return true if this area and given area are approximately co-planar
- void GetClosestPointOnArea(const Vector *pos, Vector *close) const; // return closest point to 'pos' on this area - returned point in 'close'
- float GetDistanceSquaredToPoint(const Vector *pos) const; // return shortest distance between point and this area
- bool IsDegenerate(void) const; // return true if this area is badly formed
- bool IsEdge(NavDirType dir) const; // return true if there are no bi-directional links on the given side
- int GetAdjacentCount(NavDirType dir) const // return number of connected areas in given direction
- {
- return m_connect[dir].size();
- }
- CNavArea *GetAdjacentArea(NavDirType dir, int i) const; // return the i'th adjacent area in the given direction
+ bool IsOverlapping(const Vector *pos) const; // return true if 'pos' is within 2D extents of area
+ bool IsOverlapping(const CNavArea *area) const; // return true if 'area' overlaps our 2D extents
+ bool IsOverlappingX(const CNavArea *area) const; // return true if 'area' overlaps our X extent
+ bool IsOverlappingY(const CNavArea *area) const; // return true if 'area' overlaps our Y extent
+ int GetPlayerCount(int teamID = 0, CBasePlayer *ignore = NULL) const; // return number of players with given teamID in this area (teamID == 0 means any/all)
+ float GetZ(const Vector *pos) const; // return Z of area at (x,y) of 'pos'
+ float GetZ(float x, float y) const; // return Z of area at (x,y) of 'pos'
+ bool Contains(const Vector *pos) const; // return true if given point is on or above this area, but no others
+ bool IsCoplanar(const CNavArea *area) const; // return true if this area and given area are approximately co-planar
+ void GetClosestPointOnArea(const Vector *pos, Vector *close) const; // return closest point to 'pos' on this area - returned point in 'close'
+ float GetDistanceSquaredToPoint(const Vector *pos) const; // return shortest distance between point and this area
+ bool IsDegenerate(void) const; // return true if this area is badly formed
+ bool IsEdge(NavDirType dir) const; // return true if there are no bi-directional links on the given side
+ int GetAdjacentCount(NavDirType dir) const { return m_connect[dir].size(); } // return number of connected areas in given direction
+ CNavArea *GetAdjacentArea(NavDirType dir, int i) const; // return the i'th adjacent area in the given direction
CNavArea *GetRandomAdjacentArea(NavDirType dir) const;
- const NavConnectList *GetAdjacentList(NavDirType dir) const
- {
- return &m_connect[dir];
- }
- bool IsConnected(const CNavArea *area, NavDirType dir) const; // return true if given area is connected in given direction
- float ComputeHeightChange(const CNavArea *area); // compute change in height from this area to given area
+ const NavConnectList *GetAdjacentList(NavDirType dir) const { return &m_connect[dir]; }
+ bool IsConnected(const CNavArea *area, NavDirType dir) const; // return true if given area is connected in given direction
+ float ComputeHeightChange(const CNavArea *area); // compute change in height from this area to given area
- const NavLadderList *GetLadderList(LadderDirectionType dir) const
- {
- return &m_ladder[dir];
- }
+ const NavLadderList *GetLadderList(LadderDirectionType dir) const { return &m_ladder[dir]; }
void ComputePortal(const CNavArea *to, NavDirType dir, Vector *center, float *halfWidth) const; // compute portal to adjacent area
void ComputeClosestPointInPortal(const CNavArea *to, NavDirType dir, const Vector *fromPos, Vector *closePos) const; // compute closest point within the "portal" between to adjacent areas
NavDirType ComputeDirection(Vector *point) const; // return direction from this area to the given point
// for hunting algorithm
- void SetClearedTimestamp(int teamID) // set this area's "clear" timestamp to now
- {
- m_clearedTimestamp[teamID] = gpGlobals->time;
- }
- float GetClearedTimestamp(int teamID) // get time this area was marked "clear"
- {
- return m_clearedTimestamp[teamID];
- }
+ void SetClearedTimestamp(int teamID) { m_clearedTimestamp[teamID] = gpGlobals->time; } // set this area's "clear" timestamp to now
+ float GetClearedTimestamp(int teamID) { return m_clearedTimestamp[teamID]; } // get time this area was marked "clear"
// hiding spots
- const HidingSpotList *GetHidingSpotList(void) const
- {
- return &m_hidingSpotList;
- }
+ const HidingSpotList *GetHidingSpotList(void) const { return &m_hidingSpotList; }
+
void ComputeHidingSpots(void); // analyze local area neighborhood to find "hiding spots" in this area - for map learning
void ComputeSniperSpots(void); // analyze local area neighborhood to find "sniper spots" in this area - for map learning
@@ -383,22 +349,12 @@ public:
// danger
void IncreaseDanger(int teamID, float amount); // increase the danger of this area for the given team
float GetDanger(int teamID); // return the danger of this area (decays over time)
- float GetSizeX(void) const
- {
- return m_extent.hi.x - m_extent.lo.x;
- }
- float GetSizeY(void) const
- {
- return m_extent.hi.y - m_extent.lo.y;
- }
- const Extent *GetExtent(void) const
- {
- return &m_extent;
- }
- const Vector *GetCenter(void) const
- {
- return &m_center;
- }
+
+ float GetSizeX(void) const { return m_extent.hi.x - m_extent.lo.x; }
+ float GetSizeY(void) const { return m_extent.hi.y - m_extent.lo.y; }
+
+ const Extent *GetExtent(void) const { return &m_extent; }
+ const Vector *GetCenter(void) const { return &m_center; }
const Vector *GetCorner(NavCornerType corner) const;
// approach areas
@@ -411,44 +367,22 @@ public:
NavTraverseType hereToNextHow;
};
- const ApproachInfo *GetApproachInfo(int i) const
- {
- return &m_approach[i];
- }
- int GetApproachInfoCount(void) const
- {
- return m_approachCount;
- }
- void ComputeApproachAreas(void); // determine the set of "approach areas" - for map learning
+ const ApproachInfo *GetApproachInfo(int i) const { return &m_approach[i]; }
+ int GetApproachInfoCount(void) const { return m_approachCount; }
+ void ComputeApproachAreas(void); // determine the set of "approach areas" - for map learning
// A* pathfinding algorithm
static void MakeNewMarker(void)
{
- IMPL(m_masterMarker)++;
+ ++IMPL(m_masterMarker);
if (IMPL(m_masterMarker) == 0)
IMPL(m_masterMarker) = 1;
}
- void Mark(void)
- {
- m_marker = IMPL(m_masterMarker);
- }
- BOOL IsMarked(void) const
- {
- return (m_marker == IMPL(m_masterMarker)) ? true : false;
- }
- void SetParent(CNavArea *parent, NavTraverseType how = NUM_TRAVERSE_TYPES)
- {
- m_parent = parent;
- m_parentHow = how;
- }
- CNavArea *GetParent(void) const
- {
- return m_parent;
- }
- NavTraverseType GetParentHow(void) const
- {
- return m_parentHow;
- }
+ void Mark(void) { m_marker = IMPL(m_masterMarker); }
+ BOOL IsMarked(void) const { return (m_marker == IMPL(m_masterMarker)) ? true : false; }
+ void SetParent(CNavArea *parent, NavTraverseType how = NUM_TRAVERSE_TYPES) { m_parent = parent; m_parentHow = how; }
+ CNavArea *GetParent(void) const { return m_parent; }
+ NavTraverseType GetParentHow(void) const { return m_parentHow; }
bool IsOpen(void) const; // true if on "open list"
void AddToOpenList(void); // add to open list in decreasing value order
@@ -463,22 +397,10 @@ public:
static void ClearSearchLists(void); // clears the open and closed lists for a new search
- void SetTotalCost(float value)
- {
- m_totalCost = value;
- }
- float GetTotalCost(void) const
- {
- return m_totalCost;
- }
- void SetCostSoFar(float value)
- {
- m_costSoFar = value;
- }
- float GetCostSoFar(void) const
- {
- return m_costSoFar;
- }
+ void SetTotalCost(float value) { m_totalCost = value; }
+ float GetTotalCost(void) const { return m_totalCost; }
+ void SetCostSoFar(float value) { m_costSoFar = value; }
+ float GetCostSoFar(void) const { return m_costSoFar; }
// editing
void Draw(byte red, byte green, byte blue, int duration = 50); // draw area for debugging & editing
@@ -490,18 +412,10 @@ public:
void RaiseCorner(NavCornerType corner, int amount); // raise/lower a corner (or all corners if corner == NUM_CORNERS)
// ladders
- void AddLadderUp(CNavLadder *ladder)
- {
- m_ladder[LADDER_UP].push_back(ladder);
- }
- void AddLadderDown(CNavLadder *ladder)
- {
- m_ladder[LADDER_DOWN].push_back(ladder);
- }
+ void AddLadderUp(CNavLadder *ladder) { m_ladder[LADDER_UP].push_back(ladder); }
+ void AddLadderDown(CNavLadder *ladder) { m_ladder[LADDER_DOWN].push_back(ladder); }
-#ifdef HOOK_GAMEDLL
-public:
-#else
+#ifndef HOOK_GAMEDLL
private:
#endif // HOOK_GAMEDLL
friend void ConnectGeneratedAreas(void);
@@ -602,6 +516,7 @@ inline CNavArea *CNavArea::GetAdjacentArea(NavDirType dir, int i) const
return (*iter).area;
--i;
}
+
return NULL;
}
@@ -1151,7 +1066,7 @@ void SearchSurroundingAreas(CNavArea *startArea, const Vector *startPos, Functor
// check up ladders
const NavLadderList *ladderList = area->GetLadderList(LADDER_UP);
- if (ladderList)
+ if (ladderList != NULL)
{
for (ladderIt = ladderList->begin(); ladderIt != ladderList->end(); ++ladderIt)
{
@@ -1172,7 +1087,7 @@ void SearchSurroundingAreas(CNavArea *startArea, const Vector *startPos, Functor
// check down ladders
ladderList = area->GetLadderList(LADDER_DOWN);
- if (ladderList)
+ if (ladderList != NULL)
{
for (ladderIt = ladderList->begin(); ladderIt != ladderList->end(); ++ladderIt)
{
@@ -1185,23 +1100,26 @@ void SearchSurroundingAreas(CNavArea *startArea, const Vector *startPos, Functor
}
// Apply the functor to all navigation areas
+// If functor returns false, stop processing and return false.
/* <4c4137> ../game_shared/bot/nav_area.h:1109 */
template
-void ForAllAreas(Functor &func)
+bool ForAllAreas(Functor &func)
{
NavAreaList::iterator iter;
for (iter = TheNavAreaList.begin(); iter != TheNavAreaList.end(); ++iter)
{
CNavArea *area = *iter;
- func(area);
+ if (func(area) == false)
+ return false;
}
+
+ return true;
}
// Fuctor that returns lowest cost for farthest away areas
// For use with FindMinimumCostArea()
-
-class FarAwayFunctor NOXREF
+NOXREF class FarAwayFunctor
{
public:
float operator()(CNavArea *area, CNavArea *fromArea, const CNavLadder *ladder)
@@ -1209,7 +1127,7 @@ public:
if (area == fromArea)
return 9999999.9f;
- return 1.0f/(*fromArea->GetCenter() - *area->GetCenter()).Length();
+ return 1.0f / (*fromArea->GetCenter() - *area->GetCenter()).Length();
}
};
@@ -1275,9 +1193,11 @@ CNavArea *FindMinimumCostArea(CNavArea *startArea, CostFunctor &costFunc)
{
// replace most expensive cost if this is cheaper
int expensive = 0;
- for (int i = 1; i < NUM_CHEAP_AREAS; i++)
+ for (int i = 1; i < NUM_CHEAP_AREAS; ++i)
+ {
if (cheapAreaSet[i].cost > cheapAreaSet[expensive].cost)
expensive = i;
+ }
if (cheapAreaSet[expensive].cost > cost)
{
@@ -1299,8 +1219,10 @@ CNavArea *FindMinimumCostArea(CNavArea *startArea, CostFunctor &costFunc)
NavAreaList::iterator iter;
for (iter = TheNavAreaList.begin(); iter != TheNavAreaList.end(); ++iter)
+ {
if (which-- == 0)
break;
+ }
return *iter;
}
@@ -1386,9 +1308,4 @@ void BuildLadders(void);
void MarkJumpAreas(void);
void GenerateNavigationAreaMesh(void);
-//refs
-extern float (*pGetZ__Vector)(const Vector *pos);
-extern CNavArea *(*pGetNearestNavArea)(const Vector *pos, bool anyZ);
-extern CNavArea *(*pGetNavArea)(const Vector *pos, float beneathLimit);
-
#endif // NAV_AREA_H
diff --git a/regamedll/game_shared/shared_util.cpp b/regamedll/game_shared/shared_util.cpp
index 4217c407..fae039b7 100644
--- a/regamedll/game_shared/shared_util.cpp
+++ b/regamedll/game_shared/shared_util.cpp
@@ -16,15 +16,21 @@ char s_shared_quote;
#endif // HOOK_GAMEDLL
/* <2d4a66> ../game_shared/shared_util.cpp:50 */
-NOBODY uchar32 *SharedWVarArgs(uchar32 *format, ...)
+NOXREF wchar_t *SharedWVarArgs(wchar_t *format, ...)
{
-// {
-// va_list argptr; // 52
-// intconst BufLen; // 53
-// intconst NumBuffers; // 54
-// wchar_t string; // 55
-// int curstring; // 56
-// }
+ va_list argptr;
+ const int BufLen = 1024;
+ const int NumBuffers = 4;
+ static wchar_t string[NumBuffers][BufLen];
+ static int curstring = 0;
+
+ curstring = (curstring + 1) % NumBuffers;
+
+ va_start(argptr, format);
+ Q_vsnwprintf(string[curstring], BufLen, format, argptr);
+ va_end(argptr);
+
+ return string[curstring];
}
/* <2d4b0a> ../game_shared/shared_util.cpp:68 */
@@ -59,27 +65,39 @@ char *BufPrintf(char *buf, int &len, const char *fmt, ...)
len -= Q_strlen(buf);
return buf + Q_strlen(buf);
}
+
return NULL;
}
/* <2d4c0d> ../game_shared/shared_util.cpp:106 */
-NOBODY uchar32 *BufWPrintf(uchar32 *buf, int &len, const uchar32 *fmt, ...)
+wchar_t *BufWPrintf(wchar_t *buf, int &len, const wchar_t *fmt, ...)
{
-// {
-// va_list argptr; // 111
-// }
+ if (len <= 0)
+ return NULL;
+
+ va_list argptr;
+
+ va_start(argptr, fmt);
+ Q_vsnwprintf(buf, len, fmt, argptr);
+ va_end(argptr);
+
+ len -= wcslen(buf);
+ return buf + wcslen(buf);
}
/* <2d4c7e> ../game_shared/shared_util.cpp:122 */
-NOBODY const uchar32 *NumAsWString(int val)
+NOXREF const wchar_t *NumAsWString(int val)
{
-// {
-// intconst BufLen; // 124
-// intconst NumBuffers; // 125
-// wchar_t string; // 126
-// int curstring; // 127
-// int len; // 131
-// }
+ const int BufLen = 16;
+ const int NumBuffers = 4;
+ static wchar_t string[NumBuffers][BufLen];
+ static int curstring = 0;
+
+ curstring = (curstring + 1) % NumBuffers;
+
+ int len = BufLen;
+ BufWPrintf(string[curstring], len, L"%d", val);
+ return string[curstring];
}
/* <2d4d11> ../game_shared/shared_util.cpp:137 */
@@ -118,22 +136,99 @@ NOXREF void SharedSetQuoteChar(char c)
// Parse a token out of a string
/* <2d4de7> ../game_shared/shared_util.cpp:173 */
-NOBODY const char *SharedParse(const char *data)
+const char *SharedParse(const char *data)
{
-//
-//skipwhite: // 185
-// {
-// int c; // 175
-// int len; // 176
-// }
+ int c;
+ int len;
+
+ len = 0;
+ s_shared_token[0] = '\0';
+
+ if (!data)
+ return NULL;
+
+// skip whitespace
+skipwhite:
+ while ((c = *data) <= ' ')
+ {
+ if (c == 0)
+ {
+ // end of file;
+ return NULL;
+ }
+
+ data++;
+ }
+
+ // skip // comments
+ if (c == '/' && data[1] == '/')
+ {
+ while (*data && *data != '\n')
+ data++;
+
+ goto skipwhite;
+ }
+
+ // handle quoted strings specially
+ if (c == s_shared_quote)
+ {
+ data++;
+
+ while (true)
+ {
+ c = *data++;
+ if (c == s_shared_quote || !c)
+ {
+ s_shared_token[len] = '\0';
+ return data;
+ }
+
+ s_shared_token[len] = c;
+ len++;
+ }
+ }
+
+ // parse single characters
+ if (c == '{' || c == '}'|| c == ')'|| c == '(' || c == '\'' || c == ',')
+ {
+ s_shared_token[len] = c;
+ len++;
+ s_shared_token[len] = '\0';
+ return data + 1;
+ }
+
+ // parse a regular word
+ do
+ {
+ s_shared_token[len] = c;
+ data++;
+ len++;
+ c = *data;
+
+ if (c == '{' || c == '}'|| c == ')'|| c == '(' || c == '\'' || c == ',')
+ break;
+
+ } while (c > 32);
+
+ s_shared_token[len] = '\0';
+ return data;
}
// Returns true if additional data is waiting to be processed on this line
/* <2d4e40> ../game_shared/shared_util.cpp:247 */
-NOBODY bool SharedTokenWaiting(const char *buffer)
+NOXREF bool SharedTokenWaiting(const char *buffer)
{
-// {
-// const char *p; // 249
-// }
+ const char *p;
+
+ p = buffer;
+ while (*p && *p!='\n')
+ {
+ if (!isspace(*p) || isalnum(*p))
+ return true;
+
+ p++;
+ }
+
+ return false;
}
diff --git a/regamedll/game_shared/shared_util.h b/regamedll/game_shared/shared_util.h
index 7a08a07c..01494724 100644
--- a/regamedll/game_shared/shared_util.h
+++ b/regamedll/game_shared/shared_util.h
@@ -32,6 +32,11 @@
#pragma once
#endif
+#ifndef _WIN32
+#include
+#include
+#endif // _WIN32
+
#ifdef HOOK_GAMEDLL
#define s_shared_token (*ps_shared_token)
@@ -42,16 +47,18 @@
extern char s_shared_token[ 1500 ];
extern char s_shared_quote;
-NOBODY uchar32 *SharedWVarArgs(uchar32 *format, ...);
+NOXREF wchar_t *SharedWVarArgs(wchar_t *format, ...);
char *SharedVarArgs(char *format, ...);
char *BufPrintf(char *buf, int &len, const char *fmt, ...);
-NOBODY uchar32 *BufWPrintf(uchar32 *buf, int &len, const uchar32 *fmt, ...);
-NOBODY const uchar32 *NumAsWString(int val);
+NOXREF wchar_t *BufWPrintf(wchar_t *buf, int &len, const wchar_t *fmt, ...);
+NOXREF const wchar_t *NumAsWString(int val);
const char *NumAsString(int val);
char *SharedGetToken(void);
NOXREF void SharedSetQuoteChar(char c);
-NOBODY const char *SharedParse(const char *data);
-NOBODY bool SharedTokenWaiting(const char *buffer);
+const char *SharedParse(const char *data);
+NOXREF bool SharedTokenWaiting(const char *buffer);
+
+// Simple utility function to allocate memory and duplicate a string
/* ../game_shared/shared_util.h:46 */
inline char *CloneString(const char *str)
@@ -62,20 +69,26 @@ inline char *CloneString(const char *str)
cloneStr[0] = '\0';
return cloneStr;
}
+
char *cloneStr = new char [Q_strlen(str) + 1];
Q_strcpy(cloneStr, str);
return cloneStr;
}
-#ifdef _WIN32
+// Simple utility function to allocate memory and duplicate a wide string
inline wchar_t *CloneWString(const wchar_t *str)
{
+ if (!str)
+ {
+ wchar_t *cloneStr = new wchar_t[1];
+ cloneStr[0] = L'\0';
+ return cloneStr;
+ }
+
wchar_t *cloneStr = new wchar_t [wcslen(str) + 1];
wcscpy(cloneStr, str);
return cloneStr;
}
-#endif // _WIN32
-
#endif // SHARED_UTIL
diff --git a/regamedll/game_shared/voice_gamemgr.cpp b/regamedll/game_shared/voice_gamemgr.cpp
index 78bbca67..d001597e 100644
--- a/regamedll/game_shared/voice_gamemgr.cpp
+++ b/regamedll/game_shared/voice_gamemgr.cpp
@@ -131,7 +131,7 @@ bool CVoiceGameMgr::ClientCommand(CBasePlayer *pPlayer, const char *cmd)
bool bBan = Q_stricmp(cmd, "vban") == 0;
if (bBan && CMD_ARGC() >= 2)
{
- for (int i = 1; i < CMD_ARGC(); i++)
+ for (int i = 1; i < CMD_ARGC(); ++i)
{
uint32 mask = 0;
sscanf(CMD_ARGV(i), "%x", &mask);
@@ -145,6 +145,8 @@ bool CVoiceGameMgr::ClientCommand(CBasePlayer *pPlayer, const char *cmd)
VoiceServerDebug("CVoiceGameMgr::ClientCommand: invalid index (%d)\n", i);
}
+ // Force it to update the masks now.
+ //UpdateMasks();
return true;
}
else if (Q_stricmp(cmd, "VModEnable") == 0 && CMD_ARGC() >= 2)
@@ -153,7 +155,7 @@ bool CVoiceGameMgr::ClientCommand(CBasePlayer *pPlayer, const char *cmd)
g_PlayerModEnable[ playerClientIndex ] = !!Q_atoi(CMD_ARGV(1));
g_bWantModEnable[ playerClientIndex ] = false;
-
+ //UpdateMasks();
return true;
}
@@ -167,7 +169,7 @@ void CVoiceGameMgr::UpdateMasks(void)
bool bAllTalk = !!(sv_alltalk.value);
- for (int iClient = 0; iClient < m_nMaxPlayers; iClient++)
+ for (int iClient = 0; iClient < m_nMaxPlayers; ++iClient)
{
CBaseEntity *pEnt = UTIL_PlayerByIndex(iClient + 1);
@@ -191,7 +193,7 @@ void CVoiceGameMgr::UpdateMasks(void)
if (g_PlayerModEnable[ iClient ])
{
// Build a mask of who they can hear based on the game rules.
- for (int iOtherClient = 0; iOtherClient < m_nMaxPlayers; iOtherClient++)
+ for (int iOtherClient = 0; iOtherClient < m_nMaxPlayers; ++iOtherClient)
{
CBaseEntity *pEnt = UTIL_PlayerByIndex(iOtherClient + 1);
@@ -209,7 +211,7 @@ void CVoiceGameMgr::UpdateMasks(void)
g_SentBanMasks[ iClient ] = g_BanMasks[ iClient ];
MESSAGE_BEGIN(MSG_ONE, m_msgPlayerVoiceMask, NULL, pPlayer->pev);
- for (int dw = 0; dw < VOICE_MAX_PLAYERS_DW; dw++)
+ for (int dw = 0; dw < VOICE_MAX_PLAYERS_DW; ++dw)
{
WRITE_LONG(gameRulesMask.GetDWord(dw));
WRITE_LONG(g_BanMasks[ iClient ].GetDWord(dw));
@@ -218,7 +220,7 @@ void CVoiceGameMgr::UpdateMasks(void)
}
// Tell the engine.
- for (int iOtherClient = 0; iOtherClient < m_nMaxPlayers; iOtherClient++)
+ for (int iOtherClient = 0; iOtherClient < m_nMaxPlayers; ++iOtherClient)
{
bool bCanHear = gameRulesMask[ iOtherClient ] && !g_BanMasks[ iClient ][ iOtherClient ];
SET_CLIENT_LISTENING(iClient + 1, iOtherClient + 1, bCanHear);
diff --git a/regamedll/hookers/6153_hooker.cpp b/regamedll/hookers/6153_hooker.cpp
index b3db85fe..0d39b27e 100644
--- a/regamedll/hookers/6153_hooker.cpp
+++ b/regamedll/hookers/6153_hooker.cpp
@@ -95,19 +95,21 @@ extern const size_t g_BaseOffset = 0x00000000;
//#define CS_Bot_Region
//#define CS_BotState_Region
//#define Bot_Region
+//#define Bot_Profile
//#define CS_Util_Region
//#define CS_Init_Region
//#define H_Region
//#define Tutor_CS_Region
//#define Nav_Region
//#define Hostage_Region
-//#define GameShr_BotProfile_Region
//#define VoiceManager_Region
//#define Vector_Region
//#define Data_References_Region
//#define Function_References_Region
+extern void BotPhraseManager__OnRoundRestart(int pthis);
+
FunctionHook g_FunctionHooks[] =
{
@@ -120,6 +122,7 @@ FunctionHook g_FunctionHooks[] =
{ 0x01DE12A5, "realloc", (size_t)&_realloc_mhook_ },
{ 0x01DE0E7B, "free", (size_t)&_free_mhook_ },
{ 0x01DF27C9, "strdup", (size_t)&_strdup_mhook_ },
+ //{ 0x01DDFD40, "rand", (size_t)&_rand_mhook_ },
#endif // _WIN32
@@ -2191,19 +2194,19 @@ FunctionHook g_FunctionHooks[] =
#ifndef SharedUtil_Region
#ifdef _WIN32
- //{ 0x01D50CA0, "", (size_t)&CloneString },
+ { 0x01D50CA0, "", (size_t)&CloneString },
#endif // _WIN32
- //{ 0x01D58EE0, "_Z14SharedWVarArgsPwz", (size_t)&SharedWVarArgs }, // NOXREF
+ //{ 0x01D58EE0, "_Z14SharedWVarArgsPwz", (size_t)&SharedWVarArgs }, // NOXREF
{ 0x01D58F30, "_Z13SharedVarArgsPcz", (size_t)&SharedVarArgs },
{ 0x01D58F80, "_Z9BufPrintfPcRiPKcz", (size_t)&BufPrintf },
- //{ 0x01D58FD0, "_Z10BufWPrintfPwRiPKwz", (size_t)&BufWPrintf },??
- //{ 0x01D59010, "_Z12NumAsWStringi", (size_t)&NumAsWString }, // NOXREF
+ //{ 0x01D58FD0, "_Z10BufWPrintfPwRiPKwz", (size_t)&BufWPrintf }, // NOXREF
+ //{ 0x01D59010, "_Z12NumAsWStringi", (size_t)&NumAsWString }, // NOXREF
{ 0x01D59060, "_Z11NumAsStringi", (size_t)&NumAsString },
{ 0x01D590B0, "_Z14SharedGetTokenv", (size_t)&SharedGetToken },
- //{ 0x01D590C0, "_Z18SharedSetQuoteCharc", (size_t)&SharedSetQuoteChar }, // NOXREF
- //{ 0x01D590D0, "_Z11SharedParsePKc", (size_t)&SharedParse },
- //{ 0x01D591B0, "_Z18SharedTokenWaitingPKc", (size_t)&SharedTokenWaiting }, // NOXREF
+ //{ 0x01D590C0, "_Z18SharedSetQuoteCharc", (size_t)&SharedSetQuoteChar }, // NOXREF
+ { 0x01D590D0, "_Z11SharedParsePKc", (size_t)&SharedParse },
+ //{ 0x01D591B0, "_Z18SharedTokenWaitingPKc", (size_t)&SharedTokenWaiting }, // NOXREF
#endif // SharedUtil_Region
@@ -2906,7 +2909,7 @@ FunctionHook g_FunctionHooks[] =
{ 0x01DCF2D0, "_ZN17CBasePlayerWeapon11ReloadSoundEv", mfunc_ptr_cast(&CBasePlayerWeapon::ReloadSound) },
{ 0x01DCF930, "_ZN17CBasePlayerWeapon18GetNextAttackDelayEf", mfunc_ptr_cast(&CBasePlayerWeapon::GetNextAttackDelay) },
//{ 0x01DCE630, "_ZN17CBasePlayerWeapon18HasSecondaryAttackEv", mfunc_ptr_cast(&CBasePlayerWeapon::HasSecondaryAttack) }, // NOXREF
- //{ 0x0, "_ZN17CBasePlayerWeapon8IsPistolEv", mfunc_ptr_cast(&CBasePlayerWeapon::IsPistol) },
+ { 0x01D32670, "_ZN17CBasePlayerWeapon8IsPistolEv", mfunc_ptr_cast(&CBasePlayerWeapon::IsPistol) },
{ 0x01DCDE10, "_ZN17CBasePlayerWeapon19SetPlayerShieldAnimEv", mfunc_ptr_cast(&CBasePlayerWeapon::SetPlayerShieldAnim) },
{ 0x01DCDE60, "_ZN17CBasePlayerWeapon21ResetPlayerShieldAnimEv", mfunc_ptr_cast(&CBasePlayerWeapon::ResetPlayerShieldAnim) },
{ 0x01DCE140, "_ZN17CBasePlayerWeapon19ShieldSecondaryFireEii", mfunc_ptr_cast(&CBasePlayerWeapon::ShieldSecondaryFire) },
@@ -3682,14 +3685,14 @@ FunctionHook g_FunctionHooks[] =
{ 0x01D24880, "_ZN13CCSBotManager13ClientCommandEP11CBasePlayerPKc", mfunc_ptr_cast(&CCSBotManager::ClientCommand_) },
{ 0x01D234D0, "_ZN13CCSBotManager14ServerActivateEv", mfunc_ptr_cast(&CCSBotManager::ServerActivate_) },
{ 0x01D23760, "_ZN13CCSBotManager16ServerDeactivateEv", mfunc_ptr_cast(&CCSBotManager::ServerDeactivate_) },
- //{ 0x01D23900, "_ZN13CCSBotManager13ServerCommandEPKc", mfunc_ptr_cast(&CCSBotManager::ServerCommand_) },
+ { 0x01D23900, "_ZN13CCSBotManager13ServerCommandEPKc", mfunc_ptr_cast(&CCSBotManager::ServerCommand_) },
{ 0x01D23520, "_ZN13CCSBotManager16AddServerCommandEPKc", mfunc_ptr_cast(&CCSBotManager::AddServerCommand_) },
{ 0x01D23540, "_ZN13CCSBotManager17AddServerCommandsEv", mfunc_ptr_cast(&CCSBotManager::AddServerCommands_) },
{ 0x01D22F40, "_ZN13CCSBotManager12RestartRoundEv", mfunc_ptr_cast(&CCSBotManager::RestartRound_) },
- //{ 0x01D23200, "_ZN13CCSBotManager10StartFrameEv", mfunc_ptr_cast(&CCSBotManager::StartFrame) },
+ { 0x01D23200, "_ZN13CCSBotManager10StartFrameEv", mfunc_ptr_cast(&CCSBotManager::StartFrame_) },
{ 0x01D25780, "_ZN13CCSBotManager7OnEventE13GameEventTypeP11CBaseEntityS2_", mfunc_ptr_cast(&CCSBotManager::OnEvent_) },
- //{ 0x01D25970, "_ZNK13CCSBotManager17GetPlayerPriorityEP11CBasePlayer", mfunc_ptr_cast(&CCSBotManager::GetPlayerPriority) },
- //{ 0x0, "_ZNK13CCSBotManager17IsImportantPlayerEP11CBasePlayer", mfunc_ptr_cast(&CCSBotManager::IsImportantPlayer) },
+ { 0x01D25970, "_ZNK13CCSBotManager17GetPlayerPriorityEP11CBasePlayer", mfunc_ptr_cast(&CCSBotManager::GetPlayerPriority_) },
+ { 0x01D25920, "_ZNK13CCSBotManager17IsImportantPlayerEP11CBasePlayer", mfunc_ptr_cast(&CCSBotManager::IsImportantPlayer_) },
//non-virtual func
{ 0x01D24D90, "_ZN13CCSBotManager15ValidateMapDataEv", mfunc_ptr_cast(&CCSBotManager::ValidateMapData) },
//{ 0x0, "_ZNK13CCSBotManager13IsLearningMapEv", mfunc_ptr_cast(&CCSBotManager::IsLearningMap) },
@@ -3700,24 +3703,24 @@ FunctionHook g_FunctionHooks[] =
//{ 0x0, "_ZN13CCSBotManager18GetDifficultyLevelEv", mfunc_ptr_cast(&CCSBotManager::BotDifficultyType GetDifficultyLevel) },
//{ 0x0, "_ZNK13CCSBotManager11GetScenarioEv", mfunc_ptr_cast(&CCSBotManager::GameScenarioType GetScenario) },
//{ 0x0, "_ZNK13CCSBotManager7GetZoneEi", mfunc_ptr_cast(&CCSBotManager::GetZone) }, // NOXREF
- //{ 0x01D25530, "_ZNK13CCSBotManager7GetZoneEPK6Vector", mfunc_ptr_cast(&CCSBotManager::GetZone) },
+ { 0x01D25530, "_ZNK13CCSBotManager7GetZoneEPK6Vector", mfunc_ptr_cast(&CCSBotManager::GetZone) },
{ 0x01D255C0, "_ZNK13CCSBotManager14GetClosestZoneEPK6Vector", mfunc_ptr_cast(&CCSBotManager::GetClosestZone) },
//{ 0x0, "_ZNK13CCSBotManager14GetClosestZoneEPK11CBaseEntity", mfunc_ptr_cast(&CCSBotManager::GetClosestZone) },
//{ 0x0, "_ZNK13CCSBotManager12GetZoneCountEv", mfunc_ptr_cast(&CCSBotManager::GetZoneCount) },
- //{ 0x0, "_ZNK13CCSBotManager23GetRandomPositionInZoneEPKNS_4ZoneE", mfunc_ptr_cast(&CCSBotManager::GetRandomPositionInZone) },
- //{ 0x01D25750, "_ZNK13CCSBotManager19GetRandomAreaInZoneEPKNS_4ZoneE", mfunc_ptr_cast(&CCSBotManager::GetRandomAreaInZone) },
+ { 0x01D25630, "_ZNK13CCSBotManager23GetRandomPositionInZoneEPKNS_4ZoneE", mfunc_ptr_cast(&CCSBotManager::GetRandomPositionInZone) },
+ { 0x01D25750, "_ZNK13CCSBotManager19GetRandomAreaInZoneEPKNS_4ZoneE", mfunc_ptr_cast(&CCSBotManager::GetRandomAreaInZone) },
//{ 0x0, "_ZNK13CCSBotManager13GetRandomZoneEv", mfunc_ptr_cast(&CCSBotManager::GetRandomZone) },
//{ 0x0, "_ZNK13CCSBotManager13IsBombPlantedEv", mfunc_ptr_cast(&CCSBotManager::IsBombPlanted) },
//{ 0x0, "_ZNK13CCSBotManager21GetBombPlantTimestampEv", mfunc_ptr_cast(&CCSBotManager::GetBombPlantTimestamp) },
//{ 0x0, "_ZNK13CCSBotManager17IsTimeToPlantBombEv", mfunc_ptr_cast(&CCSBotManager::IsTimeToPlantBomb) },
//{ 0x0, "_ZNK13CCSBotManager14GetBombDefuserEv", mfunc_ptr_cast(&CCSBotManager::GetBombDefuser) },
- //{ 0x0, "_ZNK13CCSBotManager15GetBombTimeLeftEv", mfunc_ptr_cast(&CCSBotManager::GetBombTimeLeft) },
+ { 0x01D258B0, "_ZNK13CCSBotManager15GetBombTimeLeftEv", mfunc_ptr_cast(&CCSBotManager::GetBombTimeLeft) },
//{ 0x0, "_ZN13CCSBotManager12GetLooseBombEv", mfunc_ptr_cast(&CCSBotManager::GetLooseBomb) },
//{ 0x0, "_ZNK13CCSBotManager16GetLooseBombAreaEv", mfunc_ptr_cast(&CCSBotManager::GetLooseBombArea) },
{ 0x01D258D0, "_ZN13CCSBotManager12SetLooseBombEP11CBaseEntity", mfunc_ptr_cast(&CCSBotManager::SetLooseBomb) },
- //{ 0x0, "_ZNK13CCSBotManager24GetRadioMessageTimestampE13GameEventTypei", mfunc_ptr_cast(&CCSBotManager::GetRadioMessageTimestamp) },
- //{ 0x0, "_ZNK13CCSBotManager23GetRadioMessageIntervalE13GameEventTypei", mfunc_ptr_cast(&CCSBotManager::GetRadioMessageInterval) },
- //{ 0x0, "_ZN13CCSBotManager24SetRadioMessageTimestampE13GameEventTypei", mfunc_ptr_cast(&CCSBotManager::SetRadioMessageTimestamp) },
+ { 0x01D25A10, "_ZNK13CCSBotManager24GetRadioMessageTimestampE13GameEventTypei", mfunc_ptr_cast(&CCSBotManager::GetRadioMessageTimestamp) },
+ { 0x01D25A40, "_ZNK13CCSBotManager23GetRadioMessageIntervalE13GameEventTypei", mfunc_ptr_cast(&CCSBotManager::GetRadioMessageInterval) },
+ { 0x01D25A70, "_ZN13CCSBotManager24SetRadioMessageTimestampE13GameEventTypei", mfunc_ptr_cast(&CCSBotManager::SetRadioMessageTimestamp) },
//{ 0x01D25AA0, "_ZN13CCSBotManager27ResetRadioMessageTimestampsEv", mfunc_ptr_cast(&CCSBotManager::ResetRadioMessageTimestamps) }, // NOXREF
//{ 0x0, "_ZNK13CCSBotManager25GetLastSeenEnemyTimestampEv", mfunc_ptr_cast(&CCSBotManager::GetLastSeenEnemyTimestamp) },
//{ 0x0, "_ZN13CCSBotManager25SetLastSeenEnemyTimestampEv", mfunc_ptr_cast(&CCSBotManager::SetLastSeenEnemyTimestamp) },
@@ -3735,81 +3738,81 @@ FunctionHook g_FunctionHooks[] =
//{ 0x0, "_ZNK13CCSBotManager23AllowFriendlyFireDamageEv", mfunc_ptr_cast(&CCSBotManager::AllowFriendlyFireDamage) },
{ 0x01D232D0, "_ZN13CCSBotManager15IsWeaponUseableEP15CBasePlayerItem", mfunc_ptr_cast(&CCSBotManager::IsWeaponUseable) },
//{ 0x0, "_ZNK13CCSBotManager16IsDefenseRushingEv", mfunc_ptr_cast(&CCSBotManager::IsDefenseRushing) },
- //{ 0x0, "_ZNK13CCSBotManager11IsOnDefenseEPK11CBasePlayer", mfunc_ptr_cast(&CCSBotManager::IsOnDefense) },
- //{ 0x0, "_ZNK13CCSBotManager11IsOnOffenseEPK11CBasePlayer", mfunc_ptr_cast(&CCSBotManager::IsOnOffense) },
+ //{ 0x01D23410, "_ZNK13CCSBotManager11IsOnDefenseEPK11CBasePlayer", mfunc_ptr_cast(&CCSBotManager::IsOnDefense) }, // NOXREF
+ { 0x01D23460, "_ZNK13CCSBotManager11IsOnOffenseEPK11CBasePlayer", mfunc_ptr_cast(&CCSBotManager::IsOnOffense) },
//{ 0x0, "_ZNK13CCSBotManager11IsRoundOverEv", mfunc_ptr_cast(&CCSBotManager::IsRoundOver) },
//{ 0x0, "_ZNK13CCSBotManager11GetNavPlaceEv", mfunc_ptr_cast(&CCSBotManager::GetNavPlace) },
//{ 0x0, "_ZN13CCSBotManager11SetNavPlaceEj", mfunc_ptr_cast(&CCSBotManager::SetNavPlace) },
//{ 0x01D24D10, "_ZN13CCSBotManager15MonitorBotCVarsEv", mfunc_ptr_cast(&CCSBotManager::MonitorBotCVars) },
- //{ 0x01D24AE0, "_ZN13CCSBotManager16MaintainBotQuotaEv", mfunc_ptr_cast(&CCSBotManager::MaintainBotQuota) },
+ { 0x01D24AE0, "_ZN13CCSBotManager16MaintainBotQuotaEv", mfunc_ptr_cast(&CCSBotManager::MaintainBotQuota) },
//{ 0x0, "_ZN13CCSBotManager16GetRandomBotNameENS_9SkillTypeE", mfunc_ptr_cast(&CCSBotManager::GetRandomBotName) },
//{ 0x01D25270, "_ZN13CCSBotManager6AddBotEPK10BotProfile18BotProfileTeamType", mfunc_ptr_cast(&CCSBotManager::AddBot) },
- //{ 0x01D248B0, "_ZN13CCSBotManager13BotAddCommandE18BotProfileTeamTypeb", mfunc_ptr_cast(&CCSBotManager::BotAddCommand) },
+ { 0x01D248B0, "_ZN13CCSBotManager13BotAddCommandE18BotProfileTeamTypeb", mfunc_ptr_cast(&CCSBotManager::BotAddCommand) },
//{ 0x01D238A0, "_Z16PrintAllEntitiesv", (size_t)&PrintAllEntities }, // NOXREF
//{ 0x01D23020, "_Z12UTIL_DrawBoxP6Extentiiii", (size_t)&UTIL_DrawBox },
//CCSBot
- //{ 0x0, "_ZN6CCSBotC2Ev", mfunc_ptr_cast(&CCSBot::CCSBot) },
+ //{ 0x01D208C0, "_ZN6CCSBotC2Ev", mfunc_ptr_cast(&CCSBot::CCSBot) },
//virtual func
- //{ 0x0, "_ZN6CCSBot10TakeDamageEP9entvars_sS1_fi", mfunc_ptr_cast(&CCSBot::TakeDamage_) },
- //{ 0x01D175A0, "_ZN6CCSBot6KilledEP9entvars_si", mfunc_ptr_cast(&CCSBot::Killed_) },
- //{ 0x0, "_ZN6CCSBot12RoundRespawnEv", mfunc_ptr_cast(&CCSBot::RoundRespawn_) },
- //{ 0x0, "_ZN6CCSBot5BlindEfffi", mfunc_ptr_cast(&CCSBot::Blind_) },
- //{ 0x01D32370, "_ZN6CCSBot16OnTouchingWeaponEP10CWeaponBox", mfunc_ptr_cast(&CCSBot::OnTouchingWeapon_) },
- //{ 0x01D20A60, "_ZN6CCSBot10InitializeEPK10BotProfile", mfunc_ptr_cast(&CCSBot::Initialize_) },
- //{ 0x01D20E40, "_ZN6CCSBot8SpawnBotEv", mfunc_ptr_cast(&CCSBot::SpawnBot_) },
+ { 0x01D173D0, "_ZN6CCSBot10TakeDamageEP9entvars_sS1_fi", mfunc_ptr_cast(&CCSBot::TakeDamage_) },
+ { 0x01D175A0, "_ZN6CCSBot6KilledEP9entvars_si", mfunc_ptr_cast(&CCSBot::Killed_) },
+ { 0x01D20EC0, "_ZN6CCSBot12RoundRespawnEv", mfunc_ptr_cast(&CCSBot::RoundRespawn_) },
+ { 0x01D30A80, "_ZN6CCSBot5BlindEfffi", mfunc_ptr_cast(&CCSBot::Blind_) },
+ { 0x01D32370, "_ZN6CCSBot16OnTouchingWeaponEP10CWeaponBox", mfunc_ptr_cast(&CCSBot::OnTouchingWeapon_) },
+ { 0x01D20A60, "_ZN6CCSBot10InitializeEPK10BotProfile", mfunc_ptr_cast(&CCSBot::Initialize_) },
+ { 0x01D20E40, "_ZN6CCSBot8SpawnBotEv", mfunc_ptr_cast(&CCSBot::SpawnBot_) },
{ 0x01D2D370, "_ZN6CCSBot6UpkeepEv", mfunc_ptr_cast(&CCSBot::Upkeep_) },
//{ 0x01D2D9B0, "_ZN6CCSBot6UpdateEv", mfunc_ptr_cast(&CCSBot::Update_) }, // using refs
- //{ 0x0, "_ZN6CCSBot4WalkEv", mfunc_ptr_cast(&CCSBot::Walk_) },
- //{ 0x0, "_ZN6CCSBot4JumpEb", mfunc_ptr_cast(&CCSBot::Jump_) },
+ { 0x01D17370, "_ZN6CCSBot4WalkEv", mfunc_ptr_cast(&CCSBot::Walk_) },
+ { 0x01D173A0, "_ZN6CCSBot4JumpEb", mfunc_ptr_cast(&CCSBot::Jump_) },
//{ 0x01D1F990, "_ZN6CCSBot7OnEventE13GameEventTypeP11CBaseEntityS2_", mfunc_ptr_cast(&CCSBot::OnEvent_) },
- //{ 0x01D2F490, "_ZNK6CCSBot9IsVisibleEPK6Vectorb", mfunc_ptr_cast(&CCSBot::IsVisible_) },
- //{ 0x01D2F5C0, "_ZNK6CCSBot9IsVisibleEP11CBasePlayerbPh", mfunc_ptr_cast(&CCSBot::IsVisible_) },
+ { 0x01D2F490, "_ZNK6CCSBot9IsVisibleEPK6Vectorb", mfunc_ptr_cast(&CCSBot::IsVisible_) },
+ { 0x01D2F5C0, "_ZNK6CCSBot9IsVisibleEP11CBasePlayerbPh", mfunc_ptr_cast(&CCSBot::IsVisible_) },
{ 0x01D21390, "_ZNK6CCSBot18IsEnemyPartVisibleEN4CBot15VisiblePartTypeE", mfunc_ptr_cast(&CCSBot::IsEnemyPartVisible_) },
//non-virtual func
{ 0x01D20EE0, "_ZN6CCSBot10DisconnectEv", mfunc_ptr_cast(&CCSBot::Disconnect) },
//{ 0x0, "_ZNK6CCSBot14GetCombatRangeEv", mfunc_ptr_cast(&CCSBot::GetCombatRange) },
{ 0x01D184D0, "_ZNK6CCSBot7IsRogueEv", mfunc_ptr_cast(&CCSBot::IsRogue) },
//{ 0x0, "_ZN6CCSBot8SetRogueEb", mfunc_ptr_cast(&CCSBot::SetRogue) },
- //{ 0x0, "_ZNK6CCSBot10IsHurryingEv", mfunc_ptr_cast(&CCSBot::IsHurrying) },
+ { 0x01D185C0, "_ZNK6CCSBot10IsHurryingEv", mfunc_ptr_cast(&CCSBot::IsHurrying) },
//{ 0x0, "_ZN6CCSBot5HurryEf", mfunc_ptr_cast(&CCSBot::Hurry) },
- //{ 0x01D18620, "_ZNK6CCSBot6IsSafeEv", mfunc_ptr_cast(&CCSBot::IsSafe) },
- //{ 0x01D18650, "_ZNK6CCSBot14IsWellPastSafeEv", mfunc_ptr_cast(&CCSBot::IsWellPastSafe) },
- //{ 0x0, "_ZNK6CCSBot15IsEndOfSafeTimeEv", mfunc_ptr_cast(&CCSBot::IsEndOfSafeTime) },
- //{ 0x0, "_ZNK6CCSBot20GetSafeTimeRemainingEv", mfunc_ptr_cast(&CCSBot::GetSafeTimeRemaining) },
+ { 0x01D18620, "_ZNK6CCSBot6IsSafeEv", mfunc_ptr_cast(&CCSBot::IsSafe) },
+ { 0x01D18650, "_ZNK6CCSBot14IsWellPastSafeEv", mfunc_ptr_cast(&CCSBot::IsWellPastSafe) },
+ { 0x01D18680, "_ZNK6CCSBot15IsEndOfSafeTimeEv", mfunc_ptr_cast(&CCSBot::IsEndOfSafeTime) },
+ { 0x01D186C0, "_ZNK6CCSBot20GetSafeTimeRemainingEv", mfunc_ptr_cast(&CCSBot::GetSafeTimeRemaining) },
//{ 0x0, "_ZNK6CCSBot11GetSafeTimeEv", mfunc_ptr_cast(&CCSBot::GetSafeTime) },
- //{ 0x0, "_ZNK6CCSBot11IsUnhealthyEv", mfunc_ptr_cast(&CCSBot::IsUnhealthy) },
+ //{ 0x0, "_ZNK6CCSBot11IsUnhealthyEv", mfunc_ptr_cast(&CCSBot::IsUnhealthy) }, // NOXREF
{ 0x01D2BE50, "_ZN6CCSBot4IdleEv", mfunc_ptr_cast(&CCSBot::Idle) },
- //{ 0x01D2C360, "_ZN6CCSBot4HideEP8CNavAreaffb", mfunc_ptr_cast(&CCSBot::Hide) },
- //{ 0x0, "_ZN6CCSBot4HideEPK6Vectorfb", mfunc_ptr_cast(&CCSBot::Hide) },
- //{ 0x0, "_ZN6CCSBot9TryToHideEP8CNavAreaffbb", mfunc_ptr_cast(&CCSBot::TryToHide) },
- //{ 0x0, "_ZN6CCSBot12TryToRetreatEv", mfunc_ptr_cast(&CCSBot::TryToRetreat) },
+ { 0x01D2C360, "_ZN6CCSBot4HideEP8CNavAreaffb", mfunc_ptr_cast(&CCSBot::Hide) },
+ { 0x01D2C620, "_ZN6CCSBot4HideEPK6Vectorfb", mfunc_ptr_cast(&CCSBot::Hide) },
+ { 0x01D2C830, "_ZN6CCSBot9TryToHideEP8CNavAreaffbb", mfunc_ptr_cast(&CCSBot::TryToHide) },
+ { 0x01D2CA10, "_ZN6CCSBot12TryToRetreatEv", mfunc_ptr_cast(&CCSBot::TryToRetreat) },
{ 0x01D2CEA0, "_ZNK6CCSBot8IsHidingEv", mfunc_ptr_cast(&CCSBot::IsHiding) },
//{ 0x01D2CEC0, "_ZNK6CCSBot14IsAtHidingSpotEv", mfunc_ptr_cast(&CCSBot::IsAtHidingSpot) },
- //{ 0x0, "_ZN6CCSBot4HuntEv", mfunc_ptr_cast(&CCSBot::Hunt) },
- //{ 0x0, "_ZNK6CCSBot9IsHuntingEv", mfunc_ptr_cast(&CCSBot::IsHunting) },
- //{ 0x01D2CB60, "_ZN6CCSBot6AttackEP11CBasePlayer", mfunc_ptr_cast(&CCSBot::Attack) },
- //{ 0x0, "_ZN6CCSBot17FireWeaponAtEnemyEv", mfunc_ptr_cast(&CCSBot::FireWeaponAtEnemy) },
+ { 0x01D2CA90, "_ZN6CCSBot4HuntEv", mfunc_ptr_cast(&CCSBot::Hunt) },
+ { 0x01D2CEE0, "_ZNK6CCSBot9IsHuntingEv", mfunc_ptr_cast(&CCSBot::IsHunting) },
+ { 0x01D2CB60, "_ZN6CCSBot6AttackEP11CBasePlayer", mfunc_ptr_cast(&CCSBot::Attack) },
+ //{ 0x01D30B70, "_ZN6CCSBot17FireWeaponAtEnemyEv", mfunc_ptr_cast(&CCSBot::FireWeaponAtEnemy) },
{ 0x01D2CD80, "_ZN6CCSBot13StopAttackingEv", mfunc_ptr_cast(&CCSBot::StopAttacking) },
{ 0x01D2CE50, "_ZNK6CCSBot11IsAttackingEv", mfunc_ptr_cast(&CCSBot::IsAttacking) },
- //{ 0x01D2CF40, "_ZN6CCSBot6MoveToEPK6Vector9RouteType", mfunc_ptr_cast(&CCSBot::MoveTo) },
- //{ 0x0, "_ZNK6CCSBot10IsMovingToEv", mfunc_ptr_cast(&CCSBot::IsMovingTo) },
- //{ 0x0, "_ZN6CCSBot9PlantBombEv", mfunc_ptr_cast(&CCSBot::PlantBomb) },
- //{ 0x0, "_ZN6CCSBot9FetchBombEv", mfunc_ptr_cast(&CCSBot::FetchBomb) },
- //{ 0x0, "_ZNK6CCSBot15NoticeLooseBombEv", mfunc_ptr_cast(&CCSBot::NoticeLooseBomb) },
- //{ 0x0, "_ZNK6CCSBot15CanSeeLooseBombEv", mfunc_ptr_cast(&CCSBot::CanSeeLooseBomb) },
+ { 0x01D2CF40, "_ZN6CCSBot6MoveToEPK6Vector9RouteType", mfunc_ptr_cast(&CCSBot::MoveTo) },
+ //{ 0x01D2CF00, "_ZNK6CCSBot10IsMovingToEv", mfunc_ptr_cast(&CCSBot::IsMovingTo) }, // NOXREF
+ { 0x01D2D030, "_ZN6CCSBot9PlantBombEv", mfunc_ptr_cast(&CCSBot::PlantBomb) },
+ { 0x01D2D100, "_ZN6CCSBot9FetchBombEv", mfunc_ptr_cast(&CCSBot::FetchBomb) },
+ { 0x01D17EA0, "_ZNK6CCSBot15NoticeLooseBombEv", mfunc_ptr_cast(&CCSBot::NoticeLooseBomb) },
+ { 0x01D17EC0, "_ZNK6CCSBot15CanSeeLooseBombEv", mfunc_ptr_cast(&CCSBot::CanSeeLooseBomb) },
//{ 0x0, "_ZNK6CCSBot14IsCarryingBombEv", mfunc_ptr_cast(&CCSBot::IsCarryingBomb) },
- //{ 0x0, "_ZN6CCSBot10DefuseBombEv", mfunc_ptr_cast(&CCSBot::DefuseBomb) },
+ { 0x01D2D1D0, "_ZN6CCSBot10DefuseBombEv", mfunc_ptr_cast(&CCSBot::DefuseBomb) },
{ 0x01D2CE80, "_ZNK6CCSBot14IsDefusingBombEv", mfunc_ptr_cast(&CCSBot::IsDefusingBomb) },
- //{ 0x0, "_ZNK6CCSBot17CanSeePlantedBombEv", mfunc_ptr_cast(&CCSBot::CanSeePlantedBomb) },
- //{ 0x0, "_ZN6CCSBot14EscapeFromBombEv", mfunc_ptr_cast(&CCSBot::EscapeFromBomb) },
- //{ 0x0, "_ZNK6CCSBot18IsEscapingFromBombEv", mfunc_ptr_cast(&CCSBot::IsEscapingFromBomb) },
- //{ 0x0, "_ZN6CCSBot14RescueHostagesEv", mfunc_ptr_cast(&CCSBot::RescueHostages) },
- //{ 0x0, "_ZN6CCSBot9UseEntityEP11CBaseEntity", mfunc_ptr_cast(&CCSBot::UseEntity) },
+ { 0x01D17F00, "_ZNK6CCSBot17CanSeePlantedBombEv", mfunc_ptr_cast(&CCSBot::CanSeePlantedBomb) },
+ { 0x01D2BF10, "_ZN6CCSBot14EscapeFromBombEv", mfunc_ptr_cast(&CCSBot::EscapeFromBomb) },
+ { 0x01D2CE60, "_ZNK6CCSBot18IsEscapingFromBombEv", mfunc_ptr_cast(&CCSBot::IsEscapingFromBomb) },
+ //{ 0x01D2C260, "_ZN6CCSBot14RescueHostagesEv", mfunc_ptr_cast(&CCSBot::RescueHostages) }, // NOXREF
+ { 0x01D2C280, "_ZN6CCSBot9UseEntityEP11CBaseEntity", mfunc_ptr_cast(&CCSBot::UseEntity) },
{ 0x01D2CF20, "_ZNK6CCSBot8IsBuyingEv", mfunc_ptr_cast(&CCSBot::IsBuying) },
- //{ 0x0, "_ZN6CCSBot5PanicEP11CBasePlayer", mfunc_ptr_cast(&CCSBot::Panic) },
- //{ 0x0, "_ZN6CCSBot6FollowEP11CBasePlayer", mfunc_ptr_cast(&CCSBot::Follow) },
- //{ 0x0, "_ZN6CCSBot17ContinueFollowingEv", mfunc_ptr_cast(&CCSBot::ContinueFollowing) },
- //{ 0x0, "_ZN6CCSBot13StopFollowingEv", mfunc_ptr_cast(&CCSBot::StopFollowing) },
+ { 0x01D17B80, "_ZN6CCSBot5PanicEP11CBasePlayer", mfunc_ptr_cast(&CCSBot::Panic) },
+ { 0x01D2BFF0, "_ZN6CCSBot6FollowEP11CBasePlayer", mfunc_ptr_cast(&CCSBot::Follow) },
+ { 0x01D2C130, "_ZN6CCSBot17ContinueFollowingEv", mfunc_ptr_cast(&CCSBot::ContinueFollowing) },
+ { 0x01D2C230, "_ZN6CCSBot13StopFollowingEv", mfunc_ptr_cast(&CCSBot::StopFollowing) },
//{ 0x0, "_ZNK6CCSBot11IsFollowingEv", mfunc_ptr_cast(&CCSBot::IsFollowing) },
//{ 0x0, "_ZN6CCSBot15GetFollowLeaderEv", mfunc_ptr_cast(&CCSBot::GetFollowLeader) },
//{ 0x0, "_ZNK6CCSBot17GetFollowDurationEv", mfunc_ptr_cast(&CCSBot::GetFollowDuration) },
@@ -3822,35 +3825,35 @@ FunctionHook g_FunctionHooks[] =
//{ 0x0, "_ZNK6CCSBot16GetSurpriseDelayEv", mfunc_ptr_cast(&CCSBot::GetSurpriseDelay) },
//{ 0x0, "_ZN6CCSBot18ClearSurpriseDelayEv", mfunc_ptr_cast(&CCSBot::ClearSurpriseDelay) },
//{ 0x0, "_ZNK6CCSBot17GetStateTimestampEv", mfunc_ptr_cast(&CCSBot::GetStateTimestamp) },
- //{ 0x0, "_ZNK6CCSBot15IsDoingScenarioEv", mfunc_ptr_cast(&CCSBot::IsDoingScenario) },
+ { 0x01D17E70, "_ZNK6CCSBot15IsDoingScenarioEv", mfunc_ptr_cast(&CCSBot::IsDoingScenario) },
//{ 0x0, "_ZNK6CCSBot12GetGameStateEv", mfunc_ptr_cast(&CCSBot::GetGameState) },
//{ 0x0, "_ZN6CCSBot12GetGameStateEv", mfunc_ptr_cast(&CCSBot::GetGameState) },
//{ 0x0, "_ZN6CCSBot12IsAtBombsiteEv", mfunc_ptr_cast(&CCSBot::IsAtBombsite) },
- //{ 0x01D18740, "_ZN6CCSBot15GuardRandomZoneEf", mfunc_ptr_cast(&CCSBot::GuardRandomZone) },
+ { 0x01D18740, "_ZN6CCSBot15GuardRandomZoneEf", mfunc_ptr_cast(&CCSBot::GuardRandomZone) },
{ 0x01D17900, "_ZNK6CCSBot6IsBusyEv", mfunc_ptr_cast(&CCSBot::IsBusy) },
//{ 0x0, "_ZN6CCSBot7SetTaskENS_8TaskTypeEP11CBaseEntity", mfunc_ptr_cast(&CCSBot::SetTask) },
//{ 0x0, "_ZNK6CCSBot7GetTaskEv", mfunc_ptr_cast(&CCSBot::GetTask) },
//{ 0x0, "_ZN6CCSBot13GetTaskEntityEv", mfunc_ptr_cast(&CCSBot::GetTaskEntity) },
- //{ 0x0, "_ZN6CCSBot14SetDispositionENS_15DispositionTypeE", mfunc_ptr_cast(&CCSBot::SetDisposition) },
+ { 0x01D18420, "_ZN6CCSBot14SetDispositionENS_15DispositionTypeE", mfunc_ptr_cast(&CCSBot::SetDisposition) },
{ 0x01D18440, "_ZNK6CCSBot14GetDispositionEv", mfunc_ptr_cast(&CCSBot::GetDisposition) },
- //{ 0x0, "_ZN6CCSBot13IgnoreEnemiesEf", mfunc_ptr_cast(&CCSBot::IgnoreEnemies) },
+ { 0x01D18470, "_ZN6CCSBot13IgnoreEnemiesEf", mfunc_ptr_cast(&CCSBot::IgnoreEnemies) },
//{ 0x0, "_ZNK6CCSBot9GetMoraleEv", mfunc_ptr_cast(&CCSBot::GetMorale) },
- //{ 0x0, "_ZN6CCSBot14IncreaseMoraleEv", mfunc_ptr_cast(&CCSBot::IncreaseMorale) },
+ { 0x01D18490, "_ZN6CCSBot14IncreaseMoraleEv", mfunc_ptr_cast(&CCSBot::IncreaseMorale) },
{ 0x01D184B0, "_ZN6CCSBot14DecreaseMoraleEv", mfunc_ptr_cast(&CCSBot::DecreaseMorale) },
//{ 0x0, "_ZNK6CCSBot12IsNoiseHeardEv", mfunc_ptr_cast(&CCSBot::IsNoiseHeard) },
- //{ 0x0, "_ZN6CCSBot22ShouldInvestigateNoiseEPf", mfunc_ptr_cast(&CCSBot::ShouldInvestigateNoise) },
- //{ 0x0, "_ZN6CCSBot16InvestigateNoiseEv", mfunc_ptr_cast(&CCSBot::InvestigateNoise) },
- //{ 0x0, "_ZNK6CCSBot16GetNoisePositionEv", mfunc_ptr_cast(&CCSBot::GetNoisePosition) },
+ { 0x01D22510, "_ZN6CCSBot22ShouldInvestigateNoiseEPf", mfunc_ptr_cast(&CCSBot::ShouldInvestigateNoise) },
+ { 0x01D2D2A0, "_ZN6CCSBot16InvestigateNoiseEv", mfunc_ptr_cast(&CCSBot::InvestigateNoise) },
+ //{ 0x0, "_ZNK6CCSBot16GetNoisePositionEv", mfunc_ptr_cast(&CCSBot::GetNoisePosition) }, // NOXREF
//{ 0x0, "_ZNK6CCSBot12GetNoiseAreaEv", mfunc_ptr_cast(&CCSBot::GetNoiseArea) },
//{ 0x0, "_ZN6CCSBot11ForgetNoiseEv", mfunc_ptr_cast(&CCSBot::ForgetNoise) },
- //{ 0x0, "_ZNK6CCSBot19CanSeeNoisePositionEv", mfunc_ptr_cast(&CCSBot::CanSeeNoisePosition) },
- //{ 0x0, "_ZNK6CCSBot13GetNoiseRangeEv", mfunc_ptr_cast(&CCSBot::GetNoiseRange) },
- //{ 0x01D227C0, "_ZNK6CCSBot25CanHearNearbyEnemyGunfireEf", mfunc_ptr_cast(&CCSBot::CanHearNearbyEnemyGunfire) },
+ //{ 0x01D229C0, "_ZNK6CCSBot19CanSeeNoisePositionEv", mfunc_ptr_cast(&CCSBot::CanSeeNoisePosition) }, // NOXREF
+ //{ 0x0, "_ZNK6CCSBot13GetNoiseRangeEv", mfunc_ptr_cast(&CCSBot::GetNoiseRange) }, // NOXREF
+ { 0x01D227C0, "_ZNK6CCSBot25CanHearNearbyEnemyGunfireEf", mfunc_ptr_cast(&CCSBot::CanHearNearbyEnemyGunfire) },
//{ 0x0, "_ZNK6CCSBot16GetNoisePriorityEv", mfunc_ptr_cast(&CCSBot::GetNoisePriority) },
- //{ 0x0, "_ZN6CCSBot16SendRadioMessageE13GameEventType", mfunc_ptr_cast(&CCSBot::SendRadioMessage) },
+ { 0x01D2BC80, "_ZN6CCSBot16SendRadioMessageE13GameEventType", mfunc_ptr_cast(&CCSBot::SendRadioMessage) },
//{ 0x0, "_ZN6CCSBot10GetChatterEv", mfunc_ptr_cast(&CCSBot::GetChatter) },
- //{ 0x0, "_ZN6CCSBot20RespondToHelpRequestEP11CBasePlayerjf", mfunc_ptr_cast(&CCSBot::RespondToHelpRequest) },
- //{ 0x0, "_ZN6CCSBot18StartVoiceFeedbackEf", mfunc_ptr_cast(&CCSBot::StartVoiceFeedback) },
+ { 0x01D2BA70, "_ZN6CCSBot20RespondToHelpRequestEP11CBasePlayerjf", mfunc_ptr_cast(&CCSBot::RespondToHelpRequest) },
+ { 0x01D2B970, "_ZN6CCSBot18StartVoiceFeedbackEf", mfunc_ptr_cast(&CCSBot::StartVoiceFeedback) },
//{ 0x0, "_ZNK6CCSBot12IsUsingVoiceEv", mfunc_ptr_cast(&CCSBot::IsUsingVoice) },
{ 0x01D179D0, "_ZN6CCSBot8SetEnemyEP11CBasePlayer", mfunc_ptr_cast(&CCSBot::SetEnemy) },
//{ 0x0, "_ZN6CCSBot8GetEnemyEv", mfunc_ptr_cast(&CCSBot::GetEnemy) },
@@ -3861,56 +3864,56 @@ FunctionHook g_FunctionHooks[] =
//{ 0x0, "_ZNK6CCSBot20GetNearbyFriendCountEv", mfunc_ptr_cast(&CCSBot::GetNearbyFriendCount) },
//{ 0x0, "_ZNK6CCSBot23GetClosestVisibleFriendEv", mfunc_ptr_cast(&CCSBot::GetClosestVisibleFriend) },
//{ 0x0, "_ZNK6CCSBot28GetClosestVisibleHumanFriendEv", mfunc_ptr_cast(&CCSBot::GetClosestVisibleHumanFriend) },
- //{ 0x01D181A0, "_ZNK6CCSBot13IsOutnumberedEv", mfunc_ptr_cast(&CCSBot::IsOutnumbered) },
- //{ 0x0, "_ZNK6CCSBot16OutnumberedCountEv", mfunc_ptr_cast(&CCSBot::OutnumberedCount) },
- //{ 0x0, "_ZNK6CCSBot17GetImportantEnemyEb", mfunc_ptr_cast(&CCSBot::GetImportantEnemy) },
- //{ 0x01D30830, "_ZN6CCSBot19UpdateReactionQueueEv", mfunc_ptr_cast(&CCSBot::UpdateReactionQueue) },
+ { 0x01D181A0, "_ZNK6CCSBot13IsOutnumberedEv", mfunc_ptr_cast(&CCSBot::IsOutnumbered) },
+ { 0x01D181F0, "_ZNK6CCSBot16OutnumberedCountEv", mfunc_ptr_cast(&CCSBot::OutnumberedCount) },
+ { 0x01D18290, "_ZNK6CCSBot17GetImportantEnemyEb", mfunc_ptr_cast(&CCSBot::GetImportantEnemy) },
+ { 0x01D30830, "_ZN6CCSBot19UpdateReactionQueueEv", mfunc_ptr_cast(&CCSBot::UpdateReactionQueue) },
{ 0x01D30980, "_ZN6CCSBot18GetRecognizedEnemyEv", mfunc_ptr_cast(&CCSBot::GetRecognizedEnemy) },
- //{ 0x0, "_ZN6CCSBot26IsRecognizedEnemyReloadingEv", mfunc_ptr_cast(&CCSBot::IsRecognizedEnemyReloading) },
- //{ 0x0, "_ZN6CCSBot34IsRecognizedEnemyProtectedByShieldEv", mfunc_ptr_cast(&CCSBot::IsRecognizedEnemyProtectedByShield) },
- //{ 0x0, "_ZN6CCSBot32GetRangeToNearestRecognizedEnemyEv", mfunc_ptr_cast(&CCSBot::GetRangeToNearestRecognizedEnemy) },
- //{ 0x0, "_ZNK6CCSBot11GetAttackerEv", mfunc_ptr_cast(&CCSBot::GetAttacker) },
+ { 0x01D309B0, "_ZN6CCSBot26IsRecognizedEnemyReloadingEv", mfunc_ptr_cast(&CCSBot::IsRecognizedEnemyReloading) },
+ { 0x01D309E0, "_ZN6CCSBot34IsRecognizedEnemyProtectedByShieldEv", mfunc_ptr_cast(&CCSBot::IsRecognizedEnemyProtectedByShield) },
+ //{ 0x01D30A10, "_ZN6CCSBot32GetRangeToNearestRecognizedEnemyEv", mfunc_ptr_cast(&CCSBot::GetRangeToNearestRecognizedEnemy) }, // NOXREF
+ { 0x01D17F40, "_ZNK6CCSBot11GetAttackerEv", mfunc_ptr_cast(&CCSBot::GetAttacker) },
//{ 0x0, "_ZNK6CCSBot20GetTimeSinceAttackedEv", mfunc_ptr_cast(&CCSBot::GetTimeSinceAttacked) },
- //{ 0x0, "_ZNK6CCSBot25GetFirstSawEnemyTimestampEv", mfunc_ptr_cast(&CCSBot::GetFirstSawEnemyTimestamp) },
+ //{ 0x0, "_ZNK6CCSBot25GetFirstSawEnemyTimestampEv", mfunc_ptr_cast(&CCSBot::GetFirstSawEnemyTimestamp) }, // NOXREF
//{ 0x0, "_ZNK6CCSBot24GetLastSawEnemyTimestampEv", mfunc_ptr_cast(&CCSBot::GetLastSawEnemyTimestamp) },
//{ 0x0, "_ZNK6CCSBot24GetTimeSinceLastSawEnemyEv", mfunc_ptr_cast(&CCSBot::GetTimeSinceLastSawEnemy) },
//{ 0x0, "_ZNK6CCSBot32GetTimeSinceAcquiredCurrentEnemyEv", mfunc_ptr_cast(&CCSBot::GetTimeSinceAcquiredCurrentEnemy) },
- //{ 0x0, "_ZNK6CCSBot26HasNotSeenEnemyForLongTimeEv", mfunc_ptr_cast(&CCSBot::HasNotSeenEnemyForLongTime) },
+ { 0x01D18710, "_ZNK6CCSBot26HasNotSeenEnemyForLongTimeEv", mfunc_ptr_cast(&CCSBot::HasNotSeenEnemyForLongTime) },
//{ 0x0, "_ZNK6CCSBot25GetLastKnownEnemyPositionEv", mfunc_ptr_cast(&CCSBot::GetLastKnownEnemyPosition) },
//{ 0x0, "_ZNK6CCSBot14IsEnemyVisibleEv", mfunc_ptr_cast(&CCSBot::IsEnemyVisible) },
//{ 0x0, "_ZNK6CCSBot22GetEnemyDeathTimestampEv", mfunc_ptr_cast(&CCSBot::GetEnemyDeathTimestamp) },
- //{ 0x01D32440, "_ZN6CCSBot20IsFriendInLineOfFireEv", mfunc_ptr_cast(&CCSBot::IsFriendInLineOfFire) },
+ { 0x01D32440, "_ZN6CCSBot20IsFriendInLineOfFireEv", mfunc_ptr_cast(&CCSBot::IsFriendInLineOfFire) },
//{ 0x0, "_ZNK6CCSBot19IsAwareOfEnemyDeathEv", mfunc_ptr_cast(&CCSBot::IsAwareOfEnemyDeath) },
//{ 0x0, "_ZNK6CCSBot15GetLastVictimIDEv", mfunc_ptr_cast(&CCSBot::GetLastVictimID) },
//{ 0x0, "_ZNK6CCSBot7HasPathEv", mfunc_ptr_cast(&CCSBot::HasPath) },
//{ 0x0, "_ZN6CCSBot11DestroyPathEv", mfunc_ptr_cast(&CCSBot::DestroyPath) },
//{ 0x0, "_ZNK6CCSBot8GetFeetZEv", mfunc_ptr_cast(&CCSBot::GetFeetZ) },
- //{ 0x0, "_ZN6CCSBot18UpdatePathMovementEb", mfunc_ptr_cast(&CCSBot::UpdatePathMovement) },
+ { 0x01D29C80, "_ZN6CCSBot18UpdatePathMovementEb", mfunc_ptr_cast(&CCSBot::UpdatePathMovement) },
//{ 0x0, "_ZN6CCSBot11AStarSearchEP8CNavAreaS1_", mfunc_ptr_cast(&CCSBot::AStarSearch) }, // NOXREF
- //{ 0x0, "_ZN6CCSBot11ComputePathEP8CNavAreaPK6Vector9RouteType", mfunc_ptr_cast(&CCSBot::ComputePath) },
- //{ 0x0, "_ZN6CCSBot13StayOnNavMeshEv", mfunc_ptr_cast(&CCSBot::StayOnNavMesh) },
+ { 0x01D2A7D0, "_ZN6CCSBot11ComputePathEP8CNavAreaPK6Vector9RouteType", mfunc_ptr_cast(&CCSBot::ComputePath) },
+ { 0x01D17A10, "_ZN6CCSBot13StayOnNavMeshEv", mfunc_ptr_cast(&CCSBot::StayOnNavMesh) },
//{ 0x0, "_ZNK6CCSBot16GetLastKnownAreaEv", mfunc_ptr_cast(&CCSBot::GetLastKnownArea) },
//{ 0x0, "_ZNK6CCSBot15GetPathEndpointEv", mfunc_ptr_cast(&CCSBot::GetPathEndpoint) },
- //{ 0x0, "_ZNK6CCSBot24GetPathDistanceRemainingEv", mfunc_ptr_cast(&CCSBot::GetPathDistanceRemaining) },
- //{ 0x0, "_ZN6CCSBot17ResetStuckMonitorEv", mfunc_ptr_cast(&CCSBot::ResetStuckMonitor) },
+ { 0x01D2ADE0, "_ZNK6CCSBot24GetPathDistanceRemainingEv", mfunc_ptr_cast(&CCSBot::GetPathDistanceRemaining) },
+ { 0x01D25BC0, "_ZN6CCSBot17ResetStuckMonitorEv", mfunc_ptr_cast(&CCSBot::ResetStuckMonitor) },
//{ 0x0, "_ZNK6CCSBot13IsAreaVisibleEPK8CNavArea", mfunc_ptr_cast(&CCSBot::IsAreaVisible) }, // NOXREF
//{ 0x0, "_ZNK6CCSBot15GetPathPositionEi", mfunc_ptr_cast(&CCSBot::GetPathPosition) }, // NOXREF
- //{ 0x0, "_ZN6CCSBot30GetSimpleGroundHeightWithFloorEPK6VectorPfPS0_", mfunc_ptr_cast(&CCSBot::GetSimpleGroundHeightWithFloor) },
- //{ 0x01D26060, "_ZNK6CCSBot8GetPlaceEv", mfunc_ptr_cast(&CCSBot::GetPlace) },
+ { 0x01D25FE0, "_ZN6CCSBot30GetSimpleGroundHeightWithFloorEPK6VectorPfPS0_", mfunc_ptr_cast(&CCSBot::GetSimpleGroundHeightWithFloor) },
+ { 0x01D26060, "_ZNK6CCSBot8GetPlaceEv", mfunc_ptr_cast(&CCSBot::GetPlace) },
//{ 0x0, "_ZNK6CCSBot13IsUsingLadderEv", mfunc_ptr_cast(&CCSBot::IsUsingLadder) },
- //{ 0x0, "_ZN6CCSBot12GetOffLadderEv", mfunc_ptr_cast(&CCSBot::GetOffLadder) },
+ { 0x01D17F70, "_ZN6CCSBot12GetOffLadderEv", mfunc_ptr_cast(&CCSBot::GetOffLadder) },
//{ 0x0, "_ZN6CCSBot13SetGoalEntityEP11CBaseEntity", mfunc_ptr_cast(&CCSBot::SetGoalEntity) },
//{ 0x0, "_ZN6CCSBot13GetGoalEntityEv", mfunc_ptr_cast(&CCSBot::GetGoalEntity) },
- //{ 0x0, "_ZNK6CCSBot10IsNearJumpEv", mfunc_ptr_cast(&CCSBot::IsNearJump) },
- //{ 0x0, "_ZNK6CCSBot24GetApproximateFallDamageEf", mfunc_ptr_cast(&CCSBot::GetApproximateFallDamage) },
+ { 0x01D291D0, "_ZNK6CCSBot10IsNearJumpEv", mfunc_ptr_cast(&CCSBot::IsNearJump) },
+ { 0x01D29230, "_ZNK6CCSBot24GetApproximateFallDamageEf", mfunc_ptr_cast(&CCSBot::GetApproximateFallDamage) },
//{ 0x0, "_ZN6CCSBot8ForceRunEf", mfunc_ptr_cast(&CCSBot::ForceRun) },
- //{ 0x0, "_ZN6CCSBot6WiggleEv", mfunc_ptr_cast(&CCSBot::Wiggle) },
- //{ 0x0, "_ZNK6CCSBot16IsFriendInTheWayEPK6Vector", mfunc_ptr_cast(&CCSBot::IsFriendInTheWay) },
- //{ 0x0, "_ZN6CCSBot22FeelerReflexAdjustmentEP6Vector", mfunc_ptr_cast(&CCSBot::FeelerReflexAdjustment) },
+ { 0x01D26720, "_ZN6CCSBot6WiggleEv", mfunc_ptr_cast(&CCSBot::Wiggle) },
+ { 0x01D29260, "_ZNK6CCSBot16IsFriendInTheWayEPK6Vector", mfunc_ptr_cast(&CCSBot::IsFriendInTheWay) },
+ { 0x01D29500, "_ZN6CCSBot22FeelerReflexAdjustmentEP6Vector", mfunc_ptr_cast(&CCSBot::FeelerReflexAdjustment) },
//{ 0x0, "_ZN6CCSBot13SetLookAnglesEff", mfunc_ptr_cast(&CCSBot::SetLookAngles) },
//2@@{ 0x01D2EDD0, "_ZN6CCSBot16UpdateLookAnglesEv", mfunc_ptr_cast(&CCSBot::UpdateLookAngles) }, // Using REFS
- //{ 0x01D2F9C0, "_ZN6CCSBot16UpdateLookAroundEb", mfunc_ptr_cast(&CCSBot::UpdateLookAround) },
- //{ 0x0, "_ZN6CCSBot17InhibitLookAroundEf", mfunc_ptr_cast(&CCSBot::InhibitLookAround) },
+ { 0x01D2F9C0, "_ZN6CCSBot16UpdateLookAroundEb", mfunc_ptr_cast(&CCSBot::UpdateLookAround) },
+ { 0x01D2F910, "_ZN6CCSBot17InhibitLookAroundEf", mfunc_ptr_cast(&CCSBot::InhibitLookAround) },
//{ 0x0, "_ZN6CCSBot15SetForwardAngleEf", mfunc_ptr_cast(&CCSBot::SetForwardAngle) }, // NOXREF
//{ 0x0, "_ZN6CCSBot17SetLookAheadAngleEf", mfunc_ptr_cast(&CCSBot::SetLookAheadAngle) }, // NOXREF
{ 0x01D2F7F0, "_ZN6CCSBot9SetLookAtEPKcPK6Vector12PriorityTypefbf", mfunc_ptr_cast(&CCSBot::SetLookAt) },
@@ -3918,134 +3921,134 @@ FunctionHook g_FunctionHooks[] =
//{ 0x0, "_ZNK6CCSBot15IsLookingAtSpotE12PriorityType", mfunc_ptr_cast(&CCSBot::IsLookingAtSpot) },
//{ 0x0, "_ZNK6CCSBot12IsViewMovingEf", mfunc_ptr_cast(&CCSBot::IsViewMoving) },
//{ 0x0, "_ZNK6CCSBot14GetEyePositionEv", mfunc_ptr_cast(&CCSBot::GetEyePosition) },
- //{ 0x01D32560, "_ZN6CCSBot23ComputeWeaponSightRangeEv", mfunc_ptr_cast(&CCSBot::ComputeWeaponSightRange) },
- //{ 0x01D26890, "_ZN6CCSBot21ComputeApproachPointsEv", mfunc_ptr_cast(&CCSBot::ComputeApproachPoints) },
+ { 0x01D32560, "_ZN6CCSBot23ComputeWeaponSightRangeEv", mfunc_ptr_cast(&CCSBot::ComputeWeaponSightRange) },
+ { 0x01D26890, "_ZN6CCSBot21ComputeApproachPointsEv", mfunc_ptr_cast(&CCSBot::ComputeApproachPoints) },
//{ 0x0, "_ZN6CCSBot20UpdateApproachPointsEv", mfunc_ptr_cast(&CCSBot::UpdateApproachPoints) },
//{ 0x0, "_ZN6CCSBot19ClearApproachPointsEv", mfunc_ptr_cast(&CCSBot::ClearApproachPoints) },
- //{ 0x01D269D0, "_ZN6CCSBot18DrawApproachPointsEv", mfunc_ptr_cast(&CCSBot::DrawApproachPoints) },
- //{ 0x01D17FA0, "_ZNK6CCSBot27GetHidingSpotCheckTimestampEP10HidingSpot", mfunc_ptr_cast(&CCSBot::GetHidingSpotCheckTimestamp) },
- //{ 0x01D17FF0, "_ZN6CCSBot27SetHidingSpotCheckTimestampEP10HidingSpot", mfunc_ptr_cast(&CCSBot::SetHidingSpotCheckTimestamp) },
- //{ 0x0, "_ZN6CCSBot15EquipBestWeaponEb", mfunc_ptr_cast(&CCSBot::EquipBestWeapon) },
- //{ 0x0, "_ZN6CCSBot11EquipPistolEv", mfunc_ptr_cast(&CCSBot::EquipPistol) },
- //{ 0x0, "_ZN6CCSBot10EquipKnifeEv", mfunc_ptr_cast(&CCSBot::EquipKnife) },
- //{ 0x0, "_ZN6CCSBot12EquipGrenadeEb", mfunc_ptr_cast(&CCSBot::EquipGrenade) },
+ { 0x01D269D0, "_ZN6CCSBot18DrawApproachPointsEv", mfunc_ptr_cast(&CCSBot::DrawApproachPoints) },
+ { 0x01D17FA0, "_ZNK6CCSBot27GetHidingSpotCheckTimestampEP10HidingSpot", mfunc_ptr_cast(&CCSBot::GetHidingSpotCheckTimestamp) },
+ { 0x01D17FF0, "_ZN6CCSBot27SetHidingSpotCheckTimestampEP10HidingSpot", mfunc_ptr_cast(&CCSBot::SetHidingSpotCheckTimestamp) },
+ { 0x01D315F0, "_ZN6CCSBot15EquipBestWeaponEb", mfunc_ptr_cast(&CCSBot::EquipBestWeapon) },
+ { 0x01D31810, "_ZN6CCSBot11EquipPistolEv", mfunc_ptr_cast(&CCSBot::EquipPistol) },
+ { 0x01D318E0, "_ZN6CCSBot10EquipKnifeEv", mfunc_ptr_cast(&CCSBot::EquipKnife) },
+ { 0x01D31930, "_ZN6CCSBot12EquipGrenadeEb", mfunc_ptr_cast(&CCSBot::EquipGrenade) },
{ 0x01D31A00, "_ZNK6CCSBot12IsUsingKnifeEv", mfunc_ptr_cast(&CCSBot::IsUsingKnife) },
{ 0x01D31A20, "_ZNK6CCSBot13IsUsingPistolEv", mfunc_ptr_cast(&CCSBot::IsUsingPistol) },
{ 0x01D31A60, "_ZNK6CCSBot14IsUsingGrenadeEv", mfunc_ptr_cast(&CCSBot::IsUsingGrenade) },
{ 0x01D313F0, "_ZNK6CCSBot18IsUsingSniperRifleEv", mfunc_ptr_cast(&CCSBot::IsUsingSniperRifle) },
{ 0x01D313A0, "_ZNK6CCSBot10IsUsingAWPEv", mfunc_ptr_cast(&CCSBot::IsUsingAWP) },
- //{ 0x0, "_ZNK6CCSBot8IsSniperEv", mfunc_ptr_cast(&CCSBot::IsSniper) },
+ { 0x01D31440, "_ZNK6CCSBot8IsSniperEv", mfunc_ptr_cast(&CCSBot::IsSniper) },
{ 0x01D314B0, "_ZNK6CCSBot9IsSnipingEv", mfunc_ptr_cast(&CCSBot::IsSniping) },
{ 0x01D314D0, "_ZNK6CCSBot14IsUsingShotgunEv", mfunc_ptr_cast(&CCSBot::IsUsingShotgun) },
{ 0x01D31500, "_ZNK6CCSBot17IsUsingMachinegunEv", mfunc_ptr_cast(&CCSBot::IsUsingMachinegun) },
{ 0x01D31AB0, "_ZN6CCSBot12ThrowGrenadeEPK6Vector", mfunc_ptr_cast(&CCSBot::ThrowGrenade) },
//{ 0x0, "_ZNK6CCSBot17IsThrowingGrenadeEv", mfunc_ptr_cast(&CCSBot::IsThrowingGrenade) },
- //{ 0x0, "_ZNK6CCSBot10HasGrenadeEv", mfunc_ptr_cast(&CCSBot::HasGrenade) },
- //{ 0x0, "_ZNK6CCSBot28DoesActiveWeaponHaveSilencerEv", mfunc_ptr_cast(&CCSBot::DoesActiveWeaponHaveSilencer) },
- //{ 0x0, "_ZNK6CCSBot16IsUsingHEGrenadeEv", mfunc_ptr_cast(&CCSBot::IsUsingHEGrenade) },
+ { 0x01D31920, "_ZNK6CCSBot10HasGrenadeEv", mfunc_ptr_cast(&CCSBot::HasGrenade) },
+ //{ 0x01D313C0, "_ZNK6CCSBot28DoesActiveWeaponHaveSilencerEv", mfunc_ptr_cast(&CCSBot::DoesActiveWeaponHaveSilencer) }, // NOXREF
+ { 0x01D31A90, "_ZNK6CCSBot16IsUsingHEGrenadeEv", mfunc_ptr_cast(&CCSBot::IsUsingHEGrenade) },
//{ 0x0, "_ZN6CCSBot14StartRapidFireEv", mfunc_ptr_cast(&CCSBot::StartRapidFire) },
//{ 0x0, "_ZN6CCSBot13StopRapidFireEv", mfunc_ptr_cast(&CCSBot::StopRapidFire) },
//{ 0x0, "_ZNK6CCSBot13IsRapidFiringEv", mfunc_ptr_cast(&CCSBot::IsRapidFiring) },
//{ 0x0, "_ZNK6CCSBot12GetZoomLevelEv", mfunc_ptr_cast(&CCSBot::GetZoomLevel) },
- //{ 0x01D31280, "_ZN6CCSBot10AdjustZoomEf", mfunc_ptr_cast(&CCSBot::AdjustZoom) },
- //{ 0x0, "_ZNK6CCSBot20IsPrimaryWeaponEmptyEv", mfunc_ptr_cast(&CCSBot::IsPrimaryWeaponEmpty) },
- //{ 0x0, "_ZNK6CCSBot13IsPistolEmptyEv", mfunc_ptr_cast(&CCSBot::IsPistolEmpty) },
- //{ 0x0, "_ZNK6CCSBot21GetHostageEscortCountEv", mfunc_ptr_cast(&CCSBot::GetHostageEscortCount) },
- //{ 0x0, "_ZN6CCSBot26IncreaseHostageEscortCountEv", mfunc_ptr_cast(&CCSBot::IncreaseHostageEscortCount) },
+ { 0x01D31280, "_ZN6CCSBot10AdjustZoomEf", mfunc_ptr_cast(&CCSBot::AdjustZoom) },
+ { 0x01D31520, "_ZNK6CCSBot20IsPrimaryWeaponEmptyEv", mfunc_ptr_cast(&CCSBot::IsPrimaryWeaponEmpty) },
+ //{ 0x01D31550, "_ZNK6CCSBot13IsPistolEmptyEv", mfunc_ptr_cast(&CCSBot::IsPistolEmpty) }, // NOXREF
+ //{ 0x0, "_ZNK6CCSBot21GetHostageEscortCountEv", mfunc_ptr_cast(&CCSBot::GetHostageEscortCount) }, // NOXREF
+ //{ 0x0, "_ZN6CCSBot26IncreaseHostageEscortCountEv", mfunc_ptr_cast(&CCSBot::IncreaseHostageEscortCount) }, // NOXREF
{ 0x01D18B10, "_ZNK6CCSBot33GetRangeToFarthestEscortedHostageEv", mfunc_ptr_cast(&CCSBot::GetRangeToFarthestEscortedHostage) },
//{ 0x0, "_ZN6CCSBot27ResetWaitForHostagePatienceEv", mfunc_ptr_cast(&CCSBot::ResetWaitForHostagePatience) },
- //{ 0x01D20AE0, "_ZN6CCSBot11ResetValuesEv", mfunc_ptr_cast(&CCSBot::ResetValues) },
- //{ 0x01D17950, "_ZN6CCSBot13BotDeathThinkEv", mfunc_ptr_cast(&CCSBot::BotDeathThink) }, // PURE
- //{ 0x0, "_ZN6CCSBot16FindNearbyPlayerEv", mfunc_ptr_cast(&CCSBot::FindNearbyPlayer) },
+ { 0x01D20AE0, "_ZN6CCSBot11ResetValuesEv", mfunc_ptr_cast(&CCSBot::ResetValues) },
+ //{ 0x01D17950, "_ZN6CCSBot13BotDeathThinkEv", mfunc_ptr_cast(&CCSBot::BotDeathThink) }, // PURE
+ //{ 0x01D17960, "_ZN6CCSBot16FindNearbyPlayerEv", mfunc_ptr_cast(&CCSBot::FindNearbyPlayer) }, // NOXREF
{ 0x01D186E0, "_ZN6CCSBot14AdjustSafeTimeEv", mfunc_ptr_cast(&CCSBot::AdjustSafeTime) },
{ 0x01D2BD80, "_ZN6CCSBot8SetStateEP8BotState", mfunc_ptr_cast(&CCSBot::SetState) },
- //{ 0x0, "_ZN6CCSBot19MoveTowardsPositionEPK6Vector", mfunc_ptr_cast(&CCSBot::MoveTowardsPosition) },
- //{ 0x0, "_ZN6CCSBot20MoveAwayFromPositionEPK6Vector", mfunc_ptr_cast(&CCSBot::MoveAwayFromPosition) },
- //{ 0x0, "_ZN6CCSBot22StrafeAwayFromPositionEPK6Vector", mfunc_ptr_cast(&CCSBot::StrafeAwayFromPosition) },
- //{ 0x01D25C50, "_ZN6CCSBot10StuckCheckEv", mfunc_ptr_cast(&CCSBot::StuckCheck) },
- //{ 0x0, "_ZN6CCSBot16BuildTrivialPathEPK6Vector", mfunc_ptr_cast(&CCSBot::BuildTrivialPath) },
- //{ 0x0, "_ZN6CCSBot20ComputePathPositionsEv", mfunc_ptr_cast(&CCSBot::ComputePathPositions) },
- //{ 0x0, "_ZN6CCSBot19SetupLadderMovementEv", mfunc_ptr_cast(&CCSBot::SetupLadderMovement) },
- //{ 0x0, "_ZN6CCSBot12SetPathIndexEi", mfunc_ptr_cast(&CCSBot::SetPathIndex) },
- //{ 0x0, "_ZN6CCSBot8DrawPathEv", mfunc_ptr_cast(&CCSBot::DrawPath) },
- //{ 0x0, "_ZNK6CCSBot21FindOurPositionOnPathEP6Vectorb", mfunc_ptr_cast(&CCSBot::FindOurPositionOnPath) },
- //{ 0x0, "_ZN6CCSBot13FindPathPointEfP6VectorPi", mfunc_ptr_cast(&CCSBot::FindPathPoint) },
- //{ 0x0, "_ZNK6CCSBot22FindClosestPointOnPathEPK6VectoriiPS0_", mfunc_ptr_cast(&CCSBot::FindClosestPointOnPath) },
- //{ 0x0, "_ZNK6CCSBot26IsStraightLinePathWalkableEPK6Vector", mfunc_ptr_cast(&CCSBot::IsStraightLinePathWalkable) },
- //{ 0x0, "_ZN6CCSBot17DiscontinuityJumpEfbb", mfunc_ptr_cast(&CCSBot::DiscontinuityJump) },
- //{ 0x0, "_ZN6CCSBot20UpdateLadderMovementEv", mfunc_ptr_cast(&CCSBot::UpdateLadderMovement) },
- //{ 0x0, "_ZN6CCSBot21ComputeLadderEndpointEb", mfunc_ptr_cast(&CCSBot::ComputeLadderEndpoint) },
- //{ 0x0, "_ZN6CCSBot24UpdateHostageEscortCountEv", mfunc_ptr_cast(&CCSBot::UpdateHostageEscortCount) },
- //{ 0x01D22A70, "_ZN6CCSBot17UpdateLookAtNoiseEv", mfunc_ptr_cast(&CCSBot::UpdateLookAtNoise) },
+ { 0x01D26080, "_ZN6CCSBot19MoveTowardsPositionEPK6Vector", mfunc_ptr_cast(&CCSBot::MoveTowardsPosition) },
+ //{ 0x01D26510, "_ZN6CCSBot20MoveAwayFromPositionEPK6Vector", mfunc_ptr_cast(&CCSBot::MoveAwayFromPosition) }, // NOXREF
+ //{ 0x01D26650, "_ZN6CCSBot22StrafeAwayFromPositionEPK6Vector", mfunc_ptr_cast(&CCSBot::StrafeAwayFromPosition) },
+ { 0x01D25C50, "_ZN6CCSBot10StuckCheckEv", mfunc_ptr_cast(&CCSBot::StuckCheck) },
+ { 0x01D2A6F0, "_ZN6CCSBot16BuildTrivialPathEPK6Vector", mfunc_ptr_cast(&CCSBot::BuildTrivialPath) },
+ { 0x01D26BA0, "_ZN6CCSBot20ComputePathPositionsEv", mfunc_ptr_cast(&CCSBot::ComputePathPositions) },
+ { 0x01D27040, "_ZN6CCSBot19SetupLadderMovementEv", mfunc_ptr_cast(&CCSBot::SetupLadderMovement) },
+ { 0x01D29130, "_ZN6CCSBot12SetPathIndexEi", mfunc_ptr_cast(&CCSBot::SetPathIndex) },
+ { 0x01D2AE70, "_ZN6CCSBot8DrawPathEv", mfunc_ptr_cast(&CCSBot::DrawPath) },
+ { 0x01D282C0, "_ZNK6CCSBot21FindOurPositionOnPathEP6Vectorb", mfunc_ptr_cast(&CCSBot::FindOurPositionOnPath) },
+ { 0x01D28620, "_ZN6CCSBot13FindPathPointEfP6VectorPi", mfunc_ptr_cast(&CCSBot::FindPathPoint) },
+ //{ 0x01D280B0, "_ZNK6CCSBot22FindClosestPointOnPathEPK6VectoriiPS0_", mfunc_ptr_cast(&CCSBot::FindClosestPointOnPath) }, // NOXREF
+ { 0x01D28610, "_ZNK6CCSBot26IsStraightLinePathWalkableEPK6Vector", mfunc_ptr_cast(&CCSBot::IsStraightLinePathWalkable) },
+ { 0x01D25EE0, "_ZN6CCSBot17DiscontinuityJumpEfbb", mfunc_ptr_cast(&CCSBot::DiscontinuityJump) },
+ { 0x01D27560, "_ZN6CCSBot20UpdateLadderMovementEv", mfunc_ptr_cast(&CCSBot::UpdateLadderMovement) },
+ { 0x01D27450, "_ZN6CCSBot21ComputeLadderEndpointEb", mfunc_ptr_cast(&CCSBot::ComputeLadderEndpoint) },
+ { 0x01D180B0, "_ZN6CCSBot24UpdateHostageEscortCountEv", mfunc_ptr_cast(&CCSBot::UpdateHostageEscortCount) },
+ { 0x01D22A70, "_ZN6CCSBot17UpdateLookAtNoiseEv", mfunc_ptr_cast(&CCSBot::UpdateLookAtNoise) },
{ 0x01D2F760, "_ZN6CCSBot12UpdateLookAtEv", mfunc_ptr_cast(&CCSBot::UpdateLookAt) },
- //{ 0x0, "_ZN6CCSBot22UpdatePeripheralVisionEv", mfunc_ptr_cast(&CCSBot::UpdatePeripheralVision) },
- //{ 0x0, "_ZNK6CCSBot15BendLineOfSightEPK6VectorS2_PS0_", mfunc_ptr_cast(&CCSBot::BendLineOfSight) },
- //{ 0x0, "_ZN6CCSBot28FindApproachPointNearestPathEP6Vector", mfunc_ptr_cast(&CCSBot::FindApproachPointNearestPath) },
- //{ 0x0, "_ZN6CCSBot25FindGrenadeTossPathTargetEP6Vector", mfunc_ptr_cast(&CCSBot::FindGrenadeTossPathTarget) },
+ { 0x01D2F930, "_ZN6CCSBot22UpdatePeripheralVisionEv", mfunc_ptr_cast(&CCSBot::UpdatePeripheralVision) },
+ { 0x01D2FF40, "_ZNK6CCSBot15BendLineOfSightEPK6VectorS2_PS0_", mfunc_ptr_cast(&CCSBot::BendLineOfSight) },
+ //{ 0x01D26A50, "_ZN6CCSBot28FindApproachPointNearestPathEP6Vector", mfunc_ptr_cast(&CCSBot::FindApproachPointNearestPath) }, // NOXREF
+ { 0x01D31B30, "_ZN6CCSBot25FindGrenadeTossPathTargetEP6Vector", mfunc_ptr_cast(&CCSBot::FindGrenadeTossPathTarget) },
{ 0x01D31030, "_ZN6CCSBot12SetAimOffsetEf", mfunc_ptr_cast(&CCSBot::SetAimOffset) },
{ 0x01D311E0, "_ZN6CCSBot15UpdateAimOffsetEv", mfunc_ptr_cast(&CCSBot::UpdateAimOffset) },
- //{ 0x0, "_ZN6CCSBot7DoEquipEP17CBasePlayerWeapon", mfunc_ptr_cast(&CCSBot::DoEquip) },
- //{ 0x0, "_ZN6CCSBot11ReloadCheckEv", mfunc_ptr_cast(&CCSBot::ReloadCheck) },
- //{ 0x0, "_ZN6CCSBot13SilencerCheckEv", mfunc_ptr_cast(&CCSBot::SilencerCheck) },
- //{ 0x01D302D0, "_ZN6CCSBot23FindMostDangerousThreatEv", mfunc_ptr_cast(&CCSBot::FindMostDangerousThreat) },
- //{ 0x0, "_ZN6CCSBot22RespondToRadioCommandsEv", mfunc_ptr_cast(&CCSBot::RespondToRadioCommands) },
- //{ 0x0, "_ZNK6CCSBot14IsRadioCommandE13GameEventType", mfunc_ptr_cast(&CCSBot::IsRadioCommand) },
+ { 0x01D31580, "_ZN6CCSBot7DoEquipEP17CBasePlayerWeapon", mfunc_ptr_cast(&CCSBot::DoEquip) },
+ { 0x01D31FC0, "_ZN6CCSBot11ReloadCheckEv", mfunc_ptr_cast(&CCSBot::ReloadCheck) },
+ { 0x01D32290, "_ZN6CCSBot13SilencerCheckEv", mfunc_ptr_cast(&CCSBot::SilencerCheck) },
+ { 0x01D302D0, "_ZN6CCSBot23FindMostDangerousThreatEv", mfunc_ptr_cast(&CCSBot::FindMostDangerousThreat) },
+ { 0x01D2B5B0, "_ZN6CCSBot22RespondToRadioCommandsEv", mfunc_ptr_cast(&CCSBot::RespondToRadioCommands) },
+ //{ 0x01D2B570, "_ZNK6CCSBot14IsRadioCommandE13GameEventType", mfunc_ptr_cast(&CCSBot::IsRadioCommand) }, // NOXREF
{ 0x01D2BA00, "_ZN6CCSBot16EndVoiceFeedbackEb", mfunc_ptr_cast(&CCSBot::EndVoiceFeedback) },
- //{ 0x0, "_ZN6CCSBot7AddNodeEPK6VectorS2_10NavDirTypeP8CNavNode", mfunc_ptr_cast(&CCSBot::AddNode) },
- //{ 0x01D21610, "_ZN6CCSBot17StartLearnProcessEv", mfunc_ptr_cast(&CCSBot::StartLearnProcess) },
- //{ 0x01D21EF0, "_ZN6CCSBot18UpdateLearnProcessEv", mfunc_ptr_cast(&CCSBot::UpdateLearnProcess) },
- //{ 0x0, "_ZN6CCSBot9LearnStepEv", mfunc_ptr_cast(&CCSBot::LearnStep) },
+ { 0x01D213C0, "_ZN6CCSBot7AddNodeEPK6VectorS2_10NavDirTypeP8CNavNode", mfunc_ptr_cast(&CCSBot::AddNode) },
+ { 0x01D21610, "_ZN6CCSBot17StartLearnProcessEv", mfunc_ptr_cast(&CCSBot::StartLearnProcess) },
+ { 0x01D21EF0, "_ZN6CCSBot18UpdateLearnProcessEv", mfunc_ptr_cast(&CCSBot::UpdateLearnProcess) },
+ { 0x01D21770, "_ZN6CCSBot9LearnStepEv", mfunc_ptr_cast(&CCSBot::LearnStep) },
{ 0x01D21FE0, "_ZN6CCSBot24StartAnalyzeAlphaProcessEv", mfunc_ptr_cast(&CCSBot::StartAnalyzeAlphaProcess) },
- //{ 0x01D22080, "_ZN6CCSBot25UpdateAnalyzeAlphaProcessEv", mfunc_ptr_cast(&CCSBot::UpdateAnalyzeAlphaProcess) },
+ { 0x01D22080, "_ZN6CCSBot25UpdateAnalyzeAlphaProcessEv", mfunc_ptr_cast(&CCSBot::UpdateAnalyzeAlphaProcess) },
//{ 0x0, "_ZN6CCSBot16AnalyzeAlphaStepEv", mfunc_ptr_cast(&CCSBot::AnalyzeAlphaStep) },
- //{ 0x0, "_ZN6CCSBot23StartAnalyzeBetaProcessEv", mfunc_ptr_cast(&CCSBot::StartAnalyzeBetaProcess) },
- //{ 0x01D22200, "_ZN6CCSBot24UpdateAnalyzeBetaProcessEv", mfunc_ptr_cast(&CCSBot::UpdateAnalyzeBetaProcess) },
+ //{ 0x01D221D0, "_ZN6CCSBot23StartAnalyzeBetaProcessEv", mfunc_ptr_cast(&CCSBot::StartAnalyzeBetaProcess) }, // NOXREF
+ { 0x01D22200, "_ZN6CCSBot24UpdateAnalyzeBetaProcessEv", mfunc_ptr_cast(&CCSBot::UpdateAnalyzeBetaProcess) },
//{ 0x0, "_ZN6CCSBot15AnalyzeBetaStepEv", mfunc_ptr_cast(&CCSBot::AnalyzeBetaStep) },
- //{ 0x0, "_ZN6CCSBot16StartSaveProcessEv", mfunc_ptr_cast(&CCSBot::StartSaveProcess) },
- //{ 0x01D22340, "_ZN6CCSBot17UpdateSaveProcessEv", mfunc_ptr_cast(&CCSBot::UpdateSaveProcess) },
+ //{ 0x01D22330, "_ZN6CCSBot16StartSaveProcessEv", mfunc_ptr_cast(&CCSBot::StartSaveProcess) }, // NOXREF
+ { 0x01D22340, "_ZN6CCSBot17UpdateSaveProcessEv", mfunc_ptr_cast(&CCSBot::UpdateSaveProcess) },
{ 0x01D22450, "_ZN6CCSBot18StartNormalProcessEv", mfunc_ptr_cast(&CCSBot::StartNormalProcess) },
- //{ 0x0, "_ZN6CCSBot8BotTouchEP11CBaseEntity", mfunc_ptr_cast(&CCSBot::BotTouch) },
+ { 0x01D17620, "_ZN6CCSBot8BotTouchEP11CBaseEntity", mfunc_ptr_cast(&CCSBot::BotTouch) },
//CSGameState
- //{ 0x0, "", mfunc_ptr_cast(&CSGameState::CSGameState) },
- //{ 0x01D32730, "_ZN11CSGameState5ResetEv", mfunc_ptr_cast(&CSGameState::Reset) },
- //{ 0x0, "_ZN11CSGameState7OnEventE13GameEventTypeP11CBaseEntityS2_", mfunc_ptr_cast(&CSGameState::OnEvent) },
- //{ 0x0, "_ZNK11CSGameState11IsRoundOverEv", mfunc_ptr_cast(&CSGameState::IsRoundOver) },
- //{ 0x0, "_ZNK11CSGameState12IsBombMovingEv", mfunc_ptr_cast(&CSGameState::IsBombMoving) },
- //{ 0x0, "_ZNK11CSGameState11IsBombLooseEv", mfunc_ptr_cast(&CSGameState::IsBombLoose) },
- //{ 0x0, "_ZNK11CSGameState13IsBombPlantedEv", mfunc_ptr_cast(&CSGameState::IsBombPlanted) },
- //{ 0x0, "_ZNK11CSGameState13IsBombDefusedEv", mfunc_ptr_cast(&CSGameState::IsBombDefused) }, // NOXREF
- //{ 0x0, "_ZNK11CSGameState14IsBombExplodedEv", mfunc_ptr_cast(&CSGameState::IsBombExploded) }, // NOXREF
- //{ 0x0, "_ZN11CSGameState15UpdateLooseBombEPK6Vector", mfunc_ptr_cast(&CSGameState::UpdateLooseBomb) },
- //{ 0x0, "_ZNK11CSGameState25TimeSinceLastSawLooseBombEv", mfunc_ptr_cast(&CSGameState::TimeSinceLastSawLooseBomb) },
- //{ 0x0, "_ZNK11CSGameState24IsLooseBombLocationKnownEv", mfunc_ptr_cast(&CSGameState::IsLooseBombLocationKnown) },
- //{ 0x0, "_ZN11CSGameState12UpdateBomberEPK6Vector", mfunc_ptr_cast(&CSGameState::UpdateBomber) },
- //{ 0x0, "_ZNK11CSGameState22TimeSinceLastSawBomberEv", mfunc_ptr_cast(&CSGameState::TimeSinceLastSawBomber) },
- //{ 0x0, "_ZN11CSGameState17UpdatePlantedBombEPK6Vector", mfunc_ptr_cast(&CSGameState::UpdatePlantedBomb) },
- //{ 0x0, "_ZNK11CSGameState26IsPlantedBombLocationKnownEv", mfunc_ptr_cast(&CSGameState::IsPlantedBombLocationKnown) },
- //{ 0x0, "_ZN11CSGameState21MarkBombsiteAsPlantedEi", mfunc_ptr_cast(&CSGameState::MarkBombsiteAsPlanted) },
- //{ 0x0, "_ZNK11CSGameState18GetPlantedBombsiteEv", mfunc_ptr_cast(&CSGameState::GetPlantedBombsite) },
- //{ 0x0, "_ZNK11CSGameState19IsAtPlantedBombsiteEv", mfunc_ptr_cast(&CSGameState::IsAtPlantedBombsite) },
- //{ 0x0, "_ZN11CSGameState23GetNextBombsiteToSearchEv", mfunc_ptr_cast(&CSGameState::GetNextBombsiteToSearch) },
- //{ 0x0, "_ZNK11CSGameState15IsBombsiteClearEi", mfunc_ptr_cast(&CSGameState::IsBombsiteClear) },
- //{ 0x0, "_ZN11CSGameState13ClearBombsiteEi", mfunc_ptr_cast(&CSGameState::ClearBombsite) },
- //{ 0x0, "_ZNK11CSGameState15GetBombPositionEv", mfunc_ptr_cast(&CSGameState::GetBombPosition) },
- //{ 0x0, "_ZNK11CSGameState21GetNearestFreeHostageEP6Vector", mfunc_ptr_cast(&CSGameState::GetNearestFreeHostage) },
- //{ 0x0, "_ZNK11CSGameState28GetRandomFreeHostagePositionEv", mfunc_ptr_cast(&CSGameState::GetRandomFreeHostagePosition) },
- //{ 0x0, "_ZNK11CSGameState26AreAllHostagesBeingRescuedEv", mfunc_ptr_cast(&CSGameState::AreAllHostagesBeingRescued) },
- //{ 0x0, "_ZNK11CSGameState18AreAllHostagesGoneEv", mfunc_ptr_cast(&CSGameState::AreAllHostagesGone) },
- //{ 0x0, "_ZN11CSGameState15AllHostagesGoneEv", mfunc_ptr_cast(&CSGameState::AllHostagesGone) },
- //{ 0x0, "_ZNK11CSGameState25HaveSomeHostagesBeenTakenEv", mfunc_ptr_cast(&CSGameState::HaveSomeHostagesBeenTaken) },
- //{ 0x0, "_ZN11CSGameState15HostageWasTakenEv", mfunc_ptr_cast(&CSGameState::HostageWasTaken) },
- //{ 0x0, "_ZNK11CSGameState28GetNearestVisibleFreeHostageEv", mfunc_ptr_cast(&CSGameState::GetNearestVisibleFreeHostage) },
- //{ 0x0, "_ZN11CSGameState24ValidateHostagePositionsEv", mfunc_ptr_cast(&CSGameState::ValidateHostagePositions) },
- //{ 0x0, "_ZN11CSGameState12SetBombStateENS_9BombStateE", mfunc_ptr_cast(&CSGameState::SetBombState) },
- //{ 0x0, "_ZNK11CSGameState12GetBombStateEv", mfunc_ptr_cast(&CSGameState::GetBombState) }, // NOXREF
- //{ 0x0, "_ZNK11CSGameState17GetNearestHostageEv", mfunc_ptr_cast(&CSGameState::GetNearestHostage) }, // NOXREF
- //{ 0x0, "_ZN11CSGameState21InitializeHostageInfoEv", mfunc_ptr_cast(&CSGameState::InitializeHostageInfo) },
-
- //{ 0x0, "_Z17GetBotFollowCountP11CBasePlayer", (size_t)&GetBotFollowCount },
- //{ 0x01D187B0, "_Z21FindNearbyRetreatSpotP6CCSBotf", (size_t)&FindNearbyRetreatSpot },
-
+ //{ 0x01D326A0, "_ZN11CSGameStateC2EP6CCSBot", mfunc_ptr_cast(&CSGameState::CSGameState) },
+ { 0x01D32730, "_ZN11CSGameState5ResetEv", mfunc_ptr_cast(&CSGameState::Reset) },
+ { 0x01D327C0, "_ZN11CSGameState7OnEventE13GameEventTypeP11CBaseEntityS2_", mfunc_ptr_cast(&CSGameState::OnEvent) },
+ { 0x01D328D0, "_ZNK11CSGameState11IsRoundOverEv", mfunc_ptr_cast(&CSGameState::IsRoundOver) },
+ //{ 0x0, "_ZNK11CSGameState12IsBombMovingEv", mfunc_ptr_cast(&CSGameState::IsBombMoving) }, // NOXREF
+ //{ 0x0, "_ZNK11CSGameState11IsBombLooseEv", mfunc_ptr_cast(&CSGameState::IsBombLoose) }, // NOXREF
+ //{ 0x0, "_ZNK11CSGameState13IsBombPlantedEv", mfunc_ptr_cast(&CSGameState::IsBombPlanted) }, // NOXREF
+ //{ 0x0, "_ZNK11CSGameState13IsBombDefusedEv", mfunc_ptr_cast(&CSGameState::IsBombDefused) }, // NOXREF
+ //{ 0x0, "_ZNK11CSGameState14IsBombExplodedEv", mfunc_ptr_cast(&CSGameState::IsBombExploded) }, // NOXREF
+ { 0x01D32900, "_ZN11CSGameState15UpdateLooseBombEPK6Vector", mfunc_ptr_cast(&CSGameState::UpdateLooseBomb) }, // NOXREF
+ //{ 0x01D32940, "_ZNK11CSGameState25TimeSinceLastSawLooseBombEv", mfunc_ptr_cast(&CSGameState::TimeSinceLastSawLooseBomb) }, // NOXREF
+ { 0x01D32970, "_ZNK11CSGameState24IsLooseBombLocationKnownEv", mfunc_ptr_cast(&CSGameState::IsLooseBombLocationKnown) },
+ { 0x01D329A0, "_ZN11CSGameState12UpdateBomberEPK6Vector", mfunc_ptr_cast(&CSGameState::UpdateBomber) },
+ //{ 0x01D329E0, "_ZNK11CSGameState22TimeSinceLastSawBomberEv", mfunc_ptr_cast(&CSGameState::TimeSinceLastSawBomber) }, // NOXREF
+ { 0x01D32B20, "_ZN11CSGameState17UpdatePlantedBombEPK6Vector", mfunc_ptr_cast(&CSGameState::UpdatePlantedBomb) },
+ { 0x01D32A10, "_ZNK11CSGameState26IsPlantedBombLocationKnownEv", mfunc_ptr_cast(&CSGameState::IsPlantedBombLocationKnown) },
+ { 0x01D32B80, "_ZN11CSGameState21MarkBombsiteAsPlantedEi", mfunc_ptr_cast(&CSGameState::MarkBombsiteAsPlanted) },
+ { 0x01D32A20, "_ZNK11CSGameState18GetPlantedBombsiteEv", mfunc_ptr_cast(&CSGameState::GetPlantedBombsite) },
+ { 0x01D32A30, "_ZNK11CSGameState19IsAtPlantedBombsiteEv", mfunc_ptr_cast(&CSGameState::IsAtPlantedBombsite) },
+ { 0x01D32A70, "_ZN11CSGameState23GetNextBombsiteToSearchEv", mfunc_ptr_cast(&CSGameState::GetNextBombsiteToSearch) },
+ { 0x01D32BC0, "_ZNK11CSGameState15IsBombsiteClearEi", mfunc_ptr_cast(&CSGameState::IsBombsiteClear) },
+ { 0x01D32BA0, "_ZN11CSGameState13ClearBombsiteEi", mfunc_ptr_cast(&CSGameState::ClearBombsite) },
+ { 0x01D32AC0, "_ZNK11CSGameState15GetBombPositionEv", mfunc_ptr_cast(&CSGameState::GetBombPosition) },
+ { 0x01D32CC0, "_ZNK11CSGameState21GetNearestFreeHostageEP6Vector", mfunc_ptr_cast(&CSGameState::GetNearestFreeHostage) },
+ { 0x01D32EB0, "_ZNK11CSGameState28GetRandomFreeHostagePositionEv", mfunc_ptr_cast(&CSGameState::GetRandomFreeHostagePosition) },
+ { 0x01D33370, "_ZNK11CSGameState26AreAllHostagesBeingRescuedEv", mfunc_ptr_cast(&CSGameState::AreAllHostagesBeingRescued) },
+ { 0x01D33440, "_ZNK11CSGameState18AreAllHostagesGoneEv", mfunc_ptr_cast(&CSGameState::AreAllHostagesGone) },
+ //{ 0x01D334A0, "_ZN11CSGameState15AllHostagesGoneEv", mfunc_ptr_cast(&CSGameState::AllHostagesGone) }, // NOXREF
+ //{ 0x0, "_ZNK11CSGameState25HaveSomeHostagesBeenTakenEv", mfunc_ptr_cast(&CSGameState::HaveSomeHostagesBeenTaken) }, // NOXREF
+ //{ 0x0, "_ZN11CSGameState15HostageWasTakenEv", mfunc_ptr_cast(&CSGameState::HostageWasTaken) }, // NOXREF
+ { 0x01D33210, "_ZNK11CSGameState28GetNearestVisibleFreeHostageEv", mfunc_ptr_cast(&CSGameState::GetNearestVisibleFreeHostage) },
+ { 0x01D32FA0, "_ZN11CSGameState24ValidateHostagePositionsEv", mfunc_ptr_cast(&CSGameState::ValidateHostagePositions) },
+ //{ 0x01D328E0, "_ZN11CSGameState12SetBombStateENS_9BombStateE", mfunc_ptr_cast(&CSGameState::SetBombState) }, // NOXREF
+ //{ 0x0, "_ZNK11CSGameState12GetBombStateEv", mfunc_ptr_cast(&CSGameState::GetBombState) }, // NOXREF
+ //{ 0x0, "_ZNK11CSGameState17GetNearestHostageEv", mfunc_ptr_cast(&CSGameState::GetNearestHostage) }, // NOXREF
+ { 0x01D32BE0, "_ZN11CSGameState21InitializeHostageInfoEv", mfunc_ptr_cast(&CSGameState::InitializeHostageInfo) },
+ //{ 0x01D15EA0, "_Z16NavAreaBuildPathI8PathCostEbP8CNavAreaS2_PK6VectorRT_PS2_", (size_t)&NavAreaBuildPath__PathCost__wrapper },
+ { 0x01D2B2E0, "_ZN8PathCostclEP8CNavAreaS1_PK10CNavLadder", mfunc_ptr_cast(&PathCost::operator()) },
+ { 0x01D172A0, "_Z17GetBotFollowCountP11CBasePlayer", (size_t)&GetBotFollowCount },
+ { 0x01D187B0, "_Z21FindNearbyRetreatSpotP6CCSBotf", mfunc_ptr_cast(&FindNearbyRetreatSpot) },
//{ 0x0, "", (size_t)&drawProgressMeter }, // NOXREF
//{ 0x0, "", (size_t)&startProgressMeter }, // NOXREF
//{ 0x0, "", (size_t)&hideProgressMeter }, // NOXREF
@@ -4056,21 +4059,21 @@ FunctionHook g_FunctionHooks[] =
//BotState
//virtual func
- //{ 0x0, "_ZN8BotState7OnEnterEP6CCSBot", mfunc_ptr_cast(&BotState::OnEnter) }, // PURE
- //{ 0x0, "_ZN8BotState8OnUpdateEP6CCSBot", mfunc_ptr_cast(&BotState::OnUpdate) }, // PURE
- //{ 0x0, "_ZN8BotState6OnExitEP6CCSBot", mfunc_ptr_cast(&BotState::OnExit) }, // PURE
+ //{ 0x0, "_ZN8BotState7OnEnterEP6CCSBot", mfunc_ptr_cast(&BotState::OnEnter_) }, // PURE
+ //{ 0x0, "_ZN8BotState8OnUpdateEP6CCSBot", mfunc_ptr_cast(&BotState::OnUpdate_) }, // PURE
+ //{ 0x01D212B0, "_ZN8BotState6OnExitEP6CCSBot", mfunc_ptr_cast(&BotState::OnExit_) }, // PURE
//{ 0x0, "_ZNK8BotState7GetNameEv", mfunc_ptr_cast(&BotState::GetName) }, // NOXREF
//IdleState
//virtual func
- //{ 0x0, "_ZN9IdleState7OnEnterEP6CCSBot", mfunc_ptr_cast(&IdleState::OnEnter) },
- //{ 0x0, "_ZN9IdleState8OnUpdateEP6CCSBot", mfunc_ptr_cast(&IdleState::OnUpdate) },
- //{ 0x0, "_ZNK9IdleState7GetNameEv", mfunc_ptr_cast(&IdleState::GetName) },
+ //{ 0x01D142A0, "_ZN9IdleState7OnEnterEP6CCSBot", mfunc_ptr_cast(&IdleState::OnEnter_) },
+ //{ 0x01D14320, "_ZN9IdleState8OnUpdateEP6CCSBot", mfunc_ptr_cast(&IdleState::OnUpdate_) },
+ //{ 0x01D212C0, "_ZNK9IdleState7GetNameEv", mfunc_ptr_cast(&IdleState::GetName_) },
//HuntState
//virtual func
- //{ 0x0, "_ZN9HuntState7OnEnterEP6CCSBot", mfunc_ptr_cast(&HuntState::OnEnter) },
- //{ 0x0, "_ZN9HuntState8OnUpdateEP6CCSBot", mfunc_ptr_cast(&HuntState::OnUpdate) },
- //{ 0x0, "_ZN9HuntState6OnExitEP6CCSBot", mfunc_ptr_cast(&HuntState::OnExit) },
- //{ 0x0, "_ZNK9HuntState7GetNameEv", mfunc_ptr_cast(&HuntState::GetName) },
+ //{ 0x01D13E20, "_ZN9HuntState7OnEnterEP6CCSBot", mfunc_ptr_cast(&HuntState::OnEnter_) },
+ //{ 0x01D13EA0, "_ZN9HuntState8OnUpdateEP6CCSBot", mfunc_ptr_cast(&HuntState::OnUpdate_) },
+ //{ 0x01D14290, "_ZN9HuntState6OnExitEP6CCSBot", mfunc_ptr_cast(&HuntState::OnExit_) },
+ //{ 0x01D212D0, "_ZNK9HuntState7GetNameEv", mfunc_ptr_cast(&HuntState::GetName_) },
//non-virtual func
//{ 0x0, "_ZN9HuntState13ClearHuntAreaEv", mfunc_ptr_cast(&HuntState::ClearHuntArea) }, // NOXREF
//AttackState
@@ -4084,84 +4087,84 @@ FunctionHook g_FunctionHooks[] =
//{ 0x01D10CC0, "_ZN11AttackState13StopAttackingEP6CCSBot", mfunc_ptr_cast(&AttackState::StopAttacking) }, // NOXREF
//InvestigateNoiseState
//virtual func
- //{ 0x0, "_ZN21InvestigateNoiseState7OnEnterEP6CCSBot", mfunc_ptr_cast(&InvestigateNoiseState::OnEnter) },
- //{ 0x0, "_ZN21InvestigateNoiseState8OnUpdateEP6CCSBot", mfunc_ptr_cast(&InvestigateNoiseState::OnUpdate) },
- //{ 0x0, "_ZN21InvestigateNoiseState6OnExitEP6CCSBot", mfunc_ptr_cast(&InvestigateNoiseState::OnExit) },
- //{ 0x0, "_ZNK21InvestigateNoiseState7GetNameEv", mfunc_ptr_cast(&InvestigateNoiseState::GetName) },
+ //{ 0x01D165C0, "_ZN21InvestigateNoiseState7OnEnterEP6CCSBot", mfunc_ptr_cast(&InvestigateNoiseState::OnEnter_) },
+ //{ 0x01D166B0, "_ZN21InvestigateNoiseState8OnUpdateEP6CCSBot", mfunc_ptr_cast(&InvestigateNoiseState::OnUpdate_) },
+ //{ 0x01D16920, "_ZN21InvestigateNoiseState6OnExitEP6CCSBot", mfunc_ptr_cast(&InvestigateNoiseState::OnExit_) },
+ //{ 0x01D212F0, "_ZNK21InvestigateNoiseState7GetNameEv", mfunc_ptr_cast(&InvestigateNoiseState::GetName_) },
//non-virtual func
- //{ 0x0, "_ZN21InvestigateNoiseState18AttendCurrentNoiseEP6CCSBot", mfunc_ptr_cast(&InvestigateNoiseState::AttendCurrentNoise) },
+ //{ 0x0, "_ZN21InvestigateNoiseState18AttendCurrentNoiseEP6CCSBot", mfunc_ptr_cast(&InvestigateNoiseState::AttendCurrentNoise) }, // NOXREF
//BuyState
//virtual func
- //{ 0x0, "_ZN8BuyState7OnEnterEP6CCSBot", mfunc_ptr_cast(&BuyState::OnEnter) },
- //{ 0x0, "_ZN8BuyState8OnUpdateEP6CCSBot", mfunc_ptr_cast(&BuyState::OnUpdate) },
- //{ 0x0, "_ZN8BuyState6OnExitEP6CCSBot", mfunc_ptr_cast(&BuyState::OnExit) },
- //{ 0x0, "_ZNK8BuyState7GetNameEv", mfunc_ptr_cast(&BuyState::GetName) },
+ //{ 0x01D11910, "_ZN8BuyState7OnEnterEP6CCSBot", mfunc_ptr_cast(&BuyState::OnEnter_) },
+ //{ 0x01D11B60, "_ZN8BuyState8OnUpdateEP6CCSBot", mfunc_ptr_cast(&BuyState::OnUpdate_) },
+ //{ 0x01D121E0, "_ZN8BuyState6OnExitEP6CCSBot", mfunc_ptr_cast(&BuyState::OnExit_) },
+ //{ 0x01D21300, "_ZNK8BuyState7GetNameEv", mfunc_ptr_cast(&BuyState::GetName_) }, // DEFAULT
//MoveToState
//virtual func
- //{ 0x0, "_ZN11MoveToState7OnEnterEP6CCSBot", mfunc_ptr_cast(&MoveToState::OnEnter) },
- //{ 0x0, "_ZN11MoveToState8OnUpdateEP6CCSBot", mfunc_ptr_cast(&MoveToState::OnUpdate) },
- //{ 0x0, "_ZN11MoveToState6OnExitEP6CCSBot", mfunc_ptr_cast(&MoveToState::OnExit) },
- //{ 0x0, "_ZNK11MoveToState7GetNameEv", mfunc_ptr_cast(&MoveToState::GetName) },
+ //{ 0x01D16930, "_ZN11MoveToState7OnEnterEP6CCSBot", mfunc_ptr_cast(&MoveToState::OnEnter_) },
+ //{ 0x01D169C0, "_ZN11MoveToState8OnUpdateEP6CCSBot", mfunc_ptr_cast(&MoveToState::OnUpdate_) },
+ //{ 0x01D16FE0, "_ZN11MoveToState6OnExitEP6CCSBot", mfunc_ptr_cast(&MoveToState::OnExit_) },
+ //{ 0x01D21310, "_ZNK11MoveToState7GetNameEv", mfunc_ptr_cast(&MoveToState::GetName_) }, // DEFAULT
//non-virtual func
- //{ 0x0, "_ZN11MoveToState15SetGoalPositionEPK6Vector", mfunc_ptr_cast(&MoveToState::SetGoalPosition) }, // NOXREF
+ //{ 0x0, "_ZN11MoveToState15SetGoalPositionEPK6Vector", mfunc_ptr_cast(&MoveToState::SetGoalPosition) }, // NOXREF
//{ 0x0, "_ZN11MoveToState12SetRouteTypeE9RouteType", mfunc_ptr_cast(&MoveToState::SetRouteType) }, // NOXREF
//FetchBombState
//virtual func
- //{ 0x0, "_ZN14FetchBombState7OnEnterEP6CCSBot", mfunc_ptr_cast(&FetchBombState::OnEnter) },
- //{ 0x0, "_ZN14FetchBombState8OnUpdateEP6CCSBot", mfunc_ptr_cast(&FetchBombState::OnUpdate) },
- //{ 0x0, "_ZNK14FetchBombState7GetNameEv", mfunc_ptr_cast(&FetchBombState::GetName) },
+ //{ 0x01D125A0, "_ZN14FetchBombState7OnEnterEP6CCSBot", mfunc_ptr_cast(&FetchBombState::OnEnter_) },
+ //{ 0x01D125C0, "_ZN14FetchBombState8OnUpdateEP6CCSBot", mfunc_ptr_cast(&FetchBombState::OnUpdate_) },
+ //{ 0x01D21320, "_ZNK14FetchBombState7GetNameEv", mfunc_ptr_cast(&FetchBombState::GetName_) }, // DEFAULT
//PlantBombState
//virtual func
- //{ 0x0, "_ZN14PlantBombState7OnEnterEP6CCSBot", mfunc_ptr_cast(&PlantBombState::OnEnter) },
- //{ 0x0, "_ZN14PlantBombState8OnUpdateEP6CCSBot", mfunc_ptr_cast(&PlantBombState::OnUpdate) },
- //{ 0x0, "_ZN14PlantBombState6OnExitEP6CCSBot", mfunc_ptr_cast(&PlantBombState::OnExit) },
- //{ 0x0, "_ZNK14PlantBombState7GetNameEv", mfunc_ptr_cast(&PlantBombState::GetName) },
+ { 0x01D17000, "_ZN14PlantBombState7OnEnterEP6CCSBot", mfunc_ptr_cast(&PlantBombState::OnEnter_) },
+ { 0x01D170B0, "_ZN14PlantBombState8OnUpdateEP6CCSBot", mfunc_ptr_cast(&PlantBombState::OnUpdate_) },
+ { 0x01D17160, "_ZN14PlantBombState6OnExitEP6CCSBot", mfunc_ptr_cast(&PlantBombState::OnExit_) },
+ //{ 0x01D21330, "_ZNK14PlantBombState7GetNameEv", mfunc_ptr_cast(&PlantBombState::GetName_) }, // DEFAULT
//DefuseBombState
//virtual func
- //{ 0x0, "_ZN15DefuseBombState7OnEnterEP6CCSBot", mfunc_ptr_cast(&DefuseBombState::OnEnter) },
- //{ 0x0, "_ZN15DefuseBombState8OnUpdateEP6CCSBot", mfunc_ptr_cast(&DefuseBombState::OnUpdate) },
- //{ 0x0, "_ZN15DefuseBombState6OnExitEP6CCSBot", mfunc_ptr_cast(&DefuseBombState::OnExit) },
- //{ 0x0, "_ZNK15DefuseBombState7GetNameEv", mfunc_ptr_cast(&DefuseBombState::GetName) },
+ //{ 0x01D12200, "_ZN15DefuseBombState7OnEnterEP6CCSBot", mfunc_ptr_cast(&DefuseBombState::OnEnter_) },
+ //{ 0x01D12270, "_ZN15DefuseBombState8OnUpdateEP6CCSBot", mfunc_ptr_cast(&DefuseBombState::OnUpdate_) },
+ //{ 0x01D12340, "_ZN15DefuseBombState6OnExitEP6CCSBot", mfunc_ptr_cast(&DefuseBombState::OnExit_) },
+ //{ 0x01D21340, "_ZNK15DefuseBombState7GetNameEv", mfunc_ptr_cast(&DefuseBombState::GetName_) }, // DEFAULT
//HideState
//virtual func
- //{ 0x0, "_ZN9HideState7OnEnterEP6CCSBot", mfunc_ptr_cast(&HideState::OnEnter) },
- //{ 0x0, "_ZN9HideState8OnUpdateEP6CCSBot", mfunc_ptr_cast(&HideState::OnUpdate) },
- //{ 0x0, "_ZN9HideState6OnExitEP6CCSBot", mfunc_ptr_cast(&HideState::OnExit) },
- //{ 0x0, "_ZNK9HideState7GetNameEv", mfunc_ptr_cast(&HideState::GetName) },
+ //{ 0x01D13250, "_ZN9HideState7OnEnterEP6CCSBot", mfunc_ptr_cast(&HideState::OnEnter_) },
+ //{ 0x01D13300, "_ZN9HideState8OnUpdateEP6CCSBot", mfunc_ptr_cast(&HideState::OnUpdate_) },
+ //{ 0x01D13D90, "_ZN9HideState6OnExitEP6CCSBot", mfunc_ptr_cast(&HideState::OnExit_) },
+ //{ 0x01D21350, "_ZNK9HideState7GetNameEv", mfunc_ptr_cast(&HideState::GetName_) }, // DEFAULT
//non-virtual func
//{ 0x0, "_ZN9HideState13SetHidingSpotEPK6Vector", mfunc_ptr_cast(&HideState::SetHidingSpot) }, // NOXREF
//{ 0x0, "_ZNK9HideState13GetHidingSpotEv", mfunc_ptr_cast(&HideState::GetHidingSpot) }, // NOXREF
- //{ 0x0, "_ZN9HideState13SetSearchAreaEP8CNavArea", mfunc_ptr_cast(&HideState::SetSearchArea) }, // NOXREF
+ //{ 0x0, "_ZN9HideState13SetSearchAreaEP8CNavArea", mfunc_ptr_cast(&HideState::SetSearchArea) }, // NOXREF
//{ 0x0, "_ZN9HideState14SetSearchRangeEf", mfunc_ptr_cast(&HideState::SetSearchRange) }, // NOXREF
- //{ 0x0, "_ZN9HideState11SetDurationEf", mfunc_ptr_cast(&HideState::SetDuration) }, // NOXREF
+ //{ 0x0, "_ZN9HideState11SetDurationEf", mfunc_ptr_cast(&HideState::SetDuration) }, // NOXREF
//{ 0x0, "_ZN9HideState15SetHoldPositionEb", mfunc_ptr_cast(&HideState::SetHoldPosition) }, // NOXREF
- //{ 0x0, "_ZNK9HideState8IsAtSpotEv", mfunc_ptr_cast(&HideState::IsAtSpot) }, // NOXREF
+ //{ 0x0, "_ZNK9HideState8IsAtSpotEv", mfunc_ptr_cast(&HideState::IsAtSpot) }, // NOXREF
//EscapeFromBombState
//virtual func
- //{ 0x0, "_ZN19EscapeFromBombState7OnEnterEP6CCSBot", mfunc_ptr_cast(&EscapeFromBombState::OnEnter) },
- //{ 0x0, "_ZN19EscapeFromBombState8OnUpdateEP6CCSBot", mfunc_ptr_cast(&EscapeFromBombState::OnUpdate) },
- //{ 0x0, "_ZN19EscapeFromBombState6OnExitEP6CCSBot", mfunc_ptr_cast(&EscapeFromBombState::OnExit) },
- //{ 0x0, "_ZNK19EscapeFromBombState7GetNameEv", mfunc_ptr_cast(&EscapeFromBombState::GetName) },
+ //{ 0x01D12390, "_ZN19EscapeFromBombState7OnEnterEP6CCSBot", mfunc_ptr_cast(&EscapeFromBombState::OnEnter_) },
+ //{ 0x01D123D0, "_ZN19EscapeFromBombState8OnUpdateEP6CCSBot", mfunc_ptr_cast(&EscapeFromBombState::OnUpdate_) },
+ //{ 0x01D12560, "_ZN19EscapeFromBombState6OnExitEP6CCSBot", mfunc_ptr_cast(&EscapeFromBombState::OnExit_) },
+ //{ 0x01D21360, "_ZNK19EscapeFromBombState7GetNameEv", mfunc_ptr_cast(&EscapeFromBombState::GetName_) }, // DEFAULT
//FollowState
//virtual func
- //{ 0x0, "_ZN11FollowState7OnEnterEP6CCSBot", mfunc_ptr_cast(&FollowState::OnEnter) },
- //{ 0x0, "_ZN11FollowState8OnUpdateEP6CCSBot", mfunc_ptr_cast(&FollowState::OnUpdate) },
- //{ 0x0, "_ZN11FollowState6OnExitEP6CCSBot", mfunc_ptr_cast(&FollowState::OnExit) },
- //{ 0x0, "_ZNK11FollowState7GetNameEv", mfunc_ptr_cast(&FollowState::GetName) },
+ //{ 0x01D12660, "_ZN11FollowState7OnEnterEP6CCSBot", mfunc_ptr_cast(&FollowState::OnEnter_) },
+ //{ 0x01D127A0, "_ZN11FollowState8OnUpdateEP6CCSBot", mfunc_ptr_cast(&FollowState::OnUpdate_) },
+ //{ 0x01D130C0, "_ZN11FollowState6OnExitEP6CCSBot", mfunc_ptr_cast(&FollowState::OnExit_) }, // PURE
+ //{ 0x01D21370, "_ZNK11FollowState7GetNameEv", mfunc_ptr_cast(&FollowState::GetName_) }, // DEFAULT
//non-virtual func
//{ 0x0, "_ZN11FollowState9SetLeaderEP11CBasePlayer", mfunc_ptr_cast(&FollowState::SetLeader) }, // NOXREF
//{ 0x0, "_ZN11FollowState24ComputeLeaderMotionStateEf", mfunc_ptr_cast(&FollowState::ComputeLeaderMotionState) },
//UseEntityState
//virtual func
- //{ 0x0, "_ZN14UseEntityState7OnEnterEP6CCSBot", mfunc_ptr_cast(&UseEntityState::OnEnter) },
- //{ 0x0, "_ZN14UseEntityState8OnUpdateEP6CCSBot", mfunc_ptr_cast(&UseEntityState::OnUpdate) },
- //{ 0x0, "_ZN14UseEntityState6OnExitEP6CCSBot", mfunc_ptr_cast(&UseEntityState::OnExit) },
- //{ 0x0, "_ZNK14UseEntityState7GetNameEv", mfunc_ptr_cast(&UseEntityState::GetName) },
+ { 0x01D171A0, "_ZN14UseEntityState7OnEnterEP6CCSBot", mfunc_ptr_cast(&UseEntityState::OnEnter_) },
+ { 0x01D171B0, "_ZN14UseEntityState8OnUpdateEP6CCSBot", mfunc_ptr_cast(&UseEntityState::OnUpdate_) },
+ { 0x01D17280, "_ZN14UseEntityState6OnExitEP6CCSBot", mfunc_ptr_cast(&UseEntityState::OnExit_) },
+ //{ 0x01D21380, "_ZNK14UseEntityState7GetNameEv", mfunc_ptr_cast(&UseEntityState::GetName_) },
//non-virtual func
//{ 0x0, "_ZN14UseEntityState9SetEntityEP11CBaseEntity", mfunc_ptr_cast(&UseEntityState::SetEntity) }, // NOXREF
#ifdef _WIN32
- //{ 0x01D12F90, "_ZN8PathCostclEP8CNavAreaS1_PK10CNavLadder", mfunc_ptr_cast(&FollowTargetCollector::operator()) },
+ //{ 0x01D12F90, "_ZN21FollowTargetCollectorclEP8CNavArea", mfunc_ptr_cast(&FollowTargetCollector::operator()) },
#endif // _WIN32
#endif // CS_BotState_Region
@@ -4179,14 +4182,14 @@ FunctionHook g_FunctionHooks[] =
//{ 0x01D340C0, "_ZNK13ActiveGrenade11GetPositionEv", mfunc_ptr_cast(&ActiveGrenade::GetPosition) },
//CBot
- //{ 0x0, "", mfunc_ptr_cast(&CBot::CBot) },
+ //{ 0x01D334D0, "", mfunc_ptr_cast(&CBot::CBot) },
//virtual func
- //{ 0x01D33550, "_ZN4CBot5SpawnEv", mfunc_ptr_cast(&CBot::Spawn_) },
- //{ 0x0, "_ZN4CBot10TakeDamageEP9entvars_sS1_fi", mfunc_ptr_cast(&CBot::TakeDamage) },
- //{ 0x0, "_ZN4CBot6KilledEP9entvars_si", mfunc_ptr_cast(&CBot::Killed) },
- //{ 0x0, "_ZN4CBot5ThinkEv", mfunc_ptr_cast(&CBot::Think) },
- //{ 0x0, "_ZN4CBot5IsBotEv", mfunc_ptr_cast(&CBot::IsBot) },
- //{ 0x0, "_ZN4CBot16GetAutoaimVectorEf", mfunc_ptr_cast(&CBot::GetAutoaimVector_) },
+ //{ 0x01D33550, "_ZN4CBot5SpawnEv", mfunc_ptr_cast(&CBot::Spawn_) }, // do not hook
+ //{ 0x01D340D0, "_ZN4CBot10TakeDamageEP9entvars_sS1_fi", mfunc_ptr_cast(&CBot::TakeDamage) },
+ //{ 0x01D340E0, "_ZN4CBot6KilledEP9entvars_si", mfunc_ptr_cast(&CBot::Killed) },
+ //{ 0x01D210C0, "_ZN4CBot5ThinkEv", mfunc_ptr_cast(&CBot::Think) }, // PURE
+ //{ 0x01D210B0, "_ZN4CBot5IsBotEv", mfunc_ptr_cast(&CBot::IsBot) },
+ { 0x01D33600, "_ZN4CBot16GetAutoaimVectorEf", mfunc_ptr_cast(&CBot::GetAutoaimVector_) },
//{ 0x0, "_ZN4CBot16OnTouchingWeaponEP10CWeaponBox", mfunc_ptr_cast(&CBot::OnTouchingWeapon) },
{ 0x01D33540, "_ZN4CBot10InitializeEPK10BotProfile", mfunc_ptr_cast(&CBot::Initialize_) },
//{ 0x0, "_ZN4CBot8SpawnBotEv", mfunc_ptr_cast(&CBot::SpawnBot) },
@@ -4194,46 +4197,46 @@ FunctionHook g_FunctionHooks[] =
//{ 0x0, "_ZN4CBot6UpdateEv", mfunc_ptr_cast(&CBot::Update) },
//{ 0x01D21110, "_ZN4CBot3RunEv", mfunc_ptr_cast(&CBot::Run) }, // DEFAULT
//{ 0x01D34110, "_ZN4CBot4WalkEv", mfunc_ptr_cast(&CBot::Walk) }, // DEFAULT
- //{ 0x0, "_ZN4CBot6CrouchEv", mfunc_ptr_cast(&CBot::Crouch_) },
- //{ 0x0, "_ZN4CBot7StandUpEv", mfunc_ptr_cast(&CBot::StandUp_) },
- //{ 0x0, "_ZN4CBot11MoveForwardEv", mfunc_ptr_cast(&CBot::MoveForward_) },
- //{ 0x0, "_ZN4CBot12MoveBackwardEv", mfunc_ptr_cast(&CBot::MoveBackward_) },
- //{ 0x0, "_ZN4CBot10StrafeLeftEv", mfunc_ptr_cast(&CBot::StrafeLeft_) },
- //{ 0x0, "_ZN4CBot11StrafeRightEv", mfunc_ptr_cast(&CBot::StrafeRight_) }, // DEFAULT
- //{ 0x0, "_ZN4CBot4JumpEb", mfunc_ptr_cast(&CBot::Jump_) },
- //{ 0x0, "_ZN4CBot13ClearMovementEv", mfunc_ptr_cast(&CBot::ClearMovement_) },
- //{ 0x0, "_ZN4CBot14UseEnvironmentEv", mfunc_ptr_cast(&CBot::UseEnvironment_) },
- //{ 0x0, "_ZN4CBot13PrimaryAttackEv", mfunc_ptr_cast(&CBot::PrimaryAttack_) },
- //{ 0x0, "_ZN4CBot18ClearPrimaryAttackEv", mfunc_ptr_cast(&CBot::ClearPrimaryAttack_) },
+ { 0x01D33940, "_ZN4CBot6CrouchEv", mfunc_ptr_cast(&CBot::Crouch_) },
+ { 0x01D33950, "_ZN4CBot7StandUpEv", mfunc_ptr_cast(&CBot::StandUp_) },
+ { 0x01D336F0, "_ZN4CBot11MoveForwardEv", mfunc_ptr_cast(&CBot::MoveForward_) },
+ { 0x01D33740, "_ZN4CBot12MoveBackwardEv", mfunc_ptr_cast(&CBot::MoveBackward_) },
+ { 0x01D33790, "_ZN4CBot10StrafeLeftEv", mfunc_ptr_cast(&CBot::StrafeLeft_) },
+ { 0x01D337E0, "_ZN4CBot11StrafeRightEv", mfunc_ptr_cast(&CBot::StrafeRight_) },
+ { 0x01D33830, "_ZN4CBot4JumpEb", mfunc_ptr_cast(&CBot::Jump_) },
+ { 0x01D338D0, "_ZN4CBot13ClearMovementEv", mfunc_ptr_cast(&CBot::ClearMovement_) },
+ { 0x01D33960, "_ZN4CBot14UseEnvironmentEv", mfunc_ptr_cast(&CBot::UseEnvironment_) },
+ { 0x01D33970, "_ZN4CBot13PrimaryAttackEv", mfunc_ptr_cast(&CBot::PrimaryAttack_) },
+ { 0x01D33980, "_ZN4CBot18ClearPrimaryAttackEv", mfunc_ptr_cast(&CBot::ClearPrimaryAttack_) },
{ 0x01D33990, "_ZN4CBot19TogglePrimaryAttackEv", mfunc_ptr_cast(&CBot::TogglePrimaryAttack_) },
- //{ 0x0, "_ZN4CBot15SecondaryAttackEv", mfunc_ptr_cast(&CBot::SecondaryAttack_) },
- //{ 0x0, "_ZN4CBot6ReloadEv", mfunc_ptr_cast(&CBot::Reload_) },
- //{ 0x0, "_ZN4CBot7OnEventE13GameEventTypeP11CBaseEntityS2_", mfunc_ptr_cast(&CBot::OnEvent) },
+ { 0x01D339C0, "_ZN4CBot15SecondaryAttackEv", mfunc_ptr_cast(&CBot::SecondaryAttack_) },
+ { 0x01D339D0, "_ZN4CBot6ReloadEv", mfunc_ptr_cast(&CBot::Reload_) },
+ //{ 0x01D34100, "_ZN4CBot7OnEventE13GameEventTypeP11CBaseEntityS2_", mfunc_ptr_cast(&CBot::OnEvent) },
//{ 0x0, "_ZNK4CBot9IsVisibleEPK6Vectorb", mfunc_ptr_cast(&CBot::IsVisible) },
//{ 0x0, "_ZNK4CBot9IsVisibleEP11CBasePlayerbPh", mfunc_ptr_cast(&CBot::IsVisible) },
//{ 0x0, "_ZNK4CBot18IsEnemyPartVisibleENS_15VisiblePartTypeE", mfunc_ptr_cast(&CBot::IsEnemyPartVisible) }, // NOXREF PURE
- //{ 0x0, "_ZNK4CBot16IsPlayerFacingMeEP11CBasePlayer", mfunc_ptr_cast(&CBot::IsPlayerFacingMe) },
- //{ 0x0, "_ZNK4CBot19IsPlayerLookingAtMeEP11CBasePlayer", mfunc_ptr_cast(&CBot::IsPlayerLookingAtMe) },
+ { 0x01D21120, "_ZNK4CBot16IsPlayerFacingMeEP11CBasePlayer", mfunc_ptr_cast(&CBot::IsPlayerFacingMe_) },
+ { 0x01D211B0, "_ZNK4CBot19IsPlayerLookingAtMeEP11CBasePlayer", mfunc_ptr_cast(&CBot::IsPlayerLookingAtMe_) },
{ 0x01D33AA0, "_ZN4CBot14ExecuteCommandEv", mfunc_ptr_cast(&CBot::ExecuteCommand_) },
- //{ 0x0, "_ZN4CBot8SetModelEPKc", mfunc_ptr_cast(&CBot::SetModel) },
+ { 0x01D210D0, "_ZN4CBot8SetModelEPKc", mfunc_ptr_cast(&CBot::SetModel_) },
//non-virtual func
//{ 0x0, "_ZNK4CBot5GetIDEv", mfunc_ptr_cast(&CBot::GetID) },
//{ 0x0, "_ZNK4CBot9IsRunningEv", mfunc_ptr_cast(&CBot::IsRunning) },
//{ 0x0, "_ZNK4CBot11IsCrouchingEv", mfunc_ptr_cast(&CBot::IsCrouching) },
//{ 0x0, "_ZN4CBot18PushPostureContextEv", mfunc_ptr_cast(&CBot::PushPostureContext) },
//{ 0x0, "_ZN4CBot17PopPostureContextEv", mfunc_ptr_cast(&CBot::PopPostureContext) },
- //{ 0x0, "_ZN4CBot9IsJumpingEv", mfunc_ptr_cast(&CBot::IsJumping) },
+ { 0x01D338F0, "_ZN4CBot9IsJumpingEv", mfunc_ptr_cast(&CBot::IsJumping) },
//{ 0x0, "_ZNK4CBot16GetJumpTimestampEv", mfunc_ptr_cast(&CBot::GetJumpTimestamp) },
- //{ 0x0, "_ZNK4CBot24GetActiveWeaponAmmoRatioEv", mfunc_ptr_cast(&CBot::GetActiveWeaponAmmoRatio) },
- //{ 0x0, "_ZNK4CBot23IsActiveWeaponClipEmptyEv", mfunc_ptr_cast(&CBot::IsActiveWeaponClipEmpty) },
- //{ 0x0, "_ZNK4CBot23IsActiveWeaponOutOfAmmoEv", mfunc_ptr_cast(&CBot::IsActiveWeaponOutOfAmmo) },
+ { 0x01D339E0, "_ZNK4CBot24GetActiveWeaponAmmoRatioEv", mfunc_ptr_cast(&CBot::GetActiveWeaponAmmoRatio) },
+ { 0x01D33A30, "_ZNK4CBot23IsActiveWeaponClipEmptyEv", mfunc_ptr_cast(&CBot::IsActiveWeaponClipEmpty) },
+ { 0x01D33A50, "_ZNK4CBot23IsActiveWeaponOutOfAmmoEv", mfunc_ptr_cast(&CBot::IsActiveWeaponOutOfAmmo) },
//{ 0x0, "_ZNK4CBot23IsActiveWeaponReloadingEv", mfunc_ptr_cast(&CBot::IsActiveWeaponReloading) },
//{ 0x0, "_ZNK4CBot24IsActiveWeaponRecoilHighEv", mfunc_ptr_cast(&CBot::IsActiveWeaponRecoilHigh) },
//{ 0x0, "_ZNK4CBot15GetActiveWeaponEv", mfunc_ptr_cast(&CBot::GetActiveWeapon) },
{ 0x01D33A80, "_ZNK4CBot12IsUsingScopeEv", mfunc_ptr_cast(&CBot::IsUsingScope) },
- //{ 0x0, "_ZNK4CBot7IsEnemyEP11CBaseEntity", mfunc_ptr_cast(&CBot::IsEnemy) },
- //{ 0x01D33C40, "_ZNK4CBot19GetEnemiesRemainingEv", mfunc_ptr_cast(&CBot::GetEnemiesRemaining) },
- //{ 0x01D33D20, "_ZNK4CBot19GetFriendsRemainingEv", mfunc_ptr_cast(&CBot::GetFriendsRemaining) },
+ { 0x01D33BF0, "_ZNK4CBot7IsEnemyEP11CBaseEntity", mfunc_ptr_cast(&CBot::IsEnemy) },
+ { 0x01D33C40, "_ZNK4CBot19GetEnemiesRemainingEv", mfunc_ptr_cast(&CBot::GetEnemiesRemaining) },
+ { 0x01D33D20, "_ZNK4CBot19GetFriendsRemainingEv", mfunc_ptr_cast(&CBot::GetFriendsRemaining) },
{ 0x01D33E30, "_ZNK4CBot23IsLocalPlayerWatchingMeEv", mfunc_ptr_cast(&CBot::IsLocalPlayerWatchingMe) },
//{ 0x01D33E90, "_ZNK4CBot5PrintEPcz", mfunc_ptr_cast(&CBot::Print) }, // NOXREF
{ 0x01D33F00, "_ZNK4CBot14PrintIfWatchedEPcz", mfunc_ptr_cast(&CBot::PrintIfWatched) },
@@ -4247,34 +4250,34 @@ FunctionHook g_FunctionHooks[] =
//{ 0x01D33B70, "_ZNK4CBot13ThrottledMsecEv", mfunc_ptr_cast(&CBot::ThrottledMsec) }, // NOXREF
//{ 0x0, "_ZN4CBot12GetMoveSpeedEv", mfunc_ptr_cast(&CBot::GetMoveSpeed) },
//BotMeme
- //{ 0x0, "_ZNK7BotMeme8TransmitEP6CCSBot", mfunc_ptr_cast(&BotMeme::Transmit) },
+ { 0x01D18C90, "_ZNK7BotMeme8TransmitEP6CCSBot", mfunc_ptr_cast(&BotMeme::Transmit) },
//{ 0x0, "_ZNK7BotMeme9InterpretEP6CCSBotS1_", mfunc_ptr_cast(&BotMeme::Interpret) }, // NOXREF
//BotAllHostagesGoneMeme
- //{ 0x0, "_ZNK22BotAllHostagesGoneMeme9InterpretEP6CCSBotS1_", mfunc_ptr_cast(&BotAllHostagesGoneMeme::Interpret) },
+ { 0x01D19470, "_ZNK22BotAllHostagesGoneMeme9InterpretEP6CCSBotS1_", mfunc_ptr_cast(&BotAllHostagesGoneMeme::Interpret_) }, // NOXREF
//BotHostageBeingTakenMeme
- //{ 0x0, "_ZNK24BotHostageBeingTakenMeme9InterpretEP6CCSBotS1_", mfunc_ptr_cast(&BotHostageBeingTakenMeme::Interpret) },
+ { 0x01D19570, "_ZNK24BotHostageBeingTakenMeme9InterpretEP6CCSBotS1_", mfunc_ptr_cast(&BotHostageBeingTakenMeme::Interpret_) },
//BotHelpMeme
- //{ 0x0, "_ZNK11BotHelpMeme9InterpretEP6CCSBotS1_", mfunc_ptr_cast(&BotHelpMeme::Interpret) },
+ { 0x01D18D90, "_ZNK11BotHelpMeme9InterpretEP6CCSBotS1_", mfunc_ptr_cast(&BotHelpMeme::Interpret_) },
//BotBombsiteStatusMeme
- //{ 0x0, "_ZNK21BotBombsiteStatusMeme9InterpretEP6CCSBotS1_", mfunc_ptr_cast(&BotBombsiteStatusMeme::Interpret) },
+ { 0x01D18DB0, "_ZNK21BotBombsiteStatusMeme9InterpretEP6CCSBotS1_", mfunc_ptr_cast(&BotBombsiteStatusMeme::Interpret_) },
//BotBombStatusMeme
- //{ 0x0, "_ZNK17BotBombStatusMeme9InterpretEP6CCSBotS1_", mfunc_ptr_cast(&BotBombStatusMeme::Interpret) },
+ { 0x01D18EE0, "_ZNK17BotBombStatusMeme9InterpretEP6CCSBotS1_", mfunc_ptr_cast(&BotBombStatusMeme::Interpret_) },
//BotFollowMeme
- //{ 0x01D19080, "_ZNK13BotFollowMeme9InterpretEP6CCSBotS1_", mfunc_ptr_cast(&BotFollowMeme::Interpret) },
+ { 0x01D19080, "_ZNK13BotFollowMeme9InterpretEP6CCSBotS1_", mfunc_ptr_cast(&BotFollowMeme::Interpret_) },
//BotDefendHereMeme
- //{ 0x0, "_ZNK17BotDefendHereMeme9InterpretEP6CCSBotS1_", mfunc_ptr_cast(&BotDefendHereMeme::Interpret) },
+ { 0x01D19280, "_ZNK17BotDefendHereMeme9InterpretEP6CCSBotS1_", mfunc_ptr_cast(&BotDefendHereMeme::Interpret_) },
//BotWhereBombMeme
- //{ 0x0, "_ZNK16BotWhereBombMeme9InterpretEP6CCSBotS1_", mfunc_ptr_cast(&BotWhereBombMeme::Interpret) },
+ { 0x01D19420, "_ZNK16BotWhereBombMeme9InterpretEP6CCSBotS1_", mfunc_ptr_cast(&BotWhereBombMeme::Interpret_) },
//BotRequestReportMeme
- //{ 0x0, "_ZNK20BotRequestReportMeme9InterpretEP6CCSBotS1_", mfunc_ptr_cast(&BotRequestReportMeme::Interpret) },
+ { 0x01D19450, "_ZNK20BotRequestReportMeme9InterpretEP6CCSBotS1_", mfunc_ptr_cast(&BotRequestReportMeme::Interpret_) },
//BotSpeakable
- //{ 0x0, "", mfunc_ptr_cast(&BotSpeakable::BotSpeakable) }, // NOXREF
- //{ 0x0, "", mfunc_ptr_cast(&BotSpeakable::~BotSpeakable) }, // NOXREF
+ //{ 0x01D19680, "", mfunc_ptr_cast(&BotSpeakable::BotSpeakable) }, // NOXREF
+ //{ 0x01D19690, "", mfunc_ptr_cast(&BotSpeakable::~BotSpeakable) }, // NOXREF
//BotPhrase
//{ 0x01D196B0, "", mfunc_ptr_cast(&BotPhrase::BotPhrase) }, // NOXREF
//{ 0x01D198E0, "", mfunc_ptr_cast(&BotPhrase::~BotPhrase) }, // NOXREF
- //{ 0x0, "_ZN9BotPhrase13InitVoiceBankEi", mfunc_ptr_cast(&BotPhrase::InitVoiceBank) },
- //3@@{ 0x01D19BB0, "_ZNK9BotPhrase12GetSpeakableEiPf", mfunc_ptr_cast(&BotPhrase::GetSpeakable) },
+ { 0x01D199C0, "_ZN9BotPhrase13InitVoiceBankEi", mfunc_ptr_cast(&BotPhrase::InitVoiceBank) },
+ { 0x01D19BB0, "_ZNK9BotPhrase12GetSpeakableEiPf", mfunc_ptr_cast(&BotPhrase::GetSpeakable) },
//{ 0x0, "_ZNK9BotPhrase13ClearCriteriaEv", mfunc_ptr_cast(&BotPhrase::ClearCriteria) },
//{ 0x0, "_ZNK9BotPhrase16SetPlaceCriteriaEj", mfunc_ptr_cast(&BotPhrase::SetPlaceCriteria) },
//{ 0x0, "_ZNK9BotPhrase16SetCountCriteriaEj", mfunc_ptr_cast(&BotPhrase::SetCountCriteria) },
@@ -4286,15 +4289,15 @@ FunctionHook g_FunctionHooks[] =
//{ 0x01D19C70, "_ZN9BotPhrase9RandomizeEv", mfunc_ptr_cast(&BotPhrase::Randomize) }, // NOXREF
//BotPhraseManager
//{ 0x01D19D20, "", mfunc_ptr_cast(&BotPhraseManager::BotPhraseManager) },
- //{ 0x0, "", mfunc_ptr_cast(&BotPhraseManager::~BotPhraseManager) },
- //{ 0x01D19ED0, "_ZN16BotPhraseManager10InitializeEPKci", mfunc_ptr_cast(&BotPhraseManager::Initialize) },
+ //{ 0x01D1A720, "", mfunc_ptr_cast(&BotPhraseManager::~BotPhraseManager) },
+ { 0x01D19ED0, "_ZN16BotPhraseManager10InitializeEPKci", mfunc_ptr_cast(&BotPhraseManager::Initialize) },
{ 0x01D19DA0, "_ZN16BotPhraseManager14OnRoundRestartEv", mfunc_ptr_cast(&BotPhraseManager::OnRoundRestart) },
- //{ 0x0, "_ZN16BotPhraseManager11OnMapChangeEv", mfunc_ptr_cast(&BotPhraseManager::OnMapChange) },
+ //{ 0x01D19D90, "_ZN16BotPhraseManager11OnMapChangeEv", mfunc_ptr_cast(&BotPhraseManager::OnMapChange) }, // NOXREF
//{ 0x01D1A830, "_ZNK16BotPhraseManager8NameToIDEPKc", mfunc_ptr_cast(&BotPhraseManager::NameToID) },
//{ 0x01D1A8A0, "_ZNK16BotPhraseManager8IDToNameEj", mfunc_ptr_cast(&BotPhraseManager::IDToName) },
- //{ 0x01D1A8F0, "_ZNK16BotPhraseManager9GetPhraseEPKc", mfunc_ptr_cast(&BotPhraseManager::GetPhrase) },
- //{ 0x0, "_ZNK16BotPhraseManager8GetPlaceEPKc", mfunc_ptr_cast(&BotPhraseManager::GetPlace) },
- //{ 0x0, "_ZNK16BotPhraseManager8GetPlaceEj", mfunc_ptr_cast(&BotPhraseManager::GetPlace) },
+ { 0x01D1A8F0, "_ZNK16BotPhraseManager9GetPhraseEPKc", mfunc_ptr_cast(&BotPhraseManager::GetPhrase) },
+ //{ 0x01D1A940, "_ZNK16BotPhraseManager8GetPlaceEPKc", mfunc_ptr_cast(&BotPhraseManager::GetPlace) }, // NOXREF
+ { 0x01D1A990, "_ZNK16BotPhraseManager8GetPlaceEj", mfunc_ptr_cast(&BotPhraseManager::GetPlace) },
//{ 0x0, "_ZNK16BotPhraseManager12GetPlaceListEv", mfunc_ptr_cast(&BotPhraseManager::GetPlaceList) },
//{ 0x0, "_ZNK16BotPhraseManager25GetPlaceStatementIntervalEj", mfunc_ptr_cast(&BotPhraseManager::GetPlaceStatementInterval) },
//{ 0x0, "_ZN16BotPhraseManager27ResetPlaceStatementIntervalEj", mfunc_ptr_cast(&BotPhraseManager::ResetPlaceStatementInterval) },
@@ -4303,85 +4306,85 @@ FunctionHook g_FunctionHooks[] =
#endif // _WIN32
//BotStatement
- //{ 0x0, "", mfunc_ptr_cast(&BotStatement::BotStatement) },
- //{ 0x0, "", mfunc_ptr_cast(&BotStatement::~BotStatement) },
- //{ 0x0, "_ZNK12BotStatement10GetChatterEv", mfunc_ptr_cast(&BotStatement::GetChatter) },
- //{ 0x0, "_ZNK12BotStatement8GetOwnerEv", mfunc_ptr_cast(&BotStatement::GetOwner) },
- //{ 0x0, "_ZNK12BotStatement7GetTypeEv", mfunc_ptr_cast(&BotStatement::GetType) },
- //{ 0x0, "_ZNK12BotStatement11IsImportantEv", mfunc_ptr_cast(&BotStatement::IsImportant) },
- //{ 0x0, "_ZNK12BotStatement10HasSubjectEv", mfunc_ptr_cast(&BotStatement::HasSubject) },
- //{ 0x0, "_ZN12BotStatement10SetSubjectEi", mfunc_ptr_cast(&BotStatement::SetSubject) },
- //{ 0x0, "_ZNK12BotStatement10GetSubjectEv", mfunc_ptr_cast(&BotStatement::GetSubject) },
- //{ 0x0, "_ZNK12BotStatement8HasPlaceEv", mfunc_ptr_cast(&BotStatement::HasPlace) },
- //{ 0x0, "_ZNK12BotStatement8GetPlaceEv", mfunc_ptr_cast(&BotStatement::GetPlace) },
- //{ 0x0, "_ZN12BotStatement8SetPlaceEj", mfunc_ptr_cast(&BotStatement::SetPlace) },
- //{ 0x0, "_ZNK12BotStatement8HasCountEv", mfunc_ptr_cast(&BotStatement::HasCount) },
- //{ 0x0, "_ZNK12BotStatement11IsRedundantEPKS_", mfunc_ptr_cast(&BotStatement::IsRedundant) },
- //{ 0x0, "_ZNK12BotStatement10IsObsoleteEv", mfunc_ptr_cast(&BotStatement::IsObsolete) },
- //{ 0x0, "_ZN12BotStatement7ConvertEPKS_", mfunc_ptr_cast(&BotStatement::Convert) },
- //{ 0x0, "_ZN12BotStatement12AppendPhraseEPK9BotPhrase", mfunc_ptr_cast(&BotStatement::AppendPhrase) },
- //{ 0x0, "_ZN12BotStatement12AppendPhraseENS_11ContextTypeE", mfunc_ptr_cast(&BotStatement::AppendPhrase) },
- //{ 0x0, "_ZN12BotStatement12SetStartTimeEf ", mfunc_ptr_cast(&BotStatement::SetStartTime) },
- //{ 0x0, "_ZNK12BotStatement12GetStartTimeEv", mfunc_ptr_cast(&BotStatement::GetStartTime) },
- //{ 0x0, "_ZN12BotStatement12AddConditionENS_13ConditionTypeE", mfunc_ptr_cast(&BotStatement::AddCondition) },
- //{ 0x0, "_ZNK12BotStatement7IsValidEv", mfunc_ptr_cast(&BotStatement::IsValid) },
- //{ 0x01D1AE20, "_ZN12BotStatement6UpdateEv", mfunc_ptr_cast(&BotStatement::Update) },
- //{ 0x0, "_ZNK12BotStatement10IsSpeakingEv", mfunc_ptr_cast(&BotStatement::IsSpeaking) },
- //{ 0x0, "_ZNK12BotStatement12GetTimestampEv", mfunc_ptr_cast(&BotStatement::GetTimestamp) },
- //{ 0x0, "_ZN12BotStatement10AttachMemeEP7BotMeme", mfunc_ptr_cast(&BotStatement::AttachMeme) },
+ //{ 0x01D1A9C0, "", mfunc_ptr_cast(&BotStatement::BotStatement) }, // NOXREF
+ //{ 0x01D1AA20, "", mfunc_ptr_cast(&BotStatement::~BotStatement) }, // NOXREF
+ //{ 0x0, "_ZNK12BotStatement10GetChatterEv", mfunc_ptr_cast(&BotStatement::GetChatter) }, // NOXREF
+ //{ 0x01D1AA30, "_ZNK12BotStatement8GetOwnerEv", mfunc_ptr_cast(&BotStatement::GetOwner) }, // NOXREF
+ //{ 0x01D1AA40, "_ZN12BotStatement10AttachMemeEP7BotMeme", mfunc_ptr_cast(&BotStatement::AttachMeme) }, // NOXREF
+ { 0x01D1AA50, "_ZN12BotStatement12AddConditionENS_13ConditionTypeE", mfunc_ptr_cast(&BotStatement::AddCondition) },
+ //{ 0x01D1AA70, "_ZNK12BotStatement11IsImportantEv", mfunc_ptr_cast(&BotStatement::IsImportant) }, // NOXREF
+ //{ 0x01D1AAB0, "_ZNK12BotStatement7IsValidEv", mfunc_ptr_cast(&BotStatement::IsValid) }, // NOXREF
+ { 0x01D1AB00, "_ZNK12BotStatement11IsRedundantEPKS_", mfunc_ptr_cast(&BotStatement::IsRedundant) },
+ //{ 0x0, "_ZNK12BotStatement7GetTypeEv", mfunc_ptr_cast(&BotStatement::GetType) }, // NOXREF
+ //{ 0x0, "_ZNK12BotStatement10HasSubjectEv", mfunc_ptr_cast(&BotStatement::HasSubject) }, // NOXREF
+ //{ 0x0, "_ZN12BotStatement10SetSubjectEi", mfunc_ptr_cast(&BotStatement::SetSubject) }, // NOXREF
+ //{ 0x0, "_ZNK12BotStatement10GetSubjectEv", mfunc_ptr_cast(&BotStatement::GetSubject) }, // NOXREF
+ //{ 0x01D1AC90, "_ZNK12BotStatement10IsObsoleteEv", mfunc_ptr_cast(&BotStatement::IsObsolete) }, // NOXREF
+ { 0x01D1ACD0, "_ZN12BotStatement7ConvertEPKS_", mfunc_ptr_cast(&BotStatement::Convert) },
+ { 0x01D1ADC0, "_ZN12BotStatement12AppendPhraseEPK9BotPhrase", mfunc_ptr_cast(&BotStatement::AppendPhrase) },
+ //{ 0x01D1ADF0, "_ZN12BotStatement12AppendPhraseENS_11ContextTypeE", mfunc_ptr_cast(&BotStatement::AppendPhrase) }, // NOXREF
+ { 0x01D1AE20, "_ZN12BotStatement6UpdateEv", mfunc_ptr_cast(&BotStatement::Update) },
+ { 0x01D1B2A0, "_ZNK12BotStatement8GetPlaceEv", mfunc_ptr_cast(&BotStatement::GetPlace) }, // NOXREF
+ //{ 0x01D1B2E0, "_ZNK12BotStatement8HasCountEv", mfunc_ptr_cast(&BotStatement::HasCount) }, // NOXREF
+ //{ 0x0, "_ZNK12BotStatement8HasPlaceEv", mfunc_ptr_cast(&BotStatement::HasPlace) }, // NOXREF
+ //{ 0x0, "_ZN12BotStatement8SetPlaceEj", mfunc_ptr_cast(&BotStatement::SetPlace) }, // NOXREF
+ //{ 0x0, "_ZN12BotStatement12SetStartTimeEf ", mfunc_ptr_cast(&BotStatement::SetStartTime) }, // NOXREF
+ //{ 0x0, "_ZNK12BotStatement12GetStartTimeEv", mfunc_ptr_cast(&BotStatement::GetStartTime) }, // NOXREF
+ //{ 0x0, "_ZNK12BotStatement10IsSpeakingEv", mfunc_ptr_cast(&BotStatement::IsSpeaking) }, // NOXREF
+ //{ 0x0, "_ZNK12BotStatement12GetTimestampEv", mfunc_ptr_cast(&BotStatement::GetTimestamp) }, // NOXREF
//BotChatterInterface
- //{ 0x0, "", mfunc_ptr_cast(&BotChatterInterface::BotChatterInterface) },
- //{ 0x0, "", mfunc_ptr_cast(&BotChatterInterface::~BotChatterInterface) },
- //{ 0x0, "_ZN19BotChatterInterface5ResetEv", mfunc_ptr_cast(&BotChatterInterface::Reset) },
- //{ 0x01D1B8E0, "_ZN19BotChatterInterface6UpdateEv", mfunc_ptr_cast(&BotChatterInterface::Update) },
- //{ 0x0, "_ZN19BotChatterInterface7OnEventE13GameEventTypeP11CBaseEntityS2_", mfunc_ptr_cast(&BotChatterInterface::OnEvent) },
- //{ 0x01D1B7E0, "_ZN19BotChatterInterface7OnDeathEv", mfunc_ptr_cast(&BotChatterInterface::OnDeath) },
+ //{ 0x01D1B340, "_ZN19BotChatterInterfaceC2EP6CCSBot", mfunc_ptr_cast(&BotChatterInterface::BotChatterInterface) },
+ //{ 0x01D1B3C0, "", mfunc_ptr_cast(&BotChatterInterface::~BotChatterInterface) },
+ { 0x01D1B3F0, "_ZN19BotChatterInterface5ResetEv", mfunc_ptr_cast(&BotChatterInterface::Reset) },
+ { 0x01D1B8E0, "_ZN19BotChatterInterface6UpdateEv", mfunc_ptr_cast(&BotChatterInterface::Update) },
+ //{ 0x01D1B7D0, "_ZN19BotChatterInterface7OnEventE13GameEventTypeP11CBaseEntityS2_", mfunc_ptr_cast(&BotChatterInterface::OnEvent) }, // PURE
+ { 0x01D1B7E0, "_ZN19BotChatterInterface7OnDeathEv", mfunc_ptr_cast(&BotChatterInterface::OnDeath) },
//{ 0x0, "_ZNK19BotChatterInterface12GetVerbosityEv", mfunc_ptr_cast(&BotChatterInterface::VerbosityType GetVerbosity) },
//{ 0x0, "_ZNK19BotChatterInterface8GetOwnerEv", mfunc_ptr_cast(&BotChatterInterface::GetOwner) },
//{ 0x0, "_ZNK19BotChatterInterface9IsTalkingEv", mfunc_ptr_cast(&BotChatterInterface::IsTalking) },
- //{ 0x0, "_ZN19BotChatterInterface23GetRadioSilenceDurationEv", mfunc_ptr_cast(&BotChatterInterface::GetRadioSilenceDuration) },
- //{ 0x0, "_ZN19BotChatterInterface25ResetRadioSilenceDurationEv", mfunc_ptr_cast(&BotChatterInterface::ResetRadioSilenceDuration) },
- //{ 0x01D1B490, "_ZN19BotChatterInterface12AddStatementEP12BotStatementb", mfunc_ptr_cast(&BotChatterInterface::AddStatement) },
- //{ 0x0, "_ZN19BotChatterInterface15RemoveStatementEP12BotStatement", mfunc_ptr_cast(&BotChatterInterface::RemoveStatement) },
- //{ 0x0, "_ZN19BotChatterInterface18GetActiveStatementEv", mfunc_ptr_cast(&BotChatterInterface::GetActiveStatement) },
+ //{ 0x01D1BDC0, "_ZN19BotChatterInterface23GetRadioSilenceDurationEv", mfunc_ptr_cast(&BotChatterInterface::GetRadioSilenceDuration) }, // NOXREF
+ { 0x01D1BE00, "_ZN19BotChatterInterface25ResetRadioSilenceDurationEv", mfunc_ptr_cast(&BotChatterInterface::ResetRadioSilenceDuration) },
+ { 0x01D1B490, "_ZN19BotChatterInterface12AddStatementEP12BotStatementb", mfunc_ptr_cast(&BotChatterInterface::AddStatement) },
+ { 0x01D1B5E0, "_ZN19BotChatterInterface15RemoveStatementEP12BotStatement", mfunc_ptr_cast(&BotChatterInterface::RemoveStatement) },
+ { 0x01D1BC00, "_ZN19BotChatterInterface18GetActiveStatementEv", mfunc_ptr_cast(&BotChatterInterface::GetActiveStatement) },
//{ 0x0, "_ZNK19BotChatterInterface12GetStatementEv", mfunc_ptr_cast(&BotChatterInterface::GetStatement) },
//{ 0x0, "_ZNK19BotChatterInterface8GetPitchEv", mfunc_ptr_cast(&BotChatterInterface::GetPitch) },
- //{ 0x0, "_ZN19BotChatterInterface3SayEPKcff", mfunc_ptr_cast(&BotChatterInterface::Say) },
- //{ 0x0, "_ZN19BotChatterInterface12AnnouncePlanEPKcj", mfunc_ptr_cast(&BotChatterInterface::AnnouncePlan) },
- //{ 0x0, "_ZN19BotChatterInterface11AffirmativeEv", mfunc_ptr_cast(&BotChatterInterface::Affirmative) },
- //{ 0x0, "_ZN19BotChatterInterface8NegativeEv", mfunc_ptr_cast(&BotChatterInterface::Negative) },
- //{ 0x0, "_ZN19BotChatterInterface12EnemySpottedEv", mfunc_ptr_cast(&BotChatterInterface::EnemySpotted) },
- //{ 0x0, "_ZN19BotChatterInterface13KilledMyEnemyEi", mfunc_ptr_cast(&BotChatterInterface::KilledMyEnemy) },
- //{ 0x0, "_ZN19BotChatterInterface16EnemiesRemainingEv", mfunc_ptr_cast(&BotChatterInterface::EnemiesRemaining) },
- //{ 0x0, "_ZN19BotChatterInterface5ClearEj", mfunc_ptr_cast(&BotChatterInterface::Clear) },
- //{ 0x0, "_ZN19BotChatterInterface8ReportInEv", mfunc_ptr_cast(&BotChatterInterface::ReportIn) },
- //{ 0x0, "_ZN19BotChatterInterface11ReportingInEv", mfunc_ptr_cast(&BotChatterInterface::ReportingIn) },
- //{ 0x01D1C6D0, "_ZN19BotChatterInterface10NeedBackupEv", mfunc_ptr_cast(&BotChatterInterface::NeedBackup) },
- //{ 0x0, "_ZN19BotChatterInterface10PinnedDownEv", mfunc_ptr_cast(&BotChatterInterface::PinnedDown) },
- //{ 0x0, "_ZN19BotChatterInterface6ScaredEv", mfunc_ptr_cast(&BotChatterInterface::Scared) },
- //{ 0x0, "_ZN19BotChatterInterface10HeardNoiseEPK6Vector", mfunc_ptr_cast(&BotChatterInterface::HeardNoise) },
- //{ 0x0, "_ZN19BotChatterInterface19TheyPickedUpTheBombEv", mfunc_ptr_cast(&BotChatterInterface::TheyPickedUpTheBomb) },
- //{ 0x0, "_ZN19BotChatterInterface19GoingToPlantTheBombEj", mfunc_ptr_cast(&BotChatterInterface::GoingToPlantTheBomb) },
- //{ 0x0, "_ZN19BotChatterInterface13BombsiteClearEi", mfunc_ptr_cast(&BotChatterInterface::BombsiteClear) },
- //{ 0x0, "_ZN19BotChatterInterface16FoundPlantedBombEi", mfunc_ptr_cast(&BotChatterInterface::FoundPlantedBomb) },
- //{ 0x0, "_ZN19BotChatterInterface15PlantingTheBombEj", mfunc_ptr_cast(&BotChatterInterface::PlantingTheBomb) },
- //{ 0x0, "_ZN19BotChatterInterface13SpottedBomberEP11CBasePlayer", mfunc_ptr_cast(&BotChatterInterface::SpottedBomber) },
- //{ 0x0, "_ZN19BotChatterInterface16SpottedLooseBombEP11CBaseEntity", mfunc_ptr_cast(&BotChatterInterface::SpottedLooseBomb) },
- //{ 0x0, "_ZN19BotChatterInterface17GuardingLooseBombEP11CBaseEntity", mfunc_ptr_cast(&BotChatterInterface::GuardingLooseBomb) },
- //{ 0x0, "_ZN19BotChatterInterface19RequestBombLocationEv", mfunc_ptr_cast(&BotChatterInterface::RequestBombLocation) },
- //{ 0x0, "_ZN19BotChatterInterface16GuardingHostagesEjb", mfunc_ptr_cast(&BotChatterInterface::GuardingHostages) },
- //{ 0x0, "_ZN19BotChatterInterface25GuardingHostageEscapeZoneEb", mfunc_ptr_cast(&BotChatterInterface::GuardingHostageEscapeZone) },
- //{ 0x0, "_ZN19BotChatterInterface18HostagesBeingTakenEv", mfunc_ptr_cast(&BotChatterInterface::HostagesBeingTaken) },
- //{ 0x0, "_ZN19BotChatterInterface13HostagesTakenEv", mfunc_ptr_cast(&BotChatterInterface::HostagesTaken) },
- //{ 0x0, "_ZN19BotChatterInterface17TalkingToHostagesEv", mfunc_ptr_cast(&BotChatterInterface::TalkingToHostages) },
- //{ 0x0, "_ZN19BotChatterInterface17EscortingHostagesEv", mfunc_ptr_cast(&BotChatterInterface::EscortingHostages) },
- //{ 0x0, "_ZN19BotChatterInterface11HostageDownEv", mfunc_ptr_cast(&BotChatterInterface::HostageDown) },
- //{ 0x0, "_ZN19BotChatterInterface12CelebrateWinEv", mfunc_ptr_cast(&BotChatterInterface::CelebrateWin) },
- //{ 0x0, "_ZN19BotChatterInterface9EncourageEPKcff", mfunc_ptr_cast(&BotChatterInterface::Encourage) },
- //{ 0x0, "_ZN19BotChatterInterface12KilledFriendEv", mfunc_ptr_cast(&BotChatterInterface::KilledFriend) },
- //{ 0x0, "_ZN19BotChatterInterface12FriendlyFireEv", mfunc_ptr_cast(&BotChatterInterface::FriendlyFire) },
- //{ 0x01D1B630, "_ZN19BotChatterInterface13ReportEnemiesEv", mfunc_ptr_cast(&BotChatterInterface::ReportEnemies) },
- //{ 0x0, "_ZNK19BotChatterInterface11ShouldSpeakEv", mfunc_ptr_cast(&BotChatterInterface::ShouldSpeak) },
+ { 0x01D1F890, "_ZN19BotChatterInterface3SayEPKcff", mfunc_ptr_cast(&BotChatterInterface::Say) },
+ { 0x01D1E100, "_ZN19BotChatterInterface12AnnouncePlanEPKcj", mfunc_ptr_cast(&BotChatterInterface::AnnouncePlan) },
+ { 0x01D1CDE0, "_ZN19BotChatterInterface11AffirmativeEv", mfunc_ptr_cast(&BotChatterInterface::Affirmative) },
+ { 0x01D1CED0, "_ZN19BotChatterInterface8NegativeEv", mfunc_ptr_cast(&BotChatterInterface::Negative) },
+ //{ 0x01D1BE20, "_ZN19BotChatterInterface12EnemySpottedEv", mfunc_ptr_cast(&BotChatterInterface::EnemySpotted) }, // NOXREF
+ { 0x01D1CBE0, "_ZN19BotChatterInterface13KilledMyEnemyEi", mfunc_ptr_cast(&BotChatterInterface::KilledMyEnemy) },
+ { 0x01D1CCF0, "_ZN19BotChatterInterface16EnemiesRemainingEv", mfunc_ptr_cast(&BotChatterInterface::EnemiesRemaining) },
+ //{ 0x01D1BF30, "_ZN19BotChatterInterface5ClearEj", mfunc_ptr_cast(&BotChatterInterface::Clear) }, // NOXREF
+ //{ 0x01D1C050, "_ZN19BotChatterInterface8ReportInEv", mfunc_ptr_cast(&BotChatterInterface::ReportIn) }, // NOXREF
+ { 0x01D1C170, "_ZN19BotChatterInterface11ReportingInEv", mfunc_ptr_cast(&BotChatterInterface::ReportingIn) },
+ { 0x01D1C6D0, "_ZN19BotChatterInterface10NeedBackupEv", mfunc_ptr_cast(&BotChatterInterface::NeedBackup) },
+ { 0x01D1C910, "_ZN19BotChatterInterface10PinnedDownEv", mfunc_ptr_cast(&BotChatterInterface::PinnedDown) },
+ { 0x01D1DD00, "_ZN19BotChatterInterface6ScaredEv", mfunc_ptr_cast(&BotChatterInterface::Scared) },
+ { 0x01D1CA90, "_ZN19BotChatterInterface10HeardNoiseEPK6Vector", mfunc_ptr_cast(&BotChatterInterface::HeardNoise) },
+ { 0x01D1D240, "_ZN19BotChatterInterface19TheyPickedUpTheBombEv", mfunc_ptr_cast(&BotChatterInterface::TheyPickedUpTheBomb) },
+ { 0x01D1CFC0, "_ZN19BotChatterInterface19GoingToPlantTheBombEj", mfunc_ptr_cast(&BotChatterInterface::GoingToPlantTheBomb) },
+ { 0x01D1DA40, "_ZN19BotChatterInterface13BombsiteClearEi", mfunc_ptr_cast(&BotChatterInterface::BombsiteClear) },
+ { 0x01D1DBB0, "_ZN19BotChatterInterface16FoundPlantedBombEi", mfunc_ptr_cast(&BotChatterInterface::FoundPlantedBomb) },
+ { 0x01D1D100, "_ZN19BotChatterInterface15PlantingTheBombEj", mfunc_ptr_cast(&BotChatterInterface::PlantingTheBomb) },
+ { 0x01D1D3A0, "_ZN19BotChatterInterface13SpottedBomberEP11CBasePlayer", mfunc_ptr_cast(&BotChatterInterface::SpottedBomber) },
+ { 0x01D1D580, "_ZN19BotChatterInterface16SpottedLooseBombEP11CBaseEntity", mfunc_ptr_cast(&BotChatterInterface::SpottedLooseBomb) },
+ //{ 0x01D1D770, "_ZN19BotChatterInterface17GuardingLooseBombEP11CBaseEntity", mfunc_ptr_cast(&BotChatterInterface::GuardingLooseBomb) }, // NOXREF
+ { 0x01D1D920, "_ZN19BotChatterInterface19RequestBombLocationEv", mfunc_ptr_cast(&BotChatterInterface::RequestBombLocation) },
+ { 0x01D1E230, "_ZN19BotChatterInterface16GuardingHostagesEjb", mfunc_ptr_cast(&BotChatterInterface::GuardingHostages) },
+ { 0x01D1E470, "_ZN19BotChatterInterface25GuardingHostageEscapeZoneEb", mfunc_ptr_cast(&BotChatterInterface::GuardingHostageEscapeZone) },
+ { 0x01D1E6B0, "_ZN19BotChatterInterface18HostagesBeingTakenEv", mfunc_ptr_cast(&BotChatterInterface::HostagesBeingTaken) },
+ { 0x01D1E7C0, "_ZN19BotChatterInterface13HostagesTakenEv", mfunc_ptr_cast(&BotChatterInterface::HostagesTaken) },
+ //{ 0x01D1E8C0, "_ZN19BotChatterInterface17TalkingToHostagesEv", mfunc_ptr_cast(&BotChatterInterface::TalkingToHostages) }, // NOXREF
+ { 0x01D1E8D0, "_ZN19BotChatterInterface17EscortingHostagesEv", mfunc_ptr_cast(&BotChatterInterface::EscortingHostages) },
+ //{ 0x01D1E9F0, "_ZN19BotChatterInterface11HostageDownEv", mfunc_ptr_cast(&BotChatterInterface::HostageDown) }, // NOXREF
+ { 0x01D1DE20, "_ZN19BotChatterInterface12CelebrateWinEv", mfunc_ptr_cast(&BotChatterInterface::CelebrateWin) },
+ { 0x01D1EAF0, "_ZN19BotChatterInterface9EncourageEPKcff", mfunc_ptr_cast(&BotChatterInterface::Encourage) },
+ { 0x01D1EC00, "_ZN19BotChatterInterface12KilledFriendEv", mfunc_ptr_cast(&BotChatterInterface::KilledFriend) },
+ { 0x01D1ED00, "_ZN19BotChatterInterface12FriendlyFireEv", mfunc_ptr_cast(&BotChatterInterface::FriendlyFire) },
+ { 0x01D1B630, "_ZN19BotChatterInterface13ReportEnemiesEv", mfunc_ptr_cast(&BotChatterInterface::ReportEnemies) },
+ //{ 0x01D1BD70, "_ZNK19BotChatterInterface11ShouldSpeakEv", mfunc_ptr_cast(&BotChatterInterface::ShouldSpeak) }, // NOXREF
{ 0x01D18C30, "_Z20GetRandomSpotAtPlacej", (size_t)&GetRandomSpotAtPlace },
#endif // Bot_Region
@@ -4392,21 +4395,21 @@ FunctionHook g_FunctionHooks[] =
{ 0x01D365E0, "_Z18UTIL_ClientsInGamev", (size_t)&UTIL_ClientsInGame },
{ 0x01D36690, "_Z24UTIL_ActivePlayersInGamev", (size_t)&UTIL_ActivePlayersInGame },
{ 0x01D36760, "_Z17UTIL_HumansInGameb", (size_t)&UTIL_HumansInGame },
- //{ 0x0, "_Z17UTIL_HumansOnTeamib", (size_t)&UTIL_HumansOnTeam },
- //{ 0x0, "_Z15UTIL_BotsInGamev", (size_t)&UTIL_BotsInGame },
+ { 0x01D36850, "_Z17UTIL_HumansOnTeamib", (size_t)&UTIL_HumansOnTeam },
+ { 0x01D36940, "_Z15UTIL_BotsInGamev", (size_t)&UTIL_BotsInGame },
{ 0x01D36A00, "_Z20UTIL_KickBotFromTeam8TeamName", (size_t)&UTIL_KickBotFromTeam },
- //{ 0x0, "_Z18UTIL_IsTeamAllBotsi", (size_t)&UTIL_IsTeamAllBots },
+ { 0x01D36C10, "_Z18UTIL_IsTeamAllBotsi", (size_t)&UTIL_IsTeamAllBots },
{ 0x01D36CE0, "_Z21UTIL_GetClosestPlayerPK6VectorPf", mfunc_ptr_cast