commit
80a1a6e5c2
@ -54,6 +54,10 @@ public:
|
||||
// dispenser
|
||||
offset_t m_iAmmoMetal; // dispenser metal reserve
|
||||
|
||||
// round timer
|
||||
offset_t m_nSetupTimeLength;
|
||||
offset_t m_nState;
|
||||
|
||||
offset_t iLifeState;
|
||||
offset_t iCond;
|
||||
offset_t iCond1;
|
||||
|
@ -113,6 +113,8 @@ void fClampAngle(Vector &qaAng);
|
||||
// const char* MakeInfoString(IClientEntity* player);
|
||||
bool GetProjectileData(CachedEntity *weapon, float &speed, float &gravity);
|
||||
bool IsVectorVisible(Vector a, Vector b, bool enviroment_only = false, CachedEntity *self = LOCAL_E, unsigned int mask = MASK_SHOT_HULL);
|
||||
// A Special function for navparser to check if a Vector is visible.
|
||||
bool IsVectorVisibleNavigation(Vector a, Vector b, unsigned int mask = MASK_SHOT_HULL);
|
||||
Vector GetForwardVector(Vector origin, Vector viewangles, float distance);
|
||||
Vector GetForwardVector(float distance);
|
||||
CachedEntity *getClosestEntity(Vector vec);
|
||||
|
@ -22,6 +22,11 @@ public:
|
||||
typedef bool (*fn_t)(IClientEntity *);
|
||||
return vfunc<fn_t>(self, offsets::PlatformOffset(184, offsets::undefined, 184), 0)(self);
|
||||
}
|
||||
inline static bool ShouldCollide(IClientEntity *self, int collisionGroup, int contentsMask)
|
||||
{
|
||||
typedef bool (*fn_t)(IClientEntity *, int, int);
|
||||
return vfunc<fn_t>(self, offsets::PlatformOffset(198, offsets::undefined, 198), 0)(self, collisionGroup, contentsMask);
|
||||
}
|
||||
inline static int &m_nPredictionRandomSeed()
|
||||
{
|
||||
static int placeholder = 0;
|
||||
|
17
include/teamroundtimer.hpp
Normal file
17
include/teamroundtimer.hpp
Normal file
@ -0,0 +1,17 @@
|
||||
#pragma once
|
||||
enum round_states
|
||||
{
|
||||
RT_STATE_SETUP = 0,
|
||||
RT_STATE_NORMAL
|
||||
};
|
||||
|
||||
class CTeamRoundTimer
|
||||
{
|
||||
public:
|
||||
int GetSetupTimeLength();
|
||||
round_states GetRoundState();
|
||||
void Update();
|
||||
|
||||
int entity;
|
||||
};
|
||||
extern CTeamRoundTimer *g_pTeamRoundTimer;
|
@ -41,6 +41,15 @@ public:
|
||||
void SetSelf(IClientEntity *self);
|
||||
virtual TraceType_t GetTraceType() const;
|
||||
};
|
||||
class FilterNavigation : public ITraceFilter
|
||||
{
|
||||
|
||||
public:
|
||||
virtual ~FilterNavigation();
|
||||
FilterNavigation();
|
||||
virtual bool ShouldHitEntity(IHandleEntity *entity, int mask);
|
||||
virtual TraceType_t GetTraceType() const;
|
||||
};
|
||||
|
||||
class FilterNoEntity : public ITraceFilter
|
||||
{
|
||||
@ -72,6 +81,7 @@ public:
|
||||
|
||||
extern FilterDefault filter_default;
|
||||
extern FilterNoPlayer filter_no_player;
|
||||
extern FilterNavigation filter_navigation;
|
||||
extern FilterNoEntity filter_no_entity;
|
||||
extern FilterPenetration filter_penetration;
|
||||
} // namespace trace
|
||||
|
@ -23,6 +23,7 @@ set(files "${CMAKE_CURRENT_LIST_DIR}/angles.cpp"
|
||||
"${CMAKE_CURRENT_LIST_DIR}/sconvars.cpp"
|
||||
"${CMAKE_CURRENT_LIST_DIR}/soundcache.cpp"
|
||||
"${CMAKE_CURRENT_LIST_DIR}/targethelper.cpp"
|
||||
"${CMAKE_CURRENT_LIST_DIR}/teamroundtimer.cpp"
|
||||
"${CMAKE_CURRENT_LIST_DIR}/textmode.cpp"
|
||||
"${CMAKE_CURRENT_LIST_DIR}/tfmm.cpp"
|
||||
"${CMAKE_CURRENT_LIST_DIR}/trace.cpp"
|
||||
|
@ -88,6 +88,10 @@ void NetVars::Init()
|
||||
// dispenser
|
||||
this->m_iAmmoMetal = gNetvars.get_offset("DT_ObjectDispenser", "m_iAmmoMetal");
|
||||
|
||||
// Round timer
|
||||
this->m_nSetupTimeLength = gNetvars.get_offset("DT_TeamRoundTimer", "m_nSetupTimeLength");
|
||||
this->m_nState = gNetvars.get_offset("DT_TeamRoundTimer", "m_nState");
|
||||
|
||||
// any building
|
||||
this->m_iUpgradeMetal = gNetvars.get_offset("DT_BaseObject", "m_iUpgradeMetal");
|
||||
this->m_flPercentageConstructed = gNetvars.get_offset("DT_BaseObject", "m_flPercentageConstructed");
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include <pwd.h>
|
||||
|
||||
#include <hacks/hacklist.hpp>
|
||||
#include "teamroundtimer.hpp"
|
||||
#if EXTERNAL_DRAWING
|
||||
#include "xoverlay.h"
|
||||
#endif
|
||||
@ -336,6 +337,7 @@ free(logname);*/
|
||||
InitNetVars();
|
||||
g_pLocalPlayer = new LocalPlayer();
|
||||
g_pPlayerResource = new TFPlayerResource();
|
||||
g_pTeamRoundTimer = new CTeamRoundTimer();
|
||||
|
||||
velocity::Init();
|
||||
playerlist::Load();
|
||||
@ -394,6 +396,10 @@ void hack::Shutdown()
|
||||
ConVar_Unregister();
|
||||
logging::Info("Unloading sharedobjects..");
|
||||
sharedobj::UnloadAllSharedObjects();
|
||||
logging::Info("Deleting global interfaces...");
|
||||
delete g_pLocalPlayer;
|
||||
delete g_pTeamRoundTimer;
|
||||
delete g_pPlayerResource;
|
||||
if (!hack::game_shutdown)
|
||||
{
|
||||
logging::Info("Running shutdown handlers");
|
||||
|
@ -68,6 +68,16 @@ static void updateAntiAfk()
|
||||
}
|
||||
else
|
||||
{
|
||||
Vector vel(0.0f);
|
||||
if (CE_GOOD(LOCAL_E) && LOCAL_E->m_bAlivePlayer())
|
||||
velocity::EstimateAbsVelocity(RAW_ENT(LOCAL_E), vel);
|
||||
// We are moving, make the timer a bit longer (only a bit to avoid issues with random movement)
|
||||
if (!vel.IsZero(1.0f))
|
||||
{
|
||||
anti_afk_timer.last += std::chrono::milliseconds(400);
|
||||
if (anti_afk_timer.last > std::chrono::system_clock::now())
|
||||
anti_afk_timer.update();
|
||||
}
|
||||
static auto afk_timer = g_ICvar->FindVar("mp_idlemaxtime");
|
||||
if (!afk_timer)
|
||||
afk_timer = g_ICvar->FindVar("mp_idlemaxtime");
|
||||
@ -82,7 +92,7 @@ static void updateAntiAfk()
|
||||
|
||||
// Game also checks if you move if you are in spawn, so spam movement keys alternatingly
|
||||
bool flip = false;
|
||||
current_late_user_cmd->buttons |= flip ? IN_FORWARD : IN_BACK;
|
||||
current_user_cmd->buttons |= flip ? IN_FORWARD : IN_BACK;
|
||||
// Flip flip
|
||||
flip = !flip;
|
||||
if (anti_afk_timer.check(afk_timer->GetInt() * 60 * 1000 + 1000))
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include "soundcache.hpp"
|
||||
#include "Misc.hpp"
|
||||
#include "MiscTemporary.hpp"
|
||||
#include "teamroundtimer.hpp"
|
||||
|
||||
namespace hacks::tf2::NavBot
|
||||
{
|
||||
@ -101,7 +102,7 @@ constexpr bot_class_config DIST_SNIPER{ 1000.0f, 1500.0f, 3000.0f };
|
||||
constexpr bot_class_config DIST_ENGINEER{ 600.0f, 1000.0f, 2500.0f };
|
||||
|
||||
// Gunslinger Engineers really don't care at all
|
||||
constexpr bot_class_config DIST_GUNSLINGER_ENGINEER{ 100.0f, 300.0f, 500.0f };
|
||||
constexpr bot_class_config DIST_GUNSLINGER_ENGINEER{ 50.0f, 200.0f, 900.0f };
|
||||
|
||||
inline bool HasGunslinger(CachedEntity *ent)
|
||||
{
|
||||
@ -120,6 +121,19 @@ static void CreateMove()
|
||||
wait_until_path.update();
|
||||
else
|
||||
current_task = task::none;
|
||||
// Check if we should path at all
|
||||
if (!blocking || task::current_task == task::engineer)
|
||||
{
|
||||
round_states round_state = g_pTeamRoundTimer->GetRoundState();
|
||||
// Still in setuptime, if on fitting team, then do not path yet
|
||||
if (round_state == RT_STATE_SETUP && g_pLocalPlayer->team == TEAM_BLU)
|
||||
{
|
||||
// Clear instructions
|
||||
if (!nav::ReadyForCommands)
|
||||
nav::clearInstructions();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (autojump)
|
||||
autoJump();
|
||||
@ -467,7 +481,7 @@ static success_build buildBuilding()
|
||||
build_attempts++;
|
||||
// Put building in hand if not already
|
||||
if (hacks::shared::misc::getCarriedBuilding() == -1 && build_command_timer.test_and_set(50))
|
||||
g_IEngine->ClientCmd_Unrestricted(format("build ", building).c_str());
|
||||
g_IEngine->ClientCmd_Unrestricted(("build " + std::to_string(building)).c_str());
|
||||
}
|
||||
else if (rotation_timer.check(200))
|
||||
{
|
||||
@ -541,9 +555,47 @@ static bool engineerLogic()
|
||||
return true;
|
||||
}
|
||||
|
||||
// Let's terrify some people (gunslinger engineer)
|
||||
// Gunslinger engineer should run at people, given their building isn't too far away
|
||||
if (HasGunslinger(LOCAL_E))
|
||||
{
|
||||
// Deconstruct too far away buildings
|
||||
for (auto &building : local_buildings)
|
||||
{
|
||||
// Too far away, destroy it
|
||||
if (building->m_vecOrigin().DistTo(LOCAL_E->m_vecOrigin()) >= 1800.0f)
|
||||
{
|
||||
Building building_type = None;
|
||||
switch (building->m_iClassID())
|
||||
{
|
||||
case CL_CLASS(CObjectDispenser):
|
||||
{
|
||||
building_type = Dispenser;
|
||||
break;
|
||||
}
|
||||
case CL_CLASS(CObjectTeleporter):
|
||||
{
|
||||
// We cannot reliably detect entrance and exit, so just destruct both but mark as "Entrance"
|
||||
building_type = TP_Entrace;
|
||||
break;
|
||||
}
|
||||
case CL_CLASS(CObjectSentrygun):
|
||||
{
|
||||
building_type = Sentry;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// If we have a valid building
|
||||
if (building_type != None)
|
||||
{
|
||||
// Destroy exit too because we have no idea what is what
|
||||
if (building_type == TP_Entrace)
|
||||
g_IEngine->ClientCmd_Unrestricted("destroy 3");
|
||||
g_IEngine->ClientCmd_Unrestricted(("destroy " + std::to_string(building_type)).c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
stayNearEngineer();
|
||||
}
|
||||
|
||||
else if (selectBuilding() != None)
|
||||
{
|
||||
@ -643,10 +695,7 @@ static bool engineerLogic()
|
||||
else if (engineer_recheck.test_and_set(15000))
|
||||
{
|
||||
if (navToBuildingSpot())
|
||||
{
|
||||
engineer_recheck.update();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -713,6 +762,9 @@ static bool isValidNearPosition(Vector vec, Vector target, const bot_class_confi
|
||||
return false;
|
||||
if (!IsVectorVisible(vec, target, true, LOCAL_E, MASK_PLAYERSOLID))
|
||||
return false;
|
||||
// Check if safe
|
||||
if (!nav::isSafe(nav::findClosestNavSquare(target)))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -904,10 +956,8 @@ static bool stayNearEngineer()
|
||||
}
|
||||
|
||||
static Timer wait_until_stay_near{};
|
||||
if (current_task == task::engineer_task::staynear_engineer)
|
||||
{
|
||||
if (current_engineer_task == task::engineer_task::staynear_engineer)
|
||||
return true;
|
||||
}
|
||||
else if (wait_until_stay_near.test_and_set(4000))
|
||||
{
|
||||
// We're doing nothing? Do something!
|
||||
@ -1189,6 +1239,7 @@ static bool getHealthAndAmmo(int metal)
|
||||
if (nav::navTo(pack, health < 0.64f || lowAmmo ? 10 : 3, true, false))
|
||||
{
|
||||
current_task = { task::health, health < 0.64f ? 10 : 3 };
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1338,7 +1338,6 @@ netvar.iHealth));
|
||||
|
||||
bool IsVectorVisible(Vector origin, Vector target, bool enviroment_only, CachedEntity *self, unsigned int mask)
|
||||
{
|
||||
|
||||
if (!enviroment_only)
|
||||
{
|
||||
trace_t trace_visible;
|
||||
@ -1363,6 +1362,17 @@ bool IsVectorVisible(Vector origin, Vector target, bool enviroment_only, CachedE
|
||||
}
|
||||
}
|
||||
|
||||
bool IsVectorVisibleNavigation(Vector origin, Vector target, unsigned int mask)
|
||||
{
|
||||
trace_t trace_visible;
|
||||
Ray_t ray;
|
||||
|
||||
ray.Init(origin, target);
|
||||
PROF_SECTION(IEVV_TraceRay);
|
||||
g_ITrace->TraceRay(ray, mask, &trace::filter_navigation, &trace_visible);
|
||||
return (trace_visible.fraction == 1.0f);
|
||||
}
|
||||
|
||||
void WhatIAmLookingAt(int *result_eindex, Vector *result_pos)
|
||||
{
|
||||
Ray_t ray;
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include <hacks/AntiAntiAim.hpp>
|
||||
#include "NavBot.hpp"
|
||||
#include "HookTools.hpp"
|
||||
#include "teamroundtimer.hpp"
|
||||
|
||||
#include "HookedMethods.hpp"
|
||||
#include "PreDataUpdate.hpp"
|
||||
|
@ -21,7 +21,10 @@ static settings::Boolean draw{ "misc.pathing.draw", "false" };
|
||||
static settings::Boolean look{ "misc.pathing.look-at-path", "false" };
|
||||
static settings::Int stuck_time{ "misc.pathing.stuck-time", "4000" };
|
||||
static settings::Int unreachable_time{ "misc.pathing.unreachable-time", "1000" };
|
||||
static settings::Boolean log_pathing{ "misc.pathing.log", "false" };
|
||||
|
||||
// Score based on how much the area was used by other players, in seconds
|
||||
static std::unordered_map<int, float> area_score;
|
||||
static std::vector<CNavArea *> crumbs;
|
||||
static Vector startPoint, endPoint;
|
||||
|
||||
@ -33,6 +36,8 @@ enum ignore_status : uint8_t
|
||||
const_ignored,
|
||||
// LOS between areas is given
|
||||
vischeck_success,
|
||||
// LOS if we ignore entities
|
||||
vischeck_blockedentity,
|
||||
// No LOS between areas
|
||||
vischeck_failed,
|
||||
// Failed to actually walk thru connection
|
||||
@ -95,24 +100,31 @@ float getZBetweenAreas(CNavArea *start, CNavArea *end)
|
||||
static std::unordered_map<std::pair<CNavArea *, CNavArea *>, ignoredata, boost::hash<std::pair<CNavArea *, CNavArea *>>> ignores;
|
||||
namespace ignoremanager
|
||||
{
|
||||
static bool vischeck(CNavArea *begin, CNavArea *end)
|
||||
static ignore_status vischeck(CNavArea *begin, CNavArea *end)
|
||||
{
|
||||
Vector first = begin->m_center;
|
||||
Vector second = end->m_center;
|
||||
first.z += 42;
|
||||
second.z += 42;
|
||||
return IsVectorVisible(first, second, true, LOCAL_E, MASK_PLAYERSOLID);
|
||||
first.z += 70;
|
||||
second.z += 70;
|
||||
// Is world blocking it?
|
||||
if (IsVectorVisibleNavigation(first, second, MASK_PLAYERSOLID))
|
||||
{
|
||||
// Is something else blocking it?
|
||||
if (!IsVectorVisible(first, second, true, LOCAL_E, MASK_PLAYERSOLID))
|
||||
return vischeck_blockedentity;
|
||||
else
|
||||
return vischeck_success;
|
||||
}
|
||||
return vischeck_failed;
|
||||
}
|
||||
static ignore_status runIgnoreChecks(CNavArea *begin, CNavArea *end)
|
||||
{
|
||||
if (getZBetweenAreas(begin, end) > 42)
|
||||
// No z check Should be done for stairs as they can go very far up
|
||||
if (getZBetweenAreas(begin, end) > 70)
|
||||
return const_ignored;
|
||||
if (!vischecks)
|
||||
return vischeck_success;
|
||||
if (vischeck(begin, end))
|
||||
return vischeck_success;
|
||||
else
|
||||
return vischeck_failed;
|
||||
return vischeck(begin, end);
|
||||
}
|
||||
static void updateDanger()
|
||||
{
|
||||
@ -249,12 +261,21 @@ static void checkPath()
|
||||
ignoredata &data = ignores[{ begin, end }];
|
||||
if (data.status == vischeck_failed)
|
||||
return;
|
||||
if (!vischeck(begin, end))
|
||||
if (data.status == vischeck_blockedentity && vischeckBlock)
|
||||
return;
|
||||
auto vis_status = vischeck(begin, end);
|
||||
if (vis_status == vischeck_failed)
|
||||
{
|
||||
data.status = vischeck_failed;
|
||||
data.ignoreTimeout.update();
|
||||
perform_repath = true;
|
||||
}
|
||||
else if (vis_status == vischeck_blockedentity && vischeckBlock)
|
||||
{
|
||||
data.status = vischeck_blockedentity;
|
||||
data.ignoreTimeout.update();
|
||||
perform_repath = true;
|
||||
}
|
||||
else if (ignores[{ end, nullptr }].status == danger_found)
|
||||
{
|
||||
perform_repath = true;
|
||||
@ -273,7 +294,7 @@ static int isIgnored(CNavArea *begin, CNavArea *end)
|
||||
status = runIgnoreChecks(begin, end);
|
||||
if (status == vischeck_success)
|
||||
return 0;
|
||||
else if (status == vischeck_failed)
|
||||
else if (status == vischeck_blockedentity && !vischeckBlock)
|
||||
return 1;
|
||||
else
|
||||
return 2;
|
||||
@ -351,6 +372,7 @@ static void updateIgnores()
|
||||
}
|
||||
break;
|
||||
case vischeck_failed:
|
||||
case vischeck_blockedentity:
|
||||
case vischeck_success:
|
||||
default:
|
||||
if (i.second.ignoreTimeout.check(30000))
|
||||
@ -399,11 +421,16 @@ struct Graph : public micropather::Graph
|
||||
continue;
|
||||
float distance = center->m_center.DistTo(i.area->m_center);
|
||||
if (isIgnored == 1)
|
||||
distance += 2000;
|
||||
// Check priority based on usage
|
||||
else
|
||||
{
|
||||
if (*vischeckBlock)
|
||||
continue;
|
||||
distance += 50000;
|
||||
float score = area_score[neighbour->m_id];
|
||||
// Formula to calculate by how much % to reduce the distance by (https://xaktly.com/LogisticFunctions.html)
|
||||
float multiplier = 2.0f * ((0.9f) / (1.0f + exp(-0.8f * score)) - 0.45f);
|
||||
distance *= 1.0f - multiplier;
|
||||
}
|
||||
|
||||
adjacent->emplace_back(micropather::StateCost{ reinterpret_cast<void *>(neighbour), distance });
|
||||
}
|
||||
}
|
||||
@ -460,6 +487,7 @@ void initThread()
|
||||
|
||||
void init()
|
||||
{
|
||||
area_score.clear();
|
||||
endPoint.Invalidate();
|
||||
ignoremanager::reset();
|
||||
status = initing;
|
||||
@ -509,7 +537,7 @@ CNavArea *findClosestNavSquare(const Vector &vec)
|
||||
bestSquare = &i;
|
||||
}
|
||||
// Check if we are within x and y bounds of an area
|
||||
if (ovBestDist >= dist || !i.IsOverlapping(vec) || !IsVectorVisible(vec, i.m_center, true, LOCAL_E, MASK_PLAYERSOLID))
|
||||
if (ovBestDist >= dist || !i.IsOverlapping(vec) || !IsVectorVisibleNavigation(vec, i.m_center, MASK_PLAYERSOLID))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
@ -536,15 +564,19 @@ std::vector<CNavArea *> findPath(const Vector &start, const Vector &end)
|
||||
if (!(local = findClosestNavSquare(start)) || !(dest = findClosestNavSquare(end)))
|
||||
return {};
|
||||
|
||||
logging::Info("Start: (%f,%f,%f)", local->m_center.x, local->m_center.y, local->m_center.z);
|
||||
logging::Info("End: (%f,%f,%f)", dest->m_center.x, dest->m_center.y, dest->m_center.z);
|
||||
if (log_pathing)
|
||||
{
|
||||
logging::Info("Start: (%f,%f,%f)", local->m_center.x, local->m_center.y, local->m_center.z);
|
||||
logging::Info("End: (%f,%f,%f)", dest->m_center.x, dest->m_center.y, dest->m_center.z);
|
||||
}
|
||||
float cost;
|
||||
std::vector<CNavArea *> pathNodes;
|
||||
|
||||
time_point begin_pathing = high_resolution_clock::now();
|
||||
int result = Map.pather->Solve(reinterpret_cast<void *>(local), reinterpret_cast<void *>(dest), reinterpret_cast<std::vector<void *> *>(&pathNodes), &cost);
|
||||
long long timetaken = duration_cast<nanoseconds>(high_resolution_clock::now() - begin_pathing).count();
|
||||
logging::Info("Pathing: Pather result: %i. Time taken (NS): %lld", result, timetaken);
|
||||
if (log_pathing)
|
||||
logging::Info("Pathing: Pather result: %i. Time taken (NS): %lld", result, timetaken);
|
||||
// If no result found, return empty Vector
|
||||
if (result == micropather::MicroPather::NO_SOLUTION)
|
||||
return {};
|
||||
@ -612,12 +644,39 @@ void repath()
|
||||
navTo(last, curr_priority, true, true, true);
|
||||
}
|
||||
|
||||
// Track pather resets
|
||||
static Timer reset_pather_timer{};
|
||||
// Update area score to prefer paths used by actual players a bit more
|
||||
void updateAreaScore()
|
||||
{
|
||||
for (int i = 1; i <= g_IEngine->GetMaxClients(); i++)
|
||||
{
|
||||
CachedEntity *ent = ENTITY(i);
|
||||
if (i == g_pLocalPlayer->entity_idx || CE_INVALID(ent) || !g_pPlayerResource->isAlive(i))
|
||||
continue;
|
||||
|
||||
// Get area
|
||||
CNavArea *closest_area = nullptr;
|
||||
if (ent->m_vecDormantOrigin())
|
||||
findClosestNavSquare(*ent->m_vecDormantOrigin());
|
||||
|
||||
// Add usage to area if valid
|
||||
if (closest_area)
|
||||
area_score[closest_area->m_id] += g_GlobalVars->interval_per_tick;
|
||||
}
|
||||
if (reset_pather_timer.test_and_set(10000))
|
||||
ResetPather();
|
||||
}
|
||||
|
||||
static Timer last_jump{};
|
||||
// Main movement function, gets path from NavTo
|
||||
static void cm()
|
||||
{
|
||||
if (!enabled || status != on)
|
||||
return;
|
||||
// Run the logic for Nav area score
|
||||
updateAreaScore();
|
||||
|
||||
if (CE_BAD(LOCAL_E) || CE_BAD(LOCAL_W))
|
||||
return;
|
||||
if (!LOCAL_E->m_bAlivePlayer())
|
||||
@ -627,6 +686,7 @@ static void cm()
|
||||
return;
|
||||
}
|
||||
ignoremanager::updateIgnores();
|
||||
|
||||
auto crumb = crumbs.begin();
|
||||
const Vector *crumb_vec;
|
||||
// Crumbs empty, prepare for next instruction
|
||||
@ -676,12 +736,21 @@ static void cm()
|
||||
current_user_cmd->viewangles = next;
|
||||
}
|
||||
// Detect when jumping is necessary
|
||||
if ((!(g_pLocalPlayer->holding_sniper_rifle && g_pLocalPlayer->bZoomed) && crumb_vec->z - g_pLocalPlayer->v_Origin.z > 18 && last_jump.test_and_set(200)) || (last_jump.test_and_set(200) && inactivity.check(*stuck_time / 2)))
|
||||
if ((!(g_pLocalPlayer->holding_sniper_rifle && g_pLocalPlayer->bZoomed) && crumb_vec->z - g_pLocalPlayer->v_Origin.z > 18 && last_jump.check(200)) || (last_jump.check(200) && inactivity.check(*stuck_time / 2)))
|
||||
{
|
||||
auto local = findClosestNavSquare(g_pLocalPlayer->v_Origin);
|
||||
// Check if current area allows jumping
|
||||
if (!local || !(local->m_attributeFlags & NAV_MESH_NO_JUMP))
|
||||
current_user_cmd->buttons |= (IN_JUMP | IN_DUCK);
|
||||
if (!local || !(local->m_attributeFlags & (NAV_MESH_NO_JUMP | NAV_MESH_STAIRS)))
|
||||
{
|
||||
static bool flip_action = false;
|
||||
// Make it crouch the second tick
|
||||
current_user_cmd->buttons |= flip_action ? IN_DUCK : IN_JUMP;
|
||||
|
||||
// Update jump timer now
|
||||
if (flip_action)
|
||||
last_jump.update();
|
||||
flip_action = !flip_action;
|
||||
}
|
||||
}
|
||||
// Walk to next crumb
|
||||
WalkTo(*crumb_vec);
|
||||
|
@ -199,7 +199,7 @@ bool ChangeState(unsigned int steamid, k_EState state, bool force)
|
||||
else
|
||||
return false;
|
||||
case k_EState::PARTY:
|
||||
if (state == k_EState::TEXTMODE || state == k_EState::FRIEND)
|
||||
if (state == k_EState::FRIEND)
|
||||
{
|
||||
ChangeState(steamid, state, true);
|
||||
return true;
|
||||
|
43
src/teamroundtimer.cpp
Normal file
43
src/teamroundtimer.cpp
Normal file
@ -0,0 +1,43 @@
|
||||
#include "common.hpp"
|
||||
#include "teamroundtimer.hpp"
|
||||
|
||||
int CTeamRoundTimer::GetSetupTimeLength()
|
||||
{
|
||||
IClientEntity *ent;
|
||||
ent = g_IEntityList->GetClientEntity(entity);
|
||||
if (!ent || ent->GetClientClass()->m_ClassID != CL_CLASS(CTeamRoundTimer))
|
||||
return -1;
|
||||
return NET_INT(ent, netvar.m_nSetupTimeLength);
|
||||
};
|
||||
|
||||
round_states CTeamRoundTimer::GetRoundState()
|
||||
{
|
||||
IClientEntity *ent;
|
||||
ent = g_IEntityList->GetClientEntity(entity);
|
||||
if (!ent || ent->GetClientClass()->m_ClassID != CL_CLASS(CTeamRoundTimer))
|
||||
return RT_STATE_NORMAL;
|
||||
int state = NET_INT(ent, netvar.m_nState);
|
||||
return state == 1 ? RT_STATE_NORMAL : RT_STATE_SETUP;
|
||||
};
|
||||
|
||||
void CTeamRoundTimer::Update()
|
||||
{
|
||||
IClientEntity *ent;
|
||||
|
||||
entity = 0;
|
||||
for (int i = 0; i <= HIGHEST_ENTITY; i++)
|
||||
{
|
||||
ent = g_IEntityList->GetClientEntity(i);
|
||||
if (ent && ent->GetClientClass()->m_ClassID == CL_CLASS(CTeamRoundTimer))
|
||||
{
|
||||
entity = i;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
CTeamRoundTimer *g_pTeamRoundTimer{ nullptr };
|
||||
|
||||
static InitRoutine init_trt([]() {
|
||||
EC::Register(
|
||||
EC::CreateMove, []() { g_pTeamRoundTimer->Update(); }, "update_teamroundtimer", EC::early);
|
||||
});
|
@ -108,6 +108,47 @@ TraceType_t trace::FilterNoPlayer::GetTraceType() const
|
||||
{
|
||||
return TRACE_EVERYTHING;
|
||||
}
|
||||
|
||||
/* Navigation filter */
|
||||
|
||||
trace::FilterNavigation::FilterNavigation(){};
|
||||
|
||||
trace::FilterNavigation::~FilterNavigation(){};
|
||||
|
||||
#define MOVEMENT_COLLISION_GROUP 8
|
||||
#define RED_CONTENTS_MASK 0x800
|
||||
#define BLU_CONTENTS_MASK 0x1000
|
||||
bool trace::FilterNavigation::ShouldHitEntity(IHandleEntity *handle, int mask)
|
||||
{
|
||||
IClientEntity *entity;
|
||||
ClientClass *clazz;
|
||||
|
||||
if (!handle)
|
||||
return false;
|
||||
entity = (IClientEntity *) handle;
|
||||
clazz = entity->GetClientClass();
|
||||
|
||||
// Ignore everything that is not the world or a CBaseEntity
|
||||
if (entity->entindex() != 0 && clazz->m_ClassID != CL_CLASS(CBaseEntity))
|
||||
{
|
||||
// Besides respawn room areas, we want to explicitly ignore those if they are not on our team
|
||||
if (clazz->m_ClassID == CL_CLASS(CFuncRespawnRoomVisualizer))
|
||||
if (CE_GOOD(LOCAL_E) && (g_pLocalPlayer->team == TEAM_RED || g_pLocalPlayer->team == TEAM_BLU))
|
||||
{
|
||||
// If we can't collide, hit it
|
||||
if (!re::C_BaseEntity::ShouldCollide(entity, MOVEMENT_COLLISION_GROUP, g_pLocalPlayer->team == TEAM_RED ? RED_CONTENTS_MASK : BLU_CONTENTS_MASK))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
TraceType_t trace::FilterNavigation::GetTraceType() const
|
||||
{
|
||||
return TRACE_EVERYTHING;
|
||||
}
|
||||
|
||||
/* No-Entity filter */
|
||||
|
||||
trace::FilterNoEntity::FilterNoEntity()
|
||||
@ -215,5 +256,6 @@ void trace::FilterPenetration::Reset()
|
||||
|
||||
trace::FilterDefault trace::filter_default{};
|
||||
trace::FilterNoPlayer trace::filter_no_player{};
|
||||
trace::FilterNavigation trace::filter_navigation{};
|
||||
trace::FilterNoEntity trace::filter_no_entity{};
|
||||
trace::FilterPenetration trace::filter_penetration{};
|
||||
|
Reference in New Issue
Block a user