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 ## 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(&UTIL_GetClosestPlayer) }, - //{ 0x0, "_Z21UTIL_GetClosestPlayerPK6VectoriPf", mfunc_ptr_cast(&UTIL_GetClosestPlayer) }, + { 0x01D36E30, "_Z21UTIL_GetClosestPlayerPK6VectoriPf", mfunc_ptr_cast(&UTIL_GetClosestPlayer) }, //{ 0x01D36F90, "_Z17UTIL_GetBotPrefixv", (size_t)&UTIL_GetBotPrefix }, // NOXREF { 0x01D36FA0, "_Z24UTIL_ConstructBotNetNamePciPK10BotProfile", (size_t)&UTIL_ConstructBotNetName }, - //{ 0x0, "_Z20UTIL_IsVisibleToTeamRK6Vectorif", (size_t)&UTIL_IsVisibleToTeam }, + { 0x01D37000, "_Z20UTIL_IsVisibleToTeamRK6Vectorif", (size_t)&UTIL_IsVisibleToTeam }, { 0x01D37190, "_Z19UTIL_GetLocalPlayerv", (size_t)&UTIL_GetLocalPlayer }, - //{ 0x0, "_Z18UTIL_ComputeOriginP9entvars_s", mfunc_ptr_cast(&UTIL_ComputeOrigin) }, - //{ 0x0, "_Z18UTIL_ComputeOriginP11CBaseEntity", mfunc_ptr_cast(&UTIL_ComputeOrigin) }, - //{ 0x0, "_Z18UTIL_ComputeOriginP7edict_s", mfunc_ptr_cast(&UTIL_ComputeOrigin) }, - //{ 0x0, "_Z20UTIL_DrawBeamFromEnti6Vectorihhh", (size_t)&UTIL_DrawBeamFromEnt }, - //{ 0x01D37480, "_Z19UTIL_DrawBeamPoints6VectorS_ihhh", (size_t)&UTIL_DrawBeamPoints }, + //{ 0x01D371B0, "_Z18UTIL_ComputeOriginP9entvars_s", mfunc_ptr_cast(&UTIL_ComputeOrigin) }, // NOXREF + //{ 0x01D37250, "_Z18UTIL_ComputeOriginP11CBaseEntity", mfunc_ptr_cast(&UTIL_ComputeOrigin) }, // NOXREF + //{ 0x01D37300, "_Z18UTIL_ComputeOriginP7edict_s", mfunc_ptr_cast(&UTIL_ComputeOrigin) }, // NOXREF + //{ 0x01D373B0, "_Z20UTIL_DrawBeamFromEnti6Vectorihhh", (size_t)&UTIL_DrawBeamFromEnt }, // NOXREF + { 0x01D37480, "_Z19UTIL_DrawBeamPoints6VectorS_ihhh", (size_t)&UTIL_DrawBeamPoints }, { 0x01D375D0, "_Z11BotPrecachev", (size_t)&BotPrecache }, { 0x01D37570, "_Z12CONSOLE_ECHOPcz", (size_t)&CONSOLE_ECHO }, //{ 0x01D375A0, "_Z19CONSOLE_ECHO_LOGGEDPcz", (size_t)&CONSOLE_ECHO_LOGGED }, // NOXREF @@ -4719,7 +4722,7 @@ FunctionHook g_FunctionHooks[] = #endif // Tutor_CS_Region -#ifndef GameShr_BotProfile_Region +#ifndef Bot_Profile //BotProfile //{ 0x0, "", mfunc_ptr_cast(&BotProfile::BotProfile) }, // NOXREF @@ -4727,29 +4730,26 @@ FunctionHook g_FunctionHooks[] = //{ 0x0, "_ZNK10BotProfile13GetAggressionEv", mfunc_ptr_cast(&BotProfile::GetAggression) }, // NOXREF //{ 0x0, "_ZNK10BotProfile8GetSkillEv", mfunc_ptr_cast(&BotProfile::GetSkill) }, // NOXREF //{ 0x0, "_ZNK10BotProfile11GetTeamworkEv", mfunc_ptr_cast(&BotProfile::GetTeamwork) }, // NOXREF - //{ 0x0, "_ZNK10BotProfile19GetWeaponPreferenceEi", mfunc_ptr_cast(&BotProfile::GetWeaponPreference) }, // NOXREF - //{ 0x0, "_ZNK10BotProfile27GetWeaponPreferenceAsStringEi", mfunc_ptr_cast(&BotProfile::GetWeaponPreferenceAsString) }, + { 0x01D34DC0, "_ZNK10BotProfile27GetWeaponPreferenceAsStringEi", mfunc_ptr_cast(&BotProfile::GetWeaponPreferenceAsString) }, //{ 0x0, "_ZNK10BotProfile24GetWeaponPreferenceCountEv", mfunc_ptr_cast(&BotProfile::GetWeaponPreferenceCount) }, // NOXREF - //{ 0x0, "_ZNK10BotProfile20HasPrimaryPreferenceEv", mfunc_ptr_cast(&BotProfile::HasPrimaryPreference) }, - //{ 0x0, "_ZNK10BotProfile19HasPistolPreferenceEv", mfunc_ptr_cast(&BotProfile::HasPistolPreference) }, + { 0x01D34DF0, "_ZNK10BotProfile20HasPrimaryPreferenceEv", mfunc_ptr_cast(&BotProfile::HasPrimaryPreference) }, + { 0x01D34E50, "_ZNK10BotProfile19HasPistolPreferenceEv", mfunc_ptr_cast(&BotProfile::HasPistolPreference) }, //{ 0x0, "_ZNK10BotProfile7GetCostEv", mfunc_ptr_cast(&BotProfile::GetCost) }, // NOXREF //{ 0x0, "_ZNK10BotProfile7GetSkinEv", mfunc_ptr_cast(&BotProfile::GetSkin) }, // NOXREF - //{ 0x0, "_ZNK10BotProfile12IsDifficultyE17BotDifficultyType", mfunc_ptr_cast(&BotProfile::IsDifficulty) }, - + //{ 0x0, "_ZNK10BotProfile12IsDifficultyE17BotDifficultyType", mfunc_ptr_cast(&BotProfile::IsDifficulty) }, // NOXREF //{ 0x0, "_ZNK10BotProfile13GetVoicePitchEv", mfunc_ptr_cast(&BotProfile::GetVoicePitch) }, // NOXREF //{ 0x0, "_ZNK10BotProfile15GetReactionTimeEv", mfunc_ptr_cast(&BotProfile::GetReactionTime) }, // NOXREF //{ 0x0, "_ZNK10BotProfile14GetAttackDelayEv", mfunc_ptr_cast(&BotProfile::GetAttackDelay) }, // NOXREF //{ 0x0, "_ZNK10BotProfile12GetVoiceBankEv", mfunc_ptr_cast(&BotProfile::GetVoiceBank) }, // NOXREF - { 0x01D34E90, "_ZNK10BotProfile14IsValidForTeamE18BotProfileTeamType", mfunc_ptr_cast(&BotProfile::IsValidForTeam) }, //{ 0x0, "_ZNK10BotProfile15PrefersSilencerEv", mfunc_ptr_cast(&BotProfile::PrefersSilencer) }, // NOXREF //{ 0x0, "_ZN10BotProfile7InheritEPKS_S1_", mfunc_ptr_cast(&BotProfile::Inherit) }, //BotProfileManager - //{ 0x0, "_ZN17BotProfileManagerC2Ev", mfunc_ptr_cast(&BotProfileManager::BotProfileManager) }, // NOXREF - //{ 0x0, "_ZN17BotProfileManagerD2Ev", mfunc_ptr_cast(&BotProfileManager::~BotProfileManager) }, // NOXREF - //{ 0x0, "_ZN17BotProfileManager4InitEPKcPj", mfunc_ptr_cast(&BotProfileManager::Init) }, - //{ 0x0, "_ZN17BotProfileManager5ResetEv", mfunc_ptr_cast(&BotProfileManager::Reset) }, + //{ 0x01D34EC0, "_ZN17BotProfileManagerC2Ev", mfunc_ptr_cast(&BotProfileManager::BotProfileManager) }, + //{ 0x01D35C30, "_ZN17BotProfileManagerD2Ev", mfunc_ptr_cast(&BotProfileManager::~BotProfileManager) }, + { 0x01D34F20, "_ZN17BotProfileManager4InitEPKcPj", mfunc_ptr_cast(&BotProfileManager::Init) }, + { 0x01D35CE0, "_ZN17BotProfileManager5ResetEv", mfunc_ptr_cast(&BotProfileManager::Reset) }, //{ 0x0, "_ZNK17BotProfileManager10GetProfileEPKc18BotProfileTeamType", mfunc_ptr_cast(&BotProfileManager::GetProfile) }, // NOXREF //{ 0x0, "_ZNK17BotProfileManager14GetProfileListEv", mfunc_ptr_cast(&BotProfileManager::GetProfileList) }, // NOXREF { 0x01D36070, "_ZNK17BotProfileManager16GetRandomProfileE17BotDifficultyType18BotProfileTeamType", mfunc_ptr_cast(&BotProfileManager::GetRandomProfile) }, @@ -4758,9 +4758,9 @@ FunctionHook g_FunctionHooks[] = { 0x01D35DB0, "_ZN17BotProfileManager18GetCustomSkinFnameEi", mfunc_ptr_cast(&BotProfileManager::GetCustomSkinFname) }, //{ 0x01D35DF0, "_ZN17BotProfileManager18GetCustomSkinIndexEPKcS1_", mfunc_ptr_cast(&BotProfileManager::GetCustomSkinIndex) }, // NOXREF //{ 0x0, "_ZNK17BotProfileManager13GetVoiceBanksEv", mfunc_ptr_cast(&BotProfileManager::GetVoiceBanks) }, // NOXREF - //{ 0x0, "_ZN17BotProfileManager18FindVoiceBankIndexEPKc", mfunc_ptr_cast(&BotProfileManager::FindVoiceBankIndex) }, + { 0x01D35E60, "_ZN17BotProfileManager18FindVoiceBankIndexEPKc", mfunc_ptr_cast(&BotProfileManager::FindVoiceBankIndex) }, -#endif // GameShr_BotProfile_Region +#endif // Bot_Profile #ifndef VoiceManager_Region @@ -4791,6 +4791,7 @@ FunctionHook g_FunctionHooks[] = { 0x01D4EA30, "", mfunc_ptr_cast(&Vector::Normalize) }, { 0x01DCB800, "", mfunc_ptr_cast(&Vector::operator==) }, { 0x01D130D0, "", mfunc_ptr_cast(&Vector::IsLengthLessThan) }, + { 0x01D18AC0, "", mfunc_ptr_cast(&Vector::IsLengthGreaterThan) }, { 0x01D34D90, "", mfunc_ptr_cast(&DotProduct) }, #endif // _WIN32 @@ -5002,7 +5003,7 @@ FunctionHook g_FunctionHooks[] = { 0x01D43360, "_ZN12CNavAreaGrid10InitializeEffff", mfunc_ptr_cast(&CNavAreaGrid::Initialize) }, { 0x01D43390, "_ZN12CNavAreaGrid10AddNavAreaEP8CNavArea", mfunc_ptr_cast(&CNavAreaGrid::AddNavArea) }, { 0x01D43560, "_ZN12CNavAreaGrid13RemoveNavAreaEP8CNavArea", mfunc_ptr_cast(&CNavAreaGrid::RemoveNavArea) }, - { 0x01D43710, "_ZNK12CNavAreaGrid10GetNavAreaEPK6Vectorf", mfunc_ptr_cast(&CNavAreaGrid::GetNavArea) }, // Used refs + { 0x01D43710, "_ZNK12CNavAreaGrid10GetNavAreaEPK6Vectorf", mfunc_ptr_cast(&CNavAreaGrid::GetNavArea) }, { 0x01D43860, "_ZNK12CNavAreaGrid17GetNearestNavAreaEPK6Vectorb", mfunc_ptr_cast(&CNavAreaGrid::GetNearestNavArea) }, { 0x01D439C0, "_ZNK12CNavAreaGrid14GetNavAreaByIDEj", mfunc_ptr_cast(&CNavAreaGrid::GetNavAreaByID) }, { 0x01D439F0, "_ZNK12CNavAreaGrid8GetPlaceEPK6Vector", mfunc_ptr_cast(&CNavAreaGrid::GetPlace) }, @@ -5031,7 +5032,14 @@ FunctionHook g_FunctionHooks[] = { 0x01D3A060, "_Z20DestroyNavigationMapv", (size_t)&DestroyNavigationMap }, { 0x01D3A210, "_Z20StripNavigationAreasv", (size_t)&StripNavigationAreas }, -#ifdef _WIN32 +#ifdef _WIN32 + { 0x01D13120, "_ZNK8CNavArea15GetAdjacentAreaE10NavDirTypei", mfunc_ptr_cast(&CNavArea::GetAdjacentArea) }, + { 0x01D2B2A0, "_ZN8CNavArea11PopOpenListEv", mfunc_ptr_cast(&CNavArea::PopOpenList) }, + { 0x01D2B2C0, "_ZNK8CNavArea8IsClosedEv", mfunc_ptr_cast(&CNavArea::IsClosed) }, + + { 0x01D224C0, "", mfunc_ptr_cast(&SnapToGrid) }, + { 0x01D22460, "", (size_t)&AddDirectionVector }, + { 0x01D13150, "", (size_t)&AddAreaToOpenList }, { 0x01D3A870, "", (size_t)&FindFirstAreaInDirection }, { 0x01D3AD20, "", (size_t)&IsAreaRoughlySquare }, { 0x01D2B030, "", (size_t)&IsEntityWalkable }, @@ -5055,10 +5063,11 @@ FunctionHook g_FunctionHooks[] = //HostageState //{ 0x01D50DA0, "", mfunc_ptr_cast(&CHostageImprov::CHostageImprov) }, + //{ 0x01D56E30, "", mfunc_ptr_cast(&CHostageImprov::~CHostageImprov) }, //virtual func - //{ 0x0, "_ZN14CHostageImprov15OnMoveToSuccessERK6Vector", mfunc_ptr_cast(&CHostageImprov::OnMoveToSuccess_) }, + //{ 0x01D56D70, "_ZN14CHostageImprov15OnMoveToSuccessERK6Vector", mfunc_ptr_cast(&CHostageImprov::OnMoveToSuccess_) }, { 0x01D562D0, "_ZN14CHostageImprov15OnMoveToFailureERK6VectorN12IImprovEvent17MoveToFailureTypeE", mfunc_ptr_cast(&CHostageImprov::OnMoveToFailure_) }, - //{ 0x0, "_ZN14CHostageImprov8OnInjuryEf", mfunc_ptr_cast(&CHostageImprov::OnInjury_) }, + //{ 0x01D56D80, "_ZN14CHostageImprov8OnInjuryEf", mfunc_ptr_cast(&CHostageImprov::OnInjury_) }, { 0x01D51040, "_ZNK14CHostageImprov7IsAliveEv", mfunc_ptr_cast(&CHostageImprov::IsAlive_) }, { 0x01D51060, "_ZN14CHostageImprov6MoveToERK6Vector", mfunc_ptr_cast(&CHostageImprov::MoveTo_) }, { 0x01D51240, "_ZN14CHostageImprov6LookAtERK6Vector", mfunc_ptr_cast(&CHostageImprov::LookAt_) }, @@ -5066,15 +5075,15 @@ FunctionHook g_FunctionHooks[] = { 0x01D51280, "_ZN14CHostageImprov6FaceToERK6Vector", mfunc_ptr_cast(&CHostageImprov::FaceTo_) }, { 0x01D512B0, "_ZN14CHostageImprov11ClearFaceToEv", mfunc_ptr_cast(&CHostageImprov::ClearFaceTo_) }, { 0x01D51AC0, "_ZNK14CHostageImprov12IsAtMoveGoalEf", mfunc_ptr_cast(&CHostageImprov::IsAtMoveGoal_) }, - //{ 0x0, "_ZNK14CHostageImprov9HasLookAtEv", mfunc_ptr_cast(&CHostageImprov::HasLookAt_) }, // DEFAULT - //{ 0x0, "_ZNK14CHostageImprov9HasFaceToEv", mfunc_ptr_cast(&CHostageImprov::HasFaceTo_) }, // DEFAULT + //{ 0x01D56C20, "_ZNK14CHostageImprov9HasLookAtEv", mfunc_ptr_cast(&CHostageImprov::HasLookAt_) }, // DEFAULT + //{ 0x01D56C30, "_ZNK14CHostageImprov9HasFaceToEv", mfunc_ptr_cast(&CHostageImprov::HasFaceTo_) }, // DEFAULT { 0x01D51B20, "_ZNK14CHostageImprov12IsAtFaceGoalEv", mfunc_ptr_cast(&CHostageImprov::IsAtFaceGoal_) }, { 0x01D51B30, "_ZNK14CHostageImprov16IsFriendInTheWayERK6Vector", mfunc_ptr_cast(&CHostageImprov::IsFriendInTheWay_) }, { 0x01D51CB0, "_ZNK14CHostageImprov16IsFriendInTheWayEP11CBaseEntityRK6Vector", mfunc_ptr_cast(&CHostageImprov::IsFriendInTheWay_) }, - //{ 0x0, "_ZN14CHostageImprov11MoveForwardEv", mfunc_ptr_cast(&CHostageImprov::MoveForward_) }, // DEFAULT - //{ 0x0, "_ZN14CHostageImprov12MoveBackwardEv", mfunc_ptr_cast(&CHostageImprov::MoveBackward_) }, // DEFAULT - //{ 0x0, "_ZN14CHostageImprov10StrafeLeftEv", mfunc_ptr_cast(&CHostageImprov::StrafeLeft_) }, // DEFAULT - //{ 0x0, "_ZN14CHostageImprov11StrafeRightEv", mfunc_ptr_cast(&CHostageImprov::StrafeRight_) }, + //{ 0x01D56C40, "_ZN14CHostageImprov11MoveForwardEv", mfunc_ptr_cast(&CHostageImprov::MoveForward_) }, // DEFAULT + //{ 0x01D56C50, "_ZN14CHostageImprov12MoveBackwardEv", mfunc_ptr_cast(&CHostageImprov::MoveBackward_) }, // DEFAULT + //{ 0x01D56C60, "_ZN14CHostageImprov10StrafeLeftEv", mfunc_ptr_cast(&CHostageImprov::StrafeLeft_) }, // DEFAULT + //{ 0x01D56C70, "_ZN14CHostageImprov11StrafeRightEv", mfunc_ptr_cast(&CHostageImprov::StrafeRight_) }, { 0x01D52260, "_ZN14CHostageImprov4JumpEv", mfunc_ptr_cast(&CHostageImprov::Jump_) }, { 0x01D56710, "_ZN14CHostageImprov6CrouchEv", mfunc_ptr_cast(&CHostageImprov::Crouch_) }, { 0x01D567A0, "_ZN14CHostageImprov7StandUpEv", mfunc_ptr_cast(&CHostageImprov::StandUp_) }, @@ -5085,13 +5094,13 @@ FunctionHook g_FunctionHooks[] = { 0x01D52350, "_ZN14CHostageImprov3RunEv", mfunc_ptr_cast(&CHostageImprov::Run_) }, { 0x01D52360, "_ZN14CHostageImprov4WalkEv", mfunc_ptr_cast(&CHostageImprov::Walk_) }, { 0x01D52380, "_ZN14CHostageImprov4StopEv", mfunc_ptr_cast(&CHostageImprov::Stop_) }, - //{ 0x0, "_ZNK14CHostageImprov12GetMoveAngleEv", mfunc_ptr_cast(&CHostageImprov::GetMoveAngle_) }, // DEFAULT - //{ 0x0, "_ZNK14CHostageImprov12GetFaceAngleEv", mfunc_ptr_cast(&CHostageImprov::GetFaceAngle_) }, // DEFAULT + //{ 0x01D56C80, "_ZNK14CHostageImprov12GetMoveAngleEv", mfunc_ptr_cast(&CHostageImprov::GetMoveAngle_) }, // DEFAULT + //{ 0x01D56C90, "_ZNK14CHostageImprov12GetFaceAngleEv", mfunc_ptr_cast(&CHostageImprov::GetFaceAngle_) }, // DEFAULT { 0x01D523F0, "_ZNK14CHostageImprov7GetFeetEv", mfunc_ptr_cast(&CHostageImprov::GetFeet_) }, { 0x01D52400, "_ZNK14CHostageImprov11GetCentroidEv", mfunc_ptr_cast(&CHostageImprov::GetCentroid_) }, { 0x01D52430, "_ZNK14CHostageImprov7GetEyesEv", mfunc_ptr_cast(&CHostageImprov::GetEyes_) }, - //{ 0x0, "_ZNK14CHostageImprov9IsRunningEv", mfunc_ptr_cast(&CHostageImprov::IsRunning_) }, // DEFAULT - //{ 0x0, "_ZNK14CHostageImprov9IsWalkingEv", mfunc_ptr_cast(&CHostageImprov::IsWalking_) }, // DEFAULT + //{ 0x01D56CA0, "_ZNK14CHostageImprov9IsRunningEv", mfunc_ptr_cast(&CHostageImprov::IsRunning_) }, // DEFAULT + //{ 0x01D56CB0, "_ZNK14CHostageImprov9IsWalkingEv", mfunc_ptr_cast(&CHostageImprov::IsWalking_) }, // DEFAULT //{ 0x01D56CC0, "_ZNK14CHostageImprov9IsStoppedEv", mfunc_ptr_cast(&CHostageImprov::IsStopped_) }, // DEFAULT //{ 0x01D56CD0, "_ZNK14CHostageImprov11IsCrouchingEv", mfunc_ptr_cast(&CHostageImprov::IsCrouching_) }, // DEFAULT //{ 0x01D56CE0, "_ZNK14CHostageImprov9IsJumpingEv", mfunc_ptr_cast(&CHostageImprov::IsJumping_) }, // DEFAULT @@ -5226,13 +5235,13 @@ FunctionHook g_FunctionHooks[] = { 0x01D4BC30, "_ZN19HostageRetreatState7OnEnterEP14CHostageImprov", mfunc_ptr_cast(&HostageRetreatState::OnEnter_) }, { 0x01D4BC50, "_ZN19HostageRetreatState8OnUpdateEP14CHostageImprov", mfunc_ptr_cast(&HostageRetreatState::OnUpdate_) }, //{ 0x01D4BDB0, "_ZN19HostageRetreatState6OnExitEP14CHostageImprov", mfunc_ptr_cast(&HostageRetreatState::OnExit_) }, // PURE - //{ 0x01D56BD0, "_ZNK19HostageRetreatState7GetNameEv", mfunc_ptr_cast(&HostageRetreatState::GetName_) }, + //{ 0x01D56BD0, "_ZNK19HostageRetreatState7GetNameEv", mfunc_ptr_cast(&HostageRetreatState::GetName_) }, // DEFAULT //HostageFollowState //virtual func { 0x01D4AC70, "_ZN18HostageFollowState7OnEnterEP14CHostageImprov", mfunc_ptr_cast(&HostageFollowState::OnEnter_) }, { 0x01D4ACF0, "_ZN18HostageFollowState8OnUpdateEP14CHostageImprov", mfunc_ptr_cast(&HostageFollowState::OnUpdate_) }, { 0x01D4B320, "_ZN18HostageFollowState6OnExitEP14CHostageImprov", mfunc_ptr_cast(&HostageFollowState::OnExit_) }, - //{ 0x0, "_ZNK18HostageFollowState7GetNameEv", mfunc_ptr_cast(&HostageFollowState::GetName_) }, + //{ 0x01D56BE0, "_ZNK18HostageFollowState7GetNameEv", mfunc_ptr_cast(&HostageFollowState::GetName_) }, { 0x01D4B330, "_ZN18HostageFollowState25UpdateStationaryAnimationEP14CHostageImprov", mfunc_ptr_cast(&HostageFollowState::UpdateStationaryAnimation_) }, //non-virtual func //{ 0x0, "_ZN18HostageFollowState9SetLeaderEP11CBaseEntity", mfunc_ptr_cast(&HostageFollowState::SetLeader) }, @@ -5328,7 +5337,7 @@ FunctionHook g_FunctionHooks[] = //{ 0x01D57A50, "_ZN9CLocalNav9PathClearER6VectorS1_iR11TraceResult", mfunc_ptr_cast(&CLocalNav::PathClear) }, // NOXREF //{ 0x0, "_ZN9CLocalNav9PathClearER6VectorS1_i", mfunc_ptr_cast(&CLocalNav::PathClear) }, // NOXREF { 0x01D58AC0, "_ZN9CLocalNav5ThinkEv", mfunc_ptr_cast(&CLocalNav::Think) }, - //!@{ 0x01D58D50, "_ZN9CLocalNav10RequestNavEP8CHostage", mfunc_ptr_cast(&CLocalNav::RequestNav) }, + { 0x01D58D50, "_ZN9CLocalNav10RequestNavEP8CHostage", mfunc_ptr_cast(&CLocalNav::RequestNav) }, { 0x01D58E20, "_ZN9CLocalNav5ResetEv", mfunc_ptr_cast(&CLocalNav::Reset) }, //{ 0x01D58E50, "_ZN9CLocalNav15HostagePrethinkEv", mfunc_ptr_cast(&CLocalNav::HostagePrethink) }, // NOXREF //{ 0x01D56F20, "_ZN9CLocalNav7AddNodeEiR6Vectoriih", mfunc_ptr_cast(&CLocalNav::AddNode) }, // NOXREF @@ -5405,11 +5414,15 @@ VirtualTableRef g_TableRefs[] = { 0x01DF6C9C, "CHostage", 76 }, { 0x01DF6FF4, "CImprov", 56 }, { 0x01DF6E24, "CHostageImprov", 56 }, - { 0x01DF6F70, "HostageRetreatState", 4 }, - { 0x01DF6FE4, "HostageStateMachine", 4 }, + + // hostage states + { 0x01DF6FE4, "HostageStateMachine", 4 }, + { 0x01DF6FC8, "HostageIdleState", 4 }, + { 0x01DF6F9C, "HostageEscapeState", 6 }, + { 0x01DF6F70, "HostageRetreatState", 4 }, + { 0x01DF6F44, "HostageFollowState", 4 }, { 0x01DF7180, "HostageEscapeToCoverState", 4 }, - { 0x01DF6F18, "HostageAnimateState", 4 }, - { 0x01DF6F9C, "HostageEscapeState", 6 }, + { 0x01DF6F18, "HostageAnimateState", 4 }, { 0x01E00BBC, "CArmoury", CBASE_VIRTUAL_COUNT }, { 0x01DFE4E4, "CSoundEnt", CBASE_VIRTUAL_COUNT }, @@ -5543,6 +5556,9 @@ VirtualTableRef g_TableRefs[] = { 0x01DFCADC, "CHalfLifeMultiplay", 70 }, { 0x01DFE7B4, "CHalfLifeTraining", 70 }, { 0x01DFC9D4, "CMapInfo", CBASE_VIRTUAL_COUNT }, + + { 0x01E01074, "CPreventDefuseTask", 0 }, + { 0x01E01084, "CCareerTask", 0 }, // effects { 0x01DF8F9C, "CBubbling", CBASE_VIRTUAL_COUNT }, @@ -5552,6 +5568,22 @@ VirtualTableRef g_TableRefs[] = { 0x01DF944C, "CGlow", CBASE_VIRTUAL_COUNT }, { 0x01DF953C, "CBombGlow", CBASE_VIRTUAL_COUNT }, { 0x01DF935C, "CSprite", CBASE_VIRTUAL_COUNT }, + { 0x01DFB2EC, "CWorldItem", CBASE_VIRTUAL_COUNT }, + { 0x01DFBB5C, "CLight", CBASE_VIRTUAL_COUNT }, + { 0x01DFBC4C, "CEnvLight", CBASE_VIRTUAL_COUNT }, + { 0x01DFEAB4, "CFrictionModifier", CBASE_VIRTUAL_COUNT }, + { 0x01DFEBA4, "CAutoTrigger", CBASE_VIRTUAL_COUNT }, + { 0x01DFBA6C, "CItemThighPack", 59 }, + { 0x01DFB97C, "CItemAssaultSuit", 59 }, + { 0x01DFB88C, "CItemKevlar", 59 }, + { 0x01DFB79C, "CItemLongJump", 59 }, + { 0x01DFB6AC, "CItemSecurity", 59 }, + { 0x01DFB5BC, "CItemAntidote", 59 }, + { 0x01DFB4CC, "CItemBattery", 59 }, + { 0x01DFB3DC, "CItemSuit", 59 }, + { 0x01DFB10C, "CHealthKit", 59 }, + { 0x01DFB1FC, "CWallHealth", 59 }, + { 0x01DFA9FC, "CRecharge", 59 }, { 0x01DF9634, "CGibShooter", 59 }, { 0x01DF9724, "CEnvShooter", 59 }, { 0x01DF9814, "CTestEffect", CBASE_VIRTUAL_COUNT }, @@ -5574,8 +5606,29 @@ VirtualTableRef g_TableRefs[] = { 0x01E01000, "CCSTutorBuyMenuState", 3 }, { 0x01E01010, "CCSTutorWaitingForStartState", 3 }, + { 0x01DF6198, "BotFollowMeme", 1 }, + { 0x01DF617C, "BotHelpMeme", 1 }, + { 0x01DF61A0, "BotDefendHereMeme", 1 }, + { 0x01DF61B0, "BotBombsiteStatusMeme", 1 }, + { 0x01DF618C, "BotBombStatusMeme", 1 }, + { 0x01DF61B8, "BotHostageBeingTakenMeme", 1 }, + { 0x01DF61A8, "BotWhereBombMeme", 1 }, + { 0x01DF6184, "BotRequestReportMeme", 1 }, + + // bot states + { 0x01DF64A0, "IdleState", 4 }, + { 0x01DF648C, "HuntState", 4 }, { 0x01DF6478, "AttackState", 4 }, - { 0x01DF6FC8, "HostageIdleState", 4 }, + { 0x01DF6464, "InvestigateNoiseState", 4 }, + { 0x01DF6450, "BuyState", 4 }, + { 0x01DF643C, "MoveToState", 4 }, + { 0x01DF6428, "FetchBombState", 4 }, + { 0x01DF6414, "PlantBombState", 4 }, + { 0x01DF6400, "DefuseBombState", 4 }, + { 0x01DF63EC, "HideState", 4 }, + { 0x01DF63D8, "EscapeFromBombState", 4 }, + { 0x01DF63C4, "FollowState", 4 }, + { 0x01DF63B0, "UseEntityState", 4 }, { NULL, NULL } // BaseClass__for_vtbl }; @@ -5585,12 +5638,8 @@ AddressRef g_FunctionRefs[] = { #ifndef Function_References_Region - //{ 0x01D3CA60, "_ZNK8CNavArea4GetZEPK6Vector", (size_t)&pGetZ__Vector }, - //{ 0x01D43860, "_ZNK12CNavAreaGrid17GetNearestNavAreaEPK6Vectorb", (size_t)&pGetNearestNavArea }, - //{ 0x01D43710, "_ZNK12CNavAreaGrid10GetNavAreaEPK6Vectorf", (size_t)&pGetNavArea }, { 0x01D2EDD0, "_ZN6CCSBot16UpdateLookAnglesEv", (size_t)&pCCSBot__UpdateLookAngles }, { 0x01D2D9B0, "_ZN6CCSBot6UpdateEv", (size_t)&pCCSBot__Update }, - { 0x01D20AE0, "_ZN6CCSBot11ResetValuesEv", (size_t)&pCCSBot__ResetValues }, { 0x01D19C70, "_ZN9BotPhrase9RandomizeEv", (size_t)&pBotPhrase__Randomize }, { 0x01D25270, "_ZN13CCSBotManager6AddBotEPK10BotProfile18BotProfileTeamType", (size_t)&pCCSBotManager__AddBot }, { 0x01D80C90, "_Z16InstallGameRulesv", (size_t)&pInstallGameRules }, @@ -5803,7 +5852,8 @@ AddressRef g_DataRefs[] = { 0x01E76580, "_ZL23s_tutorDisabledThisGame", (size_t)&ps_tutorDisabledThisGame }, { 0x01E76584, "_ZL19s_nextCvarCheckTime", (size_t)&ps_nextCvarCheckTime }, - + + { 0x01E11214, "BotDifficultyName", (size_t)&pBotDifficultyName }, { 0x01E61B88, "g_footsteps", (size_t)&pg_footsteps }, { 0x01E61B8C, "g_psv_accelerate", (size_t)&pg_psv_accelerate }, { 0x01E61B90, "g_psv_friction", (size_t)&pg_psv_friction }, @@ -6053,8 +6103,7 @@ AddressRef g_DataRefs[] = { 0x01E14D68, "_ZL18player_field_alias", (size_t)&pplayer_field_alias }, { 0x01E14DD8, "custom_entity_field_alias", (size_t)&pcustom_entity_field_alias }, { 0x01E5D718, "_ZL14g_serveractive", (size_t)&pg_serveractive }, - - { 0x01E2A0AC, "_ZL17goodSizedAreaList", (size_t)&pgoodSizedAreaList }, + { 0x01E2A0A8, "_ZL17goodSizedAreaList", (size_t)&pgoodSizedAreaList }, { 0x01E2A0D8, "TheNavAreaList", (size_t)&pTheNavAreaList }, { 0x01E29888, "TheNavAreaGrid", (size_t)&pTheNavAreaGrid }, { 0x01E2A250, "_ZN8CNavNode6m_listE", mfunc_ptr_cast(&CNavNode::pm_list) }, @@ -6116,6 +6165,9 @@ AddressRef g_DataRefs[] = { 0x01E2F8B4, "sclp", (size_t)&psclp }, { 0x01E2F8B8, "sclq", (size_t)&psclq }, + { 0x01E287E8, "_ZN19BotChatterInterface16m_encourageTimerE", mfunc_ptr_cast(&BotChatterInterface::pm_encourageTimer) }, + { 0x01E287E0, "_ZN19BotChatterInterface22m_radioSilenceIntervalE", mfunc_ptr_cast(&BotChatterInterface::pm_radioSilenceInterval) }, + #endif // Data_References_Region { NULL, NULL, NULL } diff --git a/regamedll/hookers/stl/vector b/regamedll/hookers/stl/vector index 909bebe9..1f33a64e 100644 --- a/regamedll/hookers/stl/vector +++ b/regamedll/hookers/stl/vector @@ -1,6 +1,7 @@ #pragma once #include "iterator" +#include "xutility" #include "memory" #ifdef _MSC_VER @@ -142,14 +143,14 @@ public: {erase(begin(), end()); insert(begin(), _N, _X); } iterator insert(iterator _P, const _Ty& _X = _Ty()) - {size_type _O = _P - begin(); + {size_type _O = size_type(_P - begin()); insert(_P, 1, _X); return (begin() + _O); } void insert(iterator _P, size_type _M, const _Ty& _X) - {if (_End - _Last < _M) + {if (size_type(_End - _Last) < _M) {size_type _N = size() + (_M < size() ? size() : _M); - iterator_ _S = allocator.allocate(_N, (void *)0); - iterator_ _Q = _Ucopy(_First, _P, _S); + iterator _S = allocator.allocate(_N, (void *)0); + iterator _Q = _Ucopy(_First, _P, _S); _Ufill(_Q, _M, _X); _Ucopy(_P, _Last, _Q + _M); __Destroy(_First, _Last); @@ -157,7 +158,7 @@ public: _End = _S + _N; _Last = _S + size() + _M; _First = _S; } - else if (_Last - _P < _M) + else if (size_type(_Last - _P) < _M) {_Ucopy(_P, _Last, _P + _M); _Ufill(_Last, _M - (_Last - _P), _X); fill_(_P, _Last, _X); @@ -172,8 +173,8 @@ public: __Distance(_F, _L, _M); if (_End - _Last < _M) {size_type _N = size() + (_M < size() ? size() : _M); - iterator_ _S = allocator.allocate(_N, (void *)0); - iterator_ _Q = _Ucopy(_First, _P, _S); + iterator _S = allocator.allocate(_N, (void *)0); + iterator _Q = _Ucopy(_First, _P, _S); _Q = _Ucopy(_F, _L, _Q); _Ucopy(_P, _Last, _Q); __Destroy(_First, _Last); @@ -197,7 +198,7 @@ public: --_Last; return (_P); } iterator erase(iterator _F, iterator _L) - {iterator_ _S = copy_(_L, end(), _F); + {iterator _S = copy_(_L, end(), _F); __Destroy(_S, end()); _Last = _S; return (_F); } diff --git a/regamedll/msvc/ReGameDLL.vcxproj b/regamedll/msvc/ReGameDLL.vcxproj index 8c83121d..6535cda6 100644 --- a/regamedll/msvc/ReGameDLL.vcxproj +++ b/regamedll/msvc/ReGameDLL.vcxproj @@ -838,6 +838,7 @@ + @@ -1168,7 +1169,7 @@ Level3 Disabled true - CSTRIKE;REGAMEDLL_SELF;REGAMEDLL_CHECKS;CLIENT_WEAPONS;USE_BREAKPAD_HANDLER;DEDICATED;_CRT_SECURE_NO_WARNINGS;_DEBUG;_ITERATOR_DEBUG_LEVEL=0;%(PreprocessorDefinitions) + CSTRIKE;REGAMEDLL_ADD;REGAMEDLL_FIXES;REGAMEDLL_SELF;REGAMEDLL_CHECKS;CLIENT_WEAPONS;USE_BREAKPAD_HANDLER;DEDICATED;_CRT_SECURE_NO_WARNINGS;_DEBUG;_ITERATOR_DEBUG_LEVEL=0;%(PreprocessorDefinitions) Precise /arch:IA32 %(AdditionalOptions) MultiThreadedDebug @@ -1204,7 +1205,7 @@ Level3 Disabled true - REGAMEDLL_SELF;PLAY_GAMEDLL;REGAMEDLL_CHECKS;CLIENT_WEAPONS;USE_BREAKPAD_HANDLER;DEDICATED;_CRT_SECURE_NO_WARNINGS;_DEBUG;_ITERATOR_DEBUG_LEVEL=0;%(PreprocessorDefinitions) + CSTRIKE;REGAMEDLL_SELF;PLAY_GAMEDLL;REGAMEDLL_CHECKS;CLIENT_WEAPONS;USE_BREAKPAD_HANDLER;DEDICATED;_CRT_SECURE_NO_WARNINGS;_DEBUG;_ITERATOR_DEBUG_LEVEL=0;%(PreprocessorDefinitions) Precise /arch:IA32 %(AdditionalOptions) MultiThreadedDebug diff --git a/regamedll/msvc/ReGameDLL.vcxproj.filters b/regamedll/msvc/ReGameDLL.vcxproj.filters index a285c68b..f0cc26b6 100644 --- a/regamedll/msvc/ReGameDLL.vcxproj.filters +++ b/regamedll/msvc/ReGameDLL.vcxproj.filters @@ -1136,6 +1136,9 @@ public\tier0 + + game_shared\bot + diff --git a/regamedll/regamedll/mem.cpp b/regamedll/regamedll/mem.cpp index a954369c..e6a54ea6 100644 --- a/regamedll/regamedll/mem.cpp +++ b/regamedll/regamedll/mem.cpp @@ -43,4 +43,9 @@ char *_strdup_mhook_(const char *s) return ptr; } +int __cdecl _rand_mhook_() +{ + return CRegamedllPlatformHolder::get()->rand(); +} + #endif // _WIN32 diff --git a/regamedll/regamedll/mem.h b/regamedll/regamedll/mem.h index c76b1c24..6235542b 100644 --- a/regamedll/regamedll/mem.h +++ b/regamedll/regamedll/mem.h @@ -12,6 +12,7 @@ void _free_mhook_(void *p); void *_calloc_mhook_(size_t n, size_t s); void *__nh_malloc_mhook_(size_t n); char *_strdup_mhook_(const char *s); +int __cdecl _rand_mhook_(); #endif // _WIN32 diff --git a/regamedll/unittests/struct_offsets_tests.cpp b/regamedll/unittests/struct_offsets_tests.cpp index ae5be87d..fba89c92 100644 --- a/regamedll/unittests/struct_offsets_tests.cpp +++ b/regamedll/unittests/struct_offsets_tests.cpp @@ -62,6 +62,8 @@ TEST(StructOffsets, ReversingChecks, 5000) REPEAT_SIZEOF_PRINT(CCareerTaskManager); REPEAT_SIZEOF_PRINT(CCareerTask); REPEAT_SIZEOF_PRINT(CPreventDefuseTask); + + REPEAT_SIZEOF_PRINT(BotStatement); // offset the members REPEAT_OFFSETOF_PRINT(CBaseEntity, pev); @@ -99,7 +101,8 @@ TEST(StructOffsets, ReversingChecks, 5000) //CHECK_CLASS_SIZE(CBotManager, 12u, 12); CHECK_CLASS_SIZE(CCSBot, 11404, 11424); //CHECK_CLASS_SIZE(CCSBotManager, 740, 0x2E0u);//0x2E4u | 0x2E0u - + + CHECK_CLASS_SIZE(BotStatement, 0x70u, 0x70u); //CHECK_CLASS_SIZE(HostageStateMachine, 0x10, 0x10); //CHECK_CLASS_SIZE(HostageFollowState, 0x4C, 0x4C); //CHECK_CLASS_SIZE(CCSBot, 0x2CA0, 0x2CA0);