From 9416463508611c77f3fb9942b754f87e7551eb9b Mon Sep 17 00:00:00 2001 From: s1lentq Date: Wed, 23 Dec 2015 00:07:49 +0600 Subject: [PATCH] WIP CZ: Reversed functions from Improved hostages --- README.md | 2 +- regamedll/common/mathlib.h | 4 +- regamedll/dlls/animation.h | 2 +- regamedll/dlls/bot/cs_bot_init.cpp | 8 +- regamedll/dlls/cbase.h | 2 +- regamedll/dlls/client.cpp | 2 +- regamedll/dlls/combat.cpp | 4 +- regamedll/dlls/gamerules.cpp | 8 +- regamedll/dlls/hostage/hostage.cpp | 16 +- regamedll/dlls/hostage/hostage.h | 10 +- regamedll/dlls/hostage/hostage_improv.cpp | 1630 +++++++++++------ regamedll/dlls/hostage/hostage_improv.h | 1002 +++++----- regamedll/dlls/hostage/hostage_localnav.cpp | 6 +- regamedll/dlls/hostage/hostage_states.h | 86 +- .../dlls/hostage/states/hostage_animate.cpp | 31 +- .../dlls/hostage/states/hostage_escape.cpp | 263 ++- .../dlls/hostage/states/hostage_follow.cpp | 257 ++- .../dlls/hostage/states/hostage_idle.cpp | 219 +++ .../dlls/hostage/states/hostage_retreat.cpp | 37 +- regamedll/dlls/multiplay_gamerules.cpp | 7 +- regamedll/dlls/plats.cpp | 9 +- regamedll/dlls/vector.h | 69 +- regamedll/engine/maintypes.h | 4 +- regamedll/game_shared/GameEvent.h | 109 +- regamedll/game_shared/bot/bot_manager.cpp | 184 +- regamedll/game_shared/bot/bot_manager.h | 24 +- regamedll/game_shared/bot/bot_util.cpp | 29 +- regamedll/game_shared/bot/bot_util.h | 2 +- regamedll/game_shared/bot/nav.h | 1 + regamedll/game_shared/bot/nav_area.cpp | 73 +- regamedll/game_shared/bot/nav_area.h | 546 +++--- regamedll/game_shared/bot/nav_file.cpp | 41 +- regamedll/game_shared/bot/nav_file.h | 19 +- regamedll/game_shared/bot/nav_node.cpp | 91 +- regamedll/game_shared/bot/nav_node.h | 7 +- regamedll/game_shared/bot/nav_path.cpp | 1557 ++++++++++------ regamedll/game_shared/bot/nav_path.h | 18 +- .../game_shared/bot/simple_state_machine.h | 7 +- regamedll/hookers/6153_hooker.cpp | 255 +-- regamedll/hookers/memory.cpp | 2 +- regamedll/hookers/osconfig.h | 2 +- regamedll/msvc/ReGameDLL.vcxproj | 6 +- regamedll/pm_shared/pm_math.h | 56 +- regamedll/pm_shared/pm_shared.cpp | 2 +- regamedll/regamedll/dlls.h | 1 + 45 files changed, 4266 insertions(+), 2444 deletions(-) diff --git a/README.md b/README.md index 968428bb..136beceb 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/common/mathlib.h b/regamedll/common/mathlib.h index 2c084aa7..3fb018d9 100644 --- a/regamedll/common/mathlib.h +++ b/regamedll/common/mathlib.h @@ -32,7 +32,7 @@ #pragma once #endif -#ifdef HOOK_GAMEDLL +#ifdef PLAY_GAMEDLL // probably gamedll compiled with flag /fpmath:fasted, // so we need to use type double, otherwise will be the test failed @@ -43,7 +43,7 @@ typedef double float_precision; typedef float float_precision; -#endif // HOOK_GAMEDLL +#endif // PLAY_GAMEDLL /* <42b7f> ../common/mathlib.h:3 */ typedef float vec_t; diff --git a/regamedll/dlls/animation.h b/regamedll/dlls/animation.h index 024fbcf3..4da17dfe 100644 --- a/regamedll/dlls/animation.h +++ b/regamedll/dlls/animation.h @@ -58,7 +58,7 @@ int GetBodygroup(void *pmodel, entvars_t *pev, int iGroup); C_DLLEXPORT int Server_GetBlendingInterface(int version, struct sv_blending_interface_s **ppinterface, struct engine_studio_api_s *pstudio, float *rotationmatrix, float *bonetransform); void AngleQuaternion(vec_t *angles, vec_t *quaternion); void QuaternionSlerp(vec_t *p, vec_t *q, float t, vec_t *qt); -NOBODY void QuaternionMatrix(vec_t *quaternion, float (*matrix)[4]); +void QuaternionMatrix(vec_t *quaternion, float (*matrix)[4]); mstudioanim_t *StudioGetAnim(model_t *m_pSubModel, mstudioseqdesc_t *pseqdesc); mstudioanim_t *LookupAnimation(model_t *model, mstudioseqdesc_t *pseqdesc, int index); void StudioCalcBoneAdj(float dadt, float *adj, const byte *pcontroller1, const byte *pcontroller2, byte mouthopen); diff --git a/regamedll/dlls/bot/cs_bot_init.cpp b/regamedll/dlls/bot/cs_bot_init.cpp index f7055d9d..8750b1b2 100644 --- a/regamedll/dlls/bot/cs_bot_init.cpp +++ b/regamedll/dlls/bot/cs_bot_init.cpp @@ -3,8 +3,12 @@ /* <333bca> ../cstrike/dlls/bot/cs_bot_init.cpp:57 */ NOBODY void InstallBotControl(void) { -// ~CBotManager(CBotManager *const this, -// int const __in_chrg); // 60 + if (TheBots != NULL) + { + delete TheBots; + } + + TheBots = new CCSBotManager; } /* <333cb3> ../cstrike/dlls/bot/cs_bot_init.cpp:68 */ diff --git a/regamedll/dlls/cbase.h b/regamedll/dlls/cbase.h index d6df7516..f2bb168a 100644 --- a/regamedll/dlls/cbase.h +++ b/regamedll/dlls/cbase.h @@ -718,7 +718,7 @@ public: int LookupSequence(const char *label); void ResetSequenceInfo(void); void DispatchAnimEvents(float flFutureInterval = 0.1f); - float SetBoneController(int iController, float flValue); + float SetBoneController(int iController, float flValue = 0.0f); void InitBoneControllers(void); NOXREF float SetBlending(int iBlender, float flValue); diff --git a/regamedll/dlls/client.cpp b/regamedll/dlls/client.cpp index 49c85949..7a9bf49e 100644 --- a/regamedll/dlls/client.cpp +++ b/regamedll/dlls/client.cpp @@ -2271,7 +2271,7 @@ BOOL HandleMenu_ChooseTeam(CBasePlayer *player, int slot) TheBots->OnEvent(EVENT_PLAYER_CHANGED_TEAM, player); } - TeamChangeUpdate(player, team); + TeamChangeUpdate(player, player->m_iTeam); szOldTeam = GetTeam(oldTeam); szNewTeam = GetTeam(team); diff --git a/regamedll/dlls/combat.cpp b/regamedll/dlls/combat.cpp index c23275ae..3cae8f3b 100644 --- a/regamedll/dlls/combat.cpp +++ b/regamedll/dlls/combat.cpp @@ -794,14 +794,14 @@ int CBaseMonster::__MAKE_VHOOK(TakeDamage)(entvars_t *pevInflictor, entvars_t *p if (pInflictor) { -#if 0 +#ifndef PLAY_GAMEDLL vecDir = (pInflictor->Center() - Vector(0, 0, 10) - Center()).Normalize(); #else // TODO: fix test demo vecDir = NormalizeSubtract< float_precision, float, float_precision, float_precision >(Center(), pInflictor->Center() - Vector(0, 0, 10)); -#endif +#endif // PLAY_GAMEDLL vecDir = g_vecAttackDir = vecDir.Normalize(); } } diff --git a/regamedll/dlls/gamerules.cpp b/regamedll/dlls/gamerules.cpp index 24444018..64ba8abe 100644 --- a/regamedll/dlls/gamerules.cpp +++ b/regamedll/dlls/gamerules.cpp @@ -40,13 +40,13 @@ edict_t *CGameRules::__MAKE_VHOOK(GetPlayerSpawnSpot)(CBasePlayer *pPlayer) { edict_t *pentSpawnSpot = EntSelectSpawnPoint(pPlayer); -#if HOOK_GAMEDLL +#ifndef PLAY_GAMEDLL + pPlayer->pev->origin = VARS(pentSpawnSpot)->origin + Vector(0, 0, 1); +#else // TODO: fix test demo pPlayer->pev->origin = VARS(pentSpawnSpot)->origin; pPlayer->pev->origin.z += 1; -#else - pPlayer->pev->origin = VARS(pentSpawnSpot)->origin + Vector(0, 0, 1); -#endif // HOOK_GAMEDLL +#endif // PLAY_GAMEDLL pPlayer->pev->v_angle = g_vecZero; pPlayer->pev->velocity = g_vecZero; diff --git a/regamedll/dlls/hostage/hostage.cpp b/regamedll/dlls/hostage/hostage.cpp index 4ac39323..2d1895ed 100644 --- a/regamedll/dlls/hostage/hostage.cpp +++ b/regamedll/dlls/hostage/hostage.cpp @@ -192,7 +192,7 @@ void CHostage::SetActivity(int act) void CHostage::IdleThink(void) { float flInterval; - const float upkeepRate = 0.3f; + const float upkeepRate = 0.03f; const float giveUpTime = (1 / 30.0f); float const updateRate = 0.1f; @@ -240,7 +240,7 @@ void CHostage::IdleThink(void) return; } - if (m_hTargetEnt != NULL && (m_bStuck && gpGlobals->time - m_flStuckTime > 5.0 || m_hTargetEnt->pev->deadflag != DEAD_NO)) + if (m_hTargetEnt != NULL && (m_bStuck && gpGlobals->time - m_flStuckTime > 5.0f || m_hTargetEnt->pev->deadflag != DEAD_NO)) { m_State = STAND; m_hTargetEnt = NULL; @@ -325,8 +325,8 @@ void CHostage::IdleThink(void) MESSAGE_BEGIN(MSG_SPEC, SVC_DIRECTOR); WRITE_BYTE(9); WRITE_BYTE(DRC_CMD_EVENT); - WRITE_SHORT((player != NULL) ? player->entindex() : 0); - WRITE_SHORT(player->entindex()); + WRITE_SHORT(player != NULL ? player->entindex() : 0); + WRITE_SHORT(entindex()); WRITE_LONG(15); MESSAGE_END(); @@ -840,7 +840,7 @@ void CHostage::__MAKE_VHOOK(Touch)(CBaseEntity *pOther) vPush = (pev->origin - pOther->pev->origin).Make2D(); -#ifndef HOOK_GAMEDLL +#ifndef PLAY_GAMEDLL vPush = vPush.Normalize() * pushForce; pev->velocity.x += vPush.x; @@ -848,7 +848,7 @@ void CHostage::__MAKE_VHOOK(Touch)(CBaseEntity *pOther) #else // TODO: fix test demo pev->velocity = pev->velocity + NormalizeMulScalar(vPush, pushForce); -#endif // HOOK_GAMEDLL +#endif // PLAY_GAMEDLL } /* <45dd66> ../cstrike/dlls/hostage/hostage.cpp:910 */ @@ -1173,14 +1173,14 @@ void CHostage::Wiggle(void) } } -#ifndef HOOK_GAMEDLL +#ifndef PLAY_GAMEDLL vec = vec + Vector(RANDOM_FLOAT(-3, 3), RANDOM_FLOAT(-3, 3), 0); #else // TODO: fix test demo vec.y = vec.y + RANDOM_FLOAT(-3.0, 3.0); vec.x = vec.x + RANDOM_FLOAT(-3.0, 3.0); -#endif // HOOK_GAMEDLL +#endif // PLAY_GAMEDLL pev->velocity = pev->velocity + (vec.Normalize() * 100); } diff --git a/regamedll/dlls/hostage/hostage.h b/regamedll/dlls/hostage/hostage.h index d508e839..b88cf6a1 100644 --- a/regamedll/dlls/hostage/hostage.h +++ b/regamedll/dlls/hostage/hostage.h @@ -154,12 +154,10 @@ public: bool IsFollowingSomeone(void) { - UNTESTED return m_improv->IsFollowing(); } CBaseEntity *GetLeader(void) { - UNTESTED if (m_improv != NULL) { return m_improv->GetFollowLeader(); @@ -173,19 +171,20 @@ public: } bool IsValid(void) { - UNTESTED return (pev->takedamage == DAMAGE_YES); } bool IsDead(void) { - UNTESTED return (pev->deadflag == DEAD_DEAD); } bool IsAtHome(void) { return (pev->origin - m_vStart).IsLengthGreaterThan(20) != true; } - NOBODY const Vector *GetHomePosition(void); + const Vector *GetHomePosition(void) + { + return &m_vStart; + } public: enum state @@ -243,7 +242,6 @@ public: class SimpleChatter { public: - SimpleChatter(void); ~SimpleChatter(void); diff --git a/regamedll/dlls/hostage/hostage_improv.cpp b/regamedll/dlls/hostage/hostage_improv.cpp index 69899a49..6732619b 100644 --- a/regamedll/dlls/hostage/hostage_improv.cpp +++ b/regamedll/dlls/hostage/hostage_improv.cpp @@ -1,11 +1,16 @@ #include "precompiled.h" /* <4703fc> ../cstrike/dlls/hostage/hostage_improv.cpp:19 */ -inline void DrawAxes(Vector &origin, int red, int green, int blue) +inline void DrawAxes(const Vector &origin, int red, int green, int blue) { -// { -// float size; // 21 -// } + float size = 10; + + if (cv_hostage_debug.value != 1.0f) + return; + + UTIL_DrawBeamPoints(origin - Vector(size, 0, 0), origin + Vector(size, 0, 0), 2, red, green, blue); + UTIL_DrawBeamPoints(origin - Vector(0, size, 0), origin + Vector(0, size, 0), 2, red, green, blue); + UTIL_DrawBeamPoints(origin + Vector(0, 0, size), origin - Vector(0, 0, size), 2, red, green, blue); } /* <47353e> ../cstrike/dlls/hostage/hostage_improv.cpp:41 */ @@ -72,7 +77,7 @@ bool CHostageImprov::DiscontinuityJump(float ground, bool onlyJumpDown, bool mus Jump(); return true; } - + return false; } @@ -104,290 +109,373 @@ void CHostageImprov::__MAKE_VHOOK(ClearFaceTo)(void) /* <476a30> ../cstrike/dlls/hostage/hostage_improv.cpp:154 */ void CHostageImprov::MoveTowards(const Vector &pos, float deltaT) -{ - Vector move; - float_precision accelRate; - const float crouchWalkRate = 250.0f; - - // - // 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 - // - - ClearPath(); - - if ((m_lastKnownArea == NULL || !(m_lastKnownArea->GetAttributes() & 8)) && !IsUsingLadder() && !IsJumping() && IsOnGround() && !IsCrouching()) - { - float ground; - Vector aheadRay(pos.x - GetFeet().x, pos.y - GetFeet().y, 0); - aheadRay.NormalizeInPlace(); - - bool jumped = false; - if (IsRunning()) - { - const float farLookAheadRange = 80.0f; - Vector normal; - Vector stepAhead = GetFeet() + farLookAheadRange * aheadRay; - stepAhead.z += HumanHeight; - - if (GetSimpleGroundHeightWithFloor(&stepAhead, &ground, &normal )) - { - if (normal.z > 0.9f) - jumped = DiscontinuityJump(ground, HOSTAGE_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 = GetFeet() + lookAheadRange * aheadRay; - stepAhead.z += HumanHeight; - - if (GetSimpleGroundHeightWithFloor(&stepAhead, &ground)) - { - jumped = DiscontinuityJump(ground); - } - } - - if (!jumped) - { - // about to fall gap-jumping - const float lookAheadRange = 10.0f; - Vector stepAhead = GetFeet() + lookAheadRange * aheadRay; - stepAhead.z += HumanHeight; - - if (GetSimpleGroundHeightWithFloor(&stepAhead, &ground)) - { - jumped = DiscontinuityJump(ground, HOSTAGE_ONLY_JUMP_DOWN, HOSTAGE_MUST_JUMP); - } - } - } - - move = (pos - GetFeet()); - move.z = 0; - - if (!move.IsZero()) - { - move.NormalizeInPlace(); - } - - switch (m_moveType) - { - case Stopped: - accelRate = 0; - break; - case Walking: - if (IsCrouching()) - accelRate = crouchWalkRate; - else - accelRate = 400; - break; - case Running: - if (IsCrouching()) - accelRate = crouchWalkRate; - else - accelRate = 1000; - break; - } - - m_vel.x = move.x * accelRate * deltaT + m_vel.x; +{ + Vector move; + float_precision accelRate; + const float crouchWalkRate = 250.0f; + + // 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 + + ClearPath(); + + if ((m_lastKnownArea == NULL || !(m_lastKnownArea->GetAttributes() & 8)) && !IsUsingLadder() && !IsJumping() && IsOnGround() && !IsCrouching()) + { + float ground; + Vector aheadRay(pos.x - GetFeet().x, pos.y - GetFeet().y, 0); + aheadRay.NormalizeInPlace(); + + bool jumped = false; + if (IsRunning()) + { + const float farLookAheadRange = 80.0f; + Vector normal; + Vector stepAhead = GetFeet() + farLookAheadRange * aheadRay; + stepAhead.z += HumanHeight; + + if (GetSimpleGroundHeightWithFloor(&stepAhead, &ground, &normal )) + { + if (normal.z > 0.9f) + jumped = DiscontinuityJump(ground, HOSTAGE_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 = GetFeet() + lookAheadRange * aheadRay; + stepAhead.z += HumanHeight; + + if (GetSimpleGroundHeightWithFloor(&stepAhead, &ground)) + { + jumped = DiscontinuityJump(ground); + } + } + + if (!jumped) + { + // about to fall gap-jumping + const float lookAheadRange = 10.0f; + Vector stepAhead = GetFeet() + lookAheadRange * aheadRay; + stepAhead.z += HumanHeight; + + if (GetSimpleGroundHeightWithFloor(&stepAhead, &ground)) + { + jumped = DiscontinuityJump(ground, HOSTAGE_ONLY_JUMP_DOWN, HOSTAGE_MUST_JUMP); + } + } + } + + move = (pos - GetFeet()); + move.z = 0; + + if (!move.IsZero()) + { + move.NormalizeInPlace(); + } + + switch (m_moveType) + { + case Stopped: + accelRate = 0; + break; + case Walking: + if (IsCrouching()) + accelRate = crouchWalkRate; + else + accelRate = 400; + break; + case Running: + if (IsCrouching()) + accelRate = crouchWalkRate; + else + accelRate = 1000; + break; + } + + m_vel.x = move.x * accelRate * deltaT + m_vel.x; m_vel.y = move.y * accelRate * deltaT + m_vel.y; } -void (*pCHostageImprov__FaceTowards)(); - /* <473e46> ../cstrike/dlls/hostage/hostage_improv.cpp:262 */ -NOBODY bool __declspec(naked) CHostageImprov::FaceTowards(const Vector &target, float deltaT) +bool CHostageImprov::FaceTowards(const Vector &target, float deltaT) { - __asm + float error = 0; + Vector2D to = (target - GetFeet()).Make2D(); + +#ifndef PLAY_GAMEDLL + to.NormalizeInPlace(); +#else + // TODO: fix test demo + float_precision float_x = target.x - GetFeet().x; + float_precision float_y = target.y - GetFeet().y; + float_precision flLen = to.Length(); + + if (flLen <= 0) { - jmp pCHostageImprov__FaceTowards + to.x = 1; + to.y = 0; + } + else + { + to.x = float_x / flLen; + to.y = float_y / flLen; + } +#endif // PLAY_GAMEDLL + + float moveAngle = GetMoveAngle(); + + Vector2D lat(BotCOS(moveAngle), BotSIN(moveAngle)); + Vector2D dir(-lat.y, lat.x); + + float_precision dot = DotProduct(to, dir); + + if (DotProduct(to, lat) < 0.0f) + { + if (dot >= 0.0f) + dot = 1.0f; + else + dot = -1.0f; + + error = 1; + } + + const float maxTurnRate = 0.05f; + + if (error || fabs(dot) >= maxTurnRate) + { + const float tolerance = 300.0f; + float moveRatio = dot * deltaT * tolerance + moveAngle; + + BotCOS(moveRatio); + BotSIN(moveRatio); + + m_moveAngle = moveRatio; + m_hostage->pev->angles.y = moveRatio; + + return false; } -// { -// class Vector2D to; // 264 -// float moveAngle; // 267 -// class Vector2D dir; // 270 -// class Vector2D lat; // 271 -// float const maxTurnRate; // 273 -// float error; // 275 -// float dot; // 278 -// operator-(const Vector *const this, -// const Vector &v); // 264 -// NormalizeInPlace(Vector2D *const this); // 265 -// DotProduct(const class Vector2D &a, -// const class Vector2D &b); // 275 -// DotProduct(const class Vector2D &a, -// const class Vector2D &b); // 278 -// { -// float const tolerance; // 285 -// fabs(double __x); // 286 -// } -// SetMoveAngle(CHostageImprov *const this, -// float angle); // 298 -// } + return true; } /* <47402b> ../cstrike/dlls/hostage/hostage_improv.cpp:308 */ -NOBODY void CHostageImprov::FaceOutwards(void) +void CHostageImprov::FaceOutwards(void) { -// { -// TraceResult result; // 310 -// Vector to; // 312 -// float farthestRange; // 313 -// int farthest; // 314 -// int const cornerCount; // 316 -// Vector corner; // 317 -// { -// int i; // 325 -// { -// float range; // 328 -// operator+(const Vector *const this, -// const Vector &v); // 327 -// operator-(const Vector *const this, -// const Vector &v); // 328 -// LengthSquared(const Vector *const this); // 328 -// } -// } -// operator+(const Vector *const this, -// const Vector &v); // 337 -// Vector(Vector *const this, -// float X, -// float Y, -// float Z); // 323 -// Vector(Vector *const this, -// float X, -// float Y, -// float Z); // 323 -// Vector(Vector *const this, -// float X, -// float Y, -// float Z); // 323 -// Vector(Vector *const this, -// float X, -// float Y, -// float Z); // 323 -// } + TraceResult result; + Vector to; + float farthestRange = 0.0f; + int farthest = 0; + + Vector corner[] = + { + Vector(-1000, 1000, 0), + Vector(1000, 1000, 0), + Vector(-1000, -1000, 0), + Vector(1000, -1000, 0) + }; + + const int cornerCount = ARRAYSIZE(corner); + + for (int i = 0; i < cornerCount; ++i) + { + to = GetCentroid() + corner[i]; + + UTIL_TraceLine(GetCentroid(), to, ignore_monsters, ignore_glass, m_hostage->edict(), &result); + + float_precision range = (result.vecEndPos - GetCentroid()).LengthSquared(); + + if (range > farthestRange) + { + farthestRange = range; + farthest = i; + } + } + + to = GetCentroid() + corner[farthest]; + FaceTo(to); } /* <470e23> ../cstrike/dlls/hostage/hostage_improv.cpp:344 */ -NOBODY bool CHostageImprov::__MAKE_VHOOK(IsAtMoveGoal)(float error) const +bool CHostageImprov::__MAKE_VHOOK(IsAtMoveGoal)(float error) const { -// operator-(const Vector *const this, -// const Vector &v); // 346 -// IsLengthLessThan(const Vector *const this, -// float length); // 346 + return (GetFeet() - m_moveGoal).IsLengthLessThan(error); } /* <470eab> ../cstrike/dlls/hostage/hostage_improv.cpp:353 */ -NOBODY bool CHostageImprov::__MAKE_VHOOK(IsAtFaceGoal)(void) const +bool CHostageImprov::__MAKE_VHOOK(IsAtFaceGoal)(void) const { + return false; } +// Return true if a friend is between us and the given position + /* <46fb4b> ../cstrike/dlls/hostage/hostage_improv.cpp:395 */ -NOBODY bool CHostageImprov::__MAKE_VHOOK(IsFriendInTheWay)(const Vector &goalPos) const +bool CHostageImprov::__MAKE_VHOOK(IsFriendInTheWay)(const Vector &goalPos) const { -// { -// float const avoidFriendInterval; // 403 -// IsElapsed(const class CountdownTimer *const this); // 398 -// { -// class CheckWayFunctor check; // 411 -// } -// { -// int i; // 421 -// { -// class CBasePlayer *player; // 423 -// } -// } -// } -// IsFriendInTheWay(const class CHostageImprov *const this, -// const Vector &goalPos); // 395 + // 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); + + CheckWayFunctor check(this, goalPos); + + if (g_pHostages != NULL) + { + g_pHostages->ForEachHostage(check); + + if (check.m_blocker != NULL) + { + return m_isFriendInTheWay = true; + } + } + + // check if any CT 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() || player->m_iTeam == TERRORIST) + continue; + + if (IsFriendInTheWay(player, goalPos)) + { + m_isFriendInTheWay = true; + break; + } + } + + return m_isFriendInTheWay; } +// Return true if a friend is between us and the given entity + /* <472b83> ../cstrike/dlls/hostage/hostage_improv.cpp:453 */ -NOBODY bool CHostageImprov::__MAKE_VHOOK(IsFriendInTheWay)(CBaseEntity *myFriend, const Vector &goalPos) const +bool CHostageImprov::__MAKE_VHOOK(IsFriendInTheWay)(CBaseEntity *myFriend, const Vector &goalPos) const { -// { -// Vector moveDir; // 460 -// float length; // 463 -// Vector friendFeet; // 465 -// Vector toFriend; // 476 -// float const personalSpace; // 479 -// float friendDistAlong; // 484 -// Vector pos; // 491 -// float const friendRadius; // 498 -// operator-(const Vector *const this, -// const Vector &v); // 460 -// NormalizeInPlace(Vector *const this); // 463 -// operator-(const Vector *const this, -// const Vector &v); // 476 -// IsLengthGreaterThan(const Vector *const this, -// float length); // 480 -// DotProduct(Vector &a, -// const Vector &b); // 484 -// operator-(const Vector *const this, -// const Vector &v); // 499 -// IsLengthLessThan(const Vector *const this, -// float length); // 499 -// IsZero(Vector *const this, -// float tolerance); // 504 -// DotProduct(Vector &a, -// const Vector &b); // 507 -// operator*(float fl, -// const Vector &v); // 495 -// operator+(const Vector *const this, -// const Vector &v); // 495 -// } + if (m_hostage == myFriend) + return false; + + // compute ray along intended path + Vector moveDir = goalPos - GetFeet(); + Vector friendFeet = myFriend->pev->origin; + + // make it a unit vector + float length = moveDir.NormalizeInPlace(); + + if (myFriend->IsPlayer()) + friendFeet.z = myFriend->pev->absmin.z; + + Vector toFriend = friendFeet - GetFeet(); + + // check if friend is in our "personal space" + const float personalSpace = 100.0f; + if (toFriend.IsLengthGreaterThan(personalSpace)) + return false; + + // find distance of friend along our movement path + float friendDistAlong = DotProduct(toFriend, moveDir); + + // if friend is behind us, ignore him + if (friendDistAlong <= 0.0f) + return false; + + // constrain point to be on path segment + Vector pos; + if (friendDistAlong >= length) + pos = goalPos; + else + pos = GetFeet() + moveDir * friendDistAlong; + + // check if friend overlaps our intended line of movement + const float friendRadius = 30.0f; + if (!(pos - friendFeet).IsLengthLessThan(friendRadius)) + return false; + + if (!myFriend->pev->velocity.IsZero()) + { + if (DotProduct(myFriend->pev->velocity, m_hostage->pev->velocity) >= 0.0) + return false; + } + + // friend is in our personal space and overlaps our intended line of movement + return true; } /* <474309> ../cstrike/dlls/hostage/hostage_improv.cpp:557 */ -NOBODY bool CHostageImprov::IsFriendInTheWay(void) +bool CHostageImprov::IsFriendInTheWay(void) const { -// { -// class CheckAhead check; // 559 -// CheckAhead(CheckAhead *const this, -// const class CHostageImprov *me); // 559 -// ForEachHostage(const class CHostageManager *const this, -// class CheckAhead &func); // 561 -// ForEachPlayer(CheckAhead &func); // 562 -// } + CheckAhead check(this); + g_pHostages->ForEachHostage(check); + ForEachPlayer(check); + + return check.IsBlocked(); } /* <474631> ../cstrike/dlls/hostage/hostage_improv.cpp:568 */ -NOBODY float CHostageImprov::GetSpeed(void) +float CHostageImprov::GetSpeed(void) { + return -1.0f; } /* <46f249> ../cstrike/dlls/hostage/hostage_improv.cpp:592 */ -NOBODY bool CHostageImprov::__MAKE_VHOOK(Jump)(void) +bool CHostageImprov::__MAKE_VHOOK(Jump)(void) { -// IsElapsed(const class CountdownTimer *const this); // 604 -// { -// float const epsilon; // 609 -// float const minJumpInterval; // 618 -// { -// float const fudge; // 613 -// } -// } -// Jump(CHostageImprov *const this); // 592 + if (IsCrouching() || g_pHostages->IsNearbyHostageJumping(this)) + return false; + + if (!m_jumpTimer.IsElapsed()) + return false; + + const float epsilon = 1.0f; + + m_hasJumped = false; + m_moveFlags |= IN_JUMP; + + if (m_hostage->pev->velocity.LengthSquared() < epsilon) + { + const float fudge = 2.0f; + m_hostage->pev->origin.z += fudge; + } + + const float minJumpInterval = 3.0f; + m_jumpTimer.Start(minJumpInterval); + + m_animateState.Reset(); + m_animateState.SetPerformance(HostageAnimateState::Jump); + m_animateState.AddSequence(this, ACT_HOP); + + return true; } /* <470ed3> ../cstrike/dlls/hostage/hostage_improv.cpp:632 */ -NOBODY void CHostageImprov::__MAKE_VHOOK(Run)(void) +void CHostageImprov::__MAKE_VHOOK(Run)(void) { + m_moveType = m_moveLimit; } /* <470efb> ../cstrike/dlls/hostage/hostage_improv.cpp:638 */ -NOBODY void CHostageImprov::__MAKE_VHOOK(Walk)(void) +void CHostageImprov::__MAKE_VHOOK(Walk)(void) { + m_moveType = (m_moveLimit > Walking) ? Walking : m_moveLimit; } /* <470f23> ../cstrike/dlls/hostage/hostage_improv.cpp:644 */ @@ -395,7 +483,7 @@ void CHostageImprov::__MAKE_VHOOK(Stop)(void) { MoveTo(GetFeet()); m_hostage->pev->velocity = Vector(0, 0, 0); - + if (m_moveLimit > Stopped) m_moveType = Stopped; else @@ -423,18 +511,16 @@ const Vector &CHostageImprov::__MAKE_VHOOK(GetEyes)(void) const } /* <470fc4> ../cstrike/dlls/hostage/hostage_improv.cpp:681 */ -NOBODY bool CHostageImprov::__MAKE_VHOOK(IsOnGround)(void) const +bool CHostageImprov::__MAKE_VHOOK(IsOnGround)(void) const { + return (m_hostage->pev->flags & FL_ONGROUND) != 0; } /* <470fec> ../cstrike/dlls/hostage/hostage_improv.cpp:687 */ -NOBODY bool CHostageImprov::__MAKE_VHOOK(IsMoving)(void) const +bool CHostageImprov::__MAKE_VHOOK(IsMoving)(void) const { -// { -// float const epsilon; // 689 -// IsLengthGreaterThan(const Vector *const this, -// float length); // 690 -// } + float const epsilon = 10.0f; + return m_actualVel.IsLengthGreaterThan(epsilon); } /* <4715d1> ../cstrike/dlls/hostage/hostage_improv.cpp:697 */ @@ -448,51 +534,84 @@ bool CHostageImprov::__MAKE_VHOOK(IsVisible)(const Vector &pos, bool testFOV) co } /* <472938> ../cstrike/dlls/hostage/hostage_improv.cpp:728 */ -NOBODY bool CHostageImprov::__MAKE_VHOOK(IsPlayerLookingAtMe)(CBasePlayer *other, float cosTolerance) const +bool CHostageImprov::__MAKE_VHOOK(IsPlayerLookingAtMe)(CBasePlayer *other, float cosTolerance) const { -// { -// class Vector2D toOther; // 730 -// class Vector2D otherDir; // 737 -// NormalizeInPlace(Vector2D *const this); // 733 -// operator+(const Vector *const this, -// const Vector &v); // 736 -// NormalizeInPlace(Vector2D *const this); // 740 -// } + Vector2D toOther = (other->pev->origin - GetCentroid()).Make2D(); + toOther.NormalizeInPlace(); + + UTIL_MakeVectors(other->pev->punchangle + other->pev->v_angle); + + Vector2D otherDir = gpGlobals->v_forward.Make2D(); + otherDir.NormalizeInPlace(); + + if (-cosTolerance > DotProduct(toOther, otherDir)) + { + if (IsVisible(other->EyePosition())) + { + return true; + } + } + + return false; } /* <472a9f> ../cstrike/dlls/hostage/hostage_improv.cpp:757 */ -NOBODY CBasePlayer *CHostageImprov::__MAKE_VHOOK(IsAnyPlayerLookingAtMe)(int team, float cosTolerance) const +CBasePlayer *CHostageImprov::__MAKE_VHOOK(IsAnyPlayerLookingAtMe)(int team, float cosTolerance) const { -// { -// int i; // 759 -// { -// class CBasePlayer *player; // 761 -// IsEntityValid(CBaseEntity *entity); // 763 -// } -// } + for (int i = 1; i <= gpGlobals->maxClients; ++i) + { + CBasePlayer *player = static_cast(UTIL_PlayerByIndex(i)); + + if (!IsEntityValid(player)) + continue; + + if (player->IsAlive() && (team == UNASSIGNED || player->m_iTeam == team)) + { + if (IsPlayerLookingAtMe(player, cosTolerance)) + { + return player; + } + } + } + + return NULL; } /* <472e7b> ../cstrike/dlls/hostage/hostage_improv.cpp:783 */ -NOBODY CBasePlayer *CHostageImprov::__MAKE_VHOOK(GetClosestPlayerByTravelDistance)(int team, float *range) const +CBasePlayer *CHostageImprov::__MAKE_VHOOK(GetClosestPlayerByTravelDistance)(int team, float *range) const { -// { -// class CBasePlayer *close; // 788 -// float closeRange; // 789 -// { -// int i; // 791 -// { -// class CBasePlayer *player; // 793 -// class ShortestPathCost cost; // 804 -// Vector vecCenter; // 805 -// float range; // 806 -// IsEntityValid(CBaseEntity *entity); // 795 -// NavAreaTravelDistance(const Vector *startPos, -// class CNavArea *startArea, -// const Vector *goalPos, -// class ShortestPathCost &costFunc); // 806 -// } -// } -// } + CBasePlayer *close = NULL; + float closeRange = 9.9999998e10f; + + if (GetLastKnownArea() == NULL) + return NULL; + + for (int i = 1; i <= gpGlobals->maxClients; ++i) + { + CBasePlayer *player = static_cast(UTIL_PlayerByIndex(i)); + + if (!IsEntityValid(player)) + continue; + + if (player->IsAlive() && (team == UNASSIGNED || player->m_iTeam == team)) + { + ShortestPathCost cost; + Vector vecCenter = player->Center(); + + float_precision range = NavAreaTravelDistance(GetLastKnownArea(), TheNavAreaGrid.GetNearestNavArea(&vecCenter), cost); + + if (range > 0 && range < closeRange) + { + closeRange = range; + close = player; + } + } + } + + if (range) + *range = closeRange; + + return close; } /* <47166d> ../cstrike/dlls/hostage/hostage_improv.cpp:822 */ @@ -553,28 +672,51 @@ void CHostageImprov::__MAKE_VHOOK(OnReset)(void) } /* <474659> ../cstrike/dlls/hostage/hostage_improv.cpp:886 */ -NOBODY void CHostageImprov::UpdateVision(void) +void CHostageImprov::UpdateVision(void) { -// IsElapsed(const class CountdownTimer *const this); // 888 -// { -// int i; // 893 -// { -// class CBasePlayer *player; // 895 -// FNullEnt(entvars_t *pev); // 900 -// Start(IntervalTimer *const this); // 914 -// Start(IntervalTimer *const this); // 916 -// } -// } -// Start(CountdownTimer *const this, -// float duration); // 924 + if (!m_visionTimer.IsElapsed()) + return; + + m_visiblePlayerCount = false; + + 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; + + if (player->IsAlive() && IsVisible(player->pev->origin, true)) + { + m_visiblePlayer[m_visiblePlayerCount] = player; + + if (player->m_iTeam == TERRORIST) + m_lastSawT.Start(); + else + m_lastSawCT.Start(); + + if (++m_visiblePlayerCount == ARRAYSIZE(m_visiblePlayer)) + break; + } + } + + m_visionTimer.Start(RANDOM_FLOAT(0.4, 0.6)); } /* <476e49> ../cstrike/dlls/hostage/hostage_improv.cpp:997 */ -NOBODY void CHostageImprov::__MAKE_VHOOK(TrackPath)(const Vector &pathGoal, float deltaT) +void CHostageImprov::__MAKE_VHOOK(TrackPath)(const Vector &pathGoal, float deltaT) { -// TrackPath(CHostageImprov *const this, -// const Vector &pathGoal, -// float deltaT); // 997 + FaceTowards(pathGoal, deltaT); + MoveTowards(pathGoal, deltaT); + + m_jumpTarget = pathGoal; + DrawAxes(pathGoal, 255, 0, 255); } /* <474781> ../cstrike/dlls/hostage/hostage_improv.cpp:1014 */ @@ -630,121 +772,261 @@ void CHostageImprov::ResetToKnownGoodPosition(void) } /* <47105c> ../cstrike/dlls/hostage/hostage_improv.cpp:1082 */ -void CHostageImprov::__MAKE_VHOOK(StartLadder)(const class CNavLadder *ladder, NavTraverseType how, const Vector *approachPos, const Vector *departPos) +void CHostageImprov::__MAKE_VHOOK(StartLadder)(const CNavLadder *ladder, NavTraverseType how, const Vector *approachPos, const Vector *departPos) { m_traversingLadder = true; } /* <4710c4> ../cstrike/dlls/hostage/hostage_improv.cpp:1094 */ -NOBODY bool CHostageImprov::__MAKE_VHOOK(TraverseLadder)(const CNavLadder *ladder, NavTraverseType how, const Vector *approachPos, const Vector *departPos, float deltaT) +bool CHostageImprov::__MAKE_VHOOK(TraverseLadder)(const CNavLadder *ladder, NavTraverseType how, const Vector *approachPos, const Vector *departPos, float deltaT) { -// { -// Vector goal; // 1098 -// AddDirectionVector(Vector *v, -// enum NavDirType dir, -// float amount); // 1122 -// { -// float const atGoalRange; // 1198 -// { -// float closeRange; // 1158 -// float range; // 1158 -// operator-(const Vector *const this, -// const Vector &v); // 1162 -// LengthSquared(const Vector *const this); // 1162 -// operator-(const Vector *const this, -// const Vector &v); // 1174 -// LengthSquared(const Vector *const this); // 1174 -// operator-(const Vector *const this, -// const Vector &v); // 1186 -// LengthSquared(const Vector *const this); // 1186 -// } -// operator-(const Vector *const this, -// const Vector &v); // 1199 -// IsLengthLessThan(const class Vector2D *const this, -// float length); // 1199 -// } -// { -// float const walkRange; // 1130 -// float const ladderRange; // 1135 -// operator-(const Vector *const this, -// const Vector &v); // 1131 -// IsLengthLessThan(const class Vector2D *const this, -// float length); // 1131 -// operator-(const Vector *const this, -// const Vector &v); // 1136 -// IsLengthLessThan(const class Vector2D *const this, -// float length); // 1136 -// } -// AddDirectionVector(Vector *v, -// enum NavDirType dir, -// float amount); // 1103 -// { -// float const ladderRange; // 1108 -// operator-(const Vector *const this, -// const Vector &v); // 1109 -// IsLengthLessThan(const class Vector2D *const this, -// float length); // 1109 -// } -// } + Vector goal; + + if (how == GO_LADDER_DOWN) + { + goal = ladder->m_bottom; + AddDirectionVector(&goal, ladder->m_dir, 16); + + if (ladder->m_top.z - 36.0f > GetFeet().z) + { + const float atGoalRange = 50.0f; + if ((GetFeet() - goal).Make2D().IsLengthLessThan(atGoalRange)) + { + m_hostage->pev->velocity.z = -100.0f; + } + } + + if (ladder->m_bottom.z + 36.0f > GetFeet().z) + return true; + } + else if (m_traversingLadder) + { + goal = ladder->m_top; + AddDirectionVector(&goal, ladder->m_dir, 16); + + const float walkRange = 100.0f; + + if ((GetFeet() - goal).Make2D().IsLengthLessThan(walkRange)) + { + Walk(); + } + + const float ladderRange = 40.0f; + if ((GetFeet() - goal).Make2D().IsLengthLessThan(ladderRange)) + { + m_hostage->pev->velocity.z = 150.0; + } + + if (GetFeet().z > ladder->m_top.z) + m_traversingLadder = false; + } + else + { + if (departPos != NULL) + { + float closeRange = 1e6; + float range; + + if (ladder->m_topForwardArea != NULL) + { + range = (*departPos - *ladder->m_topForwardArea->GetCenter()).LengthSquared(); + + if (range < closeRange) + { + closeRange = range; + goal = *ladder->m_topForwardArea->GetCenter(); + + if (ladder->m_topForwardArea->GetAttributes() & NAV_CROUCH) + { + Crouch(); + } + } + } + if (ladder->m_topLeftArea != NULL) + { + range = (*departPos - *ladder->m_topLeftArea->GetCenter()).LengthSquared(); + + if (closeRange > range) + { + goal = *ladder->m_topLeftArea->GetCenter(); + + if (ladder->m_topLeftArea->GetAttributes() & NAV_CROUCH) + { + Crouch(); + } + } + } + if (ladder->m_topRightArea != NULL) + { + range = (*departPos - *ladder->m_topRightArea->GetCenter()).LengthSquared(); + + if (closeRange > range) + { + goal = *ladder->m_topRightArea->GetCenter(); + + if (ladder->m_topRightArea->GetAttributes() & NAV_CROUCH) + { + Crouch(); + } + } + } + } + + const float ladderRange = 20.0f; + if ((GetFeet() - goal).Make2D().IsLengthLessThan(ladderRange)) + { + return true; + } + } + + TrackPath(goal, deltaT); + return false; } /* <477691> ../cstrike/dlls/hostage/hostage_improv.cpp:1214 */ -NOBODY void CHostageImprov::UpdatePosition(float deltaT) +void CHostageImprov::UpdatePosition(float deltaT) { -// { -// class CNavArea *area; // 1217 -// float const friction; // 1344 -// float speed; // 1349 -// float const maxSpeed; // 1351 -// class KeepPersonalSpace spacer; // 1365 -// { -// float const pushSpeed; // 1258 -// Vector dir; // 1260 -// operator-(const Vector *const this, -// const Vector &v); // 1260 -// NormalizeInPlace(Vector *const this); // 1262 -// ResetJump(CHostageImprov *const this); // 1247 -// } -// { -// Vector angles; // 1282 -// float yaw; // 1284 -// float pitch; // 1288 -// operator-(const Vector *const this, -// const Vector &v); // 1282 -// } -// { -// class HostagePathCost pathCost; // 1322 -// Compute(CNavPath *const this, -// const Vector *start, -// const Vector *goal, -// class HostagePathCost &costFunc); // 1323 -// SetPath(CNavPathFollower *const this, -// class CNavPath *path); // 1326 -// SetImprov(CNavPathFollower *const this, -// class CImprov *improv); // 1325 -// Debug(CNavPathFollower *const this, -// bool status); // 1328 -// } -// IsElapsed(const class CountdownTimer *const this); // 1333 -// ResetStuck(CNavPathFollower *const this); // 1336 -// NormalizeInPlace(Vector2D *const this); // 1349 -// operator*(float fl, -// const class Vector2D &v); // 1355 -// KeepPersonalSpace(KeepPersonalSpace *const this, -// class CHostageImprov *improv); // 1365 -// ForEachPlayer(KeepPersonalSpace &func); // 1366 -// DrawAxes(Vector &origin, -// int red, -// int green, -// int blue); // 1223 -// ForEachHostage(const class CHostageManager *const this, -// class KeepPersonalSpace &func); // 1369 -// } + CNavArea *area = TheNavAreaGrid.GetNavArea(&m_hostage->pev->origin); + + if (area != NULL) + { + m_lastKnownArea = area; + } + + DrawAxes(m_moveGoal, 255, 255, 0); + + if (IsJumping()) + { + Vector dir; + const float pushSpeed = 100.0f; + + if (!m_hasJumped) + { + m_hasJumped = true; + m_hasJumpedIntoAir = false; + m_hostage->pev->velocity.z += 300.0f; + } + else + ResetJump(); + + dir = m_jumpTarget - GetFeet(); + dir.z = 0; + + dir.NormalizeInPlace(); + + m_hostage->pev->velocity.x = dir.x * pushSpeed; + m_hostage->pev->velocity.y = dir.y * pushSpeed; + + m_hostage->SetBoneController(0); + m_hostage->SetBoneController(1); + + FaceTowards(m_jumpTarget, deltaT); + return; + } + + if (m_isLookingAt) + { + Vector angles = UTIL_VecToAngles(m_viewGoal - GetEyes()); + float_precision pitch = angles.x - m_hostage->pev->angles.x; + float_precision yaw = angles.y - m_hostage->pev->angles.y; + + while (yaw > 180.0f) + yaw -= 360.0f; + + while (yaw < -180.0f) + yaw += 360.0f; + + while (pitch > 180.0f) + pitch -= 360.0f; + + while (pitch < -180.0f) + pitch += 360.0f; + + m_hostage->SetBoneController(0, yaw); + m_hostage->SetBoneController(1, -pitch); + + if (IsAtMoveGoal() && !HasFaceTo()) + { + if (yaw < -45.0f || yaw > 45.0f) + { + FaceTowards(m_viewGoal, deltaT); + } + } + } + else + { + m_hostage->SetBoneController(0); + m_hostage->SetBoneController(1); + } + + if (HasFaceTo() && FaceTowards(m_faceGoal, deltaT)) + ClearFaceTo(); + + if (!IsAtMoveGoal() || m_path.GetSegmentCount() > 0) + { + if (m_path.GetSegmentCount() <= 0) + { + HostagePathCost pathCost; + if (m_path.Compute(&GetFeet(), &m_moveGoal, pathCost)) + { + m_follower.SetPath(&m_path); + m_follower.SetImprov(this); + + m_follower.Reset(); + m_follower.Debug(cv_hostage_debug.value > 0.0); + } + } + + m_follower.Update(deltaT, m_inhibitObstacleAvoidance.IsElapsed()); + + if (m_moveType == Stopped) + { + m_follower.ResetStuck(); + } + + if (m_follower.IsStuck()) + { + Wiggle(); + } + } + + const float friction = 3.0f; + + m_vel.x += m_vel.x * -friction * deltaT; + m_vel.y += m_vel.y * -friction * deltaT; + + float_precision speed = m_vel.NormalizeInPlace(); + + const float maxSpeed = 285.0f; + if (speed > maxSpeed) + { + speed = maxSpeed; + } + + m_vel.x = m_vel.x * speed; + m_vel.y = m_vel.y * speed; + + KeepPersonalSpace spacer(this); + ForEachPlayer(spacer); + + if (g_pHostages != NULL) + { + g_pHostages->ForEachHostage(spacer); + } + + m_hostage->pev->velocity.x = m_vel.x; + m_hostage->pev->velocity.y = m_vel.y; + + m_moveFlags = 0; } /* <47837a> ../cstrike/dlls/hostage/hostage_improv.cpp:1384 */ -NOBODY void CHostageImprov::__MAKE_VHOOK(OnUpkeep)(float deltaT) +void CHostageImprov::__MAKE_VHOOK(OnUpkeep)(float deltaT) { + if (IsAlive()) + { + UpdatePosition(deltaT); + } } /* <4749f9> ../cstrike/dlls/hostage/hostage_improv.cpp:1396 */ @@ -762,15 +1044,14 @@ bool CHostageImprov::IsTerroristNearby(void) /* <474ae7> ../cstrike/dlls/hostage/hostage_improv.cpp:1412 */ void CHostageImprov::CheckForNearbyTerrorists(void) { - const float checkInterval = 2.0f; - float range; - if (!m_checkNearbyTerroristTimer.IsElapsed()) return; - + + const float checkInterval = 2.0f; m_checkNearbyTerroristTimer.Start(checkInterval); m_isTerroristNearby = false; + float range; if (GetClosestPlayerByTravelDistance(TERRORIST, &range)) { const float nearbyTerroristRange = 2000.0f; @@ -783,45 +1064,206 @@ void CHostageImprov::CheckForNearbyTerrorists(void) } /* <4753ba> ../cstrike/dlls/hostage/hostage_improv.cpp:1440 */ -NOBODY void CHostageImprov::UpdateGrenadeReactions(void) +void CHostageImprov::UpdateGrenadeReactions(void) { -// IsElapsed(const class CountdownTimer *const this); // 1442 -// { -// class CBaseEntity *entity; // 1458 -// float const watchGrenadeRadius; // 1459 -// Start(CountdownTimer *const this, -// float duration); // 1456 -// FClassnameIs(entvars_t *pev, -// const char *szClassname); // 1464 -// { -// class CGrenade *grenade; // 1466 -// OnInjury(HostageIdleState *const this, -// float amount); // 1480 -// Start(CountdownTimer *const this, -// float duration); // 1489 -// } -// } -// Start(CountdownTimer *const this, -// float duration); // 1447 + if (m_coughTimer.IsElapsed()) + { + if (TheBots->IsInsideSmokeCloud(&GetCentroid())) + { + m_coughTimer.Start(RANDOM_FLOAT(1, 3)); + Chatter(HOSTAGE_CHATTER_COUGH); + Frighten(SCARED); + } + } + + if (m_grenadeTimer.IsElapsed()) + { + CBaseEntity *entity = NULL; + const float watchGrenadeRadius = 500.0f; + + m_grenadeTimer.Start(RANDOM_FLOAT(0.4, 0.6)); + + while ((entity = UTIL_FindEntityInSphere(entity, GetCentroid(), watchGrenadeRadius)) != NULL) + { + CGrenade *grenade = static_cast(entity); + + if (!FClassnameIs(grenade->pev, "grenade") || grenade->m_SGSmoke > 1) + continue; + + if (IsVisible(grenade->Center())) + { + Chatter(HOSTAGE_CHATTER_SAW_HE_GRENADE); + + if (grenade->pev->dmg > 50.0f) + { + m_idleState.OnInjury(); + Frighten(TERRIFIED); + } + else + Frighten(SCARED); + + m_grenadeTimer.Start(10); + break; + } + } + } } /* <475ce3> ../cstrike/dlls/hostage/hostage_improv.cpp:1502 */ -NOBODY void CHostageImprov::__MAKE_VHOOK(OnUpdate)(float deltaT) +void CHostageImprov::__MAKE_VHOOK(OnUpdate)(float deltaT) { -// { -// float const runSpeed; // 1553 -// float const walkSpeed; // 1554 -// float const fallVelocity; // 1560 -// float const safeTime; // 1687 -// { -// float dot; // 1621 -// { -// float speed; // 1632 -// } -// } -// } -// OnUpdate(CHostageImprov *const this, -// float deltaT); // 1502 + if (!IsAlive() || cv_hostage_stop.value > 0.0f) + return; + + if (m_blinkTimer.IsElapsed()) + { + if (m_scaredTimer.IsElapsed() && m_animateState.GetPerformance() != HostageAnimateState::Afraid) + { + m_blinkTimer.Start(RANDOM_FLOAT(3, 10)); + m_blinkCounter = RANDOM_LONG(2, 4); + } + else + { + m_blinkTimer.Start(RANDOM_FLOAT(0.5, 2.0)); + m_blinkCounter = RANDOM_LONG(1, 2); + + } + } + + if (m_blinkCounter) + { + m_hostage->pev->body = 1; + --m_blinkCounter; + } + else + { + m_hostage->pev->body = 0; + } + + UpdateGrenadeReactions(); + UpdateDelayedChatter(); + UpdateVision(); + + m_behavior.Update(); + + m_actualVel.x = m_hostage->pev->origin.x - m_lastPosition.x; + m_actualVel.y = m_hostage->pev->origin.y - m_lastPosition.y; + + const float runSpeed = 289.0f; + const float walkSpeed = 9.0f; + const float fallVelocity = -1000.0f; + const float safeTime = 0.4f; + + if (IsOnGround()) + { + if (IsCrouching()) + { + if (m_actualVel.LengthSquared() > 9.0f) + { + if (m_animateState.GetPerformance() != HostageAnimateState::CrouchWalk) + { + m_animateState.Reset(); + m_animateState.SetPerformance(HostageAnimateState::CrouchWalk); + + ClearLookAt(); + if (m_scaredTimer.IsElapsed() && m_animateState.GetPerformance() != HostageAnimateState::Afraid) + m_animateState.AddSequence(this, ACT_CROUCH_WALK, 99.9, 2.0); + else + m_animateState.AddSequence(this, ACT_CROUCH_WALK_SCARED, 99.9, 2.0); + } + } + else if (m_animateState.GetPerformance() != HostageAnimateState::Crouch) + { + m_animateState.Reset(); + m_animateState.SetPerformance(HostageAnimateState::Crouch); + + if (m_scaredTimer.IsElapsed()) + m_animateState.AddSequence(this, ACT_CROUCH_IDLE, 99.9); + else + m_animateState.AddSequence(this, ACT_CROUCH_IDLE_SCARED); + } + } + else + { + UTIL_MakeVectors(m_hostage->pev->angles); + + float dot = DotProduct2D(gpGlobals->v_forward, m_actualVel); + + if (dot < -3.0f) + { + if (m_animateState.GetPerformance() != HostageAnimateState::Walk) + { + m_animateState.Reset(); + m_animateState.SetPerformance(HostageAnimateState::Walk); + ClearLookAt(); + + float speed; + if (m_actualVel.LengthSquared() > runSpeed) + speed = 2.0f; + else + speed = 1.0f; + + m_animateState.AddSequence(this, ACT_WALK_BACK, 99.9, speed); + } + } + else + { + if (m_actualVel.LengthSquared() > runSpeed) + { + if (m_animateState.GetPerformance() != HostageAnimateState::Run) + { + m_animateState.Reset(); + m_animateState.SetPerformance(HostageAnimateState::Run); + ClearLookAt(); + + if (m_scaredTimer.IsElapsed() && m_animateState.GetPerformance() != HostageAnimateState::Afraid && !m_behavior.IsState(&m_escapeState)) + m_animateState.AddSequence(this, ACT_RUN, 99.9, 2.0); + else + m_animateState.AddSequence(this, ACT_RUN_SCARED, 99.9, 2.0); + } + } + else if (m_actualVel.LengthSquared() > walkSpeed) + { + if (m_animateState.GetPerformance() != HostageAnimateState::Walk) + { + m_animateState.Reset(); + m_animateState.SetPerformance(HostageAnimateState::Walk); + ClearLookAt(); + + if (m_behavior.IsState(&m_escapeState)) + { + m_animateState.AddSequence(this, ACT_WALK_SNEAKY, 99.9, 1.5); + } + else if (m_scaredTimer.IsElapsed() && m_animateState.GetPerformance() != HostageAnimateState::Afraid) + { + m_animateState.AddSequence(this, ACT_WALK, 99.9, 1.5); + } + else + m_animateState.AddSequence(this, ACT_WALK_SCARED, 99.9, 1.5); + } + } + else + { + if (m_animateState.GetPerformance() == HostageAnimateState::Walk || m_animateState.GetPerformance() == HostageAnimateState::Run) + m_animateState.Reset(); + + UpdateStationaryAnimation(); + } + } + } + } + else if (m_hostage->pev->velocity.z < fallVelocity && m_animateState.GetPerformance() != HostageAnimateState::Fall) + { + m_animateState.Reset(); + m_animateState.SetPerformance(HostageAnimateState::Fall); + m_animateState.AddSequence(this, ACT_FALL, 99.9); + } + + if (!m_collisionTimer.HasStarted() || m_collisionTimer.IsGreaterThen(safeTime)) + SetKnownGoodPosition(m_lastPosition); + + m_lastPosition = m_hostage->pev->origin; + m_animateState.OnUpdate(this); } /* <47552a> ../cstrike/dlls/hostage/hostage_improv.cpp:1705 */ @@ -842,18 +1284,18 @@ void CHostageImprov::__MAKE_VHOOK(OnGameEvent)(GameEventType event, CBaseEntity } case EVENT_PLAYER_DIED: case EVENT_HOSTAGE_KILLED: - if (IsVisible(entity->pev->origin, true)) - { - Frighten(TERRIFIED); - - if (!entity->IsPlayer() || entity->IsPlayer() && ((CBasePlayer *)entity)->m_iTeam != TERRORIST) - { - DelayedChatter(RANDOM_FLOAT(0.5, 0.7), HOSTAGE_CHATTER_SCARED_OF_MURDER, true); - } - if (!entity->IsPlayer()) - { - m_idleState.OnInjury(0); - } + if (IsVisible(entity->pev->origin, true)) + { + Frighten(TERRIFIED); + + if (!entity->IsPlayer() || entity->IsPlayer() && ((CBasePlayer *)entity)->m_iTeam != TERRORIST) + { + DelayedChatter(RANDOM_FLOAT(0.5, 0.7), HOSTAGE_CHATTER_SCARED_OF_MURDER, true); + } + if (!entity->IsPlayer()) + { + m_idleState.OnInjury(); + } } break; case EVENT_HOSTAGE_RESCUED: @@ -862,7 +1304,7 @@ void CHostageImprov::__MAKE_VHOOK(OnGameEvent)(GameEventType event, CBaseEntity if (!entity) return; - Chatter(HOSTAGE_CHATTER_RESCUED); + Chatter(HOSTAGE_CHATTER_RESCUED, false); } break; case EVENT_TERRORISTS_WIN: @@ -882,7 +1324,7 @@ void CHostageImprov::__MAKE_VHOOK(OnGameEvent)(GameEventType event, CBaseEntity float range; PriorityType priority; bool isHostile; - + if (entity != NULL && IsGameEventAudible(event, entity, other, &range, &priority, &isHostile)) { const float fudge = 0.4f; @@ -934,125 +1376,126 @@ void CHostageImprov::__MAKE_VHOOK(OnGameEvent)(GameEventType event, CBaseEntity /* <471e27> ../cstrike/dlls/hostage/hostage_improv.cpp:1854 */ void CHostageImprov::__MAKE_VHOOK(OnTouch)(CBaseEntity *other) -{ - const char *classname; - Vector2D to; - const float pushForce = 20.0f; - - classname = STRING(other->pev->classname); - - if (cv_hostage_debug.value != 0.0) - { - CONSOLE_ECHO("%5.1f: Hostage hit '%s'\n", gpGlobals->time, classname); - } - - m_collisionTimer.Start(); - - if (FStrEq(classname, "worldspawn")) - { - const float lookAheadRange = 30.0f; - float ground; - Vector normal = Vector(0, 0, 1); - Vector alongFloor; - TraceResult result; - bool isStep = false; - - UTIL_MakeVectors(m_hostage->pev->angles); - - if (!GetSimpleGroundHeightWithFloor(&GetEyes(), &ground, &normal)) - return; - - if (cv_hostage_debug.value < 0.0) - { - UTIL_DrawBeamPoints(GetFeet() + normal * 50, GetFeet(), 2, 255, 255, 0); - } - - alongFloor = CrossProduct(normal, gpGlobals->v_right); - - Vector pos = alongFloor * lookAheadRange; - - for (float offset = 1.0f; offset <= 18.0f; offset += 3.0f) - { - Vector vecStart = GetFeet(); - vecStart.z += offset; - - UTIL_TraceLine(vecStart, vecStart + pos, ignore_monsters, dont_ignore_glass, m_hostage->pev->pContainingEntity, &result); - - if (result.flFraction < 1.0f && result.vecPlaneNormal[2] < 0.7f) - { - isStep = true; - break; - } - } - - if (isStep) - { - float stepAheadGround = pos.z; - Vector stepAheadNormal = Vector(0, 0, stepAheadGround); - - m_inhibitObstacleAvoidance.Start(0.5); - - for (float range = 1.0f; range <= 30.5f; range += 5.0f) - { - Vector stepAhead = GetFeet() + alongFloor * range; - - if (GetSimpleGroundHeightWithFloor(&stepAhead, &stepAheadGround, &stepAheadNormal)) - { - float dz = stepAheadGround - GetFeet().z; - - if (dz > 0.0f && dz < 18.0f) - { - m_hostage->pev->origin.z = stepAheadGround + 3.0f; - break; - } - } - } - } - else if (!IsMoving() && !IsUsingLadder()) - { - bool isSeam = false; - const float checkSeamRange = 50.0f; - Vector posBehind; - - posBehind = GetEyes() - alongFloor * checkSeamRange; - UTIL_TraceLine(posBehind, posBehind - Vector(0, 0, 9999), ignore_monsters, dont_ignore_glass, m_hostage->pev->pContainingEntity, &result); - - if (result.flFraction < 1.0f && DotProduct(result.vecPlaneNormal, normal) < 1.0f) - { - isSeam = true; - } - else - { - Vector posAhead = GetEyes() + alongFloor * checkSeamRange; - UTIL_TraceLine(posAhead, posAhead - Vector(0, 0, 9999), ignore_monsters, dont_ignore_glass, m_hostage->pev->pContainingEntity, &result); - - if (result.flFraction < 1.0f && DotProduct(result.vecPlaneNormal, normal) < 1.0f) - isSeam = true; - } - - if (isSeam) - { - if (cv_hostage_debug.value != 0.0) - { - CONSOLE_ECHO("Hostage stuck on seam.\n"); - } - - const float nudge = 3.0f; - m_hostage->pev->origin.z += nudge; - } - } - } - else if (FStrEq(classname, "func_breakable")) - { - other->TakeDamage(m_hostage->pev, m_hostage->pev, 9999.9, DMG_BULLET); - } - else if (other->IsPlayer() || FClassnameIs(other->pev, "hostage_entity")) - { - to = (m_hostage->pev->origin - other->pev->origin).Make2D(); - to.NormalizeInPlace(); - - m_vel.x += to.x * pushForce; - m_vel.y += to.y * pushForce; +{ + const char *classname; + Vector2D to; + const float pushForce = 20.0f; + + classname = STRING(other->pev->classname); + + if (cv_hostage_debug.value != 0.0) + { + CONSOLE_ECHO("%5.1f: Hostage hit '%s'\n", gpGlobals->time, classname); + } + + m_collisionTimer.Start(); + + if (FStrEq(classname, "worldspawn")) + { + const float lookAheadRange = 30.0f; + float ground; + Vector normal = Vector(0, 0, 1); + Vector alongFloor; + TraceResult result; + bool isStep = false; + + UTIL_MakeVectors(m_hostage->pev->angles); + + if (!GetSimpleGroundHeightWithFloor(&GetEyes(), &ground, &normal)) + return; + + if (cv_hostage_debug.value < 0.0) + { + UTIL_DrawBeamPoints(GetFeet() + normal * 50, GetFeet(), 2, 255, 255, 0); + } + + alongFloor = CrossProduct(normal, gpGlobals->v_right); + + Vector pos = alongFloor * lookAheadRange; + + for (double offset = 1.0f; offset <= 18.0f; offset += 3.0f) + { + Vector vecStart = GetFeet(); + vecStart.z += offset; + + UTIL_TraceLine(vecStart, vecStart + pos, ignore_monsters, dont_ignore_glass, m_hostage->pev->pContainingEntity, &result); + + if (result.flFraction < 1.0f && result.vecPlaneNormal[2] < 0.7f) + { + isStep = true; + break; + } + } + + if (isStep) + { + float stepAheadGround = pos.z; + Vector stepAheadNormal = Vector(0, 0, stepAheadGround); + + m_inhibitObstacleAvoidance.Start(0.5); + + for (float range = 1.0f; range <= 30.5f; range += 5.0f) + { + Vector stepAhead = GetFeet() + alongFloor * range; + stepAhead.z = GetEyes().z; + + if (GetSimpleGroundHeightWithFloor(&stepAhead, &stepAheadGround, &stepAheadNormal)) + { + float dz = stepAheadGround - GetFeet().z; + + if (dz > 0.0f && dz < 18.0f) + { + m_hostage->pev->origin.z = stepAheadGround + 3.0f; + break; + } + } + } + } + else if (!IsMoving() && !IsUsingLadder()) + { + bool isSeam = false; + const float checkSeamRange = 50.0f; + Vector posBehind; + + posBehind = GetEyes() - alongFloor * checkSeamRange; + UTIL_TraceLine(posBehind, posBehind - Vector(0, 0, 9999), ignore_monsters, dont_ignore_glass, m_hostage->pev->pContainingEntity, &result); + + if (result.flFraction < 1.0f && DotProduct(result.vecPlaneNormal, normal) < 1.0f) + { + isSeam = true; + } + else + { + Vector posAhead = GetEyes() + alongFloor * checkSeamRange; + UTIL_TraceLine(posAhead, posAhead - Vector(0, 0, 9999), ignore_monsters, dont_ignore_glass, m_hostage->pev->pContainingEntity, &result); + + if (result.flFraction < 1.0f && DotProduct(result.vecPlaneNormal, normal) < 1.0f) + isSeam = true; + } + + if (isSeam) + { + if (cv_hostage_debug.value != 0.0) + { + CONSOLE_ECHO("Hostage stuck on seam.\n"); + } + + const float nudge = 3.0f; + m_hostage->pev->origin.z += nudge; + } + } + } + else if (FStrEq(classname, "func_breakable")) + { + other->TakeDamage(m_hostage->pev, m_hostage->pev, 9999.9, DMG_BULLET); + } + else if (other->IsPlayer() || FClassnameIs(other->pev, "hostage_entity")) + { + to = (m_hostage->pev->origin - other->pev->origin).Make2D(); + to.NormalizeInPlace(); + + m_vel.x += to.x * pushForce; + m_vel.y += to.y * pushForce; } } @@ -1064,13 +1507,13 @@ void CHostageImprov::ApplyForce(Vector force) } /* <474bd5> ../cstrike/dlls/hostage/hostage_improv.cpp:2016 */ -bool CHostageImprov::IsAtHome(void) +bool CHostageImprov::IsAtHome(void) const { return m_hostage->IsAtHome(); } /* <474c76> ../cstrike/dlls/hostage/hostage_improv.cpp:2025 */ -bool CHostageImprov::CanSeeRescueZone(void) +bool CHostageImprov::CanSeeRescueZone(void) const { CCSBotManager *ctrl = TheCSBots(); @@ -1140,7 +1583,7 @@ float CHostageImprov::GetTimeSinceLastNoise(void) } /* <47503a> ../cstrike/dlls/hostage/hostage_improv.cpp:2117 */ -bool CHostageImprov::IsScared(void) +bool CHostageImprov::IsScared(void) const { if (m_scaredTimer.IsElapsed()) { @@ -1202,7 +1645,7 @@ void CHostageImprov::Afraid(void) Q_sprintf(animInto, "cower_into_%d", which); Q_sprintf(animLoop, "cower_loop_%d", which); Q_sprintf(animExit, "cower_exit_%d", which); - + m_animateState.AddSequence(this, animInto); m_animateState.AddSequence(this, animLoop, RANDOM_FLOAT(3, 10)); m_animateState.AddSequence(this, animExit); @@ -1264,7 +1707,7 @@ void CHostageImprov::DelayedChatter(float delayTime, HostageChatterType sayType, } /* <475bd4> ../cstrike/dlls/hostage/hostage_improv.cpp:2268 */ -NOXREF void CHostageImprov::UpdateDelayedChatter(void) +void CHostageImprov::UpdateDelayedChatter(void) { if (!m_isDelayedChatterPending) return; @@ -1277,7 +1720,7 @@ NOXREF void CHostageImprov::UpdateDelayedChatter(void) switch (m_delayedChatterType) { case HOSTAGE_CHATTER_SCARED_OF_GUNFIRE: - if (RANDOM_FLOAT(0, 100) < 25) + if (RANDOM_FLOAT(0, 100) <= 25) { Chatter(m_delayedChatterType, m_delayedChatterMustSpeak); } @@ -1285,7 +1728,7 @@ NOXREF void CHostageImprov::UpdateDelayedChatter(void) case HOSTAGE_CHATTER_LOOK_OUT: case HOSTAGE_CHATTER_PLEASE_RESCUE_ME: case HOSTAGE_CHATTER_IMPATIENT_FOR_RESCUE: - if (RANDOM_FLOAT(0, 100) < 60) + if (RANDOM_FLOAT(0, 100) <= 60) { Chatter(m_delayedChatterType, m_delayedChatterMustSpeak); } @@ -1401,13 +1844,13 @@ void CHostageImprov::Wiggle(void) default: break; } - - if (m_follower.GetStuckDuration() > minStuckJumpTime && m_wiggleJumpTimer.IsElapsed()) - { - if (Jump()) - { - m_wiggleJumpTimer.Start(RANDOM_FLOAT(0.75, 1.2)); - } + + if (m_follower.GetStuckDuration() > minStuckJumpTime && m_wiggleJumpTimer.IsElapsed()) + { + if (Jump()) + { + m_wiggleJumpTimer.Start(RANDOM_FLOAT(0.75, 1.2)); + } } } @@ -1509,6 +1952,17 @@ void CHostageImprov::UpdateStationaryAnimation(void) #ifdef HOOK_GAMEDLL +// NavAreaBuildPath hook +bool NavAreaBuildPath__HostagePathCost__wrapper(CNavArea *startArea, CNavArea *goalArea, const Vector *goalPos, class HostagePathCost &costFunc, CNavArea **closestArea) +{ + return NavAreaBuildPath(startArea, goalArea, goalPos, costFunc, closestArea); +} + +// NavAreaBuildPath hook +bool NavAreaBuildPath__ShortestPathCost__wrapper(CNavArea *startArea, CNavArea *goalArea, const Vector *goalPos, class ShortestPathCost &costFunc, CNavArea **closestArea) +{ + return NavAreaBuildPath(startArea, goalArea, goalPos, costFunc, closestArea); +} void CHostageImprov::OnMoveToFailure(const Vector &goal, MoveToFailureType reason) { diff --git a/regamedll/dlls/hostage/hostage_improv.h b/regamedll/dlls/hostage/hostage_improv.h index 06143ca6..633497ee 100644 --- a/regamedll/dlls/hostage/hostage_improv.h +++ b/regamedll/dlls/hostage/hostage_improv.h @@ -32,6 +32,7 @@ #pragma once #endif +#include "hostage/hostage.h" #include "hostage/hostage_states.h" class CHostage; @@ -40,478 +41,607 @@ enum HostageChatterType; class CHostageImprov: public CImprov { public: - //CHostageImprov(void) {}; CHostageImprov(CBaseEntity *entity); - ~CHostageImprov(void) - { - //~HostageAnimateState(); // 49 - //~HostageFollowState(); // 49 - //~HostageRetreatState(); // 49 - //~HostageEscapeState(); // 49 - //~HostageIdleState(); // 49 - //~CImprov(); // 49 - }; + ~CHostageImprov(void) {}; - NOBODY virtual void OnMoveToSuccess(const Vector &goal) - { - //if (m_behavior.IsState(NULL)) - // IImprovEvent::OnMoveToSuccess(goal); - } - virtual void OnMoveToFailure(const Vector &goal, MoveToFailureType reason); - NOBODY virtual void OnInjury(float amount) + virtual void OnMoveToSuccess(const Vector &goal) + { + m_behavior.OnMoveToSuccess(goal); + } + virtual void OnMoveToFailure(const Vector &goal, MoveToFailureType reason); + virtual void OnInjury(float amount) + { + m_behavior.OnInjury(amount); + + m_lastInjuryTimer.Start(); + Frighten(TERRIFIED); + } + virtual bool IsAlive(void) const; + virtual void MoveTo(const Vector &goal); + virtual void LookAt(const Vector &target); + virtual void ClearLookAt(void); + 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 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; + } + + #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 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 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 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 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 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); + +#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(); } - NOBODY virtual bool IsAlive(void) const; - NOBODY virtual void MoveTo(const Vector &goal); - NOBODY virtual void LookAt(const Vector &target); - NOBODY virtual void ClearLookAt(void); - NOBODY virtual void FaceTo(const Vector &goal); - NOBODY virtual void ClearFaceTo(void); - NOBODY virtual bool IsAtMoveGoal(float error = 20.0f) const; - virtual bool HasLookAt(void) const - { - return m_isLookingAt; - } - virtual bool HasFaceTo(void) const - { - return m_isFacingTo; - } - NOBODY virtual bool IsAtFaceGoal(void) const; - NOBODY virtual bool IsFriendInTheWay(const Vector &goalPos) const; - NOBODY 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; - } - - #define HOSTAGE_MUST_JUMP true - virtual bool Jump(void); - - virtual void Crouch(void); - virtual void StandUp(void); - NOBODY virtual void TrackPath(const Vector &pathGoal, float deltaT); - NOBODY virtual void StartLadder(const CNavLadder *ladder, NavTraverseType how, const Vector *approachPos, const Vector *departPos); - NOBODY virtual bool TraverseLadder(const CNavLadder *ladder, NavTraverseType how, const Vector *approachPos, const Vector *departPos, float deltaT); - NOBODY virtual bool GetSimpleGroundHeightWithFloor(const Vector *pos, float *height, Vector *normal = NULL); - NOBODY virtual void Run(void); - NOBODY virtual void Walk(void); - NOBODY virtual void Stop(void); - 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 - { - UNTESTED - return (m_jumpTimer.IsElapsed() == false); - } - virtual bool IsUsingLadder(void) const - { - return false; - } - NOBODY virtual bool IsOnGround(void) const; - NOBODY 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; - } - NOBODY virtual bool IsVisible(const Vector &pos, bool testFOV = false) const; - NOBODY virtual bool IsPlayerLookingAtMe(CBasePlayer *other, float cosTolerance = 0.95f) const; - NOBODY virtual CBasePlayer *IsAnyPlayerLookingAtMe(int team = 0, float cosTolerance = 0.95f) const; - NOBODY virtual CBasePlayer *GetClosestPlayerByTravelDistance(int team = 0, float *range = NULL) const; - virtual CNavArea *GetLastKnownArea(void) const - { - return m_lastKnownArea; - } - NOBODY virtual void OnUpdate(float deltaT); - NOBODY virtual void OnUpkeep(float deltaT); - virtual void OnReset(void); - NOBODY virtual void OnGameEvent(GameEventType event, CBaseEntity *entity = NULL, CBaseEntity *other = NULL); - NOBODY virtual void OnTouch(CBaseEntity *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); - void ClearLookAt_(void); - void FaceTo_(const Vector &goal); - void ClearFaceTo_(void); - bool IsAtMoveGoal_(float error = 20.0f) const; - bool IsAtFaceGoal_(void) const; - bool IsFriendInTheWay_(const Vector &goalPos) const; - bool IsFriendInTheWay_(CBaseEntity *myFriend, const Vector &goalPos) const; - bool Jump_(void); - void Crouch_(void); - void StandUp_(void); - void TrackPath_(const Vector &pathGoal, float deltaT); - void StartLadder_(const CNavLadder *ladder, NavTraverseType how, const Vector *approachPos, const Vector *departPos); - bool TraverseLadder_(const CNavLadder *ladder, NavTraverseType how, const Vector *approachPos, const Vector *departPos, float deltaT); - bool GetSimpleGroundHeightWithFloor_(const Vector *pos, float *height, Vector *normal = NULL); - void Run_(void); - void Walk_(void); - void Stop_(void); - const Vector &GetFeet_(void) const; - const Vector &GetCentroid_(void) const; - const Vector &GetEyes_(void) const; - bool IsOnGround_(void) const; - bool IsMoving_(void) const; - bool IsVisible_(const Vector &pos, bool testFOV = false) const; - bool IsPlayerLookingAtMe_(CBasePlayer *other, float cosTolerance = 0.95f) const; - CBasePlayer *IsAnyPlayerLookingAtMe_(int team = 0, float cosTolerance = 0.95f) const; - CBasePlayer *GetClosestPlayerByTravelDistance_(int team = 0, float *range = NULL) const; - void OnUpdate_(float deltaT); - void OnUpkeep_(float deltaT); - void OnReset_(void); - void OnGameEvent_(GameEventType event, CBaseEntity *entity = NULL, CBaseEntity *other = NULL); + bool IsAlive_(void) const; + void MoveTo_(const Vector &goal); + void LookAt_(const Vector &target); + void ClearLookAt_(void); + void FaceTo_(const Vector &goal); + void ClearFaceTo_(void); + bool IsAtMoveGoal_(float error = 20.0f) const; + bool IsAtFaceGoal_(void) const; + bool IsFriendInTheWay_(const Vector &goalPos) const; + bool IsFriendInTheWay_(CBaseEntity *myFriend, const Vector &goalPos) const; + bool Jump_(void); + void Crouch_(void); + void StandUp_(void); + void TrackPath_(const Vector &pathGoal, float deltaT); + void StartLadder_(const CNavLadder *ladder, NavTraverseType how, const Vector *approachPos, const Vector *departPos); + bool TraverseLadder_(const CNavLadder *ladder, NavTraverseType how, const Vector *approachPos, const Vector *departPos, float deltaT); + bool GetSimpleGroundHeightWithFloor_(const Vector *pos, float *height, Vector *normal = NULL); + void Run_(void); + void Walk_(void); + void Stop_(void); + const Vector &GetFeet_(void) const; + const Vector &GetCentroid_(void) const; + const Vector &GetEyes_(void) const; + bool IsOnGround_(void) const; + bool IsMoving_(void) const; + bool IsVisible_(const Vector &pos, bool testFOV = false) const; + bool IsPlayerLookingAtMe_(CBasePlayer *other, float cosTolerance = 0.95f) const; + CBasePlayer *IsAnyPlayerLookingAtMe_(int team = 0, float cosTolerance = 0.95f) const; + CBasePlayer *GetClosestPlayerByTravelDistance_(int team = 0, float *range = NULL) const; + void OnUpdate_(float deltaT); + void OnUpkeep_(float deltaT); + void OnReset_(void); + void OnGameEvent_(GameEventType event, CBaseEntity *entity = NULL, CBaseEntity *other = NULL); void OnTouch_(CBaseEntity *other); #endif // HOOK_GAMEDLL public: - - enum MoveType - { - Stopped = 0, - Walking, - Running, - }; - - enum ScareType - { - NERVOUS = 0, - SCARED, - TERRIFIED, - }; - - void FaceOutwards(void); - bool IsFriendInTheWay(void); - void SetKnownGoodPosition(const Vector &pos); - const Vector &GetKnownGoodPosition(void); - void ResetToKnownGoodPosition(void); - void ResetJump(void); - void ApplyForce(Vector force); - const Vector GetActualVelocity(void); - void SetMoveLimit(MoveType limit) - { - m_moveLimit = limit; - } - MoveType GetMoveLimit(void) - { - return m_moveLimit; - } - CNavPath *GetPath(void); - CNavPathFollower *GetPathFollower(void); - void Idle(void) + enum MoveType { - m_behavior.SetState(&m_idleState); - } - bool IsIdle(void) - { - UNTESTED - return m_behavior.IsState(&m_idleState); - } - void Follow(CBasePlayer *leader) - { - UNTESTED - m_followState.SetLeader(leader); - m_behavior.SetState(&m_followState); - } - bool IsFollowing(const CBaseEntity *leader = NULL) - { - UNTESTED - return m_behavior.IsState(&m_followState); - } - void Escape(void); - bool IsEscaping(void); - void Retreat(void); - bool IsRetreating(void); - bool IsAtHome(void); - bool CanSeeRescueZone(void); - CBaseEntity *GetFollowLeader(void) - { - return m_followState.GetLeader(); - } - CBasePlayer *GetClosestVisiblePlayer(int team); - float GetTimeSinceLastSawPlayer(int team); - float GetTimeSinceLastInjury(void); - float GetTimeSinceLastNoise(void); - bool IsTerroristNearby(void); - void Frighten(ScareType scare); - bool IsScared(void); - ScareType GetScareIntensity(void) - { - return m_scareIntensity; - } - bool IsIgnoringTerrorists(void); - float GetAggression(void); - 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(); - } - void UpdateGrenadeReactions(void); - void Afraid(void); - void Wave(void); - void Agree(void); - void Disagree(void); - void CrouchDie(void); - void Flinch(Activity activity); - void UpdateIdleActivity(Activity activity, Activity fidget); - void UpdateStationaryAnimation(void); - CHostage *GetEntity(void) - { - return m_hostage; - } - void CheckForNearbyTerrorists(void); - void UpdatePosition(float); - void MoveTowards(const Vector &pos, float deltaT); - bool FaceTowards(const Vector &target, float deltaT); - float GetSpeed(void); - void SetMoveAngle(float angle) - { - m_moveAngle = angle; - } - void Wiggle(void); - void ClearPath(void); - - #define HOSTAGE_ONLY_JUMP_DOWN true - bool DiscontinuityJump(float ground, bool onlyJumpDown = false, bool mustJump = false); - + Stopped = 0, + Walking, + Running, + }; + + enum ScareType + { + NERVOUS = 0, + SCARED, + TERRIFIED, + }; + + void FaceOutwards(void); + bool IsFriendInTheWay(void) const; + void SetKnownGoodPosition(const Vector &pos); + const Vector &GetKnownGoodPosition(void) const + { + return m_knownGoodPos; + } + void ResetToKnownGoodPosition(void); + void ResetJump(void) + { + if (m_hasJumpedIntoAir) + { + if (IsOnGround()) + { + m_jumpTimer.Invalidate(); + } + } + else if (!IsOnGround()) + { + m_hasJumpedIntoAir = true; + } + } + void ApplyForce(Vector force); +#ifdef PLAY_GAMEDLL + void ApplyForce2(float_precision x, float_precision y) + { + m_vel.x += x; + 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; + } + 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); + } + bool IsAtHome(void) const; + bool CanSeeRescueZone(void) const; + CBaseEntity *GetFollowLeader(void) const + { + return m_followState.GetLeader(); + } + CBasePlayer *GetClosestVisiblePlayer(int team); + float GetTimeSinceLastSawPlayer(int team); + float GetTimeSinceLastInjury(void); + float GetTimeSinceLastNoise(void); + 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; + } + 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(); + } + void UpdateGrenadeReactions(void); + void Afraid(void); + void Wave(void); + void Agree(void); + void Disagree(void); + void CrouchDie(void); + void Flinch(Activity activity); + void UpdateIdleActivity(Activity activity, Activity fidget); + void UpdateStationaryAnimation(void); + 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); + float GetSpeed(void); + void SetMoveAngle(float angle) + { + m_moveAngle = angle; + } + void Wiggle(void); + void ClearPath(void); + + #define HOSTAGE_ONLY_JUMP_DOWN true + bool DiscontinuityJump(float ground, bool onlyJumpDown = false, bool mustJump = false); void UpdateVision(void); + public: - CountdownTimer m_coughTimer; + CountdownTimer m_coughTimer; CountdownTimer m_grenadeTimer; -/*private:*/ - CHostage *m_hostage; - CNavArea *m_lastKnownArea; - mutable Vector m_centroid; - mutable Vector m_eye; - HostageStateMachine m_behavior; - HostageIdleState m_idleState; - HostageEscapeState m_escapeState; - HostageRetreatState m_retreatState; - HostageFollowState m_followState; - HostageAnimateState m_animateState; - bool m_didFidget; - float m_aggression; - IntervalTimer m_lastSawCT; - IntervalTimer m_lastSawT; - CountdownTimer m_checkNearbyTerroristTimer; - bool m_isTerroristNearby; - CountdownTimer m_nearbyTerroristTimer; - CountdownTimer m_scaredTimer; - ScareType m_scareIntensity; - CountdownTimer m_ignoreTerroristTimer; - CountdownTimer m_blinkTimer; - char m_blinkCounter; - IntervalTimer m_lastInjuryTimer; - IntervalTimer m_lastNoiseTimer; - CountdownTimer m_avoidFriendTimer; - bool m_isFriendInTheWay; - CountdownTimer m_chatterTimer; - bool m_isDelayedChatterPending; - CountdownTimer m_delayedChatterTimer; - HostageChatterType m_delayedChatterType; - bool m_delayedChatterMustSpeak; - CountdownTimer m_talkingTimer; - unsigned int m_moveFlags; - Vector2D m_vel; - Vector m_actualVel; - Vector m_moveGoal; - Vector m_knownGoodPos; - bool m_hasKnownGoodPos; - Vector m_priorKnownGoodPos; - bool m_hasPriorKnownGoodPos; - CountdownTimer m_priorKnownGoodPosTimer; - IntervalTimer m_collisionTimer; - Vector m_viewGoal; - bool m_isLookingAt; - Vector m_faceGoal; - bool m_isFacingTo; - CNavPath m_path; - CNavPathFollower m_follower; - Vector m_lastPosition; - MoveType m_moveType; - MoveType m_moveLimit; - bool m_isCrouching; - CountdownTimer m_minCrouchTimer; - float m_moveAngle; - NavRelativeDirType m_wiggleDirection; - CountdownTimer m_wiggleTimer; - CountdownTimer m_wiggleJumpTimer; - CountdownTimer m_inhibitObstacleAvoidance; - CountdownTimer m_jumpTimer; - bool m_hasJumped; - bool m_hasJumpedIntoAir; - Vector m_jumpTarget; - CountdownTimer m_clearPathTimer; - bool m_traversingLadder; - EHANDLE m_visiblePlayer[32]; - int m_visiblePlayerCount; +private: + CHostage *m_hostage; + CNavArea *m_lastKnownArea; + mutable Vector m_centroid; + mutable Vector m_eye; + HostageStateMachine m_behavior; + HostageIdleState m_idleState; + HostageEscapeState m_escapeState; + HostageRetreatState m_retreatState; + HostageFollowState m_followState; + HostageAnimateState m_animateState; + bool m_didFidget; + float m_aggression; + IntervalTimer m_lastSawCT; + IntervalTimer m_lastSawT; + CountdownTimer m_checkNearbyTerroristTimer; + bool m_isTerroristNearby; + CountdownTimer m_nearbyTerroristTimer; + CountdownTimer m_scaredTimer; + ScareType m_scareIntensity; + CountdownTimer m_ignoreTerroristTimer; + CountdownTimer m_blinkTimer; + char m_blinkCounter; + IntervalTimer m_lastInjuryTimer; + IntervalTimer m_lastNoiseTimer; + mutable CountdownTimer m_avoidFriendTimer; + mutable bool m_isFriendInTheWay; + CountdownTimer m_chatterTimer; + bool m_isDelayedChatterPending; + CountdownTimer m_delayedChatterTimer; + HostageChatterType m_delayedChatterType; + bool m_delayedChatterMustSpeak; + CountdownTimer m_talkingTimer; + unsigned int m_moveFlags; + Vector2D m_vel; + Vector m_actualVel; + Vector m_moveGoal; + Vector m_knownGoodPos; + bool m_hasKnownGoodPos; + Vector m_priorKnownGoodPos; + bool m_hasPriorKnownGoodPos; + CountdownTimer m_priorKnownGoodPosTimer; + IntervalTimer m_collisionTimer; + Vector m_viewGoal; + bool m_isLookingAt; + Vector m_faceGoal; + bool m_isFacingTo; + CNavPath m_path; + CNavPathFollower m_follower; + Vector m_lastPosition; + MoveType m_moveType; + MoveType m_moveLimit; + bool m_isCrouching; + CountdownTimer m_minCrouchTimer; + float m_moveAngle; + NavRelativeDirType m_wiggleDirection; + CountdownTimer m_wiggleTimer; + CountdownTimer m_wiggleJumpTimer; + CountdownTimer m_inhibitObstacleAvoidance; + CountdownTimer m_jumpTimer; + bool m_hasJumped; + bool m_hasJumpedIntoAir; + Vector m_jumpTarget; + CountdownTimer m_clearPathTimer; + bool m_traversingLadder; + EHANDLE m_visiblePlayer[32]; + int m_visiblePlayerCount; CountdownTimer m_visionTimer; };/* size: 7308, cachelines: 115, members: 70 */ /* <46fac7> ../cstrike/dlls/hostage/hostage_improv.cpp:363 */ -class CheckWayFunctor -{ -public: - const CHostageImprov *m_me; - Vector m_goalPos; - CHostage *m_blocker; - - /* <46fa9c> ../cstrike/dlls/hostage/hostage_improv.cpp:370 */ - NOBODY inline bool operator()(CHostage *them) - { - // - } - +class CheckWayFunctor +{ +public: + CheckWayFunctor(const CHostageImprov *me, const Vector &goalPos) + { + m_me = me; + m_goalPos = goalPos; + m_blocker = NULL; + } + /* <46fa9c> ../cstrike/dlls/hostage/hostage_improv.cpp:370 */ + bool operator()(CHostage *them) + { + if (((CBaseMonster *)them)->IsAlive() && m_me->IsFriendInTheWay((CBaseEntity *)them, m_goalPos)) + { + m_blocker = them; + return false; + } + + return true; + } + + const CHostageImprov *m_me; + Vector m_goalPos; + CHostage *m_blocker; + }; /* size: 20, cachelines: 1, members: 3 */ -/* <46f426> ../cstrike/dlls/hostage/hostage_improv.h:400 */ -class HostagePathCost -{ -public: - bool operator()(CNavArea *area, class CNavArea *fromArea, const CNavLadder *ladder) - { - // { - // float dist; - // float cost; - // { - // const float ladderCost = 0.0f; - // const float crouchPenalty = 0.0f; - // const float jumpPenalty = 0.0f; - // } - // } - } -}; +/* <46f426> ../cstrike/dlls/hostage/hostage_improv.h:400 */ +class HostagePathCost +{ +public: + float operator()(CNavArea *area, CNavArea *fromArea, const CNavLadder *ladder) + { + if (fromArea == NULL) + { + // first area in path, no cost + return 0.0f; + } + else + { + // compute distance travelled along path so far + float dist; + + if (ladder != NULL) + { + const float ladderCost = 10.0f; + return ladder->m_length * ladderCost + fromArea->GetCostSoFar(); + } + + dist = (*area->GetCenter() - *fromArea->GetCenter()).Length(); + float cost = fromArea->GetCostSoFar() + dist; + + // if this is a "crouch" area, add penalty + if (area->GetAttributes() & NAV_CROUCH) + { + const float crouchPenalty = 10.0f; + cost += crouchPenalty * dist; + } + + // if this is a "jump" area, add penalty + if (area->GetAttributes() & NAV_JUMP) + { + const float jumpPenalty = 10.0f; + cost += jumpPenalty * dist; + } + + return cost; + } + } +}; /* <4700b6> ../cstrike/dlls/hostage/hostage_improv.cpp:931 */ -class KeepPersonalSpace -{ -public: - /* <46f9d7> ../cstrike/dlls/hostage/hostage_improv.cpp:939 */ - bool operator()(CBaseEntity *entity) - { - // { - // float const space; // 953 - // Vector to; // 955 - // float range; // 956 - // { - // class CBasePlayer *player; // 948 - // } - // { - // class CBasePlayer *player; // 961 - // float const cosTolerance; // 962 - // float const spring; // 967 - // float ds; // 969 - // float const minSpace; // 971 - // float const force; // 975 - // float const damper; // 979 - // } - // } - } -private: - CHostageImprov *m_improv; - Vector m_velDir; - float m_speed; - +class KeepPersonalSpace +{ +public: + /* <4700b6> ../cstrike/dlls/hostage/hostage_improv.cpp:931 */ + KeepPersonalSpace(CHostageImprov *improv) + { + m_improv = improv; + m_velDir = improv->GetActualVelocity(); + m_speed = m_velDir.NormalizeInPlace(); + } + /* <46f9d7> ../cstrike/dlls/hostage/hostage_improv.cpp:939 */ + bool operator()(CBaseEntity *entity) + { + const float space = 1.0f; + Vector to; + float range; + + if (entity == reinterpret_cast(m_improv->GetEntity())) + return true; + + if (entity->IsPlayer() && !entity->IsAlive()) + return true; + + to = entity->pev->origin - m_improv->GetCentroid(); + +#ifdef PLAY_GAMEDLL + // TODO: fix test demo + range = to.NormalizeInPlace(); +#else + range = to.NormalizeInPlace(); +#endif // PLAY_GAMEDLL + CBasePlayer *player = static_cast(entity); + + const float spring = 50.0f; + const float damper = 1.0f; + + if (range >= spring) + return true; + + const float cosTolerance = 0.8f; + if (entity->IsPlayer() && player->m_iTeam == CT && !m_improv->IsFollowing() && m_improv->IsPlayerLookingAtMe(player, cosTolerance)) + return true; + + const float minSpace = (spring - range); + float_precision ds = -minSpace; + +#ifndef PLAY_GAMEDLL + m_improv->ApplyForce(to * ds); +#else + // TODO: fix test demo + m_improv->ApplyForce2(to.x * ds, to.y * ds); +#endif // PLAY_GAMEDLL + + const float force = 0.1f; + m_improv->ApplyForce(m_speed * -force * m_velDir); + + return true; + } + +private: + CHostageImprov *m_improv; + Vector m_velDir; + float m_speed; + }; /* size: 20, cachelines: 1, members: 3 */ /* <46fbb8> ../cstrike/dlls/hostage/hostage_improv.cpp:518 */ -class CheckAhead -{ +class CheckAhead +{ public: - /* <47046f> ../cstrike/dlls/hostage/hostage_improv.cpp:525 */ - bool operator()(CBaseEntity *entity) - { -// Vector to; // 530 -// float range; // 531 -// float const closeRange; // 533 -// float const aheadTolerance; // 537 - } - /* <46f597> ../cstrike/dlls/hostage/hostage_improv.cpp:546 */ - bool IsBlocked(void) - { - return m_isBlocked; - } -private: - const CHostageImprov *m_me; - Vector m_dir; - bool m_isBlocked; - -};/* size: 20, cachelines: 1, members: 3 */ + /* <46fbb8> ../cstrike/dlls/hostage/hostage_improv.cpp:518 */ + CheckAhead(const CHostageImprov *me) + { + m_me = me; -NOBODY inline void DrawAxes(Vector &origin, int red, int green, int blue); + 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) + { + Vector to; + float_precision range; + const float closeRange = 60.0f; + const float aheadTolerance = 0.95f; + + if (entity != reinterpret_cast(m_me->GetEntity())) + { + to = (entity->Center() - m_me->GetCentroid()); + range = to.NormalizeInPlace(); + + if (range <= closeRange && DotProduct(to, m_dir) >= aheadTolerance) + m_isBlocked = true; + } + + return true; + } + /* <46f597> ../cstrike/dlls/hostage/hostage_improv.cpp:546 */ + bool IsBlocked(void) const + { + return m_isBlocked; + } + +private: + const CHostageImprov *m_me; + Vector m_dir; + bool m_isBlocked; + +};/* size: 20, cachelines: 1, members: 3 */ #ifdef HOOK_GAMEDLL +bool NavAreaBuildPath__HostagePathCost__wrapper(CNavArea *startArea, CNavArea *goalArea, const Vector *goalPos, class HostagePathCost &costFunc, CNavArea **closestArea = NULL); +bool NavAreaBuildPath__ShortestPathCost__wrapper(CNavArea *startArea, CNavArea *goalArea, const Vector *goalPos, class ShortestPathCost &costFunc, CNavArea **closestArea = NULL); + typedef bool (CHostageImprov::*IS_FRIEND_IN_THE_WAY_VECTOR)(const Vector &) const; typedef bool (CHostageImprov::*IS_FRIEND_IN_THE_WAY_CBASE)(CBaseEntity *, const Vector &) const; +typedef bool (CHostageImprov::*IS_FRIEND_IN_THE_WAY)(void) const; #endif // HOOK_GAMEDLL -// refs -extern void (*pCHostageImprov__FaceTowards)(); - #endif // HOSTAGE_IMPROV_H diff --git a/regamedll/dlls/hostage/hostage_localnav.cpp b/regamedll/dlls/hostage/hostage_localnav.cpp index 2255b43e..dfe800f9 100644 --- a/regamedll/dlls/hostage/hostage_localnav.cpp +++ b/regamedll/dlls/hostage/hostage_localnav.cpp @@ -467,14 +467,14 @@ int CLocalNav::PathTraversable(Vector &vecSource, Vector &vecDest, int fNoMonste { if (flTotal >= s_flStepSize) { -#ifndef HOOK_GAMEDLL +#ifndef PLAY_GAMEDLL vecDestTmp = vecSrcTmp + (vecDir * s_flStepSize); #else - // fix test demo + // TODO: fix test demo vecDestTmp[0] = vecSrcTmp[0] + (vecDir[0] * s_flStepSize); vecDestTmp[1] = vecSrcTmp[1] + (float)(vecDir[1] * s_flStepSize); vecDestTmp[2] = vecSrcTmp[2] + (vecDir[2] * s_flStepSize); -#endif // HOOK_GAMEDLL +#endif // PLAY_GAMEDLL } else diff --git a/regamedll/dlls/hostage/hostage_states.h b/regamedll/dlls/hostage/hostage_states.h index 7471af1f..1eadc644 100644 --- a/regamedll/dlls/hostage/hostage_states.h +++ b/regamedll/dlls/hostage/hostage_states.h @@ -49,31 +49,23 @@ class HostageStateMachine: public SimpleStateMachineOnMoveToSuccess(goal); - } } virtual void OnMoveToFailure(const Vector &goal, MoveToFailureType reason) { - if (m_state != NULL) - { + if (m_state) m_state->OnMoveToFailure(goal, reason); - } } virtual void OnInjury(float amount) { - if (m_state != NULL) - { + if (m_state) m_state->OnInjury(amount); - } } void UpdateStationaryAnimation(CHostageImprov *improv) { - if (m_state != NULL) - { + if (m_state) m_state->UpdateStationaryAnimation(improv); - } } };/* size: 16, cachelines: 1, members: 2 */ @@ -100,7 +92,7 @@ public: { m_moveState = MoveFailed; } - virtual void OnInjury(float amount) + virtual void OnInjury(float amount = -1.0f) { m_fleeTimer.Invalidate(); m_mustFlee = true; @@ -150,8 +142,22 @@ public: return "Escape:ToCover"; } virtual void OnMoveToFailure(const Vector &goal, MoveToFailureType reason); + +#ifdef HOOK_GAMEDLL + + void OnEnter_(CHostageImprov *improv); + void OnUpdate_(CHostageImprov *improv); + void OnExit_(CHostageImprov *improv); + void OnMoveToFailure_(const Vector &goal, MoveToFailureType reason); + +#endif // HOOK_GAMEDLL + public: - void SetRescueGoal(const Vector &rescueGoal); + void SetRescueGoal(const Vector &rescueGoal) + { + m_rescueGoal = rescueGoal; + } + private: Vector m_rescueGoal; Vector m_spot; @@ -173,6 +179,14 @@ public: return "Escape:LookAround"; } +#ifdef HOOK_GAMEDLL + + void OnEnter_(CHostageImprov *improv); + void OnUpdate_(CHostageImprov *improv); + void OnExit_(CHostageImprov *improv); + +#endif // HOOK_GAMEDLL + private: CountdownTimer m_timer; @@ -193,13 +207,27 @@ public: } virtual void OnMoveToFailure(const Vector &goal, MoveToFailureType reason) { - //TODO: i'm unsure - if (m_behavior.IsState(this)) - IImprovEvent::OnMoveToFailure(goal, reason); + m_behavior.OnMoveToFailure(goal, reason); } + +#ifdef HOOK_GAMEDLL + + void OnEnter_(CHostageImprov *improv); + void OnUpdate_(CHostageImprov *improv); + void OnExit_(CHostageImprov *improv); + +#endif // HOOK_GAMEDLL + public: - void ToCover(void); - void LookAround(void); + void ToCover(void) + { + m_behavior.SetState(&m_toCoverState); + } + void LookAround(void) + { + m_behavior.SetState(&m_lookAroundState); + } + private: HostageEscapeToCoverState m_toCoverState; HostageEscapeLookAroundState m_lookAroundState; @@ -252,17 +280,27 @@ public: } virtual void UpdateStationaryAnimation(CHostageImprov *improv); +#ifdef HOOK_GAMEDLL + + void OnEnter_(CHostageImprov *improv); + void OnUpdate_(CHostageImprov *improv); + void OnExit_(CHostageImprov *improv); + void UpdateStationaryAnimation_(CHostageImprov *improv); + +#endif // HOOK_GAMEDLL + public: void SetLeader(CBaseEntity *leader) { m_leader = leader; } - CBaseEntity *GetLeader(void) + CBaseEntity *GetLeader(void) const { return m_leader; } + private: - EHANDLE m_leader; + mutable EHANDLE m_leader; Vector m_lastLeaderPos; bool m_isWaiting; float m_stopRange; @@ -329,16 +367,16 @@ public: void AddSequence(CHostageImprov *improv, const char *seqName, float holdTime = -1.0f, float rate = 1.0f); void AddSequence(CHostageImprov *improv, int activity, float holdTime = -1.0f, float rate = 1.0f); - bool IsBusy(void) + bool IsBusy(void) const { return (m_sequenceCount > 0); } - bool IsPlaying(CHostageImprov *improv, const char *seqName); + NOXREF bool IsPlaying(CHostageImprov *improv, const char *seqName) const; int GetCurrentSequenceID(void) { return m_currentSequence; } - PerformanceType GetPerformance(void) + PerformanceType GetPerformance(void) const { return m_performance; } diff --git a/regamedll/dlls/hostage/states/hostage_animate.cpp b/regamedll/dlls/hostage/states/hostage_animate.cpp index 5720625b..708742c7 100644 --- a/regamedll/dlls/hostage/states/hostage_animate.cpp +++ b/regamedll/dlls/hostage/states/hostage_animate.cpp @@ -87,19 +87,13 @@ void HostageAnimateState::__MAKE_VHOOK(OnEnter)(CHostageImprov *improv) ; } -/* <410d79> ../cstrike/dlls/hostage/states/hostage_animate.cpp:139 */ -void HostageAnimateState::__MAKE_VHOOK(OnExit)(CHostageImprov *improv) -{ - ; -} - /* <410fb2> ../cstrike/dlls/hostage/states/hostage_animate.cpp:108 */ void HostageAnimateState::__MAKE_VHOOK(OnUpdate)(CHostageImprov *improv) { if (m_sequenceCount <= 0) return; - if (!improv->m_hostage->m_fSequenceFinished && m_sequence[m_currentSequence].seqID >= 0) + if (!improv->GetEntity()->m_fSequenceFinished && m_sequence[m_currentSequence].seqID >= 0) return; if (m_sequence[m_currentSequence].holdTime >= 0) @@ -120,13 +114,24 @@ void HostageAnimateState::__MAKE_VHOOK(OnUpdate)(CHostageImprov *improv) StartSequence(improv, &m_sequence[m_currentSequence]); } -/* <4112d1> ../cstrike/dlls/hostage/states/hostage_animate.cpp:147 */ -bool HostageAnimateState::IsPlaying(CHostageImprov *improv, const char *seqName) +/* <410d79> ../cstrike/dlls/hostage/states/hostage_animate.cpp:139 */ +void HostageAnimateState::__MAKE_VHOOK(OnExit)(CHostageImprov *improv) { -// { -// class CHostage *hostage; // 152 -// int id; // 154 -// } + ; +} + +/* <4112d1> ../cstrike/dlls/hostage/states/hostage_animate.cpp:147 */ +NOXREF bool HostageAnimateState::IsPlaying(CHostageImprov *improv, const char *seqName) const +{ + int id = 0; + CHostage *hostage = improv->GetEntity(); + + if (m_sequenceCount > 0) + { + id = m_sequence[m_currentSequence].seqID; + } + + return LookupSequence(hostage, seqName) == id; } #ifdef HOOK_GAMEDLL diff --git a/regamedll/dlls/hostage/states/hostage_escape.cpp b/regamedll/dlls/hostage/states/hostage_escape.cpp index 9a4c0cdd..b409fe44 100644 --- a/regamedll/dlls/hostage/states/hostage_escape.cpp +++ b/regamedll/dlls/hostage/states/hostage_escape.cpp @@ -1,105 +1,242 @@ #include "precompiled.h" /* <4205b1> ../cstrike/dlls/hostage/states/hostage_escape.cpp:12 */ -void HostageEscapeToCoverState::OnEnter(CHostageImprov *improv) +void HostageEscapeToCoverState::__MAKE_VHOOK(OnEnter)(CHostageImprov *improv) { -// { -// class CNavPath path; // 18 -// class HostagePathCost pathCost; // 19 -// Invalidate(CNavPath *const this); // 14 -// CNavPath(CNavPath *const this); // 18 -// Compute(CNavPath *const this, -// const Vector *start, -// const Vector *goal, -// class HostagePathCost &costFunc); // 20 -// { -// float const moveRange; // 23 -// int idx; // 24 -// { -// Vector pathPos; // 32 -// float const hidingRange; // 34 -// const Vector *spot; // 35 -// operator[](CNavPath *const this, -// int i); // 32 -// Vector(Vector *const this, -// const Vector &v); // 32 -// } -// } -// } + CNavPath path; + HostagePathCost pathCost; + + improv->GetPath()->Invalidate(); + m_canEscape = false; + + if (!path.Compute(&improv->GetFeet(), &m_rescueGoal, pathCost)) + return; + + const float moveRange = 500.0f; + int idx = path.GetSegmentIndexAlongPath(moveRange); + + if (idx < 0) + return; + + if (idx < path.GetSegmentCount() - 1) + ++idx; + + Vector pathPos = path[idx]->pos; + const float hidingRange = 450.0f; + const Vector *spot = FindNearbyHidingSpot(improv->GetEntity(), &pathPos, TheNavAreaGrid.GetNearestNavArea(&pathPos), hidingRange); + + if (spot == NULL) + spot = &pathPos; + + m_spot = *spot; + + improv->Run(); + improv->MoveTo(m_spot); + + m_canEscape = true; } /* <41fd51> ../cstrike/dlls/hostage/states/hostage_escape.cpp:52 */ -void HostageEscapeToCoverState::OnUpdate(CHostageImprov *improv) +void HostageEscapeToCoverState::__MAKE_VHOOK(OnUpdate)(CHostageImprov *improv) { -// Idle(CHostageImprov *const this); // 57 -// OnUpdate(HostageEscapeToCoverState *const this, -// class CHostageImprov *improv); // 52 + if (!m_canEscape) + { + improv->Idle(); + return; + } + + if (IsSpotOccupied(improv->GetEntity(), &m_spot)) + { + const float emergencyHidingRange = 300.0f; + const Vector *spot = FindNearbyHidingSpot(improv->GetEntity(), &improv->GetFeet(), improv->GetLastKnownArea(), emergencyHidingRange); + + if (spot == NULL) + { + HostageEscapeState *escape = (HostageEscapeState *)GetParent(); + escape->LookAround(); + return; + } + + m_spot = *spot; + improv->MoveTo(m_spot); + } + + if (improv->IsAtMoveGoal()) + { + HostageEscapeState *escape = (HostageEscapeState *)GetParent(); + escape->LookAround(); + return; + } } /* <41f65f> ../cstrike/dlls/hostage/states/hostage_escape.cpp:95 */ -void HostageEscapeToCoverState::OnExit(CHostageImprov *improv) +void HostageEscapeToCoverState::__MAKE_VHOOK(OnExit)(CHostageImprov *improv) { + ; } /* <41faaf> ../cstrike/dlls/hostage/states/hostage_escape.cpp:100 */ -void HostageEscapeToCoverState::OnMoveToFailure(const Vector &goal, MoveToFailureType reason) +void HostageEscapeToCoverState::__MAKE_VHOOK(OnMoveToFailure)(const Vector &goal, MoveToFailureType reason) { -// { -// class HostageEscapeState *escape; // 103 -// LookAround(HostageEscapeState *const this); // 104 -// } +#ifndef HOOK_GAMEDLL + HostageEscapeState *escape = (HostageEscapeState *)GetParent(); +#else + // TODO: why this - 1? Hacks? + // need investigation + HostageEscapeState *escape = (HostageEscapeState *)*((int *)this - 1); +#endif // HOOK_GAMEDLL + + escape->LookAround(); } /* <41fa2f> ../cstrike/dlls/hostage/states/hostage_escape.cpp:110 */ -void HostageEscapeLookAroundState::OnEnter(CHostageImprov *improv) +void HostageEscapeLookAroundState::__MAKE_VHOOK(OnEnter)(CHostageImprov *improv) { -// Start(CountdownTimer *const this, -// float duration); // 112 + m_timer.Start(RANDOM_FLOAT(5, 10)); + + improv->Stop(); + improv->FaceOutwards(); } /* <41fc67> ../cstrike/dlls/hostage/states/hostage_escape.cpp:119 */ -void HostageEscapeLookAroundState::OnUpdate(CHostageImprov *improv) +void HostageEscapeLookAroundState::__MAKE_VHOOK(OnUpdate)(CHostageImprov *improv) { -// IsElapsed(const class CountdownTimer *const this); // 123 -// OnUpdate(HostageEscapeLookAroundState *const this, -// class CHostageImprov *improv); // 119 + improv->UpdateIdleActivity(ACT_IDLE_SNEAKY, ACT_IDLE_SNEAKY_FIDGET); + + if (m_timer.IsElapsed()) + { + HostageEscapeState *escape = (HostageEscapeState *)GetParent(); + escape->ToCover(); + } } /* <41f693> ../cstrike/dlls/hostage/states/hostage_escape.cpp:133 */ -void HostageEscapeLookAroundState::OnExit(CHostageImprov *improv) +void HostageEscapeLookAroundState::__MAKE_VHOOK(OnExit)(CHostageImprov *improv) { + improv->ClearFaceTo(); } /* <41fb6b> ../cstrike/dlls/hostage/states/hostage_escape.cpp:145 */ -void HostageEscapeState::OnEnter(CHostageImprov *improv) +void HostageEscapeState::__MAKE_VHOOK(OnEnter)(CHostageImprov *improv) { -// { -// class CCSBotManager *ctrl; // 148 -// const class Zone *zone; // 149 -// GetRandomZone(const class CCSBotManager *const this); // 149 -// SetRescueGoal(HostageEscapeToCoverState *const this, -// const Vector &rescueGoal); // 153 -// SetState(SimpleStateMachine *const this, -// class HostageState *newState); // 156 -// Reset(SimpleStateMachine *const this, -// class CHostageImprov *userData); // 155 -// } + CCSBotManager *ctrl = TheCSBots(); + const CCSBotManager::Zone *zone = ctrl->GetRandomZone(); + + if (zone != NULL) + { + m_toCoverState.SetRescueGoal(zone->m_center); + + m_behavior.Reset(improv); + m_behavior.SetState(&m_toCoverState); + } + + m_canEscape = true; } /* <41fe8e> ../cstrike/dlls/hostage/states/hostage_escape.cpp:167 */ -void HostageEscapeState::OnUpdate(CHostageImprov *improv) +void HostageEscapeState::__MAKE_VHOOK(OnUpdate)(CHostageImprov *improv) { -// { -// class CBasePlayer *player; // 192 -// { -// float const farRange; // 198 -// } -// } -// OnUpdate(HostageEscapeState *const this, -// class CHostageImprov *improv); // 167 + if (!m_canEscape || (improv->IsScared() && improv->GetScareIntensity() == CHostageImprov::TERRIFIED)) + { + improv->Stop(); + improv->Idle(); + return; + } + + if (m_runTimer.IsElapsed()) + improv->Walk(); + else + improv->Run(); + + CBasePlayer *player = improv->GetClosestVisiblePlayer(UNASSIGNED); + + if (player != NULL) + { + if (player->m_iTeam != TERRORIST) + { + improv->Stop(); + improv->Idle(); + return; + } + + const float farRange = 750.0f; + if ((player->pev->origin - improv->GetCentroid().IsLengthGreaterThan(farRange))) + { + improv->Frighten(CHostageImprov::NERVOUS); + + m_runTimer.Start(RANDOM_FLOAT(3, 6)); + m_behavior.SetState(&m_toCoverState); + } + else + { + improv->Frighten(CHostageImprov::SCARED); + improv->Stop(); + improv->Idle(); + return; + } + } + else + { + m_behavior.Update(); + } } /* <41f6c7> ../cstrike/dlls/hostage/states/hostage_escape.cpp:230 */ +void HostageEscapeState::__MAKE_VHOOK(OnExit)(CHostageImprov *improv) +{ + improv->Run(); +} + +#ifdef HOOK_GAMEDLL + +void HostageEscapeToCoverState::OnEnter(CHostageImprov *improv) +{ + OnEnter_(improv); +} + +void HostageEscapeToCoverState::OnUpdate(CHostageImprov *improv) +{ + OnUpdate_(improv); +} + +void HostageEscapeToCoverState::OnExit(CHostageImprov *improv) +{ + OnExit_(improv); +} + +void HostageEscapeToCoverState::OnMoveToFailure(const Vector &goal, MoveToFailureType reason) +{ + OnMoveToFailure_(goal, reason); +} + +void HostageEscapeLookAroundState::OnEnter(CHostageImprov *improv) +{ + OnEnter_(improv); +} + +void HostageEscapeLookAroundState::OnUpdate(CHostageImprov *improv) +{ + OnUpdate_(improv); +} + +void HostageEscapeLookAroundState::OnExit(CHostageImprov *improv) +{ + OnExit_(improv); +} + +void HostageEscapeState::OnEnter(CHostageImprov *improv) +{ + OnEnter_(improv); +} + +void HostageEscapeState::OnUpdate(CHostageImprov *improv) +{ + OnUpdate_(improv); +} + void HostageEscapeState::OnExit(CHostageImprov *improv) { + OnExit_(improv); } + +#endif // HOOK_GAMEDLL diff --git a/regamedll/dlls/hostage/states/hostage_follow.cpp b/regamedll/dlls/hostage/states/hostage_follow.cpp index d16fc18b..53545fae 100644 --- a/regamedll/dlls/hostage/states/hostage_follow.cpp +++ b/regamedll/dlls/hostage/states/hostage_follow.cpp @@ -1,59 +1,234 @@ #include "precompiled.h" /* <42e3e3> ../cstrike/dlls/hostage/states/hostage_follow.cpp:12 */ -void HostageFollowState::OnEnter(CHostageImprov *improv) +void HostageFollowState::__MAKE_VHOOK(OnEnter)(CHostageImprov *improv) { -// Invalidate(CountdownTimer *const this); // 28 -// OnEnter(HostageFollowState *const this, -// class CHostageImprov *improv); // 12 + improv->Chatter(HOSTAGE_CHATTER_START_FOLLOW); + improv->Agree(); + + m_isWaiting = false; + m_isWaitingForFriend = false; + + improv->MoveTo(improv->GetFeet()); + + m_lastLeaderPos = Vector(999999, 999999, 999999); + + m_makeWayTimer.Invalidate(); + m_stopRange = RANDOM_FLOAT(125, 175); + + if (improv->IsTerroristNearby()) + { + improv->DelayedChatter(3, HOSTAGE_CHATTER_WARN_NEARBY); + } } /* <42deaf> ../cstrike/dlls/hostage/states/hostage_follow.cpp:40 */ -void HostageFollowState::OnUpdate(CHostageImprov *improv) +void HostageFollowState::__MAKE_VHOOK(OnUpdate)(CHostageImprov *improv) { -// { -// float range; // 58 -// float const giveUpRange; // 61 -// float const maxPathLength; // 62 -// float const walkRange; // 70 -// float const continueRange; // 71 -// float leaderSpeed; // 74 -// float const runThreshold; // 75 -// bool isLeaderRunning; // 76 -// float const movedRange; // 246 -// { -// float const closeRange; // 117 -// class CBasePlayer *terrorist; // 193 -// { -// bool makeWay; // 120 -// float const cosTolerance; // 123 -// { -// Vector to; // 148 -// Vector cross; // 152 -// Vector lat; // 154 -// float const sideStepSize; // 168 -// Vector sideStepPos; // 169 -// float ground; // 172 -// { -// float const push; // 178 -// } -// } -// } -// } -// { -// bool doWait; // 206 -// } -// } + // if we lost our leader, give up + if (m_leader == NULL) + { + improv->Idle(); + return; + } + + if (m_leader->pev->deadflag != DEAD_NO) + { + improv->Frighten(CHostageImprov::TERRIFIED); + improv->Idle(); + return; + } + + float_precision range = (m_leader->pev->origin - improv->GetCentroid()).Length(); + + const float maxPathLength = 3000.0f; + const float giveUpRange = 1000.0f; + + if (range > giveUpRange || improv->GetPath()->GetSegmentCount() > 0 && improv->GetPath()->GetLength() > maxPathLength) + { + improv->Idle(); + return; + } + + const float walkRange = m_stopRange + 50.0f; + const float continueRange = m_stopRange + 20.0f; + const float runThreshold = 140.0f; + + bool isLeaderRunning; + float leaderSpeed = m_leader->pev->velocity.Make2D().Length(); + + if (leaderSpeed > runThreshold) + { + isLeaderRunning = true; + m_isWaiting = false; + } + else + { + // track when began to run + isLeaderRunning = false; + + if (!m_isWaiting) + { + if (range < m_stopRange) + { + m_isWaiting = true; + m_impatientTimer.Start(RANDOM_FLOAT(5.0, 20.0)); + } + } + else if (range > continueRange) + m_isWaiting = false; + } + + if (!m_isWaiting) + { + bool makeWay = improv->IsFriendInTheWay(); + + if (makeWay && !m_isWaitingForFriend) + { + m_isWaitingForFriend = true; + m_waitForFriendTimer.Start(15.0); + + improv->Stop(); + return; + } + + if (makeWay && !m_waitForFriendTimer.IsElapsed()) + { + improv->Stop(); + return; + } + + if (improv->GetPath()->GetSegmentCount() <= 0 && m_repathTimer.IsElapsed()) + { + improv->MoveTo(m_leader->pev->origin); + + m_lastLeaderPos = m_leader->pev->origin; + m_repathTimer.Start(1.0); + } + + if (isLeaderRunning || range > walkRange) + improv->Run(); + else + improv->Walk(); + + const float movedRange = 35.0f; + if ((m_lastLeaderPos - m_leader->pev->origin).IsLengthGreaterThan(movedRange)) + { + improv->MoveTo(m_leader->pev->origin); + m_lastLeaderPos = m_leader->pev->origin; + } + + return; + } + + if (m_impatientTimer.IsElapsed() && !TheCSBots()->IsRoundOver()) + { + m_impatientTimer.Start(RANDOM_FLOAT(20.0, 30.0)); + + if (improv->CanSeeRescueZone()) + improv->Chatter(HOSTAGE_CHATTER_SEE_RESCUE_ZONE, false); + else + improv->Chatter(HOSTAGE_CHATTER_IMPATIENT_FOR_RESCUE, false); + } + + const float closeRange = 200.0f; + if ((m_leader->pev->origin - improv->GetCentroid()).IsLengthLessThan(closeRange)) + { + bool makeWay = false; + const float cosTolerance = 0.99f; + + if (improv->IsPlayerLookingAtMe((CBasePlayer *)((CBaseEntity *)m_leader), cosTolerance)) + { + if (!m_makeWayTimer.HasStarted()) + { + m_makeWayTimer.Start(RANDOM_FLOAT(0.4, 0.75)); + } + else if (m_makeWayTimer.IsElapsed()) + { + m_impatientTimer.Invalidate(); + + Vector to = (m_leader->pev->origin - improv->GetCentroid()); + to.NormalizeInPlace(); + + Vector cross(-to.y, -to.x, 0); + if (cross.x * gpGlobals->v_forward.x - cross.y * gpGlobals->v_forward.y < 0) + cross.y = to.x; + else + cross.x = to.y; + + float ground; + float const sideStepSize = 15.0f; + Vector sideStepPos = improv->GetFeet() + cross * sideStepSize; + + if (GetGroundHeight(&sideStepPos, &ground)) + { + if (abs((int)(ground - improv->GetFeet().z)) < 18.0f) + { + const float push = 20.0f; + Vector lat = cross * push; + + improv->ApplyForce(lat); + improv->MoveTo(sideStepPos); + return; + } + } + } + } + else + { + m_makeWayTimer.Invalidate(); + } + } + + improv->Stop(); + + CBasePlayer *terrorist = improv->GetClosestVisiblePlayer(TERRORIST); + + if (terrorist != NULL) + { + improv->LookAt(terrorist->EyePosition()); + } + else + { + improv->LookAt(m_leader->EyePosition()); + } } /* <42e1aa> ../cstrike/dlls/hostage/states/hostage_follow.cpp:256 */ -void HostageFollowState::OnExit(CHostageImprov *improv) +void HostageFollowState::__MAKE_VHOOK(OnExit)(CHostageImprov *improv) { + improv->Stop(); } /* <42e38f> ../cstrike/dlls/hostage/states/hostage_follow.cpp:270 */ +void HostageFollowState::__MAKE_VHOOK(UpdateStationaryAnimation)(CHostageImprov *improv) +{ + if (improv->IsScared()) + improv->UpdateIdleActivity(ACT_FOLLOW_IDLE_SCARED, ACT_RESET); + else + improv->UpdateIdleActivity(ACT_FOLLOW_IDLE, ACT_FOLLOW_IDLE_FIDGET); +} + +#ifdef HOOK_GAMEDLL + +void HostageFollowState::OnEnter(CHostageImprov *improv) +{ + OnEnter_(improv); +} + +void HostageFollowState::OnUpdate(CHostageImprov *improv) +{ + OnUpdate_(improv); +} + +void HostageFollowState::OnExit(CHostageImprov *improv) +{ + OnExit_(improv); +} + void HostageFollowState::UpdateStationaryAnimation(CHostageImprov *improv) { -// UpdateStationaryAnimation(HostageFollowState *const this, -// class CHostageImprov *improv); // 270 + UpdateStationaryAnimation_(improv); } + +#endif // HOOK_GAMEDLL diff --git a/regamedll/dlls/hostage/states/hostage_idle.cpp b/regamedll/dlls/hostage/states/hostage_idle.cpp index 8045324d..0b9a41bc 100644 --- a/regamedll/dlls/hostage/states/hostage_idle.cpp +++ b/regamedll/dlls/hostage/states/hostage_idle.cpp @@ -11,12 +11,231 @@ void HostageIdleState::__MAKE_VHOOK(OnEnter)(CHostageImprov *improv) /* <43c197> ../cstrike/dlls/hostage/states/hostage_idle.cpp:23 */ void HostageIdleState::__MAKE_VHOOK(OnUpdate)(CHostageImprov *improv) { + if (!UTIL_ActivePlayersInGame()) + return; + + if (m_mustFlee || (improv->IsScared() && !improv->IsTerroristNearby() && m_moveState != Moving)) + { + if (!m_mustFlee && improv->GetScareIntensity() == CHostageImprov::TERRIFIED) + m_mustFlee = true; + + if ((improv->GetScareIntensity() == CHostageImprov::TERRIFIED || m_mustFlee) || (m_fleeTimer.IsElapsed() && improv->GetScareIntensity() > CHostageImprov::NERVOUS)) + { + m_fleeTimer.Start(RANDOM_FLOAT(10, 20)); + + const float fleeChance = 33.3f; + const float terroristRecentTime = 5.0f; + + if (!m_mustFlee && improv->GetTimeSinceLastSawPlayer(TERRORIST) > terroristRecentTime && RANDOM_FLOAT(0, 100) < fleeChance) + m_mustFlee = true; + + if (m_mustFlee) + { + m_mustFlee = false; + + const Vector *spot = FindNearbyRetreatSpot(NULL, &improv->GetFeet(), improv->GetLastKnownArea(), 500.0, TERRORIST, false); + + if (spot != NULL) + { + improv->MoveTo(*spot); + improv->Run(); + + m_moveState = Moving; + + if (improv->GetScareIntensity() == CHostageImprov::TERRIFIED) + { + improv->Frighten(CHostageImprov::SCARED); + } + + return; + } + } + } + } + + if (m_moveState && improv->IsAtMoveGoal()) + { + m_moveState = NotMoving; + + improv->Stop(); + improv->FaceOutwards(); + + const float crouchChance = 33.3f; + if (improv->IsScared() && !improv->IsAtHome() && RANDOM_FLOAT(0, 100) <= crouchChance) + { + improv->Crouch(); + } + + return; + } + + if (m_moveState == Moving) + { + improv->Run(); + return; + } + + if (!improv->IsAtMoveGoal(75.0f)) + { + improv->Walk(); + m_moveState = Moving; + return; + } + + CBasePlayer *rescuer = improv->GetClosestVisiblePlayer(CT); + CBasePlayer *captor = improv->GetClosestVisiblePlayer(TERRORIST); + + if (rescuer != NULL) + { + improv->LookAt(rescuer->EyePosition()); + improv->Stop(); + + if (captor != NULL) + { + const float attentionRange = 700.0f; + float rangeT = (improv->GetCentroid() - captor->pev->origin).Length(); + + if (rangeT < attentionRange) + { + const float cosTolerance = 0.95f; + if (improv->IsAnyPlayerLookingAtMe(TERRORIST, cosTolerance)) + { + improv->LookAt(captor->EyePosition()); + } + else + { + TraceResult result; + UTIL_TraceLine(rescuer->pev->origin, captor->pev->origin, ignore_monsters, ignore_glass, captor->edict(), &result); + + if (result.flFraction != 1.0f && m_disagreeTimer.IsElapsed()) + { + improv->Disagree(); + m_disagreeTimer.Start(RANDOM_FLOAT(2, 4)); + } + } + + return; + } + } + else if (!TheCSBots()->IsRoundOver() && m_askTimer.IsElapsed()) + { + const float closeRange = 200.0f; + if ((rescuer->pev->origin - improv->GetCentroid()).IsLengthLessThan(closeRange)) + { + if (improv->IsPlayerLookingAtMe(rescuer, 0.99)) + { + HostageChatterType say; + if (improv->IsTerroristNearby()) + say = HOSTAGE_CHATTER_WARN_NEARBY; + else + say = HOSTAGE_CHATTER_PLEASE_RESCUE_ME; + + improv->Chatter(say, false); + m_askTimer.Start(RANDOM_FLOAT(3, 10)); + } + } + } + + if (m_waveTimer.IsElapsed()) + { + CHostage *hostage = improv->GetEntity(); + + const float waveRange = 250.0f; + if ((rescuer->pev->origin - hostage->pev->origin).IsLengthGreaterThan(waveRange)) + { + improv->Stop(); + improv->Wave(); + + improv->LookAt(rescuer->EyePosition()); + improv->Chatter(HOSTAGE_CHATTER_CALL_TO_RESCUER, false); + + m_moveState = NotMoving; + m_waveTimer.Start(RANDOM_FLOAT(10, 20)); + } + } + } + else if (captor != NULL) + { + improv->LookAt(captor->EyePosition()); + improv->Stop(); + + const float closeRange = 200.0f; + if ((captor->pev->origin - improv->GetCentroid()).IsLengthLessThan(closeRange) && improv->IsPlayerLookingAtMe(captor, 0.99)) + { + if (!m_intimidatedTimer.HasStarted()) + { + m_intimidatedTimer.Start(); + } + + if (!improv->IsScared()) + { + improv->Frighten(CHostageImprov::NERVOUS); + } + + const float minThreatenTime = 1.0f; + if ((!m_intimidatedTimer.HasStarted() || m_intimidatedTimer.IsGreaterThen(minThreatenTime)) && m_pleadTimer.IsElapsed()) + { + improv->Chatter(HOSTAGE_CHATTER_INTIMIDATED, true); + m_pleadTimer.Start(RANDOM_FLOAT(10, 20)); + } + + if (!improv->IsAtHome()) + { + improv->Chatter(HOSTAGE_CHATTER_RETREAT, true); + improv->Retreat(); + } + } + else + { + m_intimidatedTimer.Invalidate(); + } + } + else + { + improv->ClearLookAt(); + + const float pushbackRange = 60.0f; + if (pushbackRange - improv->GetAggression() * 5.0f < TheCSBots()->GetElapsedRoundTime() && m_escapeTimer.IsElapsed()) + { + const float stayHomeDuration = 5.0f; + m_escapeTimer.Start(stayHomeDuration); + + float sightTimeT = improv->GetTimeSinceLastSawPlayer(TERRORIST); + float sightTimeCT = improv->GetTimeSinceLastSawPlayer(CT); + + const float waitTime = 15.0f - improv->GetAggression() * 3.0f; + + if (sightTimeT > waitTime && sightTimeCT > waitTime) + { + if (improv->IsTerroristNearby()) + { + if (cv_hostage_debug.value > 0.0f) + { + CONSOLE_ECHO("Hostage: I want to escape, but a T is nearby\n"); + } + + m_escapeTimer.Start(waitTime); + } + else + { + improv->Escape(); + + if (cv_hostage_debug.value > 0.0f) + { + CONSOLE_ECHO("Hostage: I'm escaping!\n"); + } + } + } + } + } } /* <43c59b> ../cstrike/dlls/hostage/states/hostage_idle.cpp:297 */ void HostageIdleState::__MAKE_VHOOK(OnExit)(CHostageImprov *improv) { + improv->StandUp(); + improv->ClearFaceTo(); } /* <43c783> ../cstrike/dlls/hostage/states/hostage_idle.cpp:307 */ diff --git a/regamedll/dlls/hostage/states/hostage_retreat.cpp b/regamedll/dlls/hostage/states/hostage_retreat.cpp index 96cbb7bc..7b92f980 100644 --- a/regamedll/dlls/hostage/states/hostage_retreat.cpp +++ b/regamedll/dlls/hostage/states/hostage_retreat.cpp @@ -4,20 +4,39 @@ void HostageRetreatState::__MAKE_VHOOK(OnEnter)(CHostageImprov *improv) { improv->Walk(); - improv->MoveTo(improv->m_hostage->m_vStart); + improv->MoveTo(improv->GetEntity()->m_vStart); } /* <44a220> ../cstrike/dlls/hostage/states/hostage_retreat.cpp:20 */ void HostageRetreatState::__MAKE_VHOOK(OnUpdate)(CHostageImprov *improv) { -// { -// class CBasePlayer *player; // 40 -// { -// float const farRange; // 45 -// } -// } -// OnUpdate(HostageRetreatState *const this, -// class CHostageImprov *improv); // 20 + if (improv->IsAtHome()) + { + improv->Stop(); + improv->Idle(); + return; + } + + CBasePlayer *player = improv->GetClosestVisiblePlayer(UNASSIGNED); + + if (player != NULL) + { + const float farRange = 400.0f; + if ((player->pev->origin - improv->GetCentroid()).IsLengthGreaterThan(farRange)) + { + if (player->m_iTeam == CT && !improv->IsScared()) + { + improv->Stop(); + improv->Idle(); + return; + } + } + } + + if (improv->IsScared() && improv->GetScareIntensity() == CHostageImprov::TERRIFIED) + improv->Run(); + else + improv->Walk(); } /* <44a023> ../cstrike/dlls/hostage/states/hostage_retreat.cpp:79 */ diff --git a/regamedll/dlls/multiplay_gamerules.cpp b/regamedll/dlls/multiplay_gamerules.cpp index 41582b38..c4fe0c54 100644 --- a/regamedll/dlls/multiplay_gamerules.cpp +++ b/regamedll/dlls/multiplay_gamerules.cpp @@ -552,7 +552,10 @@ CHalfLifeMultiplay::CHalfLifeMultiplay(void) m_fRoundCount = 0; m_fIntroRoundCount = 0; +#ifndef CSTRIKE InstallBotControl(); +#endif // CSTRIKE + InstallHostageManager(); m_bSkipSpawn = m_bInCareerGame; @@ -1938,12 +1941,12 @@ void CHalfLifeMultiplay::__MAKE_VHOOK(RestartRound)(void) } // check if the losing team is in a losing streak & that the loser bonus hasen't maxed out. - if(m_iNumConsecutiveTerroristLoses > 1 && m_iLoserBonus < REWARD_LOSER_BONUS_MAX) + if (m_iNumConsecutiveTerroristLoses > 1 && m_iLoserBonus < REWARD_LOSER_BONUS_MAX) { // help out the team in the losing streak m_iLoserBonus += REWARD_LOSER_BONUS_ADD; } - else if(m_iNumConsecutiveCTLoses > 1 && m_iLoserBonus < REWARD_LOSER_BONUS_MAX) + else if (m_iNumConsecutiveCTLoses > 1 && m_iLoserBonus < REWARD_LOSER_BONUS_MAX) { // help out the team in the losing streak m_iLoserBonus += REWARD_LOSER_BONUS_ADD; diff --git a/regamedll/dlls/plats.cpp b/regamedll/dlls/plats.cpp index 7ced4996..b943ed6e 100644 --- a/regamedll/dlls/plats.cpp +++ b/regamedll/dlls/plats.cpp @@ -1195,14 +1195,14 @@ void CFuncTrackTrain::Next(void) CPathTrack *pnext = m_ppath->LookAhead(&nextPos, pev->speed * 0.1, 1); nextPos.z += m_height; -#if 0 +#ifndef PLAY_GAMEDLL pev->velocity = (nextPos - pev->origin) * 10; #else // TODO: fix test demo pev->velocity.x = ((float_precision)(nextPos.x - pev->origin.x) * 10.0f); pev->velocity.y = ((float_precision)(nextPos.y - pev->origin.y) * 10.0f); pev->velocity.z = ((nextPos.z - pev->origin.z) * 10.0f); -#endif +#endif // PLAY_GAMEDLL Vector nextFront = pev->origin; nextFront.z -= m_height; @@ -1223,7 +1223,7 @@ void CFuncTrackTrain::Next(void) angles.y += fixAngleY; // !!! All of this crap has to be done to make the angles not wrap around, revisit this. -#if 0 +#ifndef PLAY_GAMEDLL FixupAngles(angles); FixupAngles(pev->angles); #else @@ -1232,7 +1232,8 @@ void CFuncTrackTrain::Next(void) angles.z = Fix(angles.z); FixupAngles(pev->angles); -#endif +#endif // PLAY_GAMEDLL + if (!pnext || (delta.x == 0 && delta.y == 0)) angles = pev->angles; diff --git a/regamedll/dlls/vector.h b/regamedll/dlls/vector.h index 0de54539..f6204be2 100644 --- a/regamedll/dlls/vector.h +++ b/regamedll/dlls/vector.h @@ -51,7 +51,7 @@ public: { return Vector2D(x - v.x, y - v.y); } -#ifdef HOOK_GAMEDLL +#ifdef PLAY_GAMEDLL Vector2D operator*(float_precision fl) const { return Vector2D((vec_t)(x * fl), (vec_t)(y * fl)); @@ -77,7 +77,7 @@ public: { return Vector2D(x / fl, y / fl); } -#endif // HOOK_GAMEDLL +#endif // PLAY_GAMEDLL float_precision Length(void) const { return sqrt((float_precision)(x * x + y * y)); @@ -102,11 +102,11 @@ public: flLen = 1 / flLen; -#ifdef HOOK_GAMEDLL +#ifdef PLAY_GAMEDLL return Vector2D((vec_t)(x * flLen), (vec_t)(y * flLen)); #else return Vector2D(x * flLen, y * flLen); -#endif // HOOK_GAMEDLL +#endif // PLAY_GAMEDLL } bool IsLengthLessThan(float length) const { @@ -139,7 +139,7 @@ public: };/* size: 8, cachelines: 1, members: 2 */ -inline float DotProduct(const Vector2D &a, const Vector2D &b) +inline float_precision DotProduct(const Vector2D &a, const Vector2D &b) { return (a.x * b.x + a.y * b.y); } @@ -193,7 +193,7 @@ public: { return Vector(x - v.x, y - v.y, z - v.z); } -#ifdef HOOK_GAMEDLL +#ifdef PLAY_GAMEDLL Vector operator*(float_precision fl) const { return Vector((vec_t)(x * fl), (vec_t)(y * fl), (vec_t)(z * fl)); @@ -219,7 +219,7 @@ public: { return Vector(x / fl, y / fl, z / fl); } -#endif // HOOK_GAMEDLL +#endif // PLAY_GAMEDLL void CopyToArray(float *rgfl) const { rgfl[0] = x; @@ -236,7 +236,7 @@ public: //return sqrt((float_precision)(x * x + y * y + z * z)); } - float LengthSquared(void) const + float_precision LengthSquared(void) const { return (x * x + y * y + z * z); } @@ -248,7 +248,7 @@ public: { return &x; } -#ifndef HOOK_GAMEDLL +#ifndef PLAY_GAMEDLL Vector Normalize(void) { float flLen = Length(); @@ -268,11 +268,11 @@ public: vec_t fTemp = (vec_t)(1 / flLen); return Vector(x * fTemp, y * fTemp, z * fTemp); } -#endif // HOOK_GAMEDLL +#endif // PLAY_GAMEDLL // for out precision normalize Vector NormalizePrecision(void) { -#ifndef HOOK_GAMEDLL +#ifndef PLAY_GAMEDLL return Normalize(); #else float_precision flLen = Length(); @@ -281,7 +281,7 @@ public: flLen = 1 / flLen; return Vector((vec_t)(x * flLen), (vec_t)(y * flLen), (vec_t)(z * flLen)); -#endif // HOOK_GAMEDLL +#endif // PLAY_GAMEDLL } Vector2D Make2D(void) const { @@ -302,7 +302,7 @@ public: { return (LengthSquared() > length * length); } -#ifdef HOOK_GAMEDLL +#ifdef PLAY_GAMEDLL float_precision NormalizeInPlace(void) { float_precision flLen = Length(); @@ -322,7 +322,27 @@ public: return flLen; } -#else // HOOK_GAMEDLL + template + float_precision NormalizeInPlace(void) + { + T flLen = Length(); + + if (flLen > 0) + { + x = (vec_t)(1 / flLen * x); + y = (vec_t)(1 / flLen * y); + z = (vec_t)(1 / flLen * z); + } + else + { + x = 0; + y = 0; + z = 1; + } + + return flLen; + } +#else // PLAY_GAMEDLL float NormalizeInPlace(void) { float flLen = Length(); @@ -340,7 +360,7 @@ public: } return flLen; } -#endif // HOOK_GAMEDLL +#endif // PLAY_GAMEDLL bool IsZero(float tolerance = 0.01f) const { return (x > -tolerance && x < tolerance && @@ -362,6 +382,11 @@ inline float_precision DotProduct(const Vector &a, const Vector &b) return (a.x * b.x + a.y * b.y + a.z * b.z); } +inline float_precision DotProduct2D(const Vector &a, const Vector &b) +{ + return (a.x * b.x + a.y * b.y); +} + /* <1ba548> ../cstrike/dlls/vector.h:186 */ inline Vector CrossProduct(const Vector &a, const Vector &b) { @@ -401,7 +426,7 @@ inline Vector NormalizeSubtract(Vector vecStart, Vector vecDest) { Vector dir; -#ifdef HOOK_GAMEDLL +#ifdef PLAY_GAMEDLL X floatX = (vecDest.x - vecStart.x); Y floatY = (vecDest.y - vecStart.y); @@ -423,17 +448,13 @@ inline Vector NormalizeSubtract(Vector vecStart, Vector vecDest) } #else dir = (vecDest - vecStart).Normalize(); -#endif // HOOK_GAMEDLL +#endif // PLAY_GAMEDLL return dir; } -#ifdef HOOK_GAMEDLL -template< - typename X, - typename Y, - typename LenType -> +#ifdef PLAY_GAMEDLL +template inline Vector NormalizeMulScalar(Vector2D vec, float scalar) { LenType flLen; @@ -457,6 +478,6 @@ inline Vector NormalizeMulScalar(Vector2D vec, float scalar) return Vector((vec_t)(floatX * scalar), (vec_t)(floatY * scalar), 0); } -#endif // HOOK_GAMEDLL +#endif // PLAY_GAMEDLL #endif // VECTOR_H diff --git a/regamedll/engine/maintypes.h b/regamedll/engine/maintypes.h index 454d2ce2..caf0418f 100644 --- a/regamedll/engine/maintypes.h +++ b/regamedll/engine/maintypes.h @@ -35,7 +35,7 @@ #include "osconfig.h" #include "mathlib.h" -// Has no references on server side. +// Has no references on multiplayer library CS. #define NOXREF // Function body is not implemented. #define NOBODY @@ -43,8 +43,6 @@ #define UNTESTED // Function is doubt reversed #define TODOBODY -// Function is inlined in code and has no references. -#define INLINEBODY #define BIT(n) (1<<(n)) diff --git a/regamedll/game_shared/GameEvent.h b/regamedll/game_shared/GameEvent.h index 6ba3ba9d..a424a58b 100644 --- a/regamedll/game_shared/GameEvent.h +++ b/regamedll/game_shared/GameEvent.h @@ -140,113 +140,12 @@ enum GameEventType NUM_GAME_EVENTS, }; -#ifdef DEFINE_EVENT_NAMES +#ifdef HOOK_GAMEDLL -/* size: 96 */ -const char *GameEventName[NUM_GAME_EVENTS + 1] = -{ - "EVENT_INVALID", - "EVENT_WEAPON_FIRED", - "EVENT_WEAPON_FIRED_ON_EMPTY", - "EVENT_WEAPON_RELOADED", - "EVENT_HE_GRENADE_EXPLODED", - "EVENT_FLASHBANG_GRENADE_EXPLODED", - "EVENT_SMOKE_GRENADE_EXPLODED", - "EVENT_GRENADE_BOUNCED", - "EVENT_BEING_SHOT_AT", - "EVENT_PLAYER_BLINDED_BY_FLASHBANG", - "EVENT_PLAYER_FOOTSTEP", - "EVENT_PLAYER_JUMPED", - "EVENT_PLAYER_DIED", - "EVENT_PLAYER_LANDED_FROM_HEIGHT", - "EVENT_PLAYER_TOOK_DAMAGE", - "EVENT_HOSTAGE_DAMAGED", - "EVENT_HOSTAGE_KILLED", - "EVENT_DOOR", - "EVENT_BREAK_GLASS", - "EVENT_BREAK_WOOD", - "EVENT_BREAK_METAL", - "EVENT_BREAK_FLESH", - "EVENT_BREAK_CONCRETE", - "EVENT_BOMB_PLANTED", - "EVENT_BOMB_DROPPED", - "EVENT_BOMB_PICKED_UP", - "EVENT_BOMB_BEEP", - "EVENT_BOMB_DEFUSING", - "EVENT_BOMB_DEFUSE_ABORTED", - "EVENT_BOMB_DEFUSED", - "EVENT_BOMB_EXPLODED", - "EVENT_HOSTAGE_USED", - "EVENT_HOSTAGE_RESCUED", - "EVENT_ALL_HOSTAGES_RESCUED", - "EVENT_VIP_ESCAPED", - "EVENT_VIP_ASSASSINATED", - "EVENT_TERRORISTS_WIN", - "EVENT_CTS_WIN", - "EVENT_ROUND_DRAW", - "EVENT_ROUND_WIN", - "EVENT_ROUND_LOSS", - "EVENT_ROUND_START", - "EVENT_PLAYER_SPAWNED", - "EVENT_CLIENT_CORPSE_SPAWNED", - "EVENT_BUY_TIME_START", - "EVENT_PLAYER_LEFT_BUY_ZONE", - "EVENT_DEATH_CAMERA_START", - "EVENT_KILL_ALL", - "EVENT_ROUND_TIME", - "EVENT_DIE", - "EVENT_KILL", - "EVENT_HEADSHOT", - "EVENT_KILL_FLASHBANGED", - "EVENT_TUTOR_BUY_MENU_OPENNED", - "EVENT_TUTOR_AUTOBUY", - "EVENT_PLAYER_BOUGHT_SOMETHING", - "EVENT_TUTOR_NOT_BUYING_ANYTHING", - "EVENT_TUTOR_NEED_TO_BUY_PRIMARY_WEAPON", - "EVENT_TUTOR_NEED_TO_BUY_PRIMARY_AMMO", - "EVENT_TUTOR_NEED_TO_BUY_SECONDARY_AMMO", - "EVENT_TUTOR_NEED_TO_BUY_ARMOR", - "EVENT_TUTOR_NEED_TO_BUY_DEFUSE_KIT", - "EVENT_TUTOR_NEED_TO_BUY_GRENADE", - "EVENT_CAREER_TASK_DONE", - "EVENT_START_RADIO_1", - "EVENT_RADIO_COVER_ME", - "EVENT_RADIO_YOU_TAKE_THE_POINT", - "EVENT_RADIO_HOLD_THIS_POSITION", - "EVENT_RADIO_REGROUP_TEAM", - "EVENT_RADIO_FOLLOW_ME", - "EVENT_RADIO_TAKING_FIRE", - "EVENT_START_RADIO_2", - "EVENT_RADIO_GO_GO_GO", - "EVENT_RADIO_TEAM_FALL_BACK", - "EVENT_RADIO_STICK_TOGETHER_TEAM", - "EVENT_RADIO_GET_IN_POSITION_AND_WAIT", - "EVENT_RADIO_STORM_THE_FRONT", - "EVENT_RADIO_REPORT_IN_TEAM", - "EVENT_START_RADIO_3", - "EVENT_RADIO_AFFIRMATIVE", - "EVENT_RADIO_ENEMY_SPOTTED", - "EVENT_RADIO_NEED_BACKUP", - "EVENT_RADIO_SECTOR_CLEAR", - "EVENT_RADIO_IN_POSITION", - "EVENT_RADIO_REPORTING_IN", - "EVENT_RADIO_GET_OUT_OF_THERE", - "EVENT_RADIO_NEGATIVE", - "EVENT_RADIO_ENEMY_DOWN", - "EVENT_END_RADIO", - "EVENT_NEW_MATCH", - "EVENT_PLAYER_CHANGED_TEAM", - "EVENT_BULLET_IMPACT", - "EVENT_GAME_COMMENCE", - "EVENT_WEAPON_ZOOMED", - "EVENT_HOSTAGE_CALLED_FOR_HELP", - NULL, -}; +#define GameEventName (*pGameEventName) -#else // DEFINE_EVENT_NAMES +#endif // HOOK_GAMEDLL -extern const char *GameEventName[ NUM_GAME_EVENTS ]; - -#endif // DEFINE_EVENT_NAMES +extern const char *GameEventName[ NUM_GAME_EVENTS + 1 ]; #endif // GAME_EVENT_H diff --git a/regamedll/game_shared/bot/bot_manager.cpp b/regamedll/game_shared/bot/bot_manager.cpp index 21fd767c..dcc470f0 100644 --- a/regamedll/game_shared/bot/bot_manager.cpp +++ b/regamedll/game_shared/bot/bot_manager.cpp @@ -1,61 +1,158 @@ #include "precompiled.h" +/* +* Globals initialization +*/ +#ifndef HOOK_GAMEDLL + +const char *GameEventName[NUM_GAME_EVENTS + 1] = +{ + "EVENT_INVALID", + "EVENT_WEAPON_FIRED", + "EVENT_WEAPON_FIRED_ON_EMPTY", + "EVENT_WEAPON_RELOADED", + "EVENT_HE_GRENADE_EXPLODED", + "EVENT_FLASHBANG_GRENADE_EXPLODED", + "EVENT_SMOKE_GRENADE_EXPLODED", + "EVENT_GRENADE_BOUNCED", + "EVENT_BEING_SHOT_AT", + "EVENT_PLAYER_BLINDED_BY_FLASHBANG", + "EVENT_PLAYER_FOOTSTEP", + "EVENT_PLAYER_JUMPED", + "EVENT_PLAYER_DIED", + "EVENT_PLAYER_LANDED_FROM_HEIGHT", + "EVENT_PLAYER_TOOK_DAMAGE", + "EVENT_HOSTAGE_DAMAGED", + "EVENT_HOSTAGE_KILLED", + "EVENT_DOOR", + "EVENT_BREAK_GLASS", + "EVENT_BREAK_WOOD", + "EVENT_BREAK_METAL", + "EVENT_BREAK_FLESH", + "EVENT_BREAK_CONCRETE", + "EVENT_BOMB_PLANTED", + "EVENT_BOMB_DROPPED", + "EVENT_BOMB_PICKED_UP", + "EVENT_BOMB_BEEP", + "EVENT_BOMB_DEFUSING", + "EVENT_BOMB_DEFUSE_ABORTED", + "EVENT_BOMB_DEFUSED", + "EVENT_BOMB_EXPLODED", + "EVENT_HOSTAGE_USED", + "EVENT_HOSTAGE_RESCUED", + "EVENT_ALL_HOSTAGES_RESCUED", + "EVENT_VIP_ESCAPED", + "EVENT_VIP_ASSASSINATED", + "EVENT_TERRORISTS_WIN", + "EVENT_CTS_WIN", + "EVENT_ROUND_DRAW", + "EVENT_ROUND_WIN", + "EVENT_ROUND_LOSS", + "EVENT_ROUND_START", + "EVENT_PLAYER_SPAWNED", + "EVENT_CLIENT_CORPSE_SPAWNED", + "EVENT_BUY_TIME_START", + "EVENT_PLAYER_LEFT_BUY_ZONE", + "EVENT_DEATH_CAMERA_START", + "EVENT_KILL_ALL", + "EVENT_ROUND_TIME", + "EVENT_DIE", + "EVENT_KILL", + "EVENT_HEADSHOT", + "EVENT_KILL_FLASHBANGED", + "EVENT_TUTOR_BUY_MENU_OPENNED", + "EVENT_TUTOR_AUTOBUY", + "EVENT_PLAYER_BOUGHT_SOMETHING", + "EVENT_TUTOR_NOT_BUYING_ANYTHING", + "EVENT_TUTOR_NEED_TO_BUY_PRIMARY_WEAPON", + "EVENT_TUTOR_NEED_TO_BUY_PRIMARY_AMMO", + "EVENT_TUTOR_NEED_TO_BUY_SECONDARY_AMMO", + "EVENT_TUTOR_NEED_TO_BUY_ARMOR", + "EVENT_TUTOR_NEED_TO_BUY_DEFUSE_KIT", + "EVENT_TUTOR_NEED_TO_BUY_GRENADE", + "EVENT_CAREER_TASK_DONE", + "EVENT_START_RADIO_1", + "EVENT_RADIO_COVER_ME", + "EVENT_RADIO_YOU_TAKE_THE_POINT", + "EVENT_RADIO_HOLD_THIS_POSITION", + "EVENT_RADIO_REGROUP_TEAM", + "EVENT_RADIO_FOLLOW_ME", + "EVENT_RADIO_TAKING_FIRE", + "EVENT_START_RADIO_2", + "EVENT_RADIO_GO_GO_GO", + "EVENT_RADIO_TEAM_FALL_BACK", + "EVENT_RADIO_STICK_TOGETHER_TEAM", + "EVENT_RADIO_GET_IN_POSITION_AND_WAIT", + "EVENT_RADIO_STORM_THE_FRONT", + "EVENT_RADIO_REPORT_IN_TEAM", + "EVENT_START_RADIO_3", + "EVENT_RADIO_AFFIRMATIVE", + "EVENT_RADIO_ENEMY_SPOTTED", + "EVENT_RADIO_NEED_BACKUP", + "EVENT_RADIO_SECTOR_CLEAR", + "EVENT_RADIO_IN_POSITION", + "EVENT_RADIO_REPORTING_IN", + "EVENT_RADIO_GET_OUT_OF_THERE", + "EVENT_RADIO_NEGATIVE", + "EVENT_RADIO_ENEMY_DOWN", + "EVENT_END_RADIO", + "EVENT_NEW_MATCH", + "EVENT_PLAYER_CHANGED_TEAM", + "EVENT_BULLET_IMPACT", + "EVENT_GAME_COMMENCE", + "EVENT_WEAPON_ZOOMED", + "EVENT_HOSTAGE_CALLED_FOR_HELP", + NULL, +}; + +#else + +const char *GameEventName[ NUM_GAME_EVENTS + 1 ]; + +#endif // HOOK_GAMEDLL + // STL uses exceptions, but we are not compiling with them - ignore warning #pragma warning(disable : 4530) -//#define DEFINE_EVENT_NAMES +const float smokeRadius = 115.0f; // for smoke grenades -/*#include "extdll.h" -#include "util.h" -#include "cbase.h" -#include "weapons.h" -#include "soundent.h" -#include "gamerules.h" -#include "player.h" -#include "client.h" -#include "game_shared/perf_counter.h" - -#include "bot.h" -#include "bot_manager.h" -#include "nav_area.h" -#include "bot_util.h" -#include "hostage.h" - -#include "tutor.h"*/ - -//#define CHECK_PERFORMANCE - -const float smokeRadius = 115.0f; ///< for smoke grenades +// Convert name to GameEventType +// TODO: Find more appropriate place for this function /* <49f6d7> ../game_shared/bot/bot_manager.cpp:58 */ -NOBODY GameEventType NameToGameEvent(const char *name) +GameEventType NameToGameEvent(const char *name) { - /*for (int i=0; GameEventName[i]; ++i) + for (int i = 0; GameEventName[i] != NULL; ++i) + { if (!Q_stricmp(GameEventName[i], name)) - return static_cast(i);*/ + return static_cast(i); + } return EVENT_INVALID; } /* <49f733> ../game_shared/bot/bot_manager.cpp:69 */ -NOBODY CBotManager::CBotManager() +CBotManager::CBotManager() { - //InitBotTrig(); + InitBotTrig(); } +// Invoked when the round is restarting + /* <49f586> ../game_shared/bot/bot_manager.cpp:78 */ void CBotManager::__MAKE_VHOOK(RestartRound)(void) { DestroyAllGrenades(); } +// Invoked at the start of each frame + +/* <49a21c> ../game_shared/bot/bot_manager.cpp:85 */ void CBotManager::__MAKE_VHOOK(StartFrame)(void) { // debug smoke grenade visualization if (cv_bot_debug.value == 5) { - UNTESTED - Vector edge, lastEdge; ActiveGrenadeList::iterator iter = m_activeGrenadeList.begin(); @@ -115,12 +212,13 @@ void CBotManager::__MAKE_VHOOK(StartFrame)(void) if (pPlayer->IsBot() && IsEntityValid(pPlayer)) { CBot *pBot = static_cast(pPlayer); - pBot->BotThink(); } } } +// Return the filename for this map's "nav map" file + /* <49f7a6> ../game_shared/bot/bot_manager.cpp:205 */ const char *CBotManager::GetNavMapFilename(void) const { @@ -129,6 +227,10 @@ const char *CBotManager::GetNavMapFilename(void) const return filename; } +// Invoked when given player does given event (some events have NULL player). +// Events are propogated to all bots. +// TODO: This has become the game-wide event dispatcher. We should restructure this. + /* <49f17b> ../game_shared/bot/bot_manager.cpp:219 */ void CBotManager::__MAKE_VHOOK(OnEvent)(GameEventType event, CBaseEntity *entity, CBaseEntity *other) { @@ -168,6 +270,8 @@ void CBotManager::__MAKE_VHOOK(OnEvent)(GameEventType event, CBaseEntity *entity } } +// Add an active grenade to the bot's awareness + /* <49f7ff> ../game_shared/bot/bot_manager.cpp:257 */ void CBotManager::AddGrenade(int type, CGrenade *grenade) { @@ -176,6 +280,8 @@ void CBotManager::AddGrenade(int type, CGrenade *grenade) m_activeGrenadeList.push_back(ag); } +// The grenade entity in the world is going away + /* <49f95a> ../game_shared/bot/bot_manager.cpp:267 */ void CBotManager::RemoveGrenade(CGrenade *grenade) { @@ -191,6 +297,8 @@ void CBotManager::RemoveGrenade(CGrenade *grenade) } } +// Destroy any invalid active grenades + /* <49f9fc> ../game_shared/bot/bot_manager.cpp:285 */ NOXREF void CBotManager::ValidateActiveGrenades(void) { @@ -210,7 +318,7 @@ NOXREF void CBotManager::ValidateActiveGrenades(void) } /* <49faf3> ../game_shared/bot/bot_manager.cpp:305 */ -NOXREF void CBotManager::DestroyAllGrenades(void) +void CBotManager::DestroyAllGrenades(void) { for (ActiveGrenadeList::iterator iter = m_activeGrenadeList.begin(); iter != m_activeGrenadeList.end(); iter++) delete *iter; @@ -218,6 +326,8 @@ NOXREF void CBotManager::DestroyAllGrenades(void) m_activeGrenadeList.clear(); } +// Return true if position is inside a smoke cloud + /* <49fc24> ../game_shared/bot/bot_manager.cpp:317 */ bool CBotManager::IsInsideSmokeCloud(const Vector *pos) { @@ -225,6 +335,8 @@ bool CBotManager::IsInsideSmokeCloud(const Vector *pos) while (iter != m_activeGrenadeList.end()) { ActiveGrenade *ag = *iter; + + // lazy validation if (!ag->IsValid()) { delete ag; @@ -242,9 +354,15 @@ bool CBotManager::IsInsideSmokeCloud(const Vector *pos) return true; } } + return false; } +// Return true if line intersects smoke volume +// Determine the length of the line of sight covered by each smoke cloud, +// and sum them (overlap is additive for obstruction). +// If the overlap exceeds the threshold, the bot can't see through. + /* <49fd8b> ../game_shared/bot/bot_manager.cpp:355 */ bool CBotManager::IsLineBlockedBySmoke(const Vector *from, const Vector *to) { @@ -262,6 +380,7 @@ bool CBotManager::IsLineBlockedBySmoke(const Vector *from, const Vector *to) { ActiveGrenade *ag = *iter; + // lazy validation if (!ag->IsValid()) { delete ag; @@ -357,7 +476,10 @@ bool CBotManager::IsLineBlockedBySmoke(const Vector *from, const Vector *to) } } + // define how much smoke a bot can see thru const float maxSmokedLength = 0.7f * smokeRadius; + + // return true if the total length of smoke-covered line-of-sight is too much return (totalSmokedLength > maxSmokedLength); } diff --git a/regamedll/game_shared/bot/bot_manager.h b/regamedll/game_shared/bot/bot_manager.h index bde086d3..576c17af 100644 --- a/regamedll/game_shared/bot/bot_manager.h +++ b/regamedll/game_shared/bot/bot_manager.h @@ -36,19 +36,6 @@ #pragma warning(disable : 4530) #include -#include "game_shared/GameEvent.h" - -#ifndef _WIN32 - -//#ifndef max -//#define max(a,b) ((a) > (b) ? (a) : (b)) -//#endif // max - -//#ifndef min -//#define min(a,b) ((a) < (b) ? (a) : (b)) -//#endif // min - -#endif // _WIN32 class CNavArea; class CGrenade; @@ -82,7 +69,7 @@ private: };/* size: 24, cachelines: 1, members: 4 */ -typedef std::list ActiveGrenadeList; +typedef std::STD_LIST ActiveGrenadeList; class CBotManager { @@ -138,16 +125,11 @@ public: private: -#if defined(_WIN32) && defined(HOOK_GAMEDLL) - // The member m_activeGrenadeList on Windows must be with offset +8 - // on Linux : +4 - - int unknown_padding; -#endif // HOOK_GAMEDLL - // the list of active grenades the bots are aware of ActiveGrenadeList m_activeGrenadeList; // };/* size: 12, cachelines: 1, members: 2 */ +GameEventType NameToGameEvent(const char *name); + #endif // BOT_MANAGER_H diff --git a/regamedll/game_shared/bot/bot_util.cpp b/regamedll/game_shared/bot/bot_util.cpp index df1e0559..44c37e21 100644 --- a/regamedll/game_shared/bot/bot_util.cpp +++ b/regamedll/game_shared/bot/bot_util.cpp @@ -57,7 +57,7 @@ bool UTIL_IsNameTaken(const char *name, bool ignoreHumans) int UTIL_ClientsInGame(void) { int iCount = 0; - for (int iIndex = 1; iIndex <= gpGlobals->maxClients; iIndex++) + for (int iIndex = 1; iIndex <= gpGlobals->maxClients; ++iIndex) { CBaseEntity *pPlayer = UTIL_PlayerByIndex(iIndex); @@ -70,8 +70,9 @@ int UTIL_ClientsInGame(void) if (FStrEq(STRING(pPlayer->pev->netname), "")) continue; - iCount++; + ++iCount; } + return iCount; } @@ -79,7 +80,7 @@ int UTIL_ClientsInGame(void) int UTIL_ActivePlayersInGame(void) { int iCount = 0; - for (int iIndex = 1; iIndex <= gpGlobals->maxClients; iIndex++) + for (int iIndex = 1; iIndex <= gpGlobals->maxClients; ++iIndex) { CBaseEntity *entity = UTIL_PlayerByIndex(iIndex); @@ -101,7 +102,7 @@ int UTIL_ActivePlayersInGame(void) if (player->m_iJoiningState != JOINED) continue; - iCount++; + ++iCount; } return iCount; @@ -112,7 +113,7 @@ int UTIL_HumansInGame(bool ignoreSpectators) { int iCount = 0; - for (int iIndex = 1; iIndex <= gpGlobals->maxClients; iIndex++) + for (int iIndex = 1; iIndex <= gpGlobals->maxClients; ++iIndex) { CBaseEntity *entity = UTIL_PlayerByIndex(iIndex); @@ -136,7 +137,7 @@ int UTIL_HumansInGame(bool ignoreSpectators) if (ignoreSpectators && player->m_iJoiningState != JOINED) continue; - iCount++; + ++iCount; } return iCount; @@ -146,7 +147,7 @@ int UTIL_HumansInGame(bool ignoreSpectators) NOBODY int UTIL_HumansOnTeam(int teamID, bool isAlive) { int iCount = 0; - for (int iIndex = 1; iIndex <= gpGlobals->maxClients; iIndex++) + for (int iIndex = 1; iIndex <= gpGlobals->maxClients; ++iIndex) { CBaseEntity *entity = UTIL_PlayerByIndex(iIndex); @@ -170,7 +171,7 @@ NOBODY int UTIL_HumansOnTeam(int teamID, bool isAlive) if (isAlive && !player->IsAlive()) continue; - iCount++; + ++iCount; } return iCount; @@ -181,7 +182,7 @@ NOBODY int UTIL_BotsInGame(void) { int iCount = 0; - for (int iIndex = 1; iIndex <= gpGlobals->maxClients; iIndex++) + for (int iIndex = 1; iIndex <= gpGlobals->maxClients; ++iIndex) { CBasePlayer *pPlayer = static_cast(UTIL_PlayerByIndex(iIndex)); @@ -197,7 +198,7 @@ NOBODY int UTIL_BotsInGame(void) if (!pPlayer->IsBot()) continue; - iCount++; + ++iCount; } return iCount; @@ -267,7 +268,7 @@ bool UTIL_KickBotFromTeam(TeamName kickTeam) NOBODY bool UTIL_IsTeamAllBots(int team) { int botCount = 0; - for (int i=1; i <= gpGlobals->maxClients; ++i) + for (int i = 1; i <= gpGlobals->maxClients; ++i) { CBasePlayer *player = static_cast(UTIL_PlayerByIndex(i)); @@ -301,7 +302,7 @@ NOBODY bool UTIL_IsTeamAllBots(int team) CBasePlayer *closePlayer = NULL; float closeDistSq = 1.0e12f; // 999999999999.9f - for (int i = 1; i <= gpGlobals->maxClients; i++) + for (int i = 1; i <= gpGlobals->maxClients; ++i) { CBasePlayer *player = static_cast(UTIL_PlayerByIndex(i)); @@ -334,7 +335,7 @@ NOBODY /*extern*/ CBasePlayer *UTIL_GetClosestPlayer(const Vector *pos, int team CBasePlayer *closePlayer = NULL; float closeDistSq = 1.0e12f; // 999999999999.9f - for (int i = 1; i <= gpGlobals->maxClients; i++) + for (int i = 1; i <= gpGlobals->maxClients; ++i) { CBasePlayer *player = static_cast(UTIL_PlayerByIndex(i)); @@ -546,7 +547,7 @@ void BotPrecache(void) /* <4ae1b1> ../game_shared/bot/bot_util.cpp:666 */ void InitBotTrig(void) { - for (int i = 0; i < COS_TABLE_SIZE; i++) + for (int i = 0; i < COS_TABLE_SIZE; ++i) { float_precision angle = 2.0f * M_PI * (float)i / (float)(COS_TABLE_SIZE - 1); cosTable[i] = cos(angle); diff --git a/regamedll/game_shared/bot/bot_util.h b/regamedll/game_shared/bot/bot_util.h index b906ba13..805f8bca 100644 --- a/regamedll/game_shared/bot/bot_util.h +++ b/regamedll/game_shared/bot/bot_util.h @@ -97,7 +97,7 @@ public: { return (gpGlobals->time - m_timestamp > duration) ? true : false; } -private: +/*private:*/ float m_timestamp; };/* size: 4, cachelines: 1, members: 1 */ diff --git a/regamedll/game_shared/bot/nav.h b/regamedll/game_shared/bot/nav.h index 5248ddf4..2066d1d9 100644 --- a/regamedll/game_shared/bot/nav.h +++ b/regamedll/game_shared/bot/nav.h @@ -400,6 +400,7 @@ inline bool IsEntityWalkable(entvars_t *entity, unsigned int flags) } // Check LOS, ignoring any entities that we can walk through + /* <38d33d> ../game_shared/bot/nav.h:330 */ inline bool IsWalkableTraceLineClear(Vector &from, Vector &to, unsigned int flags = 0) { diff --git a/regamedll/game_shared/bot/nav_area.cpp b/regamedll/game_shared/bot/nav_area.cpp index 4d4b7f63..6fc860b8 100644 --- a/regamedll/game_shared/bot/nav_area.cpp +++ b/regamedll/game_shared/bot/nav_area.cpp @@ -2069,17 +2069,8 @@ bool CNavArea::IsCoplanar(const CNavArea *area) const // NOTE: pos->z is not used. /* <4c8963> ../game_shared/bot/nav_area.cpp:2114 */ -float (*pGetZ__Vector)(const Vector *pos); - -float __declspec(naked) CNavArea::GetZ(const Vector *pos) const +float CNavArea::GetZ(const Vector *pos) const { - __asm - { - jmp pGetZ__Vector - } - UNTESTED - // Crash -/* float dx = m_extent.hi.x - m_extent.lo.x; float dy = m_extent.hi.y - m_extent.lo.y; @@ -2105,7 +2096,6 @@ float __declspec(naked) CNavArea::GetZ(const Vector *pos) const float southZ = m_swZ + u * (m_extent.hi.z - m_swZ); return northZ + v * (southZ - northZ); -*/ } /* <4caa36> ../game_shared/bot/nav_area.cpp:2143 */ @@ -3462,10 +3452,14 @@ const Vector *FindNearbyHidingSpot(CBaseEntity *me, const Vector *pos, CNavArea } // select a hiding spot at random - int which = RANDOM_LONG(0, collector.m_count-1); + int which = RANDOM_LONG(0, collector.m_count - 1); return collector.m_hidingSpot[ which ]; } +// Return true if moving from "start" to "finish" will cross a player's line of fire +// The path from "start" to "finish" is assumed to be a straight line +// "start" and "finish" are assumed to be points on the ground + /* <4c3feb> ../game_shared/bot/nav_area.cpp:3591 */ bool IsCrossingLineOfFire(const Vector &start, const Vector &finish, CBaseEntity *ignore, int ignoreTeam) { @@ -4925,49 +4919,43 @@ void CNavAreaGrid::RemoveNavArea(CNavArea *area) --m_areaCount; } -CNavArea *(*pGetNavArea)(const Vector *pos, float beneathLimit); - // Given a position, return the nav area that IsOverlapping and is *immediately* beneath it /* <4cff5e> ../game_shared/bot/nav_area.cpp:5080 */ -CNavArea __declspec(naked) *CNavAreaGrid::GetNavArea(const Vector *pos, float beneathLimit) const +CNavArea *CNavAreaGrid::GetNavArea(const Vector *pos, float beneathLimit) const { - __asm - { - jmp pGetNavArea - } - - UNTESTED - //TODO: Crash NavAreaList::iterator iter = list->begin() -/* if (m_grid == NULL) return NULL; + // get list in cell that contains position int x = WorldToGridX(pos->x); int y = WorldToGridY(pos->y); - NavAreaList *list = &m_grid[x + y * m_gridSizeX]; + // search cell list to find correct area CNavArea *use = NULL; - float useZ = -100000000.0f; + float useZ = -99999999.9f; Vector testPos = *pos + Vector(0, 0, 5); - if (list == NULL) - return NULL; - for (NavAreaList::iterator iter = list->begin(); iter != list->end(); ++iter) { CNavArea *area = *iter; + // check if position is within 2D boundaries of this area if (area->IsOverlapping(&testPos)) { + // project position onto area to get Z float z = area->GetZ(&testPos); + + // if area is above us, skip it if (z > testPos.z) continue; + // if area is too far below us, skip it if (z < pos->z - beneathLimit) continue; + // if area is higher than the one we have, use this instead if (z > useZ) { use = area; @@ -4975,36 +4963,29 @@ CNavArea __declspec(naked) *CNavAreaGrid::GetNavArea(const Vector *pos, float be } } } - return use; -*/ -} -CNavArea *(*pGetNearestNavArea)(const Vector *pos, bool anyZ); + return use; +} // Given a position in the world, return the nav area that is closest // and at the same height, or beneath it. // Used to find initial area if we start off of the mesh. /* <4d33b4> ../game_shared/bot/nav_area.cpp:5133 */ -NOBODY __declspec(naked) CNavArea *CNavAreaGrid::GetNearestNavArea(const Vector *pos, bool anyZ) const +CNavArea *CNavAreaGrid::GetNearestNavArea(const Vector *pos, bool anyZ) const { - __asm - { - jmp pGetNearestNavArea - } - //TODO: UNTESTED - // Result: Crashed TheNavAreaList.begin() - -/* if (m_grid == NULL) + if (m_grid == NULL) return NULL; CNavArea *close = NULL; float closeDistSq = 100000000.0f; + // quick check close = GetNavArea(pos); if (close) return close; + // ensure source position is well behaved Vector source; source.x = pos->x; source.y = pos->y; @@ -5014,6 +4995,9 @@ NOBODY __declspec(naked) CNavArea *CNavAreaGrid::GetNearestNavArea(const Vector source.z += HalfHumanHeight; + // TODO: Step incrementally using grid for speed + + // find closest nav area for (NavAreaList::iterator iter = TheNavAreaList.begin(); iter != TheNavAreaList.end(); ++iter) { CNavArea *area = *iter; @@ -5022,8 +5006,11 @@ NOBODY __declspec(naked) CNavArea *CNavAreaGrid::GetNearestNavArea(const Vector area->GetClosestPointOnArea(&source, &areaPos); float distSq = (areaPos - source).LengthSquared(); + + // keep the closest area if (distSq < closeDistSq) { + // check LOS to area if (!anyZ) { TraceResult result; @@ -5035,8 +5022,8 @@ NOBODY __declspec(naked) CNavArea *CNavAreaGrid::GetNearestNavArea(const Vector close = area; } } + return close; -*/ } // Given an ID, return the associated area @@ -5063,7 +5050,7 @@ Place CNavAreaGrid::GetPlace(const Vector *pos) const { CNavArea *area = GetNearestNavArea(pos, true); - if (area) + if (area != NULL) { return area->GetPlace(); } diff --git a/regamedll/game_shared/bot/nav_area.h b/regamedll/game_shared/bot/nav_area.h index 0e7344e8..fcd3d045 100644 --- a/regamedll/game_shared/bot/nav_area.h +++ b/regamedll/game_shared/bot/nav_area.h @@ -63,44 +63,40 @@ enum { MAX_BLOCKED_AREAS = 256 }; #endif // HOOK_GAMEDLL void DestroyHidingSpots(void); -NOBODY void StripNavigationAreas(void); -//bool SaveNavigationMap(const char *filename); -//NavErrorType LoadNavigationMap(void); -NOBODY void DestroyNavigationMap(void); +void StripNavigationAreas(void); +bool SaveNavigationMap(const char *filename); +NavErrorType LoadNavigationMap(void); +void DestroyNavigationMap(void); enum NavEditCmdType { EDIT_NONE, - EDIT_DELETE, - EDIT_SPLIT, - EDIT_MERGE, - EDIT_JOIN, - EDIT_BREAK, - EDIT_MARK, - EDIT_ATTRIB_CROUCH, - EDIT_ATTRIB_JUMP, - EDIT_ATTRIB_PRECISE, - EDIT_ATTRIB_NO_JUMP, - EDIT_BEGIN_AREA, - EDIT_END_AREA, - EDIT_CONNECT, - EDIT_DISCONNECT, - EDIT_SPLICE, - EDIT_TOGGLE_PLACE_MODE, - EDIT_TOGGLE_PLACE_PAINTING, - EDIT_PLACE_FLOODFILL, - EDIT_PLACE_PICK, - EDIT_MARK_UNNAMED, - EDIT_WARP_TO_MARK, - EDIT_SELECT_CORNER, - EDIT_RAISE_CORNER, - EDIT_LOWER_CORNER, + EDIT_DELETE, // delete current area + EDIT_SPLIT, // split current area + EDIT_MERGE, // merge adjacent areas + EDIT_JOIN, // define connection between areas + EDIT_BREAK, // break connection between areas + EDIT_MARK, // mark an area for further operations + EDIT_ATTRIB_CROUCH, // toggle crouch attribute on current area + EDIT_ATTRIB_JUMP, // toggle jump attribute on current area + EDIT_ATTRIB_PRECISE, // toggle precise attribute on current area + EDIT_ATTRIB_NO_JUMP, // toggle inhibiting discontinuity jumping in current area + EDIT_BEGIN_AREA, // begin creating a new nav area + EDIT_END_AREA, // end creation of the new nav area + EDIT_CONNECT, // connect marked area to selected area + EDIT_DISCONNECT, // disconnect marked area from selected area + EDIT_SPLICE, // create new area in between marked and selected areas + EDIT_TOGGLE_PLACE_MODE, // switch between normal and place editing + EDIT_TOGGLE_PLACE_PAINTING, // switch between "painting" places onto areas + EDIT_PLACE_FLOODFILL, // floodfill areas out from current area + EDIT_PLACE_PICK, // "pick up" the place at the current area + EDIT_MARK_UNNAMED, // mark an unnamed area for further operations + EDIT_WARP_TO_MARK, // warp a spectating local player to the selected mark + EDIT_SELECT_CORNER, // select a corner on the current area + EDIT_RAISE_CORNER, // raise a corner on the current area + EDIT_LOWER_CORNER, // lower a corner on the current area }; -//#define NO_CROUCH_SPOTS false -//class CBasePlayer; -//class CBaseEntity; - enum RouteType { FASTEST_ROUTE, @@ -278,14 +274,16 @@ struct SpotEncounter NavDirType fromDir; NavConnect to; NavDirType toDir; - Ray path; - SpotOrderList spotList; + Ray path; // the path segment + SpotOrderList spotList; // list of spots to look at, in order of occurrence };/* size: 48, cachelines: 1, members: 6 */ typedef std::STD_LIST SpotEncounterList; typedef std::STD_LIST NavAreaList; +// A CNavArea is a rectangular region defining a walkable area in the map + class CNavArea { public: @@ -296,8 +294,8 @@ public: ~CNavArea(); - void ConnectTo(CNavArea *area, NavDirType dir); - void Disconnect(CNavArea *area); + void ConnectTo(CNavArea *area, NavDirType dir); // connect this area to given area in given direction + void Disconnect(CNavArea *area); // disconnect this area from given area void Save(FILE *fp) const; void Save(int fd, unsigned int version); @@ -317,73 +315,74 @@ public: { return m_attributeFlags; } - void SetPlace(Place place) + void SetPlace(Place place) // set place descriptor { m_place = place; } - Place GetPlace(void) const + Place GetPlace(void) const // get place descriptor { return m_place; } - bool IsOverlapping(const Vector *pos) const; - bool IsOverlapping(const CNavArea *area) const; - bool IsOverlappingX(const CNavArea *area) const; - bool IsOverlappingY(const CNavArea *area) const; - int GetPlayerCount(int teamID = 0, CBasePlayer *ignore = NULL) const; - float GetZ(const Vector *pos) const; - float GetZ(float x, float y) const; - bool Contains(const Vector *pos) const; - bool IsCoplanar(const CNavArea *area) const; - void GetClosestPointOnArea(const Vector *pos, Vector *close) const; - float GetDistanceSquaredToPoint(const Vector *pos) const; - bool IsDegenerate(void) const; - - bool IsEdge(NavDirType dir) const; - - int GetAdjacentCount(NavDirType dir) const + 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; + 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; - float ComputeHeightChange(const CNavArea *area); + 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]; } - void ComputePortal(const CNavArea *to, NavDirType dir, Vector *center, float *halfWidth) const; - void ComputeClosestPointInPortal(const CNavArea *to, NavDirType dir, const Vector *fromPos, Vector *closePos) const; - NavDirType ComputeDirection(Vector *point) const; + 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 - void SetClearedTimestamp(int teamID) + // for hunting algorithm + void SetClearedTimestamp(int teamID) // set this area's "clear" timestamp to now { m_clearedTimestamp[teamID] = gpGlobals->time; } - float GetClearedTimestamp(int teamID) + float GetClearedTimestamp(int teamID) // get time this area was marked "clear" { return m_clearedTimestamp[teamID]; } + + // hiding spots const HidingSpotList *GetHidingSpotList(void) const { return &m_hidingSpotList; } - void ComputeHidingSpots(void); - void ComputeSniperSpots(void); + 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 - SpotEncounter *GetSpotEncounter(const CNavArea *from, const CNavArea *to); - void ComputeSpotEncounters(void); - void IncreaseDanger(int teamID, float amount); + SpotEncounter *GetSpotEncounter(const CNavArea *from, const CNavArea *to); // given the areas we are moving between, return the spots we will encounter + void ComputeSpotEncounters(void); // compute spot encounter data - for map learning - float GetDanger(int teamID); + // 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; @@ -402,12 +401,13 @@ public: } const Vector *GetCorner(NavCornerType corner) const; + // approach areas struct ApproachInfo { - NavConnect here; - NavConnect prev; + NavConnect here; // the approach area + NavConnect prev; // the area just before the approach area on the path NavTraverseType prevToHereHow; - NavConnect next; + NavConnect next; // the area just after the approach area on the path NavTraverseType hereToNextHow; }; @@ -419,7 +419,9 @@ public: { return m_approachCount; } - void ComputeApproachAreas(void); + void ComputeApproachAreas(void); // determine the set of "approach areas" - for map learning + + // A* pathfinding algorithm static void MakeNewMarker(void) { IMPL(m_masterMarker)++; @@ -448,18 +450,18 @@ public: return m_parentHow; } - bool IsOpen(void) const; - void AddToOpenList(void); - void UpdateOnOpenList(void); + bool IsOpen(void) const; // true if on "open list" + void AddToOpenList(void); // add to open list in decreasing value order + void UpdateOnOpenList(void); // a smaller value has been found, update this area on the open list void RemoveFromOpenList(void); static bool IsOpenListEmpty(void); - static CNavArea *PopOpenList(void); + static CNavArea *PopOpenList(void); // remove and return the first element of the open list - bool IsClosed(void) const; - void AddToClosedList(void); + bool IsClosed(void) const; // true if on "closed list" + void AddToClosedList(void); // add to the closed list void RemoveFromClosedList(void); - static void ClearSearchLists(void); + static void ClearSearchLists(void); // clears the open and closed lists for a new search void SetTotalCost(float value) { @@ -478,13 +480,16 @@ public: return m_costSoFar; } - void Draw(byte red, byte green, byte blue, int duration = 50); + // editing + void Draw(byte red, byte green, byte blue, int duration = 50); // draw area for debugging & editing void DrawConnectedAreas(void); void DrawMarkedCorner(NavCornerType corner, byte red, byte green, byte blue, int duration = 50); - bool SplitEdit(bool splitAlongX, float splitEdge, CNavArea **outAlpha = NULL, CNavArea **outBeta = NULL); - bool MergeEdit(CNavArea *adj); - bool SpliceEdit(CNavArea *other); - void RaiseCorner(NavCornerType corner, int amount); + bool SplitEdit(bool splitAlongX, float splitEdge, CNavArea **outAlpha = NULL, CNavArea **outBeta = NULL); // split this area into two areas at the given edge + bool MergeEdit(CNavArea *adj); // merge this area and given adjacent area + bool SpliceEdit(CNavArea *other); // create a new area between this area and given area + 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); @@ -499,16 +504,6 @@ public: #else private: #endif // HOOK_GAMEDLL - bool IsHidingSpotCollision(const Vector *pos) const; - void AddSpotEncounters(const CNavArea *from, NavDirType fromDir, const CNavArea *to, NavDirType toDir); - void Strip(void); - void FinishMerge(CNavArea *adjArea); - void MergeAdjacentConnections(CNavArea *adjArea); - void AssignNodes(CNavArea *area); - void FinishSplitEdit(CNavArea *newArea, NavDirType ignoreEdge); - void OnDestroyNotify(CNavArea *dead); - void DecayDanger(void); -private: friend void ConnectGeneratedAreas(void); friend void MergeGeneratedAreas(void); friend void MarkJumpAreas(void); @@ -517,85 +512,75 @@ private: friend void DestroyNavigationMap(void); friend void DestroyHidingSpots(void); friend void StripNavigationAreas(void); - friend class CNavAreaGrid; friend class CCSBotManager; - void Initialize(void); + void Initialize(void); // to keep constructors consistent + static bool IMPL(m_isReset); // if true, don't bother cleaning up in destructor since everything is going away -#ifdef HOOK_GAMEDLL -public: -#endif // HOOK_GAMEDLL - static bool IMPL(m_isReset); - static unsigned int IMPL(m_nextID); - -#ifdef HOOK_GAMEDLL -private: -#endif // HOOK_GAMEDLL - - unsigned int m_id; - Extent m_extent; - Vector m_center; - unsigned char m_attributeFlags; - Place m_place; + static unsigned int IMPL(m_nextID); // used to allocate unique IDs + unsigned int m_id; // unique area ID + Extent m_extent; // extents of area in world coords (NOTE: lo.z is not necessarily the minimum Z, but corresponds to Z at point (lo.x, lo.y), etc + Vector m_center; // centroid of area + unsigned char m_attributeFlags; // set of attribute bit flags (see NavAttributeType) + Place m_place; // place descriptor + // height of the implicit corners float m_neZ; float m_swZ; enum { MAX_AREA_TEAMS = 2 }; - float m_clearedTimestamp[MAX_AREA_TEAMS]; - float m_danger[MAX_AREA_TEAMS]; - float m_dangerTimestamp[MAX_AREA_TEAMS]; + // for hunting + float m_clearedTimestamp[MAX_AREA_TEAMS]; // time this area was last "cleared" of enemies + // danger + float m_danger[MAX_AREA_TEAMS]; // danger of this area, allowing bots to avoid areas where they died in the past - zero is no danger + float m_dangerTimestamp[MAX_AREA_TEAMS]; // time when danger value was set - used for decaying + void DecayDanger(void); + + // hiding spots HidingSpotList m_hidingSpotList; + bool IsHidingSpotCollision(const Vector *pos) const; // returns true if an existing hiding spot is too close to given position -#ifdef HOOK_GAMEDLL -public: -#endif // HOOK_GAMEDLL - SpotEncounterList m_spotEncounterList; + // encounter spots + SpotEncounterList m_spotEncounterList; // list of possible ways to move thru this area, and the spots to look at as we do + void AddSpotEncounters(const CNavArea *from, NavDirType fromDir, const CNavArea *to, NavDirType toDir); + // approach areas enum { MAX_APPROACH_AREAS = 16 }; - - ApproachInfo m_approach[MAX_APPROACH_AREAS];//104 + ApproachInfo m_approach[MAX_APPROACH_AREAS]; unsigned char m_approachCount; -#ifdef HOOK_GAMEDLL -public: -#endif // HOOK_GAMEDLL + void Strip(void); // remove "analyzed" data from nav area + + // A* pathfinding algorithm static unsigned int IMPL(m_masterMarker); + unsigned int m_marker; // used to flag the area as visited + CNavArea *m_parent; // the area just prior to this on in the search path + NavTraverseType m_parentHow; // how we get from parent to us + float m_totalCost; // the distance so far plus an estimate of the distance left + float m_costSoFar; // distance travelled so far -#ifdef HOOK_GAMEDLL -private: -#endif // HOOK_GAMEDLL - - unsigned int m_marker; - CNavArea *m_parent; - NavTraverseType m_parentHow; - float m_totalCost; - float m_costSoFar; - -#ifdef HOOK_GAMEDLL -public: -#endif // HOOK_GAMEDLL static CNavArea *IMPL(m_openList); + CNavArea *m_nextOpen, *m_prevOpen; // only valid if m_openMarker == m_masterMarker + unsigned int m_openMarker; // if this equals the current marker value, we are on the open list -#ifdef HOOK_GAMEDLL -private: -#endif // HOOK_GAMEDLL + // connections to adjacent areas + NavConnectList m_connect[ NUM_DIRECTIONS ]; // a list of adjacent areas for each direction + NavLadderList m_ladder[ NUM_LADDER_DIRECTIONS ]; // list of ladders leading up and down from this area - CNavArea *m_nextOpen; - CNavArea *m_prevOpen; - unsigned int m_openMarker; + CNavNode *m_node[ NUM_CORNERS ]; // nav nodes at each corner of the area - NavConnectList m_connect[ NUM_DIRECTIONS ]; - NavLadderList m_ladder[ NUM_LADDER_DIRECTIONS ]; - CNavNode *m_node[ NUM_CORNERS ]; + void FinishMerge(CNavArea *adjArea); // recompute internal data once nodes have been adjusted during merge + void MergeAdjacentConnections(CNavArea *adjArea); // for merging with "adjArea" - pick up all of "adjArea"s connections + void AssignNodes(CNavArea *area); // assign internal nodes to the given area + void FinishSplitEdit(CNavArea *newArea, NavDirType ignoreEdge); // given the portion of the original area, update its internal data - NavAreaList m_overlapList; + NavAreaList m_overlapList; // list of areas that overlap this area + void OnDestroyNotify(CNavArea *dead); // invoked when given area is going away - CNavArea *m_prevHash; - CNavArea *m_nextHash; + CNavArea *m_prevHash, *m_nextHash; // for hash table in CNavAreaGrid };/* size: 532, cachelines: 9, members: 32 */ @@ -635,21 +620,15 @@ inline bool CNavArea::IsOpenListEmpty(void) /* <5a1483> ../game_shared/bot/nav_area.h:445 */ inline CNavArea *CNavArea::PopOpenList(void) { -#ifndef HOOK_GAMEDLL - if (m_openList) - { - CNavArea *area = m_openList; - area->RemoveFromOpenList(); - return area; - } -#else if (IMPL(m_openList)) { CNavArea *area = IMPL(m_openList); + + // disconnect from list area->RemoveFromOpenList(); return area; } -#endif // HOOK_GAMEDLL + return NULL; } @@ -671,9 +650,13 @@ inline void CNavArea::AddToClosedList(void) /* <5a01f8> ../game_shared/bot/nav_area.h:473 */ inline void CNavArea::RemoveFromClosedList(void) { - + // since "closed" is defined as visited (marked) and not on open list, do nothing } +// The CNavAreaGrid is used to efficiently access navigation areas by world position +// Each cell of the grid contains a list of areas that overlap it +// Given a world position, the corresponding grid cell is ( x/cellsize, y/cellsize ) + /* <4cf943> ../game_shared/bot/nav_area.cpp:4947 */ class CNavAreaGrid { @@ -681,26 +664,36 @@ public: CNavAreaGrid(void); ~CNavAreaGrid(); - void Reset(void); - void Initialize(float minX, float maxX, float minY, float maxY); - void AddNavArea(CNavArea *area); - void RemoveNavArea(CNavArea *area); - unsigned int GetNavAreaCount(void) const + void Reset(void); // clear the grid to empty + void Initialize(float minX, float maxX, float minY, float maxY); // clear and reset the grid to the given extents + void AddNavArea(CNavArea *area); // add an area to the grid + void RemoveNavArea(CNavArea *area); // remove an area from the grid + unsigned int GetNavAreaCount(void) const // return total number of nav areas { return m_areaCount; } - CNavArea *GetNavArea(const Vector *pos, float beneathLimt = 120.0f) const; + CNavArea *GetNavArea(const Vector *pos, float beneathLimt = 120.0f) const; // given a position, return the nav area that IsOverlapping and is *immediately* beneath it CNavArea *GetNavAreaByID(unsigned int id) const; CNavArea *GetNearestNavArea(const Vector *pos, bool anyZ = false) const; - Place GetPlace(const Vector *pos) const; + Place GetPlace(const Vector *pos) const; // return radio chatter place for given coordinate private: + const float m_cellSize; + NavAreaList *m_grid; + int m_gridSizeX; + int m_gridSizeY; + float m_minX; + float m_minY; + unsigned int m_areaCount; // total number of nav areas - inline int ComputeHashKey(unsigned int id) const + enum { HASH_TABLE_SIZE = 256 }; + CNavArea *m_hashTable[HASH_TABLE_SIZE]; // hash table to optimize lookup by ID + inline int ComputeHashKey(unsigned int id) const // returns a hash key for the given nav area ID { return id & 0xFF; } + inline int WorldToGridX(float wx) const { int x = (wx - m_minX) / m_cellSize; @@ -723,31 +716,21 @@ private: return y; } -private: - const float m_cellSize; - NavAreaList *m_grid; - int m_gridSizeX; - int m_gridSizeY; - float m_minX; - float m_minY; - unsigned int m_areaCount; - - enum { HASH_TABLE_SIZE = 256 }; - CNavArea *m_hashTable[HASH_TABLE_SIZE]; - };/* size: 1052, cachelines: 17, members: 8 */ class ShortestPathCost { public: - float operator() (CNavArea *area, CNavArea *fromArea, const CNavLadder *ladder) + float operator()(CNavArea *area, CNavArea *fromArea, const CNavLadder *ladder) { if (fromArea == NULL) { + // first area in path, no cost return 0.0f; } else { + // compute distance travelled along path so far float dist; if (ladder) @@ -756,20 +739,34 @@ public: dist = (*area->GetCenter() - *fromArea->GetCenter()).Length(); float cost = dist + fromArea->GetCostSoFar(); + + // if this is a "crouch" area, add penalty if (area->GetAttributes() & NAV_CROUCH) { const float crouchPenalty = 20.0f; cost += crouchPenalty * dist; } + + // if this is a "jump" area, add penalty if (area->GetAttributes() & NAV_JUMP) { const float jumpPenalty = 5.0f; cost += jumpPenalty * dist; } + return cost; } } -};/* size: 0, cachelines: 0, members: 0 */ +}; + +// Find path from startArea to goalArea via an A* search, using supplied cost heuristic. +// If cost functor returns -1 for an area, that area is considered a dead end. +// This doesn't actually build a path, but the path is defined by following parent +// pointers back from goalArea to startArea. +// If 'closestArea' is non-NULL, the closest area to the goal is returned (useful if the path fails). +// If 'goalArea' is NULL, will compute a path as close as possible to 'goalPos'. +// If 'goalPos' is NULL, will use the center of 'goalArea' as the goal position. +// Returns true if a path exists. /* <4c3e99> ../game_shared/bot/nav_area.h:679 */ template @@ -781,12 +778,16 @@ bool NavAreaBuildPath(CNavArea *startArea, CNavArea *goalArea, const Vector *goa if (startArea == NULL) return false; + // If goalArea is NULL, this function will return the closest area to the goal. + // However, if there is also no goal, we can't do anything. if (goalArea == NULL && goalPos == NULL) { return false; } startArea->SetParent(NULL); + + // if we are already in the goal area, build trivial path if (startArea == goalArea) { goalArea->SetParent(NULL); @@ -796,25 +797,37 @@ bool NavAreaBuildPath(CNavArea *startArea, CNavArea *goalArea, const Vector *goa return true; } - Vector actualGoalPos = (goalPos) ? *goalPos : *goalArea->GetCenter(); + + // determine actual goal position + Vector actualGoalPos = (goalPos != NULL) ? (*goalPos) : (*goalArea->GetCenter()); + + // start search CNavArea::ClearSearchLists(); + + // compute estimate of path length + // TODO: Cost might work as "manhattan distance" startArea->SetTotalCost((*startArea->GetCenter() - actualGoalPos).Length()); - float initCost = costFunc(startArea, NULL, NULL); + float_precision initCost = costFunc(startArea, NULL, NULL); if (initCost < 0.0f) return false; startArea->SetCostSoFar(initCost); - startArea->AddToOpenList(); + // keep track of the area we visit that is closest to the goal if (closestArea) *closestArea = startArea; float closestAreaDist = startArea->GetTotalCost(); + + // do A* search while (!CNavArea::IsOpenListEmpty()) { + // get next area to check CNavArea *area = CNavArea::PopOpenList(); + + // check if we have found the goal area if (area == goalArea) { if (closestArea) @@ -823,6 +836,7 @@ bool NavAreaBuildPath(CNavArea *startArea, CNavArea *goalArea, const Vector *goa return true; } + // search adjacent areas bool searchFloor = true; int dir = NORTH; const NavConnectList *floorList = area->GetAdjacentList(NORTH); @@ -847,14 +861,17 @@ bool NavAreaBuildPath(CNavArea *startArea, CNavArea *goalArea, const Vector *goa NavTraverseType how; const CNavLadder *ladder = NULL; + // Get next adjacent area - either on floor or via ladder if (searchFloor) { + // if exhausted adjacent connections in current direction, begin checking next direction if (floorIter == floorList->end()) { ++dir; if (dir == NUM_DIRECTIONS) { + // checked all directions on floor - check ladders next searchFloor = false; ladderList = area->GetLadderList(LADDER_UP); @@ -863,7 +880,7 @@ bool NavAreaBuildPath(CNavArea *startArea, CNavArea *goalArea, const Vector *goa } else { - + // start next direction floorList = area->GetAdjacentList((NavDirType)dir); floorIter = floorList->begin(); } @@ -874,15 +891,19 @@ bool NavAreaBuildPath(CNavArea *startArea, CNavArea *goalArea, const Vector *goa how = (NavTraverseType)dir; ++floorIter; } + // search ladders else { if (ladderIter == ladderList->end()) { if (!ladderUp) + { + // checked both ladder directions - done break; - + } else { + // check down ladders ladderUp = false; ladderList = area->GetLadderList(LADDER_DOWN); ladderIter = ladderList->begin(); @@ -893,12 +914,15 @@ bool NavAreaBuildPath(CNavArea *startArea, CNavArea *goalArea, const Vector *goa if (ladderUp) { ladder = (*ladderIter); + + // cannot use this ladder if the ladder bottom is hanging above our head if (ladder->m_isDangling) { ++ladderIter; continue; } + // do not use BEHIND connection, as its very hard to get to when going up a ladder if (ladderTopDir == AHEAD) newArea = ladder->m_topForwardArea; else if (ladderTopDir == LEFT) @@ -926,19 +950,27 @@ bool NavAreaBuildPath(CNavArea *startArea, CNavArea *goalArea, const Vector *goa continue; } + // don't backtrack if (newArea == area) continue; - float newCostSoFar = costFunc(newArea, area, ladder); + float_precision newCostSoFar = costFunc(newArea, area, ladder); + + // check if cost functor says this area is a dead-end if (newCostSoFar < 0.0f) continue; if ((newArea->IsOpen() || newArea->IsClosed()) && newArea->GetCostSoFar() <= newCostSoFar) + { + // this is a worse path - skip it continue; - + } else { - float newCostRemaining = (*newArea->GetCenter() - actualGoalPos).Length(); + // compute estimate of distance left to go + float_precision newCostRemaining = (*newArea->GetCenter() - actualGoalPos).Length(); + + // track closest area to goal in case path fails if (closestArea && newCostRemaining < closestAreaDist) { *closestArea = newArea; @@ -953,21 +985,27 @@ bool NavAreaBuildPath(CNavArea *startArea, CNavArea *goalArea, const Vector *goa newArea->RemoveFromClosedList(); if (newArea->IsOpen()) + { + // area already on open list, update the list order to keep costs sorted newArea->UpdateOnOpenList(); + } else newArea->AddToOpenList(); } } + // we have searched this area area->AddToClosedList(); } return false; } +// Compute distance between two areas. Return -1 if can't reach 'endArea' from 'startArea'. + /* <3fcb64> ../game_shared/bot/nav_area.h:914 */ template -float NavAreaTravelDistance(CNavArea *startArea, CNavArea *endArea, CostFunctor &costFunc) +float_precision NavAreaTravelDistance(CNavArea *startArea, CNavArea *endArea, CostFunctor &costFunc) { if (startArea == NULL) return -1.0f; @@ -978,24 +1016,29 @@ float NavAreaTravelDistance(CNavArea *startArea, CNavArea *endArea, CostFunctor if (startArea == endArea) return 0.0f; + // compute path between areas using given cost heuristic if (NavAreaBuildPath(startArea, endArea, NULL, costFunc) == false) return -1.0f; - float distance = 0.0f; + // compute distance along path + float_precision distance = 0.0f; for (CNavArea *area = endArea; area->GetParent(); area = area->GetParent()) { distance += (*area->GetCenter() - *area->GetParent()->GetCenter()).Length(); } + return distance; } -// OVERLOAD +// Compute distance from area to position. Return -1 if can't reach position. + template float NavAreaTravelDistance(const Vector *startPos, CNavArea *startArea, const Vector *goalPos, CostFunctor &costFunc) { if (startArea == NULL || startPos == NULL || goalPos == NULL) return -1.0f; + // compute path between areas using given cost heuristic CNavArea *goalArea = NULL; if (NavAreaBuildPath(startArea, TheNavAreaGrid.GetNearestNavArea(goalPos), goalPos, costFunc, &goalArea) == false) return -1.0f; @@ -1003,9 +1046,11 @@ float NavAreaTravelDistance(const Vector *startPos, CNavArea *startArea, const V if (goalArea == NULL) return -1.0f; + // compute distance along path if (goalArea->GetParent() == NULL) + { return (*goalPos - *startPos).Length(); - + } else { CNavArea *area = goalArea->GetParent(); @@ -1015,10 +1060,20 @@ float NavAreaTravelDistance(const Vector *startPos, CNavArea *startArea, const V { distance += (*area->GetCenter() - *area->GetParent()->GetCenter()).Length(); } + return distance; } } +// Do a breadth-first search, invoking functor on each area. +// If functor returns 'true', continue searching from this area. +// If functor returns 'false', the area's adjacent areas are not explored (dead end). +// If 'maxRange' is 0 or less, no range check is done (all areas will be examined). +// NOTE: Returns all areas that overlap range, even partially +// TODO: Use ladder connections + +// helper function + /* <2e7572> ../game_shared/bot/nav_area.h:990 */ inline void AddAreaToOpenList(CNavArea *area, CNavArea *parent, const Vector *startPos, float maxRange) { @@ -1033,20 +1088,26 @@ inline void AddAreaToOpenList(CNavArea *area, CNavArea *parent, const Vector *st if (maxRange > 0.0f) { + // make sure this area overlaps range Vector closePos; area->GetClosestPointOnArea(startPos, &closePos); if ((closePos - *startPos).Make2D().IsLengthLessThan(maxRange)) { + // compute approximate distance along path to limit travel range, too float distAlong = parent->GetCostSoFar(); distAlong += (*area->GetCenter() - *parent->GetCenter()).Length(); area->SetCostSoFar(distAlong); + // allow for some fudge due to large size areas if (distAlong <= 1.5f * maxRange) area->AddToOpenList(); } } else + { + // infinite range area->AddToOpenList(); + } } } @@ -1123,6 +1184,8 @@ void SearchSurroundingAreas(CNavArea *startArea, const Vector *startPos, Functor } } +// Apply the functor to all navigation areas + /* <4c4137> ../game_shared/bot/nav_area.h:1109 */ template void ForAllAreas(Functor &func) @@ -1135,6 +1198,24 @@ void ForAllAreas(Functor &func) } } +// Fuctor that returns lowest cost for farthest away areas +// For use with FindMinimumCostArea() + +class FarAwayFunctor NOXREF +{ +public: + float operator()(CNavArea *area, CNavArea *fromArea, const CNavLadder *ladder) + { + if (area == fromArea) + return 9999999.9f; + + return 1.0f/(*fromArea->GetCenter() - *area->GetCenter()).Length(); + } +}; + +// Fuctor that returns lowest cost for farthest away areas +// For use with FindMinimumCostArea() + /* <5497fa> ../game_shared/bot/nav_area.h:1143 */ class FarAwayFromPositionFunctor { @@ -1151,14 +1232,18 @@ public: private: const Vector *m_pos; + };/* size: 4, cachelines: 1, members: 1 */ +// Pick a low-cost area of "decent" size + /* <549838> ../game_shared/bot/nav_area.h:1162 */ template CNavArea *FindMinimumCostArea(CNavArea *startArea, CostFunctor &costFunc) { const float minSize = 150.0f; + // collect N low-cost areas of a decent size enum { NUM_CHEAP_AREAS = 32 }; struct { @@ -1172,11 +1257,15 @@ CNavArea *FindMinimumCostArea(CNavArea *startArea, CostFunctor &costFunc) for (iter = TheNavAreaList.begin(); iter != TheNavAreaList.end(); ++iter) { CNavArea *area = *iter; + + // skip the small areas const Extent *extent = area->GetExtent(); if (extent->hi.x - extent->lo.x < minSize || extent->hi.y - extent->lo.y < minSize) continue; + // compute cost of this area float cost = costFunc(area, startArea, NULL); + if (cheapAreaSetCount < NUM_CHEAP_AREAS) { cheapAreaSet[cheapAreaSetCount].area = area; @@ -1184,6 +1273,7 @@ CNavArea *FindMinimumCostArea(CNavArea *startArea, CostFunctor &costFunc) } else { + // replace most expensive cost if this is cheaper int expensive = 0; for (int i = 1; i < NUM_CHEAP_AREAS; i++) if (cheapAreaSet[i].cost > cheapAreaSet[expensive].cost) @@ -1198,12 +1288,14 @@ CNavArea *FindMinimumCostArea(CNavArea *startArea, CostFunctor &costFunc) } if (cheapAreaSetCount) { - return cheapAreaSet[RANDOM_LONG(0, cheapAreaSetCount-1)].area; + // pick one of the areas at random + return cheapAreaSet[RANDOM_LONG(0, cheapAreaSetCount - 1)].area; } else { + // degenerate case - no decent sized areas - pick a random area int numAreas = TheNavAreaList.size(); - int which = RANDOM_LONG(0, numAreas-1); + int which = RANDOM_LONG(0, numAreas - 1); NavAreaList::iterator iter; for (iter = TheNavAreaList.begin(); iter != TheNavAreaList.end(); ++iter) @@ -1219,7 +1311,7 @@ CNavArea *FindMinimumCostArea(CNavArea *startArea, CostFunctor &costFunc) typedef const Vector *(FIND_SPOT_CBASE)(CBaseEntity *, const Vector *, CNavArea *, float, int, bool); typedef void (CNavArea::*SAVE_FD)(int fd, unsigned int version); -typedef void (CNavArea::*SAVE_FILE)(FILE *fp); +typedef void (CNavArea::*SAVE_FILE)(FILE *fp) const; typedef bool (CNavArea::*OVERLAP_VECTOR)(const Vector *pos) const; typedef bool (CNavArea::*OVERLAP_CNAV)(const CNavArea *area) const; @@ -1256,43 +1348,43 @@ extern float editTimestamp; extern unsigned int BlockedID[ MAX_BLOCKED_AREAS ]; extern int BlockedIDCount; -NOBODY bool IsHidingSpotInCover(const Vector *spot); -NOBODY void ClassifySniperSpot(HidingSpot *spot); -NOBODY void DestroyHidingSpots(void); -NOBODY void EditNavAreas(NavEditCmdType cmd); +bool IsHidingSpotInCover(const Vector *spot); +void ClassifySniperSpot(HidingSpot *spot); +void DestroyHidingSpots(void); +void EditNavAreas(NavEditCmdType cmd); bool GetGroundHeight(const Vector *pos, float *height, Vector *normal = NULL); bool GetSimpleGroundHeight(const Vector *pos, float *height, Vector *normal = NULL); -NOBODY inline bool IsAreaVisible(const Vector *pos, const CNavArea *area); -NOBODY CNavArea *GetMarkedArea(void); +CNavArea *GetMarkedArea(void); void EditNavAreasReset(void); -NOBODY void DrawHidingSpots(const CNavArea *area); -NOBODY void IncreaseDangerNearby(int teamID, float amount, CNavArea *startArea, const Vector *pos, float maxRadius); -NOBODY void DrawDanger(void); -bool IsSpotOccupied(CBaseEntity *me, const Vector *pos); -NOBODY const Vector *FindNearbyHidingSpot(CBaseEntity *me, const Vector *pos, CNavArea *startArea, float maxRange = 1000.0f, bool isSniper = false, bool useNearest = false); -NOBODY const Vector *FindNearbyRetreatSpot(CBaseEntity *me, const Vector *start, CNavArea *startArea, float maxRange = 1000.0f, int avoidTeam = 0, bool useCrouchAreas = true); -NOBODY bool IsCrossingLineOfFire(const Vector &start, const Vector &finish, CBaseEntity *ignore = NULL, int ignoreTeam = 0); -NOBODY const Vector *FindRandomHidingSpot(CBaseEntity *me, Place place, bool isSniper = false); -NOBODY HidingSpot *GetHidingSpotByID(unsigned int id); +void DrawHidingSpots(const CNavArea *area); +void IncreaseDangerNearby(int teamID, float amount, CNavArea *startArea, const Vector *pos, float maxRadius); +void DrawDanger(void); +bool IsSpotOccupied(CBaseEntity *me, const Vector *pos); // if a player is at the given spot, return true +const Vector *FindNearbyHidingSpot(CBaseEntity *me, const Vector *pos, CNavArea *startArea, float maxRange = 1000.0f, bool isSniper = false, bool useNearest = false); +const Vector *FindNearbyRetreatSpot(CBaseEntity *me, const Vector *start, CNavArea *startArea, float maxRange = 1000.0f, int avoidTeam = 0, bool useCrouchAreas = true); + +// return true if moving from "start" to "finish" will cross a player's line of fire +bool IsCrossingLineOfFire(const Vector &start, const Vector &finish, CBaseEntity *ignore = NULL, int ignoreTeam = 0); +const Vector *FindRandomHidingSpot(CBaseEntity *me, Place place, bool isSniper = false); +HidingSpot *GetHidingSpotByID(unsigned int id); void ApproachAreaAnalysisPrep(void); void CleanupApproachAreaAnalysisPrep(void); void DestroyLadders(void); -NOBODY void DestroyNavigationMap(void); -NOBODY void StripNavigationAreas(void); -inline CNavArea *FindFirstAreaInDirection(const Vector *start, NavDirType dir, float range, float beneathLimit, CBaseEntity *traceIgnore, Vector *closePos); -NOBODY inline bool testJumpDown(const Vector *fromPos, const Vector *toPos); -NOBODY inline CNavArea *findJumpDownArea(const Vector *fromPos, NavDirType dir); -NOBODY void ConnectGeneratedAreas(void); -NOBODY void MergeGeneratedAreas(void); -NOBODY inline bool IsAreaRoughlySquare(const CNavArea *area); -NOBODY void SplitX(CNavArea *area); -NOBODY void SplitY(CNavArea *area); -NOBODY void SquareUpAreas(void); -NOBODY bool TestArea(CNavNode *node, int width, int height); -NOBODY int BuildArea(CNavNode *node, int width, int height); -NOBODY void BuildLadders(void); -NOBODY void MarkJumpAreas(void); -NOBODY void GenerateNavigationAreaMesh(void); +void DestroyNavigationMap(void); +void StripNavigationAreas(void); +CNavArea *FindFirstAreaInDirection(const Vector *start, NavDirType dir, float range, float beneathLimit, CBaseEntity *traceIgnore, Vector *closePos); +bool testJumpDown(const Vector *fromPos, const Vector *toPos); +void ConnectGeneratedAreas(void); +void MergeGeneratedAreas(void); +bool IsAreaRoughlySquare(const CNavArea *area); +void SplitX(CNavArea *area); +void SplitY(CNavArea *area); +void SquareUpAreas(void); +bool TestArea(CNavNode *node, int width, int height); +int BuildArea(CNavNode *node, int width, int height); +void BuildLadders(void); +void MarkJumpAreas(void); +void GenerateNavigationAreaMesh(void); //refs extern float (*pGetZ__Vector)(const Vector *pos); diff --git a/regamedll/game_shared/bot/nav_file.cpp b/regamedll/game_shared/bot/nav_file.cpp index 195b9af8..3b30de1f 100644 --- a/regamedll/game_shared/bot/nav_file.cpp +++ b/regamedll/game_shared/bot/nav_file.cpp @@ -142,7 +142,6 @@ void PlaceDirectory::Load(SteamFile *file) char *GetBspFilename(const char *navFilename) { static char bspFilename[256]; - Q_sprintf(bspFilename, "maps\\%s.bsp", STRING(gpGlobals->mapname)); int len = Q_strlen(bspFilename); @@ -174,7 +173,7 @@ void CNavArea::Save(FILE *fp) const } /* <4f09b8> ../game_shared/bot/nav_file.cpp:212 */ -NOBODY void CNavArea::Save(int fd, unsigned int version) +void CNavArea::Save(int fd, unsigned int version) { // save ID Q_write(fd, &m_id, sizeof(unsigned int)); @@ -235,8 +234,11 @@ NOBODY void CNavArea::Save(int fd, unsigned int version) // Save the approach areas for this area // save number of approach areas Q_write(fd, &m_approachCount, sizeof(unsigned char)); + if (cv_bot_debug.value > 0.0f) + { CONSOLE_ECHO(" m_approachCount = %d\n", m_approachCount); + } // save approach area info unsigned char type; @@ -333,7 +335,7 @@ NOBODY void CNavArea::Save(int fd, unsigned int version) } /* <4ee669> ../game_shared/bot/nav_file.cpp:379 */ -NOBODY void CNavArea::Load(SteamFile *file, unsigned int version) +void CNavArea::Load(SteamFile *file, unsigned int version) { // load ID file->Read(&m_id, sizeof(unsigned int)); @@ -395,7 +397,7 @@ NOBODY void CNavArea::Load(SteamFile *file, unsigned int version) else { // load HidingSpot objects for this area - for (int h=0; h ../game_shared/bot/nav_file.cpp:562 */ -NOBODY NavErrorType CNavArea::PostLoad(void) +NavErrorType CNavArea::PostLoad(void) { NavErrorType error = NAV_OK; @@ -611,9 +613,10 @@ NOBODY NavErrorType CNavArea::PostLoad(void) return error; } +// Changes all '/' characters into '\' characters, in place. /* <4edbe0> ../game_shared/bot/nav_file.cpp:680 */ -void COM_FixSlashes(char *pname) +inline void COM_FixSlashes(char *pname) { #ifdef _WIN32 while (*pname) @@ -632,8 +635,10 @@ void COM_FixSlashes(char *pname) #endif // _WIN32 } +// Store AI navigation data to a file + /* <4f3e47> ../game_shared/bot/nav_file.cpp:702 */ -NOBODY bool SaveNavigationMap(const char *filename) +bool SaveNavigationMap(const char *filename) { if (filename == NULL) return false; @@ -723,8 +728,11 @@ NOBODY bool SaveNavigationMap(const char *filename) return true; } +// Load place map +// This is legacy code - Places are stored directly in the nav file now + /* <4f169d> ../game_shared/bot/nav_file.cpp:811 */ -NOBODY void LoadLocationFile(const char *filename) +void LoadLocationFile(const char *filename) { char locFilename[256]; Q_strcpy(locFilename, filename); @@ -783,8 +791,10 @@ NOBODY void LoadLocationFile(const char *filename) } } +// Performs a lightweight sanity-check of the specified map's nav mesh + /* <4f05c5> ../game_shared/bot/nav_file.cpp:876 */ -NOBODY void SanityCheckNavigationMap(const char *mapName) +void SanityCheckNavigationMap(const char *mapName) { if (!mapName) { @@ -849,19 +859,13 @@ NOBODY void SanityCheckNavigationMap(const char *mapName) return; } } + CONSOLE_ECHO("navigation file %s passes the sanity check.\n", navFilename); } -void (*pLoadNavigationMap)(void); - /* <4f19c7> ../game_shared/bot/nav_file.cpp:947 */ -NOBODY NavErrorType __declspec(naked) LoadNavigationMap(void) +NavErrorType LoadNavigationMap(void) { - __asm - { - jmp pLoadNavigationMap - } -/* // since the navigation map is destroyed on map change, // if it exists it has already been loaded for this map if (!TheNavAreaList.empty()) @@ -992,5 +996,4 @@ NOBODY NavErrorType __declspec(naked) LoadNavigationMap(void) BuildLadders(); return NAV_OK; -*/ } diff --git a/regamedll/game_shared/bot/nav_file.h b/regamedll/game_shared/bot/nav_file.h index 0facee2d..3bc04741 100644 --- a/regamedll/game_shared/bot/nav_file.h +++ b/regamedll/game_shared/bot/nav_file.h @@ -60,21 +60,12 @@ private: std::vector m_directory; }; -#ifdef HOOK_GAMEDLL - -#define placeDirectory (*pplaceDirectory) - -#endif // HOOK_GAMEDLL - extern PlaceDirectory placeDirectory; -NOBODY char *GetBspFilename(const char *navFilename); -NOBODY void COM_FixSlashes(char *pname); -NOBODY bool SaveNavigationMap(const char *filename); -NOBODY void LoadLocationFile(const char *filename); -NOBODY void SanityCheckNavigationMap(const char *mapName); -NOBODY NavErrorType LoadNavigationMap(void); - -extern void (*pLoadNavigationMap)(void); +char *GetBspFilename(const char *navFilename); +bool SaveNavigationMap(const char *filename); +void LoadLocationFile(const char *filename); +void SanityCheckNavigationMap(const char *mapName); // Performs a lightweight sanity-check of the specified map's nav mesh +NavErrorType LoadNavigationMap(void); #endif // NAV_FILE_H diff --git a/regamedll/game_shared/bot/nav_node.cpp b/regamedll/game_shared/bot/nav_node.cpp index a0a75221..358bdef3 100644 --- a/regamedll/game_shared/bot/nav_node.cpp +++ b/regamedll/game_shared/bot/nav_node.cpp @@ -5,70 +5,97 @@ */ #ifndef HOOK_GAMEDLL -//NavDirType Opposite[ NUM_DIRECTIONS ] = { SOUTH, WEST, NORTH, EAST }; +NavDirType Opposite[ NUM_DIRECTIONS ] = { SOUTH, WEST, NORTH, EAST }; CNavNode *CNavNode::m_list = NULL; unsigned int CNavNode::m_listLength = 0; -//Extent NodeMapExtent; - #else // HOOK_GAMEDLL -//NavDirType Opposite[ NUM_DIRECTIONS ]; +NavDirType Opposite[ NUM_DIRECTIONS ]; CNavNode *IMPL_CLASS(CNavNode, m_list); unsigned int IMPL_CLASS(CNavNode, m_listLength); -//Extent NodeMapExtent; - #endif // HOOK_GAMEDLL +//NOXREF Extent NodeMapExtent; + /* <4f79dc> ../game_shared/bot/nav_node.cpp:23 */ -CNavNode::CNavNode(const Vector *pos, const Vector *normal, class CNavNode *parent) +CNavNode::CNavNode(const Vector *pos, const Vector *normal, CNavNode *parent) { -// { -// unsigned int nextID; // 28 -// { -// int i; // 31 -// } -// } + m_pos = *pos; + m_normal = *normal; + + static unsigned int nextID = 1; + m_id = nextID++; + + for (int i = 0; i < NUM_DIRECTIONS; ++i) + m_to[i] = NULL; + + m_visited = 0; + m_parent = parent; + + m_next = IMPL(m_list); + IMPL(m_list) = this; + IMPL(m_listLength)++; + + m_isCovered = FALSE; + m_area = NULL; + + m_attributeFlags = 0; } +// Create a connection FROM this node TO the given node, in the given direction + /* <4f7a31> ../game_shared/bot/nav_node.cpp:54 */ void CNavNode::ConnectTo(CNavNode *node, NavDirType dir) { + m_to[ dir ] = node; } +// Return node at given position +// TODO: Need a hash table to make this lookup fast + /* <4f7a75> ../game_shared/bot/nav_node.cpp:64 */ const CNavNode *CNavNode::GetNode(const Vector *pos) { -// { -// float const tolerance; // 66 -// { -// const class CNavNode *node; // 68 -// { -// float dx; // 70 -// float dy; // 71 -// float dz; // 72 -// } -// } -// } + const float tolerance = 0.45f * GenerationStepSize; + + for (const CNavNode *node = IMPL(m_list); node != NULL; node = node->m_next) + { + float dx = ABS(node->m_pos.x - pos->x); + float dy = ABS(node->m_pos.y - pos->y); + float dz = ABS(node->m_pos.z - pos->z); + + if (dx < tolerance && dy < tolerance && dz < tolerance) + return node; + } + + return NULL; } +// Return true if this node is bidirectionally linked to +// another node in the given direction + /* <4f7af2> ../game_shared/bot/nav_node.cpp:86 */ BOOL CNavNode::IsBiLinked(NavDirType dir) const { + if (m_to[ dir ] && m_to[ dir ]->m_to[ Opposite[dir] ] == this) + return true; + + return false; } +// Return true if this node is the NW corner of a quad of nodes +// that are all bidirectionally linked + /* <4f7b1c> ../game_shared/bot/nav_node.cpp:100 */ BOOL CNavNode::IsClosedCell(void) const { -// IsBiLinked(const class CNavNode *const this, -// enum NavDirType dir); // 102 -// IsBiLinked(const class CNavNode *const this, -// enum NavDirType dir); // 103 -// IsBiLinked(const class CNavNode *const this, -// enum NavDirType dir); // 104 -// IsBiLinked(const class CNavNode *const this, -// enum NavDirType dir); // 105 + if (IsBiLinked( SOUTH ) && IsBiLinked( EAST ) && m_to[ EAST ]->IsBiLinked( SOUTH ) && m_to[ SOUTH ]->IsBiLinked( EAST ) + && m_to[ EAST ]->m_to[ SOUTH ] == m_to[ SOUTH ]->m_to[ EAST ]) + return true; + + return false; } diff --git a/regamedll/game_shared/bot/nav_node.h b/regamedll/game_shared/bot/nav_node.h index b2416326..c89329e6 100644 --- a/regamedll/game_shared/bot/nav_node.h +++ b/regamedll/game_shared/bot/nav_node.h @@ -34,14 +34,11 @@ #ifdef HOOK_GAMEDLL -//#define Opposite (*pOpposite) -//#define m_list (*pm_list) -//#define NodeMapExtent (*pNodeMapExtent) +#define Opposite (*pOpposite) #endif // HOOK_GAMEDLL -//extern NavDirType Opposite[ NUM_DIRECTIONS ]; -//extern Extent NodeMapExtent; +extern NavDirType Opposite[ NUM_DIRECTIONS ]; class CNavNode { diff --git a/regamedll/game_shared/bot/nav_path.cpp b/regamedll/game_shared/bot/nav_path.cpp index 3743473e..f1a37acd 100644 --- a/regamedll/game_shared/bot/nav_path.cpp +++ b/regamedll/game_shared/bot/nav_path.cpp @@ -1,152 +1,276 @@ #include "precompiled.h" +// Determine actual path positions + /* <505025> ../game_shared/bot/nav_path.cpp:24 */ -NOBODY bool CNavPath::ComputePathPositions(void) +bool CNavPath::ComputePathPositions(void) { -// { -// int i; // 34 -// { -// const class PathSegment *from; // 36 -// class PathSegment *to; // 37 -// { -// const NavLadderList *list; // 118 -// const_iterator iter; // 119 -// { -// class CNavLadder *ladder; // 122 -// AddDirectionVector(Vector *v, -// enum NavDirType dir, -// float amount); // 128 -// } -// end(const class list> *const this); // 120 -// operator++(_List_const_iterator *const this); // 120 -// } -// { -// const NavLadderList *list; // 91 -// const_iterator iter; // 92 -// end(const class list> *const this); // 93 -// { -// class CNavLadder *ladder; // 95 -// AddDirectionVector(Vector *v, -// enum NavDirType dir, -// float amount); // 104 -// } -// operator++(_List_const_iterator *const this); // 93 -// } -// { -// float const stepInDist; // 47 -// AddDirectionVector(Vector *v, -// enum NavDirType dir, -// float amount); // 48 -// { -// class Vector2D dir; // 59 -// float const pushDist; // 63 -// DirectionToVector2D(NavDirType dir, -// class Vector2D *v); // 60 -// { -// int j; // 71 -// } -// } -// } -// } -// } + if (m_segmentCount == 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_segmentCount; ++i) + { + const PathSegment *from = &m_path[i - 1]; + PathSegment *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; + 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_segmentCount < MAX_PATH_SEGMENTS - 1) + { + // copy nodes down + for (int j = m_segmentCount; j > i; --j) + m_path[j] = m_path[j - 1]; + + // path is one node longer + ++m_segmentCount; + + // 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, 2.0f * HalfHumanWidth); + 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), 2.0f * HalfHumanWidth); + break; + } + } + if (iter == list->end()) + { + //PrintIfWatched( "ERROR: Can't find ladder in path\n" ); + return false; + } + } + } + + return true; } +// Return true if position is at the end of the path + /* <50525f> ../game_shared/bot/nav_path.cpp:148 */ -NOBODY bool CNavPath::IsAtEnd(const Vector &pos) const +bool CNavPath::IsAtEnd(const Vector &pos) const { -// { -// float const epsilon; // 153 -// operator-(const Vector *const this, -// const Vector &v); // 154 -// IsLengthLessThan(const Vector *const this, -// float length); // 154 -// } + if (!IsValid()) + return false; + + const float epsilon = 20.0f; + return (pos - GetEndpoint()).IsLengthLessThan(epsilon); } +// Return length of path from start to finish + /* <5052f6> ../game_shared/bot/nav_path.cpp:161 */ -NOBODY float CNavPath::GetLength(void) const +float CNavPath::GetLength(void) const { -// { -// float length; // 163 -// { -// int i; // 164 -// operator-(const Vector *const this, -// const Vector &v); // 166 -// Length(const Vector *const this); // 166 -// } -// } + float length = 0.0f; + for (int i = 1; i < GetSegmentCount(); ++i) + { + length += (m_path[i].pos - m_path[i - 1].pos).Length(); + } + + return length; } +// Return point a given distance along the path - if distance is out of path bounds, point is clamped to start/end +// TODO: Be careful of returning "positions" along one-way drops, ladders, etc. + /* <50537f> ../game_shared/bot/nav_path.cpp:177 */ -NOBODY bool CNavPath::GetPointAlongPath(float distAlong, Vector *pointOnPath) const +NOXREF bool CNavPath::GetPointAlongPath(float distAlong, Vector *pointOnPath) const { -// { -// float lengthSoFar; // 188 -// float segmentLength; // 189 -// Vector dir; // 190 -// { -// int i; // 191 -// operator-(const Vector *const this, -// const Vector &v); // 193 -// Length(const Vector *const this); // 194 -// { -// float delta; // 199 -// float t; // 200 -// operator*(float fl, -// const Vector &v); // 202 -// operator+(const Vector *const this, -// const Vector &v); // 202 -// } -// } -// } + if (!IsValid() || pointOnPath == NULL) + return false; + + if (distAlong <= 0.0f) + { + *pointOnPath = m_path[0].pos; + return true; + } + + float lengthSoFar = 0.0f; + float segmentLength; + Vector dir; + for (int i = 1; i < GetSegmentCount(); ++i) + { + dir = m_path[i].pos - m_path[i - 1].pos; + segmentLength = dir.Length(); + + if (segmentLength + lengthSoFar >= distAlong) + { + // desired point is on this segment of the path + float delta = distAlong - lengthSoFar; + float t = delta / segmentLength; + + *pointOnPath = m_path[i].pos + t * dir; + + return true; + } + + lengthSoFar += segmentLength; + } + + *pointOnPath = m_path[ GetSegmentCount() - 1 ].pos; + return true; } +// Return the node index closest to the given distance along the path without going over - returns (-1) if error + /* <5054da> ../game_shared/bot/nav_path.cpp:218 */ -NOBODY int CNavPath::GetSegmentIndexAlongPath(float distAlong) const +int CNavPath::GetSegmentIndexAlongPath(float distAlong) const { -// { -// float lengthSoFar; // 228 -// Vector dir; // 229 -// { -// int i; // 230 -// operator-(const Vector *const this, -// const Vector &v); // 232 -// Length(const Vector *const this); // 232 -// } -// } + if (!IsValid()) + return -1; + + if (distAlong <= 0.0f) + { + return 0; + } + + float lengthSoFar = 0.0f; + Vector dir; + for (int i = 1; i < GetSegmentCount(); ++i) + { + lengthSoFar += (m_path[i].pos - m_path[i - 1].pos).Length(); + + if (lengthSoFar > distAlong) + { + return i - 1; + } + } + + return GetSegmentCount() - 1; } +// 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 + /* <50557e> ../game_shared/bot/nav_path.cpp:250 */ -NOBODY bool CNavPath::FindClosestPointOnPath(const Vector *worldPos, int startIndex, int endIndex, Vector *close) const +NOXREF bool CNavPath::FindClosestPointOnPath(const Vector *worldPos, int startIndex, int endIndex, Vector *close) const { -// { -// Vector along; // 255 -// Vector toWorldPos; // 255 -// Vector pos; // 256 -// const Vector *from; // 257 -// const Vector *to; // 257 -// float length; // 258 -// float closeLength; // 259 -// float closeDistSq; // 260 -// float distSq; // 261 -// { -// int i; // 263 -// NormalizeInPlace(Vector *const this); // 272 -// operator-(const Vector *const this, -// const Vector &v); // 275 -// DotProduct(Vector &a, -// const Vector &b); // 278 -// operator-(const Vector *const this, -// const Vector &v); // 288 -// LengthSquared(const Vector *const this); // 288 -// operator-(const Vector *const this, -// const Vector &v); // 269 -// operator*(float fl, -// const Vector &v); // 286 -// operator+(const Vector *const this, -// const Vector &v); // 286 -// } -// } + if (!IsValid() || close == NULL) + return false; + + Vector along, toWorldPos; + Vector pos; + const Vector *from, *to; + float length; + float closeLength; + float closeDistSq = 9999999999.9; + 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; } // Build trivial path when start and goal are in the same nav area @@ -183,456 +307,827 @@ bool CNavPath::BuildTrivialPath(const Vector *start, const Vector *goal) return true; } +// Draw the path for debugging + /* <505853> ../game_shared/bot/nav_path.cpp:340 */ -NOBODY void CNavPath::Draw(void) +void CNavPath::Draw(void) { -// { -// int i; // 345 -// operator+(const Vector *const this, -// const Vector &v); // 347 -// operator+(const Vector *const this, -// const Vector &v); // 347 -// } + if (!IsValid()) + return; + + for (int i = 1; i < m_segmentCount; ++i) + { + UTIL_DrawBeamPoints(m_path[i - 1].pos + Vector(0, 0, HalfHumanHeight), m_path[i].pos + Vector(0, 0, HalfHumanHeight), 2, 255, 75, 0); + } } +// Check line of sight from 'anchor' node on path to subsequent nodes until +// we find a node that can't been seen from 'anchor' + /* <505931> ../game_shared/bot/nav_path.cpp:357 */ -NOBODY int CNavPath::FindNextOccludedNode(int anchor) +int CNavPath::FindNextOccludedNode(int anchor_) { -// { -// int lastVisible; // 359 -// { -// int i; // 360 -// { -// Vector anchorPlusHalf; // 372 -// Vector iPlusHalf; // 373 -// Vector anchorPlusFull; // 380 -// Vector iPlusFull; // 381 -// IsWalkableTraceLineClear(Vector &from, -// Vector &to, -// unsigned int flags); // 366 -// operator+(const Vector *const this, -// const Vector &v); // 372 -// IsWalkableTraceLineClear(Vector &from, -// Vector &to, -// unsigned int flags); // 374 -// operator+(const Vector *const this, -// const Vector &v); // 373 -// operator+(const Vector *const this, -// const Vector &v); // 380 -// IsWalkableTraceLineClear(Vector &from, -// Vector &to, -// unsigned int flags); // 382 -// operator+(const Vector *const this, -// const Vector &v); // 381 -// } -// } -// } + int lastVisible = anchor_; + for (int i = anchor_ + 1; i < m_segmentCount; ++i) + { + // don't remove ladder nodes + if (m_path[i].ladder) + return i; + + if (!IsWalkableTraceLineClear(m_path[ anchor_ ].pos, m_path[ i ].pos)) + { + // cant see this node from anchor node + return i; + } + + Vector anchorPlusHalf = m_path[ anchor_ ].pos + Vector(0, 0, HalfHumanHeight); + Vector iPlusHalf = m_path[ i ].pos + Vector(0, 0, HalfHumanHeight); + if (!IsWalkableTraceLineClear(anchorPlusHalf, iPlusHalf)) + { + // cant see this node from anchor node + return i; + } + + Vector anchorPlusFull = m_path[ anchor_ ].pos + Vector(0, 0, HumanHeight); + Vector iPlusFull = m_path[ i ].pos + Vector(0, 0, HumanHeight); + if (!IsWalkableTraceLineClear(anchorPlusFull, iPlusFull)) + { + // cant see this node from anchor node + return i; + } + } + + return m_segmentCount; } +// Smooth out path, removing redundant nodes + /* <505c26> ../game_shared/bot/nav_path.cpp:396 */ -NOBODY void CNavPath::Optimize(void) +void CNavPath::Optimize(void) { + // DONT USE THIS: Optimizing the path results in cutting thru obstacles +#if 0 + if (m_segmentCount < 3) + return; + + int anchor_ = 0; + while (anchor_ < m_segmentCount) + { + int occluded = FindNextOccludedNode(anchor_); + int nextAnchor = occluded - 1; + + if (nextAnchor > anchor_) + { + // remove redundant nodes between anchor and nextAnchor + int removeCount = nextAnchor - anchor_ - 1; + if (removeCount > 0) + { + for (int i = nextAnchor; i < m_segmentCount; ++i) + { + m_path[i - removeCount] = m_path[i]; + } + m_segmentCount -= removeCount; + } + } + + ++anchor_; + } +#endif } /* <505c6d> ../game_shared/bot/nav_path.cpp:436 */ -NOBODY CNavPathFollower::CNavPathFollower(void) +CNavPathFollower::CNavPathFollower(void) { -// CStuckMonitor(CStuckMonitor *const this); // 436 + m_improv = NULL; + m_path = NULL; + + m_segmentIndex = 0; + m_isLadderStarted = false; + + m_isDebug = false; } /* <505cce> ../game_shared/bot/nav_path.cpp:447 */ -NOBODY void CNavPathFollower::Reset(void) +void CNavPathFollower::Reset(void) { -// Reset(CStuckMonitor *const this); // 452 + m_segmentIndex = 1; + m_isLadderStarted = false; + + m_stuckMonitor.Reset(); } +// Move improv along path + /* <507c31> ../game_shared/bot/nav_path.cpp:459 */ -NOBODY void CNavPathFollower::Update(float deltaT, bool avoidObstacles) +void CNavPathFollower::Update(float deltaT, bool avoidObstacles) { -// { -// const class PathSegment *node; // 464 -// float const closeRange; // 507 -// float const aheadRange; // 523 -// bool isApproachingJumpArea; // 529 -// float const giveUpTime; // 596 -// operator[](CNavPath *const this, -// int i); // 464 -// Invalidate(CNavPath *const this); // 600 -// { -// const Vector *approachPos; // 476 -// const Vector *departPos; // 477 -// operator[](CNavPath *const this, -// int i); // 480 -// operator[](CNavPath *const this, -// int i); // 483 -// } -// operator-(const Vector *const this, -// const Vector &v); // 508 -// IsLengthLessThan(const Vector *const this, -// float length); // 508 -// FindPathPoint(CNavPathFollower *const this, -// float aheadRange, -// Vector *point, -// int *prevIndex); // 524 -// { -// float const crouchRange; // 547 -// bool didCrouch; // 548 -// { -// int i; // 549 -// { -// const class CNavArea *to; // 551 -// Vector close; // 560 -// operator-(const Vector *const this, -// const Vector &v); // 563 -// IsLengthGreaterThan(const class Vector2D *const this, -// float length); // 563 -// operator[](CNavPath *const this, -// int i); // 551 -// } -// } -// } -// GetDuration(const class CStuckMonitor *const this); // 597 -// GetEndpoint(const class CNavPath *const this); // 599 -// { -// float const closeRange; // 608 -// class Vector2D to; // 609 -// IsLengthLessThan(const class Vector2D *const this, -// float length); // 610 -// { -// const class PathSegment *nextNode; // 614 -// operator[](CNavPath *const this, -// int i); // 614 -// GetEndpoint(const class CNavPath *const this); // 620 -// Invalidate(CNavPath *const this); // 621 -// Invalidate(CNavPath *const this); // 629 -// } -// } -// operator+(const Vector *const this, -// const Vector &v); // 587 -// Vector(Vector *const this, -// const Vector &v); // 587 -// operator+(const Vector *const this, -// const Vector &v); // 588 -// Vector(Vector *const this, -// const Vector &v); // 588 -// Invalidate(CNavPath *const this); // 515 -// } + if (m_path == NULL || m_path->IsValid() == false) + return; + + const CNavPath::PathSegment *node = (*m_path)[m_segmentIndex]; + + if (node == NULL) + { + m_improv->OnMoveToFailure(m_path->GetEndpoint(), IImprovEvent::FAIL_INVALID_PATH); + m_path->Invalidate(); + return; + } + + // handle ladders + if (node->ladder) + { + const Vector *approachPos = NULL; + const Vector *departPos = NULL; + + if (m_segmentIndex) + approachPos = &(*m_path)[m_segmentIndex - 1]->pos; + + if (m_segmentIndex < m_path->GetSegmentCount() - 1) + departPos = &(*m_path)[m_segmentIndex + 1]->pos; + + if (!m_isLadderStarted) + { + // set up ladder movement + m_improv->StartLadder(node->ladder, node->how, approachPos, departPos); + m_isLadderStarted = true; + } + + // move improv along ladder + if (m_improv->TraverseLadder(node->ladder, node->how, approachPos, departPos, deltaT)) + { + // completed ladder + ++m_segmentIndex; + } + + return; + } + + // reset ladder init flag + m_isLadderStarted = false; + + // Check if we reached the end of the path + const float closeRange = 20.0f; + if ((m_improv->GetFeet() - node->pos).IsLengthLessThan(closeRange)) + { + ++m_segmentIndex; + + if (m_segmentIndex >= m_path->GetSegmentCount()) + { + m_improv->OnMoveToSuccess(m_path->GetEndpoint()); + m_path->Invalidate(); + return; + } + } + + m_goal = node->pos; + + const float aheadRange = 300.0f; + m_segmentIndex = FindPathPoint(aheadRange, &m_goal, &m_behindIndex); + if (m_segmentIndex >= m_path->GetSegmentCount()) + m_segmentIndex = m_path->GetSegmentCount() - 1; + + bool isApproachingJumpArea = false; + + // Crouching + if (!m_improv->IsUsingLadder()) + { + // because hostage crouching is not really supported by the engine, + // if we are standing in a crouch area, we must crouch to avoid collisions + if (m_improv->GetLastKnownArea() && (m_improv->GetLastKnownArea()->GetAttributes() & NAV_CROUCH) && !(m_improv->GetLastKnownArea()->GetAttributes() & NAV_JUMP)) + { + m_improv->Crouch(); + } + + // 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 = m_segmentIndex; i < m_path->GetSegmentCount(); ++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 + if (to->GetAttributes() & NAV_JUMP) + { + isApproachingJumpArea = true; + break; + } + + Vector close; + to->GetClosestPointOnArea(&m_improv->GetCentroid(), &close); + + if ((close - m_improv->GetFeet()).Make2D().IsLengthGreaterThan(crouchRange)) + break; + + if (to->GetAttributes() & NAV_CROUCH) + { + m_improv->Crouch(); + didCrouch = true; + break; + } + } + + if (!didCrouch && !m_improv->IsJumping()) + { + // no crouch areas coming up + m_improv->StandUp(); + } + } // end crouching logic + + if (m_isDebug) + { + m_path->Draw(); + UTIL_DrawBeamPoints(m_improv->GetCentroid(), m_goal + Vector(0, 0, StepHeight), 1, 255, 0, 255); + UTIL_DrawBeamPoints(m_goal + Vector(0, 0, StepHeight), m_improv->GetCentroid(), 1, 255, 0, 255); + } + + // check if improv becomes stuck + m_stuckMonitor.Update(m_improv); + + // if improv has been stuck for too long, give up + const float giveUpTime = 2.0f; + if (m_stuckMonitor.GetDuration() > giveUpTime) + { + m_improv->OnMoveToFailure(m_path->GetEndpoint(), IImprovEvent::FAIL_STUCK); + m_path->Invalidate(); + return; + } + + // if our goal is high above us, we must have fallen + if (m_goal.z - m_improv->GetFeet().z > JumpCrouchHeight) + { + const float closeRange = 75.0f; + Vector2D to(m_improv->GetFeet().x - m_goal.x, m_improv->GetFeet().y - m_goal.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 + const CNavPath::PathSegment *nextNode = (*m_path)[m_behindIndex + 1]; + if (m_behindIndex >= 0 && nextNode) + { + if (nextNode->pos.z - m_improv->GetFeet().z > JumpCrouchHeight) + { + // the next node is too high, too - we really did fall of the path + m_improv->OnMoveToFailure(m_path->GetEndpoint(), IImprovEvent::FAIL_FELL_OFF); + m_path->Invalidate(); + return; + } + } + else + { + // fell trying to get to the last node in the path + m_improv->OnMoveToFailure(m_path->GetEndpoint(), IImprovEvent::FAIL_FELL_OFF); + m_path->Invalidate(); + return; + } + } + } + + // avoid small obstacles + if (avoidObstacles && !isApproachingJumpArea && !m_improv->IsJumping() && m_segmentIndex < m_path->GetSegmentCount() - 1) + { + FeelerReflexAdjustment(&m_goal); + + // currently, this is only used for hostages, and their collision physics stinks + // do more feeler checks to avoid short obstacles + /* + const float inc = 0.25f; + for (float t = 0.5f; t < 1.0f; t += inc) + { + FeelerReflexAdjustment(&m_goal, t * StepHeight); + } + */ + } + + // move improv along path + m_improv->TrackPath(m_goal, deltaT); } +// 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 + /* <505d18> ../game_shared/bot/nav_path.cpp:662 */ -NOBODY int CNavPathFollower::FindOurPositionOnPath(Vector *close, bool local) const +int CNavPathFollower::FindOurPositionOnPath(Vector *close, bool local) const { -// { -// Vector along; // 667 -// Vector toFeet; // 667 -// Vector feet; // 668 -// Vector eyes; // 669 -// Vector pos; // 670 -// const Vector *from; // 671 -// const Vector *to; // 671 -// float length; // 672 -// float closeLength; // 673 -// float closeDistSq; // 674 -// int closeIndex; // 675 -// float distSq; // 676 -// int start; // 678 -// int end; // 678 -// Vector(Vector *const this, -// const Vector &v); // 668 -// Vector(Vector *const this, -// const Vector &v); // 669 -// { -// int i; // 696 -// NormalizeInPlace(Vector *const this); // 705 -// operator-(const Vector *const this, -// const Vector &v); // 708 -// DotProduct(Vector &a, -// const Vector &b); // 711 -// operator-(const Vector *const this, -// const Vector &v); // 721 -// LengthSquared(const Vector *const this); // 721 -// { -// Vector probe; // 727 -// operator+(const Vector *const this, -// const Vector &v); // 727 -// IsWalkableTraceLineClear(Vector &from, -// Vector &to, -// unsigned int flags); // 728 -// } -// operator[](CNavPath *const this, -// int i); // 698 -// operator[](CNavPath *const this, -// int i); // 699 -// operator-(const Vector *const this, -// const Vector &v); // 702 -// operator*(float fl, -// const Vector &v); // 719 -// operator+(const Vector *const this, -// const Vector &v); // 719 -// } -// } + Vector along, toFeet; + Vector feet = m_improv->GetFeet(); + Vector eyes = m_improv->GetEyes(); + Vector pos; + const Vector *from, *to; + float_precision length; + float closeLength; + float closeDistSq = 1.0e10; + int closeIndex = -1; + float_precision distSq; + int start, end; + + if (!m_path->IsValid()) + return -1; + + if (local) + { + start = m_segmentIndex - 3; + if (start < 1) + start = 1; + + end = m_segmentIndex + 3; + if (end > m_path->GetSegmentCount()) + end = m_path->GetSegmentCount(); + } + else + { + start = 1; + end = m_path->GetSegmentCount(); + } + + 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_DOORS | WALK_THRU_BREAKABLES)) + continue; + + // don't use points we cant reach + //if (!IsStraightLinePathWalkable(&pos)) + // continue; + + closeDistSq = distSq; + if (close) + *close = pos; + closeIndex = i - 1; + } + } + + return closeIndex; } +// Compute a point a fixed distance ahead along our path +// Returns path index just after point + /* <506248> ../game_shared/bot/nav_path.cpp:750 */ -NOBODY int CNavPathFollower::FindPathPoint(float aheadRange, Vector *point, int *prevIndex) +int CNavPathFollower::FindPathPoint(float aheadRange, Vector *point, int *prevIndex) { -// { -// int afterIndex; // 753 -// Vector close; // 756 -// int startIndex; // 757 -// Vector initDir; // 838 -// Vector feet; // 841 -// Vector eyes; // 842 -// float rangeSoFar; // 843 -// bool visible; // 846 -// Vector prevDir; // 848 -// bool isCorner; // 851 -// int i; // 852 -// { -// int index; // 774 -// float const closeEpsilon; // 782 -// operator[](CNavPath *const this, -// int i); // 778 -// operator-(const Vector *const this, -// const Vector &v); // 783 -// IsLengthLessThan(const class Vector2D *const this, -// float length); // 783 -// operator[](CNavPath *const this, -// int i); // 793 -// } -// { -// Vector pos; // 802 -// float const closeEpsilon; // 805 -// operator-(const Vector *const this, -// const Vector &v); // 806 -// operator[](CNavPath *const this, -// int i); // 802 -// IsLengthLessThan(const class Vector2D *const this, -// float length); // 806 -// } -// operator[](CNavPath *const this, -// int i); // 818 -// operator[](CNavPath *const this, -// int i); // 820 -// operator[](CNavPath *const this, -// int i); // 818 -// operator[](CNavPath *const this, -// int i); // 831 -// operator[](CNavPath *const this, -// int i); // 833 -// operator[](CNavPath *const this, -// int i); // 831 -// operator[](CNavPath *const this, -// int i); // 838 -// operator[](CNavPath *const this, -// int i); // 838 -// operator-(const Vector *const this, -// const Vector &v); // 838 -// NormalizeInPlace(Vector *const this); // 839 -// Vector(Vector *const this, -// const Vector &v); // 841 -// { -// Vector pos; // 855 -// Vector to; // 856 -// Vector dir; // 857 -// Vector probe; // 876 -// Vector along; // 897 -// operator[](CNavPath *const this, -// int i); // 855 -// Vector(Vector *const this, -// const Vector &v); // 855 -// operator[](CNavPath *const this, -// int i); // 856 -// operator-(const Vector *const this, -// const Vector &v); // 856 -// Normalize(const Vector *const this); // 857 -// DotProduct(Vector &a, -// const Vector &b); // 860 -// DotProduct(Vector &a, -// const Vector &b); // 867 -// operator+(const Vector *const this, -// const Vector &v); // 876 -// IsWalkableTraceLineClear(Vector &from, -// Vector &to, -// unsigned int flags); // 877 -// operator[](CNavPath *const this, -// int i); // 886 -// operator[](CNavPath *const this, -// int i); // 886 -// operator[](CNavPath *const this, -// int i); // 897 -// operator-(const Vector *const this, -// const Vector &v); // 897 -// Length2D(const Vector *const this); // 898 -// operator-(const Vector *const this, -// const Vector &v); // 897 -// } -// Vector(Vector *const this, -// const Vector &v); // 842 -// operator[](CNavPath *const this, -// int i); // 916 -// { -// const Vector *afterPoint; // 921 -// const Vector *beforePoint; // 922 -// Vector to; // 924 -// float length; // 925 -// float t; // 927 -// operator[](CNavPath *const this, -// int i); // 921 -// operator[](CNavPath *const this, -// int i); // 922 -// operator-(const Vector *const this, -// const Vector &v); // 924 -// Length2D(const Vector *const this); // 925 -// operator*(float fl, -// const Vector &v); // 934 -// { -// float const sightStepSize; // 939 -// float dt; // 940 -// Vector probe; // 942 -// operator+(const Vector *const this, -// const Vector &v); // 942 -// IsWalkableTraceLineClear(Vector &from, -// Vector &to, -// unsigned int flags); // 943 -// operator+(const Vector *const this, -// const Vector &v); // 946 -// operator*(float fl, -// const Vector &v); // 946 -// } -// operator+(const Vector *const this, -// const Vector &v); // 934 -// } -// { -// float const epsilon; // 957 -// class Vector2D toPoint; // 958 -// class Vector2D centroid; // 959 -// DotProduct(const class Vector2D &a, -// const class Vector2D &b); // 964 -// IsLengthLessThan(const class Vector2D *const this, -// float length); // 964 -// { -// int i; // 966 -// operator[](CNavPath *const this, -// int i); // 969 -// operator[](CNavPath *const this, -// int i); // 973 -// operator[](CNavPath *const this, -// int i); // 971 -// IsLengthGreaterThan(const class Vector2D *const this, -// float length); // 971 -// } -// } -// } + // 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_segmentIndex; + } + + // if we are crouching, just follow the path exactly + if (m_improv->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_path->GetSegmentCount()) + index = m_path->GetSegmentCount() - 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; + while ((*point - close).Make2D().IsLengthLessThan(closeEpsilon)) + { + ++index; + + if (index >= m_path->GetSegmentCount()) + { + index = m_path->GetSegmentCount() - 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_path->GetSegmentCount() - 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 or jump area, must stop (dont use ladder behind us) + if (startIndex > m_segmentIndex && startIndex < m_path->GetSegmentCount() && ((*m_path)[startIndex]->ladder || ((*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_path->GetSegmentCount()) + startIndex = m_path->GetSegmentCount() - 1; + + // if we hit a ladder or jump area, must stop + if (startIndex < m_path->GetSegmentCount() && ((*m_path)[startIndex]->ladder || ((*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 = m_improv->GetFeet(); + Vector eyes = m_improv->GetEyes(); + 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_path->GetSegmentCount(); ++i) + { + Vector pos = (*m_path)[i]->pos; + Vector to = pos - (*m_path)[i - 1]->pos; + Vector dir = to.Normalize(); + + // 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_path->GetSegmentCount() && ((*m_path)[i]->ladder || (*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_path->GetSegmentCount()) + afterIndex = i; + else + afterIndex = m_path->GetSegmentCount() - 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; + Vector2D centroid(m_improv->GetCentroid().x, m_improv->GetCentroid().y); + + toPoint.x = point->x - centroid.x; + toPoint.y = point->y - centroid.y; + + if (DotProduct(toPoint, initDir.Make2D()) < 0.0f || toPoint.IsLengthLessThan(epsilon)) + { + int i; + for (i = startIndex; i < m_path->GetSegmentCount(); ++i) + { + toPoint.x = (*m_path)[i]->pos.x - centroid.x; + toPoint.y = (*m_path)[i]->pos.y - centroid.y; + if ((*m_path)[i]->ladder || ((*m_path)[i]->area->GetAttributes() & NAV_JUMP) || toPoint.IsLengthGreaterThan(epsilon)) + { + *point = (*m_path)[i]->pos; + startIndex = i; + break; + } + } + + if (i == m_path->GetSegmentCount()) + { + *point = m_path->GetEndpoint(); + startIndex = m_path->GetSegmentCount() - 1; + } + } + } + + // m_pathIndex should always be the next point on the path, even if we're not moving directly towards it + if (startIndex < m_path->GetSegmentCount()) + return startIndex; + + return m_path->GetSegmentCount() - 1; } +// Do reflex avoidance movements if our "feelers" are touched +// TODO: Parameterize feeler spacing + /* <507004> ../game_shared/bot/nav_path.cpp:1000 */ -NOBODY void CNavPathFollower::FeelerReflexAdjustment(Vector *goalPosition, float height) +void CNavPathFollower::FeelerReflexAdjustment(Vector *goalPosition, float height) { -// { -// Vector dir; // 1006 -// Vector lat; // 1010 -// float const feelerOffset; // 1012 -// float const feelerLengthRun; // 1013 -// float const feelerLengthWalk; // 1014 -// float const feelerHeight; // 1016 -// float feelerLength; // 1018 -// float ground; // 1025 -// Vector normal; // 1026 -// Vector feet; // 1037 -// Vector from; // 1040 -// Vector to; // 1041 -// bool leftClear; // 1043 -// bool rightClear; // 1057 -// float const avoidRange; // 1070 -// NormalizeInPlace(Vector *const this); // 1008 -// CrossProduct(Vector &a, -// const Vector &b); // 1031 -// IsWalkableTraceLineClear(Vector &from, -// Vector &to, -// unsigned int flags); // 1043 -// CrossProduct(Vector &a, -// const Vector &b); // 1034 -// Vector(Vector *const this, -// const Vector &v); // 1037 -// operator*(float fl, -// const Vector &v); // 1040 -// operator+(const Vector *const this, -// const Vector &v); // 1040 -// operator*(float fl, -// const Vector &v); // 1041 -// operator+(const Vector *const this, -// const Vector &v); // 1041 -// Vector(Vector *const this, -// const Vector &v); // 1049 -// Vector(Vector *const this, -// const Vector &v); // 1049 -// operator-(const Vector *const this, -// const Vector &v); // 1054 -// IsWalkableTraceLineClear(Vector &from, -// Vector &to, -// unsigned int flags); // 1057 -// operator+(const Vector *const this, -// const Vector &v); // 1055 -// Vector(Vector *const this, -// const Vector &v); // 1063 -// Vector(Vector *const this, -// const Vector &v); // 1063 -// operator*(float fl, -// const Vector &v); // 1077 -// operator+(const Vector *const this, -// const Vector &v); // 1077 -// operator*(float fl, -// const Vector &v); // 1086 -// operator-(const Vector *const this, -// const Vector &v); // 1086 -// Vector(Vector *const this, -// const Vector &v); // 1065 -// Vector(Vector *const this, -// const Vector &v); // 1065 -// Vector(Vector *const this, -// const Vector &v); // 1051 -// Vector(Vector *const this, -// const Vector &v); // 1051 -// } + // if we are in a "precise" area, do not do feeler adjustments + if (m_improv->GetLastKnownArea() && (m_improv->GetLastKnownArea()->GetAttributes() & NAV_PRECISE)) + return; + + Vector dir(BotCOS(m_improv->GetMoveAngle()), BotSIN(m_improv->GetMoveAngle()), 0.0f); + dir.z = 0.0f; + +#ifndef PLAY_GAMEDLL + dir.NormalizeInPlace(); +#else + // TODO: fix test demo + float_precision flLen = dir.Length(); + + if (flLen > 0) + dir = dir * (float)(1 / flLen); + else + dir = Vector(0, 0, 0); +#endif // PLAY_GAMEDLL + + Vector lat(-dir.y, dir.x, 0.0f); + + const float feelerOffset = (m_improv->IsCrouching()) ? 20.0f : 25.0f; // 15, 20 + const float feelerLengthRun = 50.0f; // 100 - too long for tight hallways (cs_747) + const float feelerLengthWalk = 30.0f; + + // if obstacle is lower than StepHeight, we'll walk right over it + const float feelerHeight = (height > 0.0f) ? height : StepHeight + 0.1f; + float feelerLength = (m_improv->IsRunning()) ? feelerLengthRun : feelerLengthWalk; + + feelerLength = (m_improv->IsCrouching()) ? 20.0f : feelerLength; + + // Feelers must follow floor slope + float ground; + Vector normal; + if (m_improv->GetSimpleGroundHeightWithFloor(&m_improv->GetEyes(), &ground, &normal) == false) + return; + + // get forward vector along floor + dir = CrossProduct(lat, normal); + + // correct the sideways vector + lat = CrossProduct(dir, normal); + + Vector feet = m_improv->GetFeet(); + feet.z += feelerHeight; + + Vector from = feet + feelerOffset * lat; + Vector to = from + feelerLength * dir; + + bool leftClear = IsWalkableTraceLineClear(from, to, WALK_THRU_DOORS | WALK_THRU_BREAKABLES); + + // draw debug beams + if (m_isDebug) + { + 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_DOORS | WALK_THRU_BREAKABLES); + + // draw debug beams + if (m_isDebug) + { + if (rightClear) + UTIL_DrawBeamPoints(from, to, 1, 0, 255, 0); + else + UTIL_DrawBeamPoints(from, to, 1, 255, 0, 0); + } + + const float_precision avoidRange = (m_improv->IsCrouching()) ? 150.0f : 300.0f; + + if (!rightClear) + { + if (leftClear) + { + // right hit, left clear - veer left + *goalPosition = *goalPosition + avoidRange * lat; + //*goalPosition = m_improv->GetFeet() + avoidRange * lat; + //m_improv->StrafeLeft(); + } + } + else if (!leftClear) + { + // right clear, left hit - veer right + *goalPosition = *goalPosition - avoidRange * lat; + //*goalPosition = m_improv->GetFeet() - avoidRange * lat; + //m_improv->StrafeRight(); + } } +// Reset the stuck-checker + /* <507a31> ../game_shared/bot/nav_path.cpp:1098 */ -NOBODY CStuckMonitor::CStuckMonitor(void) +CStuckMonitor::CStuckMonitor(void) { -// IntervalTimer(IntervalTimer *const this); // 1098 + m_isStuck = false; + m_avgVelIndex = 0; + m_avgVelCount = 0; } +// Reset the stuck-checker + /* <507a73> ../game_shared/bot/nav_path.cpp:1108 */ -NOBODY void CStuckMonitor::Reset(void) +void CStuckMonitor::Reset(void) { + m_isStuck = false; + m_avgVelIndex = 0; + m_avgVelCount = 0; } +// Test if the improv has become stuck + /* <507a96> ../game_shared/bot/nav_path.cpp:1119 */ -NOBODY void CStuckMonitor::Update(CImprov *improv) +void CStuckMonitor::Update(CImprov *improv) { -// { -// float const unstuckRange; // 1124 -// operator-(const Vector *const this, -// const Vector &v); // 1125 -// IsLengthGreaterThan(const Vector *const this, -// float length); // 1125 -// Reset(CStuckMonitor *const this); // 1128 -// } -// { -// Vector vel; // 1137 -// float moveDist; // 1148 -// float deltaT; // 1150 -// operator-(const Vector *const this, -// const Vector &v); // 1137 -// Length(const Vector *const this); // 1148 -// { -// float avgVel; // 1170 -// float stuckVel; // 1177 -// { -// int t; // 1171 -// } -// Start(IntervalTimer *const this); // 1182 -// } -// } + if (m_isStuck) + { + // improv is stuck - see if it has moved far enough to be considered unstuck + const float unstuckRange = 75.0f; + if ((improv->GetCentroid() - m_stuckSpot).IsLengthGreaterThan(unstuckRange)) + { + // no longer stuck + Reset(); + //PrintIfWatched( "UN-STUCK\n" ); + } + } + else + { + // check if improv has become stuck + + // compute average velocity over a short period (for stuck check) + Vector vel = improv->GetCentroid() - m_lastCentroid; + + // if we are jumping, ignore Z + //if (improv->IsJumping()) + // vel.z = 0.0f; + + // ignore Z unless we are on a ladder (which is only Z) + if (!improv->IsUsingLadder()) + vel.z = 0.0f; + + // cannot be Length2D, or will break ladder movement (they are only Z) + float moveDist = vel.Length(); + + float deltaT = gpGlobals->time - m_lastTime; + if (deltaT <= 0.0f) + return; + + m_lastTime = gpGlobals->time; + + // compute current velocity + 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 actors will get "stuck" when going down ladders + float stuckVel = (improv->IsUsingLadder()) ? 10.0f : 20.0f; + + if (avgVel < stuckVel) + { + // note when and where we initially become stuck + m_stuckTimer.Start(); + m_stuckSpot = improv->GetCentroid(); + m_isStuck = true; + } + } + } + + // always need to track this + m_lastCentroid = improv->GetCentroid(); } diff --git a/regamedll/game_shared/bot/nav_path.h b/regamedll/game_shared/bot/nav_path.h index 6b539694..49bb27bf 100644 --- a/regamedll/game_shared/bot/nav_path.h +++ b/regamedll/game_shared/bot/nav_path.h @@ -66,9 +66,9 @@ public: return m_path[ m_segmentCount - 1 ].pos; } - bool IsAtEnd(const Vector &pos) const; // return true if position is at the end of the path - float GetLength(void) const; // return length of path from start to finish - bool GetPointAlongPath(float distAlong, Vector *pointOnPath) const; // return point a given distance along the path - if distance is out of path bounds, point is clamped to start/end + bool IsAtEnd(const Vector &pos) const; // return true if position is at the end of the path + float GetLength(void) const; // return length of path from start to finish + NOXREF bool GetPointAlongPath(float distAlong, Vector *pointOnPath) const; // return point a given distance along the path - if distance is out of path bounds, point is clamped to start/end /// return the node index closest to the given distance along the path without going over - returns (-1) if error int GetSegmentIndexAlongPath(float distAlong) const; @@ -86,7 +86,7 @@ public: void Draw(void); /// compute closest point on path to given point - bool FindClosestPointOnPath(const Vector *worldPos, int startIndex, int endIndex, Vector *close) const; + NOXREF bool FindClosestPointOnPath(const Vector *worldPos, int startIndex, int endIndex, Vector *close) const; void Optimize(void); @@ -176,16 +176,16 @@ private: PathSegment m_path[ MAX_PATH_SEGMENTS ]; int m_segmentCount; - // determine actual path positions - bool ComputePathPositions(void); #ifdef HOOK_GAMEDLL public: #endif // HOOK_GAMEDLL + // determine actual path positions + bool ComputePathPositions(void); // utility function for when start and goal are in the same area bool BuildTrivialPath(const Vector *start, const Vector *goal); // used by Optimize() - int FindNextOccludedNode(int anchor); + int FindNextOccludedNode(int anchor_); };/* size: 6148, cachelines: 97, members: 2 */ @@ -263,7 +263,11 @@ public: // adjust goal position if "feelers" are touched void FeelerReflexAdjustment(Vector *goalPosition, float height = -1.0f); +#ifdef HOOK_GAMEDLL +public: +#else private: +#endif // HOOK_GAMEDLL int FindOurPositionOnPath(Vector *close, bool local) const; // return the closest point to our current position on current path int FindPathPoint(float aheadRange, Vector *point, int *prevIndex); // compute a point a fixed distance ahead along our path. diff --git a/regamedll/game_shared/bot/simple_state_machine.h b/regamedll/game_shared/bot/simple_state_machine.h index 1e764f2e..e085a59c 100644 --- a/regamedll/game_shared/bot/simple_state_machine.h +++ b/regamedll/game_shared/bot/simple_state_machine.h @@ -33,8 +33,9 @@ #endif // Encapsulation of a finite-state-machine state -template + /* <5c4388> ../game_shared/bot/simple_state_machine.h:21 */ +template class SimpleState { public: @@ -57,14 +58,16 @@ public: { return m_parent; } + private: // the parent state that contains this state SimpleState *m_parent; }; // Encapsulation of a finite state machine -template + /* <5c4bab> ../game_shared/bot/simple_state_machine.h:68 */ +template class SimpleStateMachine { public: diff --git a/regamedll/hookers/6153_hooker.cpp b/regamedll/hookers/6153_hooker.cpp index 3f7becd4..b3db85fe 100644 --- a/regamedll/hookers/6153_hooker.cpp +++ b/regamedll/hookers/6153_hooker.cpp @@ -248,7 +248,7 @@ FunctionHook g_FunctionHooks[] = { 0x01D59250, "_ZN8CAirtank4SaveER5CSave", mfunc_ptr_cast(&CAirtank::Save_) }, { 0x01D59280, "_ZN8CAirtank7RestoreER8CRestore", mfunc_ptr_cast(&CAirtank::Restore_) }, { 0x01D593C0, "_ZN8CAirtank6KilledEP9entvars_si", mfunc_ptr_cast(&CAirtank::Killed_) }, - { 0x01D59240, "_ZN8CAirtank10BloodColorEv", mfunc_ptr_cast(&CAirtank::BloodColor_) }, + //{ 0x01D59240, "_ZN8CAirtank10BloodColorEv", mfunc_ptr_cast(&CAirtank::BloodColor_) }, // DEFAULT //non-virtual func { 0x01D59410, "_ZN8CAirtank9TankThinkEv", mfunc_ptr_cast(&CAirtank::TankThink) }, { 0x01D59430, "_ZN8CAirtank9TankTouchEP11CBaseEntity", mfunc_ptr_cast(&CAirtank::TankTouch) }, @@ -840,7 +840,7 @@ FunctionHook g_FunctionHooks[] = { 0x01DA08D0, "_ZN8CWShield5SpawnEv", mfunc_ptr_cast(&CWShield::Spawn_) }, { 0x01DA0920, "_ZN8CWShield5TouchEP11CBaseEntity", mfunc_ptr_cast(&CWShield::Touch_) }, //non-virtual func - //{ 0x0, "_ZN8CWShield23SetCantBePickedUpByUserEP11CBaseEntityf", mfunc_ptr_cast(&CWShield::SetCantBePickedUpByUser) } // NOXREF INLINEBODY + //{ 0x0, "_ZN8CWShield23SetCantBePickedUpByUserEP11CBaseEntityf", mfunc_ptr_cast(&CWShield::SetCantBePickedUpByUser) } // NOXREF //CSprayCan //virtual func @@ -3104,7 +3104,7 @@ FunctionHook g_FunctionHooks[] = { 0x01D03120, "_ZN3CC411GetItemInfoEP8ItemInfo", mfunc_ptr_cast(&CC4::GetItemInfo_) }, { 0x01D03190, "_ZN3CC46DeployEv", mfunc_ptr_cast(&CC4::Deploy_) }, { 0x01D03200, "_ZN3CC47HolsterEi", mfunc_ptr_cast(&CC4::Holster_) }, - //{ 0x01D03A80, "_ZN3CC411GetMaxSpeedEv", mfunc_ptr_cast(&CC4::GetMaxSpeed_) }, // DEFAULT + { 0x01D03A80, "_ZN3CC411GetMaxSpeedEv", mfunc_ptr_cast(&CC4::GetMaxSpeed_) }, //{ 0x01D03A70, "_ZN3CC49iItemSlotEv", mfunc_ptr_cast(&CC4::iItemSlot_) }, // DEFAULT { 0x01D03280, "_ZN3CC413PrimaryAttackEv", mfunc_ptr_cast(&CC4::PrimaryAttack_) }, { 0x01D03750, "_ZN3CC410WeaponIdleEv", mfunc_ptr_cast(&CC4::WeaponIdle_) }, @@ -3665,7 +3665,7 @@ FunctionHook g_FunctionHooks[] = { 0x01D34210, "_ZN11CBotManager10StartFrameEv", mfunc_ptr_cast(&CBotManager::StartFrame_) }, { 0x01D34540, "_ZN11CBotManager7OnEventE13GameEventTypeP11CBaseEntityS2_", mfunc_ptr_cast(&CBotManager::OnEvent_) }, //non-virtual func - ////{ 0x0, "", mfunc_ptr_cast(&CBotManager::CBotManager) }, + //{ 0x01D34170, "", mfunc_ptr_cast(&CBotManager::CBotManager) }, { 0x01D34510, "_ZNK11CBotManager17GetNavMapFilenameEv", mfunc_ptr_cast(&CBotManager::GetNavMapFilename) }, { 0x01D34650, "_ZN11CBotManager10AddGrenadeEiP8CGrenade", mfunc_ptr_cast(&CBotManager::AddGrenade) }, { 0x01D346C0, "_ZN11CBotManager13RemoveGrenadeEP8CGrenade", mfunc_ptr_cast(&CBotManager::RemoveGrenade) }, @@ -3674,9 +3674,10 @@ FunctionHook g_FunctionHooks[] = { 0x01D347A0, "_ZN11CBotManager18IsInsideSmokeCloudEPK6Vector", mfunc_ptr_cast(&CBotManager::IsInsideSmokeCloud) }, // FIXME!! { 0x01D34850, "_ZN11CBotManager20IsLineBlockedBySmokeEPK6VectorS2_", mfunc_ptr_cast(&CBotManager::IsLineBlockedBySmoke) }, //non-class func - //{ 0x0, "_Z15NameToGameEventPKc", (size_t)&NameToGameEvent }, + { 0x01D34120, "_Z15NameToGameEventPKc", (size_t)&NameToGameEvent }, //CCSBotManager //virtual func + //{ 0x01D22D60, "", mfunc_ptr_cast(&CCSBotManager::CCSBotManager) }, { 0x01D23770, "_ZN13CCSBotManager16ClientDisconnectEP11CBasePlayer", mfunc_ptr_cast(&CCSBotManager::ClientDisconnect_) }, { 0x01D24880, "_ZN13CCSBotManager13ClientCommandEP11CBasePlayerPKc", mfunc_ptr_cast(&CCSBotManager::ClientCommand_) }, { 0x01D234D0, "_ZN13CCSBotManager14ServerActivateEv", mfunc_ptr_cast(&CCSBotManager::ServerActivate_) }, @@ -3951,7 +3952,7 @@ FunctionHook g_FunctionHooks[] = //{ 0x0, "_ZNK6CCSBot13IsPistolEmptyEv", mfunc_ptr_cast(&CCSBot::IsPistolEmpty) }, //{ 0x0, "_ZNK6CCSBot21GetHostageEscortCountEv", mfunc_ptr_cast(&CCSBot::GetHostageEscortCount) }, //{ 0x0, "_ZN6CCSBot26IncreaseHostageEscortCountEv", mfunc_ptr_cast(&CCSBot::IncreaseHostageEscortCount) }, - //{ 0x0, "_ZNK6CCSBot33GetRangeToFarthestEscortedHostageEv", mfunc_ptr_cast(&CCSBot::GetRangeToFarthestEscortedHostage) }, + { 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 @@ -4191,8 +4192,8 @@ FunctionHook g_FunctionHooks[] = //{ 0x0, "_ZN4CBot8SpawnBotEv", mfunc_ptr_cast(&CBot::SpawnBot) }, //{ 0x0, "_ZN4CBot6UpkeepEv", mfunc_ptr_cast(&CBot::Upkeep) }, //{ 0x0, "_ZN4CBot6UpdateEv", mfunc_ptr_cast(&CBot::Update) }, - //{ 0x0, "_ZN4CBot3RunEv", mfunc_ptr_cast(&CBot::Run) }, - //{ 0x0, "_ZN4CBot4WalkEv", mfunc_ptr_cast(&CBot::Walk) }, + //{ 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_) }, @@ -4790,6 +4791,7 @@ FunctionHook g_FunctionHooks[] = { 0x01D4EA30, "", mfunc_ptr_cast(&Vector::Normalize) }, { 0x01DCB800, "", mfunc_ptr_cast(&Vector::operator==) }, { 0x01D130D0, "", mfunc_ptr_cast(&Vector::IsLengthLessThan) }, + { 0x01D34D90, "", mfunc_ptr_cast(&DotProduct) }, #endif // _WIN32 @@ -4798,12 +4800,12 @@ FunctionHook g_FunctionHooks[] = #ifndef Nav_Region //Nav_File - //{ 0x0, "_Z14GetBspFilenamePKc", (size_t)&GetBspFilename }, - //{ 0x0, "", (size_t)&COM_FixSlashes }, // NOXREF - //{ 0x01D45CF0, "_Z17SaveNavigationMapPKc", (size_t)&SaveNavigationMap }, - //{ 0x01D45F80, "_Z16LoadLocationFilePKc", (size_t)&LoadLocationFile }, - //{ 0x01D46170, "_Z24SanityCheckNavigationMapPKc", (size_t)&SanityCheckNavigationMap }, - //{ 0x01D46310, "_Z17LoadNavigationMapv", (size_t)&LoadNavigationMap }, + //{ 0x01D44E00, "_Z14GetBspFilenamePKc", (size_t)&GetBspFilename }, // NOXREF + //{ 0x0, "", (size_t)&COM_FixSlashes }, // NOXREF + { 0x01D45CF0, "_Z17SaveNavigationMapPKc", (size_t)&SaveNavigationMap }, + { 0x01D45F80, "_Z16LoadLocationFilePKc", (size_t)&LoadLocationFile }, + { 0x01D46170, "_Z24SanityCheckNavigationMapPKc", (size_t)&SanityCheckNavigationMap }, + { 0x01D46310, "_Z17LoadNavigationMapv", (size_t)&LoadNavigationMap }, //IImprovEvent //virtual func //{ 0x0, "_ZN12IImprovEvent15OnMoveToSuccessERK6Vector", mfunc_ptr_cast(&IImprovEvent::OnMoveToSuccess) }, @@ -4864,8 +4866,8 @@ FunctionHook g_FunctionHooks[] = //{ 0x0, "_ZN7CImprov11OnGameEventE13GameEventTypeP11CBaseEntityS2_", mfunc_ptr_cast(&CImprov::OnGameEvent) }, //{ 0x0, "_ZN7CImprov7OnTouchEP11CBaseEntity", mfunc_ptr_cast(&CImprov::OnTouch) }, //CNavNode - //{ 0x0, "", mfunc_ptr_cast(&CNavNode::CNavNode) }, - //{ 0x0, "_ZN8CNavNode7GetNodeEPK6Vector", mfunc_ptr_cast(&CNavNode::GetNode) }, + //{ 0x01D46F60, "_ZN8CNavNodeC2EPK6VectorS2_PS_", mfunc_ptr_cast(&CNavNode::CNavNode) }, + { 0x01D47000, "_ZN8CNavNode7GetNodeEPK6Vector", mfunc_ptr_cast(&CNavNode::GetNode) }, //{ 0x0, "_ZNK8CNavNode16GetConnectedNodeE10NavDirType", mfunc_ptr_cast(&CNavNode::GetConnectedNode) }, //{ 0x0, "_ZNK8CNavNode11GetPositionEv", mfunc_ptr_cast(&CNavNode::GetPosition) }, //{ 0x0, "_ZNK8CNavNode9GetNormalEv", mfunc_ptr_cast(&CNavNode::GetNormal) }, @@ -4873,12 +4875,12 @@ FunctionHook g_FunctionHooks[] = //{ 0x0, "_ZN8CNavNode8GetFirstEv", mfunc_ptr_cast(&CNavNode::GetFirst) }, //{ 0x0, "_ZN8CNavNode13GetListLengthEv", mfunc_ptr_cast(&CNavNode::GetListLength) }, //{ 0x0, "_ZN8CNavNode7GetNextEv", mfunc_ptr_cast(&CNavNode::GetNext) }, - //{ 0x0, "_ZN8CNavNode9ConnectToEPS_10NavDirType", mfunc_ptr_cast(&CNavNode::ConnectTo) }, + { 0x01D46FF0, "_ZN8CNavNode9ConnectToEPS_10NavDirType", mfunc_ptr_cast(&CNavNode::ConnectTo) }, //{ 0x0, "_ZNK8CNavNode9GetParentEv", mfunc_ptr_cast(&CNavNode::GetParent) }, //{ 0x0, "_ZN8CNavNode13MarkAsVisitedE10NavDirType", mfunc_ptr_cast(&CNavNode::MarkAsVisited) }, //{ 0x0, "_ZN8CNavNode10HasVisitedE10NavDirType", mfunc_ptr_cast(&CNavNode::HasVisited) }, - //{ 0x0, "_ZNK8CNavNode10IsBiLinkedE10NavDirType", mfunc_ptr_cast(&CNavNode::IsBiLinked) }, - //{ 0x0, "_ZNK8CNavNode12IsClosedCellEv", mfunc_ptr_cast(&CNavNode::IsClosedCell) }, + //{ 0x01D470E0, "_ZNK8CNavNode10IsBiLinkedE10NavDirType", mfunc_ptr_cast(&CNavNode::IsBiLinked) }, // NOXREF + { 0x01D47110, "_ZNK8CNavNode12IsClosedCellEv", mfunc_ptr_cast(&CNavNode::IsClosedCell) }, //{ 0x0, "_ZN8CNavNode5CoverEv", mfunc_ptr_cast(&CNavNode::Cover) }, //{ 0x0, "_ZNK8CNavNode9IsCoveredEv", mfunc_ptr_cast(&CNavNode::IsCovered) }, //{ 0x0, "_ZN8CNavNode10AssignAreaEP8CNavArea", mfunc_ptr_cast(&CNavNode::AssignArea) }, @@ -4890,54 +4892,61 @@ FunctionHook g_FunctionHooks[] = //{ 0x0, "_ZN8CNavPathixEi", mfunc_ptr_cast(&CNavPath::operator[]) }, //{ 0x0, "_ZNK8CNavPath15GetSegmentCountEv", mfunc_ptr_cast(&CNavPath::GetSegmentCount) }, //{ 0x0, "_ZNK8CNavPath11GetEndpointEv", mfunc_ptr_cast(&CNavPath::GetEndpoint) }, - //{ 0x0, "_ZNK8CNavPath7IsAtEndERK6Vector", mfunc_ptr_cast(&CNavPath::IsAtEnd) }, - //{ 0x0, "_ZNK8CNavPath9GetLengthEv", mfunc_ptr_cast(&CNavPath::GetLength) }, - //{ 0x0, "_ZNK8CNavPath17GetPointAlongPathEfP6Vector", mfunc_ptr_cast(&CNavPath::GetPointAlongPath) }, - //{ 0x0, "_ZNK8CNavPath24GetSegmentIndexAlongPathEf", mfunc_ptr_cast(&CNavPath::GetSegmentIndexAlongPath) }, + { 0x01D47570, "_ZNK8CNavPath7IsAtEndERK6Vector", mfunc_ptr_cast(&CNavPath::IsAtEnd) }, + { 0x01D475D0, "_ZNK8CNavPath9GetLengthEv", mfunc_ptr_cast(&CNavPath::GetLength) }, + //{ 0x01D47620, "_ZNK8CNavPath17GetPointAlongPathEfP6Vector", mfunc_ptr_cast(&CNavPath::GetPointAlongPath) }, // NOXREF + { 0x01D47760, "_ZNK8CNavPath24GetSegmentIndexAlongPathEf", mfunc_ptr_cast(&CNavPath::GetSegmentIndexAlongPath) }, //{ 0x0, "_ZNK8CNavPath7IsValidEv", mfunc_ptr_cast(&CNavPath::IsValid) }, //{ 0x0, "_ZN8CNavPath10InvalidateEv", mfunc_ptr_cast(&CNavPath::Invalidate) }, - //{ 0x0, "_ZN8CNavPath4DrawEv", mfunc_ptr_cast(&CNavPath::Draw) }, - //{ 0x0, "_ZNK8CNavPath22FindClosestPointOnPathEPK6VectoriiPS0_", mfunc_ptr_cast(&CNavPath::FindClosestPointOnPath) }, - //{ 0x0, "_ZN8CNavPath8OptimizeEv", mfunc_ptr_cast(&CNavPath::Optimize) }, - //{ 0x0, "_ZN8CNavPath20ComputePathPositionsEv", mfunc_ptr_cast(&CNavPath::ComputePathPositions) }, + //{ 0x01D47AB0, "_ZN8CNavPath4DrawEv", mfunc_ptr_cast(&CNavPath::Draw) }, // NOXREF + //{ 0x01D477F0, "_ZNK8CNavPath22FindClosestPointOnPathEPK6VectoriiPS0_", mfunc_ptr_cast(&CNavPath::FindClosestPointOnPath) }, // NOXREF + { 0x01D47E20, "_ZN8CNavPath8OptimizeEv", mfunc_ptr_cast(&CNavPath::Optimize) }, // PURE + { 0x01D47170, "_ZN8CNavPath20ComputePathPositionsEv", mfunc_ptr_cast(&CNavPath::ComputePathPositions) }, { 0x01D47A00, "_ZN8CNavPath16BuildTrivialPathEPK6VectorS2_", mfunc_ptr_cast(&CNavPath::BuildTrivialPath) }, - //{ 0x0, "_ZN8CNavPath20FindNextOccludedNodeEi", mfunc_ptr_cast(&CNavPath::FindNextOccludedNode) }, - + //{ 0x01D47B40, "_ZN8CNavPath20FindNextOccludedNodeEi", mfunc_ptr_cast(&CNavPath::FindNextOccludedNode) }, // NOXREF //CStuckMonitor - //{ 0x0, "", mfunc_ptr_cast(&CStuckMonitor::CStuckMonitor) }, - //{ 0x0, "_ZN13CStuckMonitor5ResetEv", mfunc_ptr_cast(&CStuckMonitor::Reset) }, - //{ 0x0, "_ZN13CStuckMonitor6UpdateEP7CImprov", mfunc_ptr_cast(&CStuckMonitor::Update) }, + //{ 0x01D49B70, "", mfunc_ptr_cast(&CStuckMonitor::CStuckMonitor) }, + { 0x01D49B90, "_ZN13CStuckMonitor5ResetEv", mfunc_ptr_cast(&CStuckMonitor::Reset) }, + { 0x01D49BA0, "_ZN13CStuckMonitor6UpdateEP7CImprov", mfunc_ptr_cast(&CStuckMonitor::Update) }, //{ 0x0, "_ZNK13CStuckMonitor7IsStuckEv", mfunc_ptr_cast(&CStuckMonitor::IsStuck) }, //{ 0x0, "_ZNK13CStuckMonitor11GetDurationEv", mfunc_ptr_cast(&CStuckMonitor::GetDuration) }, //CNavPathFollower - //{ 0x0, "", mfunc_ptr_cast(&CNavPathFollower::CNavPathFollower) }, + //{ 0x01D47E30, "", mfunc_ptr_cast(&CNavPathFollower::CNavPathFollower) }, //{ 0x0, "_ZN16CNavPathFollower9SetImprovEP7CImprov", mfunc_ptr_cast(&CNavPathFollower::SetImprov) }, //{ 0x0, "_ZN16CNavPathFollower7SetPathEP8CNavPath", mfunc_ptr_cast(&CNavPathFollower::SetPath) }, - //{ 0x0, "_ZN16CNavPathFollower5ResetEv", mfunc_ptr_cast(&CNavPathFollower::Reset) }, - //{ 0x0, "_ZN16CNavPathFollower6UpdateEfb", mfunc_ptr_cast(&CNavPathFollower::Update) }, + { 0x01D47E60, "_ZN16CNavPathFollower5ResetEv", mfunc_ptr_cast(&CNavPathFollower::Reset) }, + { 0x01D47E80, "_ZN16CNavPathFollower6UpdateEfb", mfunc_ptr_cast(&CNavPathFollower::Update) }, //{ 0x0, "_ZN16CNavPathFollower5DebugEb", mfunc_ptr_cast(&CNavPathFollower::Debug) }, //{ 0x0, "_ZNK16CNavPathFollower7IsStuckEv", mfunc_ptr_cast(&CNavPathFollower::IsStuck) }, //{ 0x0, "_ZN16CNavPathFollower10ResetStuckEv", mfunc_ptr_cast(&CNavPathFollower::ResetStuck) }, //{ 0x0, "_ZNK16CNavPathFollower16GetStuckDurationEv", mfunc_ptr_cast(&CNavPathFollower::GetStuckDuration) }, - //{ 0x0, "_ZN16CNavPathFollower22FeelerReflexAdjustmentEP6Vectorf", mfunc_ptr_cast(&CNavPathFollower::FeelerReflexAdjustment) }, - //{ 0x0, "_ZNK16CNavPathFollower21FindOurPositionOnPathEP6Vectorb", mfunc_ptr_cast(&CNavPathFollower::FindOurPositionOnPath) }, - //{ 0x0, "_ZN16CNavPathFollower13FindPathPointEfP6VectorPi", mfunc_ptr_cast(&CNavPathFollower::FindPathPoint) }, + { 0x01D49460, "_ZN16CNavPathFollower22FeelerReflexAdjustmentEP6Vectorf", mfunc_ptr_cast(&CNavPathFollower::FeelerReflexAdjustment) }, + { 0x01D48450, "_ZNK16CNavPathFollower21FindOurPositionOnPathEP6Vectorb", mfunc_ptr_cast(&CNavPathFollower::FindOurPositionOnPath) }, + { 0x01D487B0, "_ZN16CNavPathFollower13FindPathPointEfP6VectorPi", mfunc_ptr_cast(&CNavPathFollower::FindPathPoint) }, //HidingSpot //{ 0x01D37DB0, "", mfunc_ptr_cast(&HidingSpot::HidingSpot) }, //{ 0x01D37E40, "", mfunc_ptr_cast(&HidingSpot::HidingSpot) }, { 0x01D37EC0, "_ZNK10HidingSpot4SaveEij", mfunc_ptr_cast(&HidingSpot::Save) }, { 0x01D37F00, "_ZN10HidingSpot4LoadEP9SteamFilej", mfunc_ptr_cast(&HidingSpot::Load) }, +//SteamFile + //{ 0x0, "", mfunc_ptr_cast(&SteamFile::SteamFile) }, + //{ 0x0, "", mfunc_ptr_cast(&SteamFile::~SteamFile) }, + //{ 0x0, "_ZNK9SteamFile7IsValidEv", mfunc_ptr_cast(&SteamFile::IsValid) }, + { 0x01D46F00, "_ZN9SteamFile4ReadEPvi", mfunc_ptr_cast(&SteamFile::Read) }, //CNavArea - //{ 0x01D44F80, "_ZN8CNavArea4SaveEij", mfunc_ptr_cast(&CNavArea::Save) }, - //{ 0x0, "_ZNK8CNavArea4SaveEP8_IO_FILE", mfunc_ptr_cast(&CNavArea::Save) }, + //{ 0x01D45A50, "_ZNK14PlaceDirectory12EntryToPlaceEt", mfunc_ptr_cast(&PlaceDirectory::EntryToPlace) }, // NOTE: need hook LoadNavigationMap + { 0x01D44F80, "_ZN8CNavArea4SaveEij", mfunc_ptr_cast(&CNavArea::Save) }, + { 0x01D44E60, "_ZNK8CNavArea4SaveEP8_IO_FILE", mfunc_ptr_cast(&CNavArea::Save) }, + { 0x01D45330, "_ZN8CNavArea4LoadEP9SteamFilej", mfunc_ptr_cast(&CNavArea::Load) }, + { 0x01D45AA0, "_ZN8CNavArea8PostLoadEv", mfunc_ptr_cast(&CNavArea::PostLoad) }, //{ 0x01D38040, "", mfunc_ptr_cast(&CNavArea::CNavArea) }, //{ 0x0, "", mfunc_ptr_cast(&CNavArea::CNavArea) }, //{ 0x0, "", mfunc_ptr_cast(&CNavArea::CNavArea) }, //{ 0x0, "", mfunc_ptr_cast(&CNavArea::CNavArea) }, //{ 0x01D386A0, "", mfunc_ptr_cast(&CNavArea::~CNavArea) }, - //{ 0x01D37FE0, "_ZN8CNavArea10InitializeEv", mfunc_ptr_cast(&CNavArea::Initialize) }, // PRIVATE + { 0x01D37FE0, "_ZN8CNavArea10InitializeEv", mfunc_ptr_cast(&CNavArea::Initialize) }, // PRIVATE //{ 0x01D388A0, "_ZN8CNavArea15OnDestroyNotifyEPS_", mfunc_ptr_cast(&CNavArea::OnDestroyNotify) }, // NOXREF - //{ 0x01D38960, "_ZN8CNavArea9ConnectToEPS_10NavDirType", mfunc_ptr_cast(&CNavArea::ConnectTo) }, + { 0x01D38960, "_ZN8CNavArea9ConnectToEPS_10NavDirType", mfunc_ptr_cast(&CNavArea::ConnectTo) }, //{ 0x01D389D0, "_ZN8CNavArea10DisconnectEPS_", mfunc_ptr_cast(&CNavArea::Disconnect) }, // NOXREF { 0x01D38A40, "_ZN8CNavArea11FinishMergeEPS_", mfunc_ptr_cast(&CNavArea::FinishMerge) }, { 0x01D38B60, "_ZN8CNavArea24MergeAdjacentConnectionsEPS_", mfunc_ptr_cast(&CNavArea::MergeAdjacentConnections) }, @@ -4955,7 +4964,7 @@ FunctionHook g_FunctionHooks[] = //{ 0x01D3C790, "_ZNK8CNavArea14IsOverlappingYEPKS_", mfunc_ptr_cast(&CNavArea::IsOverlappingY) }, // NOXREF { 0x01D3C7C0, "_ZNK8CNavArea8ContainsEPK6Vector", mfunc_ptr_cast(&CNavArea::Contains) }, { 0x01D3C8B0, "_ZNK8CNavArea10IsCoplanarEPKS_", mfunc_ptr_cast(&CNavArea::IsCoplanar) }, - //!@{ 0x01D3CA60, "_ZNK8CNavArea4GetZEPK6Vector", mfunc_ptr_cast(&CNavArea::GetZ) }, // Used refs + { 0x01D3CA60, "_ZNK8CNavArea4GetZEPK6Vector", mfunc_ptr_cast(&CNavArea::GetZ) }, // NOTE: definitely need to hook CNavAreaGrid::GetNavArea!! //{ 0x01D3CB50, "_ZNK8CNavArea4GetZEff", mfunc_ptr_cast(&CNavArea::GetZ) }, // NOXREF { 0x01D3CB80, "_ZNK8CNavArea21GetClosestPointOnAreaEPK6VectorPS0_", mfunc_ptr_cast(&CNavArea::GetClosestPointOnArea) }, //{ 0x01D3CCD0, "_ZNK8CNavArea25GetDistanceSquaredToPointEPK6Vector", mfunc_ptr_cast(&CNavArea::GetDistanceSquaredToPoint) }, // NOXREF @@ -4993,9 +5002,9 @@ 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 - //!@{ 0x01D43860, "_ZNK12CNavAreaGrid17GetNearestNavAreaEPK6Vectorb", mfunc_ptr_cast(&CNavAreaGrid::GetNearestNavArea) }, // Used refs - //{ 0x0, "_ZNK12CNavAreaGrid14GetNavAreaByIDEj", mfunc_ptr_cast(&CNavAreaGrid::GetNavAreaByID) }, + { 0x01D43710, "_ZNK12CNavAreaGrid10GetNavAreaEPK6Vectorf", mfunc_ptr_cast(&CNavAreaGrid::GetNavArea) }, // Used refs + { 0x01D43860, "_ZNK12CNavAreaGrid17GetNearestNavAreaEPK6Vectorb", mfunc_ptr_cast(&CNavAreaGrid::GetNearestNavArea) }, + { 0x01D439C0, "_ZNK12CNavAreaGrid14GetNavAreaByIDEj", mfunc_ptr_cast(&CNavAreaGrid::GetNavAreaByID) }, { 0x01D439F0, "_ZNK12CNavAreaGrid8GetPlaceEPK6Vector", mfunc_ptr_cast(&CNavAreaGrid::GetPlace) }, { 0x01D3E4F0, "_Z18ClassifySniperSpotP10HidingSpot", (size_t)&ClassifySniperSpot }, //{ 0x0, "", (size_t)&buildGoodSizedList }, // NOXREF @@ -5011,8 +5020,9 @@ FunctionHook g_FunctionHooks[] = { 0x01D3F020, "_Z10DrawDangerv", (size_t)&DrawDanger }, { 0x01D3F1C0, "_Z14IsSpotOccupiedP11CBaseEntityPK6Vector", (size_t)&IsSpotOccupied }, { 0x01D3F2A0, "_Z20FindNearbyHidingSpotP11CBaseEntityPK6VectorP8CNavAreafbb", (size_t)&FindNearbyHidingSpot }, + //{ 0x01D3F650, "_ZN25CollectHidingSpotsFunctorclEP8CNavArea", mfunc_ptr_cast(&CollectHidingSpotsFunctor::operator()) }, { 0x01D3FDE0, "_Z21FindNearbyRetreatSpotP11CBaseEntityPK6VectorP8CNavAreafib", mfunc_ptr_cast(&FindNearbyRetreatSpot) }, - //{ 0x0, "_Z20IsCrossingLineOfFireRK6VectorS1_P11CBaseEntityi", (size_t)&IsCrossingLineOfFire }, + { 0x01D3FAD0, "_Z20IsCrossingLineOfFireRK6VectorS1_P11CBaseEntityi", (size_t)&IsCrossingLineOfFire }, { 0x01D3F850, "_Z20FindRandomHidingSpotP11CBaseEntityjb", (size_t)&FindRandomHidingSpot }, { 0x01D37FB0, "_Z17GetHidingSpotByIDj", (size_t)&GetHidingSpotByID }, { 0x01D39F30, "_Z24ApproachAreaAnalysisPrepv", (size_t)&ApproachAreaAnalysisPrep }, @@ -5020,23 +5030,25 @@ FunctionHook g_FunctionHooks[] = //{ 0x01D3A010, "_Z14DestroyLaddersv", (size_t)&DestroyLadders }, // NOXREF { 0x01D3A060, "_Z20DestroyNavigationMapv", (size_t)&DestroyNavigationMap }, { 0x01D3A210, "_Z20StripNavigationAreasv", (size_t)&StripNavigationAreas }, + #ifdef _WIN32 { 0x01D3A870, "", (size_t)&FindFirstAreaInDirection }, - { 0x01D3A9E0, "", (size_t)&testJumpDown }, // NOXREF - { 0x01D3AD20, "", (size_t)&IsAreaRoughlySquare }, // NOXREF + { 0x01D3AD20, "", (size_t)&IsAreaRoughlySquare }, + { 0x01D2B030, "", (size_t)&IsEntityWalkable }, + { 0x01D2B0B0, "", (size_t)&IsWalkableTraceLineClear }, + { 0x01D3A9E0, "", (size_t)&testJumpDown }, #endif // _WIN32 - //{ 0x0, "", (size_t)&findJumpDownArea }, // NOXREF + //{ 0x0, "", (size_t)&findJumpDownArea }, // NOXREF { 0x01D3A330, "_Z21ConnectGeneratedAreasv", (size_t)&ConnectGeneratedAreas }, { 0x01D3AAF0, "_Z19MergeGeneratedAreasv", (size_t)&MergeGeneratedAreas }, - //{ 0x0, "_Z6SplitXP8CNavArea", (size_t)&SplitX }, - //{ 0x0, "_Z6SplitYP8CNavArea", (size_t)&SplitY }, - //{ 0x0, "_Z13SquareUpAreasv", (size_t)&SquareUpAreas }, + { 0x01D3AE00, "_Z6SplitXP8CNavArea", (size_t)&SplitX }, + //{ 0x0, "_Z6SplitYP8CNavArea", (size_t)&SplitY }, // NOXREF + { 0x01D3AEE0, "_Z13SquareUpAreasv", (size_t)&SquareUpAreas }, { 0x01D3B100, "_Z8TestAreaP8CNavNodeii", (size_t)&TestArea }, { 0x01D3B2E0, "_Z9BuildAreaP8CNavNodeii", (size_t)&BuildArea }, { 0x01D3B3F0, "_Z12BuildLaddersv", (size_t)&BuildLadders }, { 0x01D3C1B0, "_Z13MarkJumpAreasv", (size_t)&MarkJumpAreas }, { 0x01D3C280, "_Z26GenerateNavigationAreaMeshv", (size_t)&GenerateNavigationAreaMesh }, - #endif // Nav_Region #ifndef Hostage_Region @@ -5053,25 +5065,25 @@ FunctionHook g_FunctionHooks[] = { 0x01D51270, "_ZN14CHostageImprov11ClearLookAtEv", mfunc_ptr_cast(&CHostageImprov::ClearLookAt_) }, { 0x01D51280, "_ZN14CHostageImprov6FaceToERK6Vector", mfunc_ptr_cast(&CHostageImprov::FaceTo_) }, { 0x01D512B0, "_ZN14CHostageImprov11ClearFaceToEv", mfunc_ptr_cast(&CHostageImprov::ClearFaceTo_) }, - //{ 0x0, "_ZNK14CHostageImprov12IsAtMoveGoalEf", mfunc_ptr_cast(&CHostageImprov::IsAtMoveGoal_) }, + { 0x01D51AC0, "_ZNK14CHostageImprov12IsAtMoveGoalEf", mfunc_ptr_cast(&CHostageImprov::IsAtMoveGoal_) }, //{ 0x0, "_ZNK14CHostageImprov9HasLookAtEv", mfunc_ptr_cast(&CHostageImprov::HasLookAt_) }, // DEFAULT //{ 0x0, "_ZNK14CHostageImprov9HasFaceToEv", mfunc_ptr_cast(&CHostageImprov::HasFaceTo_) }, // DEFAULT - //{ 0x0, "_ZNK14CHostageImprov12IsAtFaceGoalEv", mfunc_ptr_cast(&CHostageImprov::IsAtFaceGoal_) }, - //{ 0x0, "_ZNK14CHostageImprov16IsFriendInTheWayERK6Vector", mfunc_ptr_cast(&CHostageImprov::IsFriendInTheWay_) }, - //{ 0x0, "_ZNK14CHostageImprov16IsFriendInTheWayEP11CBaseEntityRK6Vector", mfunc_ptr_cast(&CHostageImprov::IsFriendInTheWay_) }, + { 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_) }, - //{ 0x0, "_ZN14CHostageImprov4JumpEv", mfunc_ptr_cast(&CHostageImprov::Jump_) }, + { 0x01D52260, "_ZN14CHostageImprov4JumpEv", mfunc_ptr_cast(&CHostageImprov::Jump_) }, { 0x01D56710, "_ZN14CHostageImprov6CrouchEv", mfunc_ptr_cast(&CHostageImprov::Crouch_) }, { 0x01D567A0, "_ZN14CHostageImprov7StandUpEv", mfunc_ptr_cast(&CHostageImprov::StandUp_) }, - //{ 0x0, "_ZN14CHostageImprov9TrackPathERK6Vectorf", mfunc_ptr_cast(&CHostageImprov::TrackPath_) }, + { 0x01D52D80, "_ZN14CHostageImprov9TrackPathERK6Vectorf", mfunc_ptr_cast(&CHostageImprov::TrackPath_) }, { 0x01D530D0, "_ZN14CHostageImprov11StartLadderEPK10CNavLadder15NavTraverseTypePK6VectorS6_", mfunc_ptr_cast(&CHostageImprov::StartLadder_) }, - //{ 0x01D530E0, "_ZN14CHostageImprov14TraverseLadderEPK10CNavLadder15NavTraverseTypePK6VectorS6_f", mfunc_ptr_cast(&CHostageImprov::TraverseLadder_) }, + { 0x01D530E0, "_ZN14CHostageImprov14TraverseLadderEPK10CNavLadder15NavTraverseTypePK6VectorS6_f", mfunc_ptr_cast(&CHostageImprov::TraverseLadder_) }, { 0x01D51150, "_ZN14CHostageImprov30GetSimpleGroundHeightWithFloorEPK6VectorPfPS0_", mfunc_ptr_cast(&CHostageImprov::GetSimpleGroundHeightWithFloor_) }, - //{ 0x0, "_ZN14CHostageImprov3RunEv", mfunc_ptr_cast(&CHostageImprov::Run_) }, - //{ 0x0, "_ZN14CHostageImprov4WalkEv", mfunc_ptr_cast(&CHostageImprov::Walk_) }, + { 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 @@ -5081,27 +5093,30 @@ FunctionHook g_FunctionHooks[] = //{ 0x0, "_ZNK14CHostageImprov9IsRunningEv", mfunc_ptr_cast(&CHostageImprov::IsRunning_) }, // DEFAULT //{ 0x0, "_ZNK14CHostageImprov9IsWalkingEv", mfunc_ptr_cast(&CHostageImprov::IsWalking_) }, // DEFAULT //{ 0x01D56CC0, "_ZNK14CHostageImprov9IsStoppedEv", mfunc_ptr_cast(&CHostageImprov::IsStopped_) }, // DEFAULT - //{ 0x0, "_ZNK14CHostageImprov11IsCrouchingEv", mfunc_ptr_cast(&CHostageImprov::IsCrouching_) }, // DEFAULT - //{ 0x0, "_ZNK14CHostageImprov9IsJumpingEv", mfunc_ptr_cast(&CHostageImprov::IsJumping_) }, // DEFAULT - //{ 0x0, "_ZNK14CHostageImprov13IsUsingLadderEv", mfunc_ptr_cast(&CHostageImprov::IsUsingLadder_) }, // DEFAULT - //{ 0x0, "_ZNK14CHostageImprov10IsOnGroundEv", mfunc_ptr_cast(&CHostageImprov::IsOnGround_) }, - //{ 0x0, "_ZNK14CHostageImprov8IsMovingEv", mfunc_ptr_cast(&CHostageImprov::IsMoving_) }, + //{ 0x01D56CD0, "_ZNK14CHostageImprov11IsCrouchingEv", mfunc_ptr_cast(&CHostageImprov::IsCrouching_) }, // DEFAULT + //{ 0x01D56CE0, "_ZNK14CHostageImprov9IsJumpingEv", mfunc_ptr_cast(&CHostageImprov::IsJumping_) }, // DEFAULT + //{ 0x01D56D20, "_ZNK14CHostageImprov13IsUsingLadderEv", mfunc_ptr_cast(&CHostageImprov::IsUsingLadder_) }, // DEFAULT + { 0x01D52460, "_ZNK14CHostageImprov10IsOnGroundEv", mfunc_ptr_cast(&CHostageImprov::IsOnGround_) }, + { 0x01D52480, "_ZNK14CHostageImprov8IsMovingEv", mfunc_ptr_cast(&CHostageImprov::IsMoving_) }, //{ 0x0, "_ZNK14CHostageImprov6CanRunEv", mfunc_ptr_cast(&CHostageImprov::CanRun_) }, // DEFAULT //{ 0x0, "_ZNK14CHostageImprov9CanCrouchEv", mfunc_ptr_cast(&CHostageImprov::CanCrouch_) }, // DEFAULT //{ 0x0, "_ZNK14CHostageImprov7CanJumpEv", mfunc_ptr_cast(&CHostageImprov::CanJump_) }, // DEFAULT { 0x01D524C0, "_ZNK14CHostageImprov9IsVisibleERK6Vectorb", mfunc_ptr_cast(&CHostageImprov::IsVisible_) }, - //{ 0x0, "_ZNK14CHostageImprov19IsPlayerLookingAtMeEP11CBasePlayerf", mfunc_ptr_cast(&CHostageImprov::IsPlayerLookingAtMe_) }, - //{ 0x0, "_ZNK14CHostageImprov22IsAnyPlayerLookingAtMeEif", mfunc_ptr_cast(&CHostageImprov::IsAnyPlayerLookingAtMe_) }, - //{ 0x0, "_ZNK14CHostageImprov32GetClosestPlayerByTravelDistanceEiPf", mfunc_ptr_cast(&CHostageImprov::GetClosestPlayerByTravelDistance_) }, + { 0x01D52530, "_ZNK14CHostageImprov19IsPlayerLookingAtMeEP11CBasePlayerf", mfunc_ptr_cast(&CHostageImprov::IsPlayerLookingAtMe_) }, + { 0x01D526A0, "_ZNK14CHostageImprov22IsAnyPlayerLookingAtMeEif", mfunc_ptr_cast(&CHostageImprov::IsAnyPlayerLookingAtMe_) }, + { 0x01D527B0, "_ZNK14CHostageImprov32GetClosestPlayerByTravelDistanceEiPf", mfunc_ptr_cast(&CHostageImprov::GetClosestPlayerByTravelDistance_) }, //{ 0x01D56D60, "_ZNK14CHostageImprov16GetLastKnownAreaEv", mfunc_ptr_cast(&CHostageImprov::GetLastKnownArea_) }, // DEFAULT - //{ 0x0, "_ZN14CHostageImprov8OnUpdateEf", mfunc_ptr_cast(&CHostageImprov::OnUpdate_) }, - //{ 0x0, "_ZN14CHostageImprov8OnUpkeepEf", mfunc_ptr_cast(&CHostageImprov::OnUpkeep_) }, + { 0x01D54500, "_ZN14CHostageImprov8OnUpdateEf", mfunc_ptr_cast(&CHostageImprov::OnUpdate_) }, + { 0x01D53FF0, "_ZN14CHostageImprov8OnUpkeepEf", mfunc_ptr_cast(&CHostageImprov::OnUpkeep_) }, { 0x01D52A60, "_ZN14CHostageImprov7OnResetEv", mfunc_ptr_cast(&CHostageImprov::OnReset_) }, { 0x01D54C10, "_ZN14CHostageImprov11OnGameEventE13GameEventTypeP11CBaseEntityS2_", mfunc_ptr_cast(&CHostageImprov::OnGameEvent_) }, { 0x01D55280, "_ZN14CHostageImprov7OnTouchEP11CBaseEntity", mfunc_ptr_cast(&CHostageImprov::OnTouch_) }, //non-virtual func - //{ 0x01D51900, "_ZN14CHostageImprov12FaceOutwardsEv", mfunc_ptr_cast(&CHostageImprov::FaceOutwards) }, - //{ 0x0, "_ZNK14CHostageImprov16IsFriendInTheWayEv", mfunc_ptr_cast(&CHostageImprov::IsFriendInTheWay) }, + { 0x01D51900, "_ZN14CHostageImprov12FaceOutwardsEv", mfunc_ptr_cast(&CHostageImprov::FaceOutwards) }, + { 0x01D51F80, "_ZNK14CHostageImprov16IsFriendInTheWayEv", mfunc_ptr_cast(&CHostageImprov::IsFriendInTheWay) }, + //{ 0x01D52150, "_ZN10CheckAheadclEP11CBaseEntity", mfunc_ptr_cast(&CheckAhead::operator()) }, + //{ 0x0, "_ZN15CheckWayFunctorclEP8CHostage", mfunc_ptr_cast(&CheckWayFunctor::operator()) }, + { 0x01D53E70, "_ZNK17KeepPersonalSpaceclEP11CBaseEntity", mfunc_ptr_cast(&KeepPersonalSpace::operator()) }, //{ 0x01D52EE0, "_ZN14CHostageImprov20SetKnownGoodPositionERK6Vector", mfunc_ptr_cast(&CHostageImprov::SetKnownGoodPosition) }, // NOXREF //{ 0x0, "_ZNK14CHostageImprov20GetKnownGoodPositionEv", mfunc_ptr_cast(&CHostageImprov::GetKnownGoodPosition) }, { 0x01D52F90, "_ZN14CHostageImprov24ResetToKnownGoodPositionEv", mfunc_ptr_cast(&CHostageImprov::ResetToKnownGoodPosition) }, @@ -5130,14 +5145,14 @@ FunctionHook g_FunctionHooks[] = { 0x01D54010, "_ZN14CHostageImprov17IsTerroristNearbyEv", mfunc_ptr_cast(&CHostageImprov::IsTerroristNearby) }, { 0x01D55C20, "_ZN14CHostageImprov8FrightenENS_9ScareTypeE", mfunc_ptr_cast(&CHostageImprov::Frighten) }, { 0x01D55BF0, "_ZNK14CHostageImprov8IsScaredEv", mfunc_ptr_cast(&CHostageImprov::IsScared) }, - //{ 0x0, "_ZNK14CHostageImprov17GetScareIntensityEv", mfunc_ptr_cast(&CHostageImprov::GetScareIntensity) }, - //{ 0x0, "_ZNK14CHostageImprov20IsIgnoringTerroristsEv", mfunc_ptr_cast(&CHostageImprov::IsIgnoringTerrorists) }, - //{ 0x0, "_ZNK14CHostageImprov13GetAggressionEv", mfunc_ptr_cast(&CHostageImprov::GetAggression) }, + //{ 0x0, "_ZNK14CHostageImprov17GetScareIntensityEv", mfunc_ptr_cast(&CHostageImprov::GetScareIntensity) }, // DEFAULT + //{ 0x0, "_ZNK14CHostageImprov20IsIgnoringTerroristsEv", mfunc_ptr_cast(&CHostageImprov::IsIgnoringTerrorists) }, // DEFAULT + //{ 0x0, "_ZNK14CHostageImprov13GetAggressionEv", mfunc_ptr_cast(&CHostageImprov::GetAggression) }, // DEFAULT { 0x01D55ED0, "_ZN14CHostageImprov7ChatterE18HostageChatterTypeb", mfunc_ptr_cast(&CHostageImprov::Chatter) }, { 0x01D55F80, "_ZN14CHostageImprov14DelayedChatterEf18HostageChatterTypeb", mfunc_ptr_cast(&CHostageImprov::DelayedChatter) }, //{ 0x01D55FE0, "_ZN14CHostageImprov20UpdateDelayedChatterEv", mfunc_ptr_cast(&CHostageImprov::UpdateDelayedChatter) }, // NOXREF - //{ 0x0, "_ZNK14CHostageImprov9IsTalkingEv", mfunc_ptr_cast(&CHostageImprov::IsTalking) }, - //{ 0x0, "_ZN14CHostageImprov22UpdateGrenadeReactionsEv", mfunc_ptr_cast(&CHostageImprov::UpdateGrenadeReactions) }, + //{ 0x0, "_ZNK14CHostageImprov9IsTalkingEv", mfunc_ptr_cast(&CHostageImprov::IsTalking) }, // DEFAULT + { 0x01D54150, "_ZN14CHostageImprov22UpdateGrenadeReactionsEv", mfunc_ptr_cast(&CHostageImprov::UpdateGrenadeReactions) }, { 0x01D55D20, "_ZN14CHostageImprov6AfraidEv", mfunc_ptr_cast(&CHostageImprov::Afraid) }, { 0x01D56290, "_ZN14CHostageImprov4WaveEv", mfunc_ptr_cast(&CHostageImprov::Wave) }, { 0x01D56210, "_ZN14CHostageImprov5AgreeEv", mfunc_ptr_cast(&CHostageImprov::Agree) }, @@ -5148,25 +5163,27 @@ FunctionHook g_FunctionHooks[] = //{ 0x01D56910, "_ZN14CHostageImprov25UpdateStationaryAnimationEv", mfunc_ptr_cast(&CHostageImprov::UpdateStationaryAnimation) }, // NOXREF //{ 0x0, "_ZNK14CHostageImprov9GetEntityEv", mfunc_ptr_cast(&CHostageImprov::GetEntity) }, //{ 0x01D540C0, "_ZN14CHostageImprov24CheckForNearbyTerroristsEv", mfunc_ptr_cast(&CHostageImprov::CheckForNearbyTerrorists) }, // NOXREF - //{ 0x01D534F0, "_ZN14CHostageImprov14UpdatePositionEf", mfunc_ptr_cast(&CHostageImprov::UpdatePosition) }, + { 0x01D534F0, "_ZN14CHostageImprov14UpdatePositionEf", mfunc_ptr_cast(&CHostageImprov::UpdatePosition) }, { 0x01D512C0, "_ZN14CHostageImprov11MoveTowardsERK6Vectorf", mfunc_ptr_cast(&CHostageImprov::MoveTowards) }, - //{ 0x01D517A0, "_ZN14CHostageImprov11FaceTowardsERK6Vectorf", mfunc_ptr_cast(&CHostageImprov::FaceTowards) }, - //{ 0x0, "_ZN14CHostageImprov8GetSpeedEv", mfunc_ptr_cast(&CHostageImprov::GetSpeed) }, + { 0x01D517A0, "_ZN14CHostageImprov11FaceTowardsERK6Vectorf", mfunc_ptr_cast(&CHostageImprov::FaceTowards) }, + //{ 0x01D52250, "_ZN14CHostageImprov8GetSpeedEv", mfunc_ptr_cast(&CHostageImprov::GetSpeed) }, // NOXREF //{ 0x0, "_ZN14CHostageImprov12SetMoveAngleEf", mfunc_ptr_cast(&CHostageImprov::SetMoveAngle) }, { 0x01D56300, "_ZN14CHostageImprov6WiggleEv", mfunc_ptr_cast(&CHostageImprov::Wiggle) }, { 0x01D564E0, "_ZN14CHostageImprov9ClearPathEv", mfunc_ptr_cast(&CHostageImprov::ClearPath) }, + { 0x01D4A890, "_Z16NavAreaBuildPathI15HostagePathCostEbP8CNavAreaS2_PK6VectorRT_PS2_", (size_t)&NavAreaBuildPath__HostagePathCost__wrapper }, + { 0x01D15AD0, "_Z16NavAreaBuildPathI16ShortestPathCostEbP8CNavAreaS2_PK6VectorRT_PS2_", (size_t)&NavAreaBuildPath__ShortestPathCost__wrapper }, //{ 0x01D511C0, "_ZN14CHostageImprov17DiscontinuityJumpEfbb", mfunc_ptr_cast(&CHostageImprov::DiscontinuityJump) }, // NOXREF - //{ 0x0, "_ZN14CHostageImprov12UpdateVisionEv", mfunc_ptr_cast(&CHostageImprov::UpdateVision) }, + { 0x01D52C00, "_ZN14CHostageImprov12UpdateVisionEv", mfunc_ptr_cast(&CHostageImprov::UpdateVision) }, //HostageState //virtual func //{ 0x0, "_ZN12HostageStateD0Ev", mfunc_ptr_cast(&HostageState::~HostageState) }, //{ 0x0, "_ZN12HostageStateD2Ev", mfunc_ptr_cast(&HostageState::~HostageState) }, - //{ 0x0, "_ZN12HostageState25UpdateStationaryAnimationEP14CHostageImprov", mfunc_ptr_cast(&HostageState::UpdateStationaryAnimation) }, + //{ 0x01D569C0, "_ZN12HostageState25UpdateStationaryAnimationEP14CHostageImprov", mfunc_ptr_cast(&HostageState::UpdateStationaryAnimation) }, //HostageIdleState //virtual func { 0x01D4B3A0, "_ZN16HostageIdleState7OnEnterEP14CHostageImprov", mfunc_ptr_cast(&HostageIdleState::OnEnter_) }, - //{ 0x01D4B3C0, "_ZN16HostageIdleState8OnUpdateEP14CHostageImprov", mfunc_ptr_cast(&HostageIdleState::OnUpdate_) }, - //{ 0x0, "_ZN16HostageIdleState6OnExitEP14CHostageImprov", mfunc_ptr_cast(&HostageIdleState::OnExit_) }, + { 0x01D4B3C0, "_ZN16HostageIdleState8OnUpdateEP14CHostageImprov", mfunc_ptr_cast(&HostageIdleState::OnUpdate_) }, + { 0x01D4BBB0, "_ZN16HostageIdleState6OnExitEP14CHostageImprov", mfunc_ptr_cast(&HostageIdleState::OnExit_) }, //{ 0x0, "_ZNK16HostageIdleState7GetNameEv", mfunc_ptr_cast(&HostageIdleState::GetName_) }, // DEFAULT { 0x01D4BBD0, "_ZN16HostageIdleState25UpdateStationaryAnimationEP14CHostageImprov", mfunc_ptr_cast(&HostageIdleState::UpdateStationaryAnimation_) }, //{ 0x0, "_ZN16HostageIdleState15OnMoveToSuccessERK6Vector", mfunc_ptr_cast(&HostageIdleState::OnMoveToSuccess_) }, // DEFAULT @@ -5181,42 +5198,42 @@ FunctionHook g_FunctionHooks[] = //{ 0x0, "_ZN19HostageStateMachine25UpdateStationaryAnimationEP14CHostageImprov", mfunc_ptr_cast(&HostageStateMachine::UpdateStationaryAnimation) }, //HostageEscapeToCoverState //virtual func - //{ 0x0, "_ZN25HostageEscapeToCoverState7OnEnterEP14CHostageImprov", mfunc_ptr_cast(&HostageEscapeToCoverState::OnEnter) }, - //{ 0x0, "_ZN25HostageEscapeToCoverState8OnUpdateEP14CHostageImprov", mfunc_ptr_cast(&HostageEscapeToCoverState::OnUpdate) }, - //{ 0x0, "_ZN25HostageEscapeToCoverState6OnExitEP14CHostageImprov", mfunc_ptr_cast(&HostageEscapeToCoverState::OnExit) }, - //{ 0x0, "_ZNK25HostageEscapeToCoverState7GetNameEv", mfunc_ptr_cast(&HostageEscapeToCoverState::GetName) }, - //{ 0x0, "_ZN25HostageEscapeToCoverState15OnMoveToFailureERK6VectorN12IImprovEvent17MoveToFailureTypeE", mfunc_ptr_cast(&HostageEscapeToCoverState::OnMoveToFailure) }, + { 0x01D4A200, "_ZN25HostageEscapeToCoverState7OnEnterEP14CHostageImprov", mfunc_ptr_cast(&HostageEscapeToCoverState::OnEnter_) }, + { 0x01D4A4A0, "_ZN25HostageEscapeToCoverState8OnUpdateEP14CHostageImprov", mfunc_ptr_cast(&HostageEscapeToCoverState::OnUpdate_) }, + //{ 0x01D4A590, "_ZN25HostageEscapeToCoverState6OnExitEP14CHostageImprov", mfunc_ptr_cast(&HostageEscapeToCoverState::OnExit_) }, // PURE + //{ 0x01D56B00, "_ZNK25HostageEscapeToCoverState7GetNameEv", mfunc_ptr_cast(&HostageEscapeToCoverState::GetName_) }, + { 0x01D4A5A0, "_ZN25HostageEscapeToCoverState15OnMoveToFailureERK6VectorN12IImprovEvent17MoveToFailureTypeE", mfunc_ptr_cast(&HostageEscapeToCoverState::OnMoveToFailure_) }, //non-virtual func //{ 0x0, "_ZN25HostageEscapeToCoverState13SetRescueGoalERK6Vector", mfunc_ptr_cast(&HostageEscapeToCoverState::SetRescueGoal) }, //HostageEscapeLookAroundState //virtual func - //{ 0x0, "_ZN28HostageEscapeLookAroundState7OnEnterEP14CHostageImprov", mfunc_ptr_cast(&HostageEscapeLookAroundState::OnEnter) }, - //{ 0x0, "_ZN28HostageEscapeLookAroundState8OnUpdateEP14CHostageImprov", mfunc_ptr_cast(&HostageEscapeLookAroundState::OnUpdate) }, - //{ 0x0, "_ZN28HostageEscapeLookAroundState6OnExitEP14CHostageImprov", mfunc_ptr_cast(&HostageEscapeLookAroundState::OnExit) }, - //{ 0x0, "_ZNK28HostageEscapeLookAroundState7GetNameEv", mfunc_ptr_cast(&HostageEscapeLookAroundState::GetName) }, + { 0x01D4A5E0, "_ZN28HostageEscapeLookAroundState7OnEnterEP14CHostageImprov", mfunc_ptr_cast(&HostageEscapeLookAroundState::OnEnter_) }, + { 0x01D4A620, "_ZN28HostageEscapeLookAroundState8OnUpdateEP14CHostageImprov", mfunc_ptr_cast(&HostageEscapeLookAroundState::OnUpdate_) }, + { 0x01D4A680, "_ZN28HostageEscapeLookAroundState6OnExitEP14CHostageImprov", mfunc_ptr_cast(&HostageEscapeLookAroundState::OnExit_) }, + //{ 0x0, "_ZNK28HostageEscapeLookAroundState7GetNameEv", mfunc_ptr_cast(&HostageEscapeLookAroundState::GetName_) }, //HostageEscapeState //virtual func - //{ 0x0, "_ZN18HostageEscapeState7OnEnterEP14CHostageImprov", mfunc_ptr_cast(&HostageEscapeState::OnEnter) }, - //{ 0x0, "_ZN18HostageEscapeState8OnUpdateEP14CHostageImprov", mfunc_ptr_cast(&HostageEscapeState::OnUpdate) }, - //{ 0x0, "_ZN18HostageEscapeState6OnExitEP14CHostageImprov", mfunc_ptr_cast(&HostageEscapeState::OnExit) }, - //{ 0x0, "_ZNK18HostageEscapeState7GetNameEv", mfunc_ptr_cast(&HostageEscapeState::GetName) }, - //{ 0x0, "_ZN18HostageEscapeState15OnMoveToFailureERK6VectorN12IImprovEvent17MoveToFailureTypeE", mfunc_ptr_cast(&HostageEscapeState::OnMoveToFailure) }, + { 0x01D4A690, "_ZN18HostageEscapeState7OnEnterEP14CHostageImprov", mfunc_ptr_cast(&HostageEscapeState::OnEnter_) }, + { 0x01D4A720, "_ZN18HostageEscapeState8OnUpdateEP14CHostageImprov", mfunc_ptr_cast(&HostageEscapeState::OnUpdate_) }, + { 0x01D4A880, "_ZN18HostageEscapeState6OnExitEP14CHostageImprov", mfunc_ptr_cast(&HostageEscapeState::OnExit_) }, + //{ 0x01D56A80, "_ZNK18HostageEscapeState7GetNameEv", mfunc_ptr_cast(&HostageEscapeState::GetName_) }, + //{ 0x0, "_ZN18HostageEscapeState15OnMoveToFailureERK6VectorN12IImprovEvent17MoveToFailureTypeE", mfunc_ptr_cast(&HostageEscapeState::OnMoveToFailure_) }, // NOXREF //non-virtual func //{ 0x0, "_ZN18HostageEscapeState7ToCoverEv", mfunc_ptr_cast(&HostageEscapeState::ToCover) }, //{ 0x0, "_ZN18HostageEscapeState10LookAroundEv", mfunc_ptr_cast(&HostageEscapeState::LookAround) }, //HostageRetreatState //virtual func - //{ 0x01D4BC30, "_ZN19HostageRetreatState7OnEnterEP14CHostageImprov", mfunc_ptr_cast(&HostageRetreatState::OnEnter_) }, + { 0x01D4BC30, "_ZN19HostageRetreatState7OnEnterEP14CHostageImprov", mfunc_ptr_cast(&HostageRetreatState::OnEnter_) }, { 0x01D4BC50, "_ZN19HostageRetreatState8OnUpdateEP14CHostageImprov", mfunc_ptr_cast(&HostageRetreatState::OnUpdate_) }, - //{ 0x01D4BDB0, "_ZN19HostageRetreatState6OnExitEP14CHostageImprov", mfunc_ptr_cast(&HostageRetreatState::OnExit_) }, + //{ 0x01D4BDB0, "_ZN19HostageRetreatState6OnExitEP14CHostageImprov", mfunc_ptr_cast(&HostageRetreatState::OnExit_) }, // PURE //{ 0x01D56BD0, "_ZNK19HostageRetreatState7GetNameEv", mfunc_ptr_cast(&HostageRetreatState::GetName_) }, //HostageFollowState //virtual func - //{ 0x0, "_ZN18HostageFollowState7OnEnterEP14CHostageImprov", mfunc_ptr_cast(&HostageFollowState::OnEnter) }, - //{ 0x0, "_ZN18HostageFollowState8OnUpdateEP14CHostageImprov", mfunc_ptr_cast(&HostageFollowState::OnUpdate) }, - //{ 0x0, "_ZN18HostageFollowState6OnExitEP14CHostageImprov", mfunc_ptr_cast(&HostageFollowState::OnExit) }, - //{ 0x0, "_ZNK18HostageFollowState7GetNameEv", mfunc_ptr_cast(&HostageFollowState::GetName) }, - //{ 0x0, "_ZN18HostageFollowState25UpdateStationaryAnimationEP14CHostageImprov", mfunc_ptr_cast(&HostageFollowState::UpdateStationaryAnimation) }, + { 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_) }, + { 0x01D4B330, "_ZN18HostageFollowState25UpdateStationaryAnimationEP14CHostageImprov", mfunc_ptr_cast(&HostageFollowState::UpdateStationaryAnimation_) }, //non-virtual func //{ 0x0, "_ZN18HostageFollowState9SetLeaderEP11CBaseEntity", mfunc_ptr_cast(&HostageFollowState::SetLeader) }, //{ 0x0, "_ZNK18HostageFollowState9GetLeaderEv", mfunc_ptr_cast(&HostageFollowState::GetLeader) }, @@ -5231,7 +5248,7 @@ FunctionHook g_FunctionHooks[] = { 0x01D49E10, "_ZN19HostageAnimateState11AddSequenceEP14CHostageImprovPKcff", mfunc_ptr_cast(&HostageAnimateState::AddSequence) }, { 0x01D49F00, "_ZN19HostageAnimateState11AddSequenceEP14CHostageImproviff", mfunc_ptr_cast(&HostageAnimateState::AddSequence) }, //{ 0x0, "_ZNK19HostageAnimateState6IsBusyEv", mfunc_ptr_cast(&HostageAnimateState::IsBusy) }, - //{ 0x0, "_ZNK19HostageAnimateState9IsPlayingEP14CHostageImprovPKc", mfunc_ptr_cast(&HostageAnimateState::IsPlaying) }, + //{ 0x01D4A1C0, "_ZNK19HostageAnimateState9IsPlayingEP14CHostageImprovPKc", mfunc_ptr_cast(&HostageAnimateState::IsPlaying) }, // NOXREF //{ 0x0, "_ZN19HostageAnimateState20GetCurrentSequenceIDEv", mfunc_ptr_cast(&HostageAnimateState::GetCurrentSequenceID) }, // NOXREF //{ 0x0, "_ZNK19HostageAnimateState14GetPerformanceEv", mfunc_ptr_cast(&HostageAnimateState::GetPerformance) }, //{ 0x0, "_ZN19HostageAnimateState14SetPerformanceENS_15PerformanceTypeE", mfunc_ptr_cast(&HostageAnimateState::SetPerformance) }, @@ -5248,7 +5265,6 @@ FunctionHook g_FunctionHooks[] = //{ 0x01D50D90, "_ZN8CHostage10BloodColorEv", mfunc_ptr_cast(&CHostage::BloodColor_) }, { 0x01D4DB10, "_ZN8CHostage5TouchEP11CBaseEntity", mfunc_ptr_cast(&CHostage::Touch_) }, { 0x01D4D710, "_ZN8CHostage3UseEP11CBaseEntityS1_8USE_TYPEf", mfunc_ptr_cast(&CHostage::Use_) }, - //non-virtual func //!!{ 0x01D4C450, "_ZN8CHostage9IdleThinkEv", mfunc_ptr_cast(&CHostage::IdleThink) }, // export func { 0x01D4CBB0, "_ZN8CHostage6RemoveEv", mfunc_ptr_cast(&CHostage::Remove) }, @@ -5279,7 +5295,6 @@ FunctionHook g_FunctionHooks[] = //{ 0x0, "_ZN8CHostage6IsDeadEv", mfunc_ptr_cast(&CHostage::IsDead) }, // NOXREF //{ 0x0, "_ZNK8CHostage8IsAtHomeEv", mfunc_ptr_cast(&CHostage::IsAtHome) }, // NOXREF //{ 0x0, "_ZNK8CHostage15GetHomePositionEv", mfunc_ptr_cast(&CHostage::GetHomePosition) }, // NOXREF - { 0x01D4BDC0, "hostage_entity", (size_t)&hostage_entity }, { 0x01D4BE10, "monster_scientist", (size_t)&monster_scientist }, //CHostageManager @@ -5394,6 +5409,7 @@ VirtualTableRef g_TableRefs[] = { 0x01DF6FE4, "HostageStateMachine", 4 }, { 0x01DF7180, "HostageEscapeToCoverState", 4 }, { 0x01DF6F18, "HostageAnimateState", 4 }, + { 0x01DF6F9C, "HostageEscapeState", 6 }, { 0x01E00BBC, "CArmoury", CBASE_VIRTUAL_COUNT }, { 0x01DFE4E4, "CSoundEnt", CBASE_VIRTUAL_COUNT }, @@ -5569,20 +5585,16 @@ AddressRef g_FunctionRefs[] = { #ifndef Function_References_Region - { 0x01D3CA60, "_ZNK8CNavArea4GetZEPK6Vector", (size_t)&pGetZ__Vector }, - { 0x01D43860, "_ZNK12CNavAreaGrid17GetNearestNavAreaEPK6Vectorb", (size_t)&pGetNearestNavArea }, - { 0x01D43710, "_ZNK12CNavAreaGrid10GetNavAreaEPK6Vectorf", (size_t)&pGetNavArea }, + //{ 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 }, - - { 0x01D46310, "_Z17LoadNavigationMapv", (size_t)&pLoadNavigationMap }, { 0x01D19C70, "_ZN9BotPhrase9RandomizeEv", (size_t)&pBotPhrase__Randomize }, - { 0x01D25270, "_ZN13CCSBotManager6AddBotEPK10BotProfile18BotProfileTeamType", (size_t)&pCCSBotManager__AddBot }, { 0x01D80C90, "_Z16InstallGameRulesv", (size_t)&pInstallGameRules }, { 0x01D4C450, "_ZN8CHostage9IdleThinkEv", (size_t)&pCHostage__IdleThink }, - { 0x01D517A0, "_ZN14CHostageImprov11FaceTowardsERK6Vectorf", (size_t)&pCHostageImprov__FaceTowards }, #endif // Function_References_Region @@ -5595,7 +5607,8 @@ AddressRef g_DataRefs[] = { 0x01E61BD0, "g_engfuncs", (size_t)&pg_engfuncs }, { 0x01E61E48, "gpGlobals", (size_t)&pgpGlobals }, - + + { 0x01E10768, "GameEventName", (size_t)&pGameEventName }, { 0x01E2A3F8, "_ZL14s_shared_token", (size_t)&ps_shared_token }, { 0x01E13218, "_ZL14s_shared_quote", (size_t)&ps_shared_quote }, @@ -6024,7 +6037,7 @@ AddressRef g_DataRefs[] = { 0x01E23470, "cv_tutor_hint_interval_time", (size_t)&pcv_tutor_hint_interval_time }, { 0x01E11EE4, "cv_hostage_debug", (size_t)&pcv_hostage_debug }, { 0x01E11EF8, "cv_hostage_stop", (size_t)&pcv_hostage_stop }, - //{ 0x0, "_ZL14placeDirectory", (size_t)&pplaceDirectory }, + //{ 0x0, "_ZL14placeDirectory", (size_t)&pplaceDirectory }, // DONT USE - NOXREF { 0x01E2A0E4, "TheNavLadderList", (size_t)&pTheNavLadderList }, { 0x01E2A0F0, "TheHidingSpotList", (size_t)&pTheHidingSpotList }, { 0x01E14C5C, "sPlayerModelFiles", (size_t)&psPlayerModelFiles }, @@ -6046,6 +6059,8 @@ AddressRef g_DataRefs[] = { 0x01E29888, "TheNavAreaGrid", (size_t)&pTheNavAreaGrid }, { 0x01E2A250, "_ZN8CNavNode6m_listE", mfunc_ptr_cast(&CNavNode::pm_list) }, { 0x01E2A254, "_ZN8CNavNode12m_listLengthE", mfunc_ptr_cast(&CNavNode::pm_listLength) }, + { 0x01E11E88, "Opposite", (size_t)&pOpposite }, + //{ 0x0, "_ZN8CNavArea8m_nextIDE", mfunc_ptr_cast(&CNavArea::m_nextID) }, { 0x01E11584, "_ZN8CNavArea14m_masterMarkerE", mfunc_ptr_cast(&CNavArea::pm_masterMarker) }, { 0x01E11588, "_ZN10HidingSpot8m_nextIDE", mfunc_ptr_cast(&HidingSpot::pm_nextID) }, diff --git a/regamedll/hookers/memory.cpp b/regamedll/hookers/memory.cpp index 09da73b0..a172351f 100644 --- a/regamedll/hookers/memory.cpp +++ b/regamedll/hookers/memory.cpp @@ -740,7 +740,7 @@ bool HIDDEN HookFunction(Module *module, FunctionHook *hook) //int seedad = pUTIL_SharedRandomLong(seed,low,high); //memcpy(addr_orig,patchByte,5); - if (strcmp(hook->symbolName,"_ZNK14CHostageImprov16IsFriendInTheWayEv")==0) + if (strcmp(hook->symbolName,"_ZN25HostageEscapeToCoverState15OnMoveToFailureERK6VectorN12IImprovEvent17MoveToFailureTypeE")==0) { addr_orig = (void *)hook->originalAddress; diff --git a/regamedll/hookers/osconfig.h b/regamedll/hookers/osconfig.h index 200a93e6..b5dff9f2 100644 --- a/regamedll/hookers/osconfig.h +++ b/regamedll/hookers/osconfig.h @@ -236,7 +236,7 @@ static const bool __isLinux = true; #endif -#define EXT_FUNC FORCE_STACK_ALIGN +#define EXT_FUNC /*FORCE_STACK_ALIGN*/ extern void regamedll_log(const char *fmt, ...); extern void __declspec(noreturn) regamedll_syserror(const char *fmt, ...); diff --git a/regamedll/msvc/ReGameDLL.vcxproj b/regamedll/msvc/ReGameDLL.vcxproj index 0ef36650..8c83121d 100644 --- a/regamedll/msvc/ReGameDLL.vcxproj +++ b/regamedll/msvc/ReGameDLL.vcxproj @@ -1132,7 +1132,7 @@ Level3 Disabled true - HOOK_GAMEDLL;REGAMEDLL_SELF;REGAMEDLL_CHECKS;CLIENT_WEAPONS;USE_BREAKPAD_HANDLER;DEDICATED;_CRT_SECURE_NO_WARNINGS;_DEBUG;_ITERATOR_DEBUG_LEVEL=0;%(PreprocessorDefinitions) + PLAY_GAMEDLL;HOOK_GAMEDLL;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 +1204,7 @@ Level3 Disabled true - REGAMEDLL_SELF;REGAMEDLL_CHECKS;CLIENT_WEAPONS;USE_BREAKPAD_HANDLER;DEDICATED;_CRT_SECURE_NO_WARNINGS;_DEBUG;_ITERATOR_DEBUG_LEVEL=0;%(PreprocessorDefinitions) + 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 @@ -1317,7 +1317,7 @@ true true true - REGAMEDLL_SELF;HOOK_GAMEDLL;REGAMEDLL_CHECKS;CLIENT_WEAPONS;USE_BREAKPAD_HANDLER;DEDICATED;_CRT_SECURE_NO_WARNINGS;NOMINMAX;%(PreprocessorDefinitions) + REGAMEDLL_SELF;PLAY_GAMEDLL;HOOK_GAMEDLL;REGAMEDLL_CHECKS;CLIENT_WEAPONS;USE_BREAKPAD_HANDLER;DEDICATED;_CRT_SECURE_NO_WARNINGS;NOMINMAX;%(PreprocessorDefinitions) MultiThreaded /arch:IA32 %(AdditionalOptions) Use diff --git a/regamedll/pm_shared/pm_math.h b/regamedll/pm_shared/pm_math.h index 63d4be33..01f01e22 100644 --- a/regamedll/pm_shared/pm_math.h +++ b/regamedll/pm_shared/pm_math.h @@ -32,8 +32,8 @@ #pragma once #endif -#define PITCH 0 // up/down -#define YAW 1 // left/right +#define PITCH 0 // up/down +#define YAW 1 // left/right #define ROLL 2 // fall over #ifdef HOOK_GAMEDLL @@ -48,32 +48,32 @@ extern int nanmask; #define IS_NAN(x) ((*reinterpret_cast(&(x)) & nanmask) == nanmask) -NOBODY float anglemod(float a); -void AngleVectors(const vec_t *angles, vec_t *forward, vec_t *right, vec_t *up); -NOBODY void AngleVectorsTranspose(const vec_t *angles, vec_t *forward, vec_t *right, vec_t *up); -void AngleMatrix(const vec_t *angles, float (*matrix)[4]); -NOBODY void AngleIMatrix(const vec_t *angles, float (*matrix)[4]); -NOBODY void NormalizeAngles(float *angles); -NOBODY void InterpolateAngles(float *start, float *end, float *output, float frac); -NOBODY float AngleBetweenVectors(const vec_t *v1, const vec_t *v2); -NOBODY void VectorTransform(const vec_t *in1, float *in2, vec_t *out); -int VectorCompare(const vec_t *v1, const vec_t *v2); -void VectorMA(const vec_t *veca, float scale, const vec_t *vecb, vec_t *vecc); - -float_precision _DotProduct(vec_t *v1, vec_t *v2); -void _VectorSubtract(vec_t *veca, vec_t *vecb, vec_t *out); -void _VectorAdd(vec_t *veca, vec_t *vecb, vec_t *out); -void _VectorCopy(vec_t *in, vec_t *out); -void _CrossProduct(const vec_t *v1, const vec_t *v2, vec_t *cross); - -float_precision Length(const vec_t *v); -NOBODY float Distance(const vec_t *v1, const vec_t *v2); -float_precision VectorNormalize(vec_t *v); - -NOBODY void VectorInverse(vec_t *v); -NOBODY void VectorScale(const vec_t *in, vec_t scale, vec_t *out); -NOBODY int Q_log2(int val); -NOBODY void VectorMatrix(vec_t *forward, vec_t *right, vec_t *up); +NOBODY float anglemod(float a); +void AngleVectors(const vec_t *angles, vec_t *forward, vec_t *right, vec_t *up); +NOBODY void AngleVectorsTranspose(const vec_t *angles, vec_t *forward, vec_t *right, vec_t *up); +void AngleMatrix(const vec_t *angles, float (*matrix)[4]); +NOBODY void AngleIMatrix(const vec_t *angles, float (*matrix)[4]); +NOBODY void NormalizeAngles(float *angles); +NOBODY void InterpolateAngles(float *start, float *end, float *output, float frac); +NOBODY float AngleBetweenVectors(const vec_t *v1, const vec_t *v2); +NOBODY void VectorTransform(const vec_t *in1, float *in2, vec_t *out); +int VectorCompare(const vec_t *v1, const vec_t *v2); +void VectorMA(const vec_t *veca, float scale, const vec_t *vecb, vec_t *vecc); + +float_precision _DotProduct(vec_t *v1, vec_t *v2); +void _VectorSubtract(vec_t *veca, vec_t *vecb, vec_t *out); +void _VectorAdd(vec_t *veca, vec_t *vecb, vec_t *out); +void _VectorCopy(vec_t *in, vec_t *out); +void _CrossProduct(const vec_t *v1, const vec_t *v2, vec_t *cross); + +float_precision Length(const vec_t *v); +NOBODY float Distance(const vec_t *v1, const vec_t *v2); +float_precision VectorNormalize(vec_t *v); + +NOBODY void VectorInverse(vec_t *v); +NOBODY void VectorScale(const vec_t *in, vec_t scale, vec_t *out); +NOBODY int Q_log2(int val); +NOBODY void VectorMatrix(vec_t *forward, vec_t *right, vec_t *up); NOBODY void VectorAngles(const vec_t *forward, vec_t *angles); #endif // PM_MATH_H diff --git a/regamedll/pm_shared/pm_shared.cpp b/regamedll/pm_shared/pm_shared.cpp index 83120358..e110c29d 100644 --- a/regamedll/pm_shared/pm_shared.cpp +++ b/regamedll/pm_shared/pm_shared.cpp @@ -2644,7 +2644,7 @@ void PM_DropPunchAngle(vec_t *punchangle) len = VectorNormalize(punchangle); len -= (10.0 + len * 0.5) * pmove->frametime; -#ifdef HOOK_GAMEDLL +#ifdef PLAY_GAMEDLL len = Q_max(len, 0.0); #else len = Q_max(len, 0.0f); diff --git a/regamedll/regamedll/dlls.h b/regamedll/regamedll/dlls.h index 72f04568..b346ed0d 100644 --- a/regamedll/regamedll/dlls.h +++ b/regamedll/regamedll/dlls.h @@ -99,6 +99,7 @@ #include "buttons.h" // CSBOT and Nav +#include "game_shared/GameEvent.h" // Game event enum used by career mode, tutor system, and bots #include "game_shared/bot/bot_util.h" #include "game_shared/bot/simple_state_machine.h"