Merge branch 'nav_improve' into octopus-merge
This commit is contained in:
commit
962dc06492
@ -30,20 +30,25 @@
|
||||
</Box>
|
||||
<Box padding="12 6 6 6" width="content" height="content" name="NavBot" y="65">
|
||||
<List width="150">
|
||||
<AutoVariable width="fill" target="misc.pathing" label="Enable pathing"/>
|
||||
<AutoVariable width="fill" target="misc.pathing.draw" label="Draw path"/>
|
||||
<AutoVariable width="fill" target="misc.pathing.look-at-path" label="Look at path"/>
|
||||
<AutoVariable width="fill" target="nav.enabled" label="Enable pathing"/>
|
||||
<AutoVariable width="fill" target="nav.draw" label="Draw path"/>
|
||||
<AutoVariable width="fill" target="nav.look-at-path" label="Look at path"/>
|
||||
<AutoVariable width="fill" target="navbot.enabled" label="Enable NavBot"/>
|
||||
<AutoVariable width="fill" target="navbot.engineer-mode" label="Enable Engineer mode"/>
|
||||
<AutoVariable width="fill" target="navbot.get-health-and-ammo" label="Get health and ammo"/>
|
||||
<AutoVariable width="fill" target="navbot.spy-mode" label="Enable Spy mode"/>
|
||||
<AutoVariable width="fill" target="navbot.other-mode" label="General mode"/>
|
||||
<AutoVariable width="fill" target="navbot.capture-objectives" label="Capture objectives" tooltip="Automatically capture objectives (CTF,CP and PL only)"/>
|
||||
<!--AutoVariable width="fill" target="navbot.engineer-mode" label="Enable Engineer mode"/-->
|
||||
<AutoVariable width="fill" target="navbot.search-health" label="Search health"/>
|
||||
<AutoVariable width="fill" target="navbot.search-ammo" label="Search ammo"/>
|
||||
<AutoVariable width="fill" target="navbot.escape-danger" label="Escape danger"/>
|
||||
<AutoVariable width="fill" target="navbot.escape-danger.slight-danger.capping" label="Safe capping" tooltip="Make bots run pre-emptively from capture points in case of danger"/>
|
||||
<AutoVariable width="fill" target="navbot.escape-danger.ctf-cap" label="Escape danger w. intel" tooltip="Also try to escape from danger when carrying intel."/>
|
||||
<!--AutoVariable width="fill" target="navbot.spy-mode" label="Enable Spy mode"/>
|
||||
<AutoVariable width="fill" target="navbot.other-mode" label="General mode"/-->
|
||||
<AutoVariable width="fill" target="navbot.primary-only" label="Best weapon only"/>
|
||||
<AutoVariable width="fill" target="navbot.autojump.enabled" label="Enable autojump"/>
|
||||
<AutoVariable width="fill" target="navbot.autojump.trigger-distance" label="Jump distance"/>
|
||||
<!--AutoVariable width="fill" target="navbot.target-sentry" label="Try to target sentries"/-->
|
||||
<AutoVariable width="fill" target="navbot.stay-near" label="Zone enemies (stay near)"/>
|
||||
<AutoVariable width="fill" target="navbot.spy-ignore-time" label="Spy ignore time"/>
|
||||
<AutoVariable width="fill" target="navbot.snipe-sentries" label="Try to target sentries"/>
|
||||
<AutoVariable width="fill" target="navbot.snipe-sentries.shortrange" label="Scout/Pyro sentry mode" tooltip="Try to target sentries as scout/pyro aswell. Usually not recommended."/>
|
||||
<AutoVariable width="fill" target="navbot.stay-near" label="Stalk enemies" tooltip="Try to outrange as sniper and close distance as scout/heavy"/>
|
||||
<!-- <!AutoVariable width="fill" target="navbot.take-teleporters" label="take teleporters"/> -->
|
||||
</List>
|
||||
</Box>
|
||||
|
2
external/TF2_NavFile_Reader
vendored
2
external/TF2_NavFile_Reader
vendored
@ -1 +1 @@
|
||||
Subproject commit 5f2940c4707127db1581e5708eecca1d6130610f
|
||||
Subproject commit 55ae8047a24203cec834f54fd67ee6d571f497f6
|
85
include/CaptureLogic.hpp
Normal file
85
include/CaptureLogic.hpp
Normal file
@ -0,0 +1,85 @@
|
||||
#pragma once
|
||||
|
||||
#include <entitycache.hpp>
|
||||
|
||||
// Tf2 flag types
|
||||
enum ETFFlagType
|
||||
{
|
||||
TF_FLAGTYPE_CTF = 0,
|
||||
TF_FLAGTYPE_ATTACK_DEFEND,
|
||||
TF_FLAGTYPE_TERRITORY_CONTROL,
|
||||
TF_FLAGTYPE_INVADE,
|
||||
TF_FLAGTYPE_RESOURCE_CONTROL,
|
||||
TF_FLAGTYPE_ROBOT_DESTRUCTION,
|
||||
TF_FLAGTYPE_PLAYER_DESTRUCTION
|
||||
|
||||
//
|
||||
// ADD NEW ITEMS HERE TO AVOID BREAKING DEMOS
|
||||
//
|
||||
};
|
||||
|
||||
// Flag Drop status
|
||||
enum ETFFlagStatus
|
||||
{
|
||||
TF_FLAGINFO_HOME = 0,
|
||||
TF_FLAGINFO_STOLEN,
|
||||
TF_FLAGINFO_DROPPED
|
||||
};
|
||||
|
||||
struct flag_info
|
||||
{
|
||||
CachedEntity *ent{ nullptr };
|
||||
std::optional<Vector> spawn_pos;
|
||||
int team{ TEAM_UNK };
|
||||
flag_info(){};
|
||||
flag_info(CachedEntity *ent, Vector spawn_pos, int team)
|
||||
{
|
||||
this->ent = ent;
|
||||
this->spawn_pos = spawn_pos;
|
||||
this->team = team;
|
||||
}
|
||||
};
|
||||
|
||||
struct pl_info
|
||||
{
|
||||
CachedEntity *ent;
|
||||
std::optional<Vector> position;
|
||||
pl_info(){};
|
||||
};
|
||||
|
||||
#define MAX_CONTROL_POINTS 8
|
||||
#define MAX_PREVIOUS_POINTS 3
|
||||
struct cp_info
|
||||
{
|
||||
// Index in the ObjectiveResource
|
||||
int cp_index{ -1 };
|
||||
std::optional<Vector> position;
|
||||
// For BLU and RED to show who can and who cannnot cap
|
||||
std::array<bool, 2> can_cap{};
|
||||
cp_info(){};
|
||||
};
|
||||
|
||||
namespace flagcontroller
|
||||
{
|
||||
// Use incase you don't get the needed information from the functions below
|
||||
flag_info getFlag(int team);
|
||||
|
||||
Vector getPosition(CachedEntity *flag);
|
||||
std::optional<Vector> getPosition(int team);
|
||||
CachedEntity *getCarrier(CachedEntity *flag);
|
||||
CachedEntity *getCarrier(int team);
|
||||
ETFFlagStatus getStatus(CachedEntity *flag);
|
||||
ETFFlagStatus getStatus(int team);
|
||||
} // namespace flagcontroller
|
||||
|
||||
namespace plcontroller
|
||||
{
|
||||
// Get the closest Control Payload
|
||||
std::optional<Vector> getClosestPayload(Vector source, int team);
|
||||
} // namespace plcontroller
|
||||
|
||||
namespace cpcontroller
|
||||
{
|
||||
// Get the closest Control Point we can cap
|
||||
std::optional<Vector> getClosestControlPoint(Vector source, int team);
|
||||
} // namespace cpcontroller
|
@ -73,7 +73,6 @@
|
||||
#include "core/sharedobj.hpp"
|
||||
#include "init.hpp"
|
||||
#include "reclasses/reclasses.hpp"
|
||||
#include <CNavFile.h>
|
||||
#include "HookTools.hpp"
|
||||
#include "bytepatch.hpp"
|
||||
|
||||
|
@ -83,6 +83,7 @@ public:
|
||||
offset_t m_bPlacing;
|
||||
offset_t m_bBuilding;
|
||||
offset_t m_bPlasmaDisable;
|
||||
offset_t m_bCarryDeploy;
|
||||
|
||||
// teleporter
|
||||
offset_t m_iTeleState; // teleport state [1 = idle, 2 = active, 3 = teleporting, 4 = charging]
|
||||
@ -204,6 +205,19 @@ public:
|
||||
offset_t m_iHealingAssist_Resource;
|
||||
offset_t m_iPlayerLevel_Resource;
|
||||
|
||||
offset_t m_nFlagType;
|
||||
offset_t m_nFlagStatus;
|
||||
|
||||
offset_t m_bTeamCanCap;
|
||||
offset_t m_iNumControlPoints;
|
||||
offset_t m_vCPPositions;
|
||||
offset_t m_iOwningTeam;
|
||||
offset_t m_bCPLocked;
|
||||
offset_t m_bPlayingMiniRounds;
|
||||
offset_t m_bInMiniRound;
|
||||
offset_t m_iPreviousPoints;
|
||||
offset_t m_iBaseControlPoints;
|
||||
|
||||
offset_t m_iPlayerIndex;
|
||||
offset_t m_hTargetPlayer;
|
||||
offset_t m_flResetTime;
|
||||
|
@ -36,6 +36,7 @@ bool BacktrackVisCheck(CachedEntity *entity);
|
||||
void Reset();
|
||||
|
||||
// Stuff to make storing functions easy
|
||||
bool isAiming();
|
||||
CachedEntity *CurrentTarget();
|
||||
bool ShouldAim();
|
||||
CachedEntity *RetrieveBestTarget(bool aimkey_state);
|
||||
|
@ -1,4 +1,4 @@
|
||||
#pragma once
|
||||
/*#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <stdint.h>
|
||||
@ -19,7 +19,8 @@ enum task : uint8_t
|
||||
dispenser,
|
||||
followbot,
|
||||
outofbounds,
|
||||
engineer
|
||||
engineer,
|
||||
capture
|
||||
};
|
||||
|
||||
enum engineer_task : uint8_t
|
||||
@ -70,3 +71,4 @@ struct bot_class_config
|
||||
float max;
|
||||
};
|
||||
} // namespace hacks::tf2::NavBot
|
||||
*/
|
@ -203,7 +203,7 @@ float GetFov(Vector ang, Vector src, Vector dst);
|
||||
void ReplaceString(std::string &input, const std::string &what, const std::string &with_what);
|
||||
void ReplaceSpecials(std::string &input);
|
||||
|
||||
std::pair<float, float> ComputeMove(const Vector &a, const Vector &b);
|
||||
Vector ComputeMove(const Vector &a, const Vector &b);
|
||||
std::pair<float, float> ComputeMovePrecise(const Vector &a, const Vector &b);
|
||||
void WalkTo(const Vector &vector);
|
||||
|
||||
|
@ -36,6 +36,8 @@ public:
|
||||
char life_state;
|
||||
int clazz;
|
||||
bool bZoomed;
|
||||
bool bRevving;
|
||||
bool bRevved;
|
||||
float flZoomBegin;
|
||||
bool holding_sniper_rifle;
|
||||
bool holding_sapper;
|
||||
|
@ -1,42 +1,101 @@
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include "mathlib/vector.h"
|
||||
#include <vector>
|
||||
#include "CNavFile.h"
|
||||
|
||||
class CNavFile;
|
||||
class CNavArea;
|
||||
|
||||
namespace nav
|
||||
enum Priority_list
|
||||
{
|
||||
|
||||
enum init_status : uint8_t
|
||||
{
|
||||
off = 0,
|
||||
unavailable,
|
||||
initing,
|
||||
on
|
||||
patrol = 5,
|
||||
lowprio_health,
|
||||
staynear,
|
||||
snipe_sentry,
|
||||
followbot,
|
||||
ammo,
|
||||
capture,
|
||||
health,
|
||||
danger,
|
||||
};
|
||||
|
||||
// Call prepare first and check its return value
|
||||
extern std::unique_ptr<CNavFile> navfile;
|
||||
namespace navparser
|
||||
{
|
||||
constexpr float PLAYER_WIDTH = 49;
|
||||
constexpr float HALF_PLAYER_WIDTH = PLAYER_WIDTH / 2.0f;
|
||||
constexpr float PLAYER_JUMP_HEIGHT = 72.0f;
|
||||
|
||||
// Current path priority
|
||||
extern int curr_priority;
|
||||
// Check if ready to recieve another NavTo (to avoid overwriting of
|
||||
// instructions)
|
||||
extern bool ReadyForCommands;
|
||||
// Ignore. For level init only
|
||||
extern std::atomic<init_status> status;
|
||||
#define TICKCOUNT_TIMESTAMP(seconds) (g_GlobalVars->tickcount + int(seconds / g_GlobalVars->interval_per_tick))
|
||||
|
||||
// Nav to vector
|
||||
bool navTo(const Vector &destination, int priority = 5, bool should_repath = true, bool nav_to_local = true, bool is_repath = false);
|
||||
// Find closest to vector area
|
||||
CNavArea *findClosestNavSquare(const Vector &vec);
|
||||
// Check and init navparser
|
||||
bool prepare();
|
||||
// Clear current path
|
||||
void clearInstructions();
|
||||
// Check if area is safe from stickies and sentries
|
||||
bool isSafe(CNavArea *area);
|
||||
// Basic Blacklist reasons, you can add your own externally and use them
|
||||
enum BlacklistReason_enum
|
||||
{
|
||||
SENTRY,
|
||||
STICKY,
|
||||
ENEMY_NORMAL,
|
||||
ENEMY_DORMANT,
|
||||
// Always last
|
||||
BLACKLIST_LENGTH
|
||||
};
|
||||
|
||||
} // namespace nav
|
||||
class BlacklistReason
|
||||
{
|
||||
public:
|
||||
BlacklistReason_enum value;
|
||||
int time = 0;
|
||||
void operator=(BlacklistReason_enum const &reason)
|
||||
{
|
||||
this->value = reason;
|
||||
}
|
||||
BlacklistReason()
|
||||
{
|
||||
this->value = (BlacklistReason_enum) -1;
|
||||
this->time = 0;
|
||||
}
|
||||
BlacklistReason(BlacklistReason_enum reason)
|
||||
{
|
||||
this->value = reason;
|
||||
this->time = 0;
|
||||
}
|
||||
BlacklistReason(BlacklistReason_enum reason, int time)
|
||||
{
|
||||
this->value = reason;
|
||||
this->time = time;
|
||||
}
|
||||
};
|
||||
|
||||
struct Crumb
|
||||
{
|
||||
CNavArea *navarea;
|
||||
Vector vec;
|
||||
};
|
||||
|
||||
namespace NavEngine
|
||||
{
|
||||
|
||||
// Is the Nav engine ready to run?
|
||||
bool isReady();
|
||||
// Are we currently pathing?
|
||||
bool isPathing();
|
||||
CNavFile *getNavFile();
|
||||
// Get closest nav square to target vector
|
||||
CNavArea *findClosestNavSquare(const Vector origin);
|
||||
// Get the path nodes
|
||||
std::vector<Crumb> *getCrumbs();
|
||||
bool navTo(const Vector &destination, int priority = 5, bool should_repath = true, bool nav_to_local = true, bool is_repath = true);
|
||||
// Use when something unexpected happens, e.g. vischeck fails
|
||||
void abandonPath();
|
||||
// Use to cancel pathing completely
|
||||
void cancelPath();
|
||||
|
||||
// Return the whole thing
|
||||
std::unordered_map<CNavArea *, BlacklistReason> *getFreeBlacklist();
|
||||
// Return a specific category, we keep the same indexes to provide single element erasing
|
||||
std::unordered_map<CNavArea *, BlacklistReason> getFreeBlacklist(BlacklistReason reason);
|
||||
|
||||
// Clear whole blacklist
|
||||
void clearFreeBlacklist();
|
||||
// Clear by category
|
||||
void clearFreeBlacklist(BlacklistReason reason);
|
||||
|
||||
extern int current_priority;
|
||||
} // namespace NavEngine
|
||||
} // namespace navparser
|
||||
|
@ -13,4 +13,6 @@ public:
|
||||
int roundmode; // 48 | 4 bytes | 52
|
||||
int pad1[1]; // 52 | 4 bytes | 56
|
||||
int winning_team; // 56 | 4 bytes | 60
|
||||
char pad2[974]; // 60 | 974 bytes | 1034
|
||||
bool isPVEMode; // 1034 | 1 byte | 1035
|
||||
};
|
||||
|
@ -1,4 +1,5 @@
|
||||
set(files "${CMAKE_CURRENT_LIST_DIR}/angles.cpp"
|
||||
"${CMAKE_CURRENT_LIST_DIR}/CaptureLogic.cpp"
|
||||
"${CMAKE_CURRENT_LIST_DIR}/chatlog.cpp"
|
||||
"${CMAKE_CURRENT_LIST_DIR}/chatstack.cpp"
|
||||
"${CMAKE_CURRENT_LIST_DIR}/conditions.cpp"
|
||||
|
492
src/CaptureLogic.cpp
Normal file
492
src/CaptureLogic.cpp
Normal file
@ -0,0 +1,492 @@
|
||||
#include "CaptureLogic.hpp"
|
||||
#include "common.hpp"
|
||||
|
||||
namespace flagcontroller
|
||||
{
|
||||
|
||||
std::array<flag_info, 2> flags;
|
||||
bool is_ctf = true;
|
||||
|
||||
// Check if a flag is good or not
|
||||
bool isGoodFlag(CachedEntity *flag)
|
||||
{
|
||||
if (CE_INVALID(flag) || flag->m_iClassID() != CL_CLASS(CCaptureFlag))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
// Not ctf, no need to update
|
||||
if (!is_ctf)
|
||||
return;
|
||||
// Find flags if missing
|
||||
if (!flags[0].ent || !flags[1].ent)
|
||||
for (int i = g_IEngine->GetMaxClients() + 1; i < MAX_ENTITIES; i++)
|
||||
{
|
||||
CachedEntity *ent = ENTITY(i);
|
||||
// We cannot identify a bad entity as a flag due to the unreliability of it
|
||||
if (CE_BAD(ent) || ent->m_iClassID() != CL_CLASS(CCaptureFlag))
|
||||
continue;
|
||||
|
||||
// Store flags
|
||||
if (!flags[0].ent)
|
||||
flags[0].ent = ent;
|
||||
else if (ent != flags[0].ent)
|
||||
flags[1].ent = ent;
|
||||
}
|
||||
// Update flag data
|
||||
for (auto &flag : flags)
|
||||
{
|
||||
// Not inited
|
||||
if (!flag.ent)
|
||||
continue;
|
||||
|
||||
// Bad Flag, reset
|
||||
if (!isGoodFlag(flag.ent))
|
||||
{
|
||||
flag = flag_info();
|
||||
continue;
|
||||
}
|
||||
|
||||
// Cannot use "bad" flag, but it is still potentially valid
|
||||
if (CE_BAD(flag.ent))
|
||||
continue;
|
||||
|
||||
int flag_type = CE_INT(flag.ent, netvar.m_nFlagType);
|
||||
|
||||
// Only CTF support for now
|
||||
if (flag_type != TF_FLAGTYPE_CTF)
|
||||
continue;
|
||||
|
||||
// Assign team if missing
|
||||
if (flag.team == TEAM_UNK)
|
||||
flag.team = flag.ent->m_iTeam();
|
||||
|
||||
// Assign spawn point if it is missing and the flag is at spawn
|
||||
if (!flag.spawn_pos)
|
||||
{
|
||||
int flag_status = CE_INT(flag.ent, netvar.m_nFlagStatus);
|
||||
|
||||
// Flag is home
|
||||
if (flag_status == TF_FLAGINFO_HOME)
|
||||
flag.spawn_pos = flag.ent->m_vecOrigin();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LevelInit()
|
||||
{
|
||||
// Resez everything
|
||||
for (auto &flag : flags)
|
||||
flag = flag_info();
|
||||
is_ctf = true;
|
||||
}
|
||||
|
||||
// Get the info for the flag
|
||||
flag_info getFlag(int team)
|
||||
{
|
||||
for (auto &flag : flags)
|
||||
{
|
||||
if (flag.team == team)
|
||||
return flag;
|
||||
}
|
||||
// None found
|
||||
return flag_info();
|
||||
}
|
||||
|
||||
// Get the Position of a flag on a specific team
|
||||
Vector getPosition(CachedEntity *flag)
|
||||
{
|
||||
return flag->m_vecOrigin();
|
||||
}
|
||||
|
||||
std::optional<Vector> getPosition(int team)
|
||||
{
|
||||
auto flag = getFlag(team);
|
||||
if (isGoodFlag(flag.ent))
|
||||
return getPosition(flag.ent);
|
||||
// No good flag
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
// Get the person carrying the flag
|
||||
CachedEntity *getCarrier(CachedEntity *flag)
|
||||
{
|
||||
int entidx = HandleToIDX(CE_INT(flag, netvar.m_hOwnerEntity));
|
||||
// None/Invalid
|
||||
if (IDX_BAD(entidx))
|
||||
return nullptr;
|
||||
CachedEntity *carrier = ENTITY(entidx);
|
||||
// Carrier is invalid
|
||||
if (CE_BAD(carrier) || carrier->m_Type() != ENTITY_PLAYER)
|
||||
return nullptr;
|
||||
return carrier;
|
||||
}
|
||||
|
||||
// Wrapper for when you don't have the entity
|
||||
CachedEntity *getCarrier(int team)
|
||||
{
|
||||
auto flag = getFlag(team);
|
||||
// Only use good flags
|
||||
if (isGoodFlag(flag.ent))
|
||||
return getCarrier(flag.ent);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Get the status of the flag (Home, being carried, dropped)
|
||||
ETFFlagStatus getStatus(CachedEntity *flag)
|
||||
{
|
||||
return (ETFFlagStatus) CE_INT(flag, netvar.m_nFlagStatus);
|
||||
}
|
||||
|
||||
ETFFlagStatus getStatus(int team)
|
||||
{
|
||||
auto flag = getFlag(team);
|
||||
// Only use good flags
|
||||
if (isGoodFlag(flag.ent))
|
||||
return getStatus(flag.ent);
|
||||
// Mark as home if nothing is found
|
||||
return TF_FLAGINFO_HOME;
|
||||
}
|
||||
} // namespace flagcontroller
|
||||
|
||||
namespace plcontroller
|
||||
{
|
||||
|
||||
// Array that controls all the payloads for each team. Red team is first, then comes blue team.
|
||||
static std::array<std::vector<CachedEntity *>, 2> payloads;
|
||||
static Timer update_payloads{};
|
||||
|
||||
void Update()
|
||||
{
|
||||
// We should update the payload list
|
||||
if (update_payloads.test_and_set(3000))
|
||||
{
|
||||
// Reset entries
|
||||
for (auto &entry : payloads)
|
||||
entry.clear();
|
||||
|
||||
for (int i = g_IEngine->GetMaxClients() + 1; i < MAX_ENTITIES; i++)
|
||||
{
|
||||
CachedEntity *ent = ENTITY(i);
|
||||
// Not the object we need or invalid (team)
|
||||
if (CE_BAD(ent) || ent->m_iClassID() != CL_CLASS(CObjectCartDispenser) || ent->m_iTeam() < TEAM_RED || ent->m_iTeam() > TEAM_BLU)
|
||||
continue;
|
||||
int team = ent->m_iTeam();
|
||||
|
||||
// Add new entry for the team
|
||||
payloads.at(team - TEAM_RED).push_back(ent);
|
||||
}
|
||||
}
|
||||
}
|
||||
std::optional<Vector> getClosestPayload(Vector source, int team)
|
||||
{
|
||||
// Invalid team
|
||||
if (team < TEAM_RED || team > TEAM_BLU)
|
||||
return std::nullopt;
|
||||
// Convert to index
|
||||
int index = team - TEAM_RED;
|
||||
auto entry = payloads[index];
|
||||
|
||||
float best_distance = FLT_MAX;
|
||||
std::optional<Vector> best_pos;
|
||||
|
||||
// Find best payload
|
||||
for (auto payload : entry)
|
||||
{
|
||||
if (CE_BAD(payload) || payload->m_iClassID() != CL_CLASS(CObjectCartDispenser))
|
||||
continue;
|
||||
if (payload->m_vecOrigin().DistTo(source) < best_distance)
|
||||
{
|
||||
best_pos = payload->m_vecOrigin();
|
||||
best_distance = payload->m_vecOrigin().DistTo(source);
|
||||
}
|
||||
}
|
||||
return best_pos;
|
||||
}
|
||||
|
||||
void LevelInit()
|
||||
{
|
||||
for (auto &entry : payloads)
|
||||
entry.clear();
|
||||
}
|
||||
} // namespace plcontroller
|
||||
|
||||
namespace cpcontroller
|
||||
{
|
||||
|
||||
std::array<cp_info, MAX_CONTROL_POINTS> controlpoint_data;
|
||||
CachedEntity *objective_resource = nullptr;
|
||||
|
||||
struct point_ignore
|
||||
{
|
||||
std::string mapname;
|
||||
int point_idx;
|
||||
point_ignore(std::string str, int idx) : mapname{ str }, point_idx{ idx } {};
|
||||
};
|
||||
|
||||
// TODO: Find a way to fix these edge-cases.
|
||||
// clang-format off
|
||||
std::array<point_ignore, 1> ignore_points
|
||||
{
|
||||
point_ignore("cp_steel", 4)
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
// This function updates the Entity used for the Object resource
|
||||
void UpdateObjectiveResource()
|
||||
{
|
||||
// Already set and valid
|
||||
if (CE_GOOD(objective_resource) && objective_resource->m_iClassID() == CL_CLASS(CTFObjectiveResource))
|
||||
return;
|
||||
// Find ObjectiveResource and gamerules
|
||||
for (int i = g_IEngine->GetMaxClients() + 1; i < MAX_ENTITIES; i++)
|
||||
{
|
||||
CachedEntity *ent = ENTITY(i);
|
||||
if (CE_BAD(ent) || ent->m_iClassID() != CL_CLASS(CTFObjectiveResource))
|
||||
continue;
|
||||
// Found it
|
||||
objective_resource = ent;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// A Bunch of defines for netvars that don't deserve their own function
|
||||
#define GET_NUM_CONTROL_POINTS() (CE_INT(objective_resource, netvar.m_iNumControlPoints))
|
||||
#define GET_OWNING_TEAM(index) ((&CE_INT(objective_resource, netvar.m_iOwningTeam))[index])
|
||||
#define GET_BASE_CONTROL_POINT_FOR_TEAM(team) ((&CE_INT(objective_resource, netvar.m_iBaseControlPoints))[team])
|
||||
#define GET_CP_LOCKED(index) ((&CE_VAR(objective_resource, netvar.m_bCPLocked, bool))[index])
|
||||
#define IN_MINI_ROUND(index) ((&CE_VAR(objective_resource, netvar.m_bInMiniRound, bool))[index])
|
||||
|
||||
bool TeamCanCapPoint(int index, int team)
|
||||
{
|
||||
int arr_index = index + team * MAX_CONTROL_POINTS;
|
||||
return (&CE_VAR(objective_resource, netvar.m_bTeamCanCap, bool))[arr_index];
|
||||
}
|
||||
|
||||
int GetPreviousPointForPoint(int index, int team, int previndex)
|
||||
{
|
||||
int iIntIndex = previndex + (index * MAX_PREVIOUS_POINTS) + (team * MAX_CONTROL_POINTS * MAX_PREVIOUS_POINTS);
|
||||
return (&CE_INT(objective_resource, netvar.m_iPreviousPoints))[iIntIndex];
|
||||
}
|
||||
|
||||
int GetFarthestOwnedControlPoint(int team)
|
||||
{
|
||||
int iOwnedEnd = GET_BASE_CONTROL_POINT_FOR_TEAM(team);
|
||||
if (iOwnedEnd == -1)
|
||||
return -1;
|
||||
|
||||
int iNumControlPoints = GET_NUM_CONTROL_POINTS();
|
||||
int iWalk = 1;
|
||||
int iEnemyEnd = iNumControlPoints - 1;
|
||||
if (iOwnedEnd != 0)
|
||||
{
|
||||
iWalk = -1;
|
||||
iEnemyEnd = 0;
|
||||
}
|
||||
|
||||
// Walk towards the other side, and find the farthest owned point
|
||||
int iFarthestPoint = iOwnedEnd;
|
||||
for (int iPoint = iOwnedEnd; iPoint != iEnemyEnd; iPoint += iWalk)
|
||||
{
|
||||
// If we've hit a point we don't own, we're done
|
||||
if (GET_OWNING_TEAM(iPoint) != team)
|
||||
break;
|
||||
|
||||
iFarthestPoint = iPoint;
|
||||
}
|
||||
|
||||
return iFarthestPoint;
|
||||
}
|
||||
|
||||
// Can we cap this point?
|
||||
bool isPointUseable(int index, int team)
|
||||
{
|
||||
// We Own it, can't cap it
|
||||
if (GET_OWNING_TEAM(index) == team)
|
||||
return false;
|
||||
|
||||
// Can we cap the point?
|
||||
if (!TeamCanCapPoint(index, team))
|
||||
return false;
|
||||
|
||||
// We are playing a sectioned map, check if the CP is in it
|
||||
if (CE_VAR(objective_resource, netvar.m_bPlayingMiniRounds, bool) && !IN_MINI_ROUND(index))
|
||||
return false;
|
||||
|
||||
// Is the point locked?
|
||||
if (GET_CP_LOCKED(index))
|
||||
return false;
|
||||
|
||||
// Linear cap means that it won't require previous points, bail
|
||||
static auto tf_caplinear = g_ICvar->FindVar("tf_caplinear");
|
||||
if (tf_caplinear && !tf_caplinear->GetBool())
|
||||
return true;
|
||||
|
||||
// Any previous points necessary?
|
||||
int iPointNeeded = GetPreviousPointForPoint(index, team, 0);
|
||||
|
||||
// Points set to require themselves are always cappable
|
||||
if (iPointNeeded == index)
|
||||
return true;
|
||||
|
||||
// No required points specified? Require all previous points.
|
||||
if (iPointNeeded == -1)
|
||||
{
|
||||
// No Mini rounds
|
||||
if (!CE_VAR(objective_resource, netvar.m_bPlayingMiniRounds, bool))
|
||||
{
|
||||
// No custom previous point, team must own all previous points
|
||||
int iFarthestPoint = GetFarthestOwnedControlPoint(team);
|
||||
return (abs(iFarthestPoint - index) <= 1);
|
||||
}
|
||||
// We got a section map
|
||||
else
|
||||
{
|
||||
// Tf2 itself does not seem to have any more code for this, so here goes
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Loop through each previous point and see if the team owns it
|
||||
for (int iPrevPoint = 0; iPrevPoint < MAX_PREVIOUS_POINTS; iPrevPoint++)
|
||||
{
|
||||
iPointNeeded = GetPreviousPointForPoint(index, team, iPrevPoint);
|
||||
if (iPointNeeded != -1)
|
||||
{
|
||||
// We don't own the needed points
|
||||
if (GET_OWNING_TEAM(iPointNeeded) != team)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Don't constantly update the cap status
|
||||
static Timer capstatus_update{};
|
||||
// Update the control points
|
||||
void UpdateControlPoints()
|
||||
{
|
||||
// No objective ressource, can't run
|
||||
if (!objective_resource)
|
||||
return;
|
||||
int num_cp = CE_INT(objective_resource, netvar.m_iNumControlPoints);
|
||||
// No control points
|
||||
if (!num_cp)
|
||||
return;
|
||||
// Clear the invalid controlpoints
|
||||
if (num_cp <= MAX_CONTROL_POINTS)
|
||||
for (int i = num_cp; i < MAX_CONTROL_POINTS; i++)
|
||||
controlpoint_data.at(i) = cp_info();
|
||||
|
||||
for (int i = 0; i < num_cp; i++)
|
||||
{
|
||||
auto &data = controlpoint_data.at(i);
|
||||
data.cp_index = i;
|
||||
|
||||
// Update position (m_vCPPositions[index])
|
||||
data.position = (&CE_VAR(objective_resource, netvar.m_vCPPositions, Vector))[i];
|
||||
}
|
||||
|
||||
if (capstatus_update.test_and_set(1000))
|
||||
for (int i = 0; i < num_cp; i++)
|
||||
{
|
||||
auto &data = controlpoint_data.at(i);
|
||||
// Check accessibility for both teams, requires alot of checks
|
||||
data.can_cap.at(0) = isPointUseable(i, TEAM_RED);
|
||||
data.can_cap.at(1) = isPointUseable(i, TEAM_BLU);
|
||||
}
|
||||
}
|
||||
|
||||
// Get the closest controlpoint to cap
|
||||
std::optional<Vector> getClosestControlPoint(Vector source, int team)
|
||||
{
|
||||
// No resource for it
|
||||
if (!objective_resource)
|
||||
return std::nullopt;
|
||||
// Check if it's a cp map
|
||||
static auto tf_gamemode_cp = g_ICvar->FindVar("tf_gamemode_cp");
|
||||
if (!tf_gamemode_cp)
|
||||
{
|
||||
tf_gamemode_cp = g_ICvar->FindVar("tf_gamemode_cp");
|
||||
return std::nullopt;
|
||||
}
|
||||
if (!tf_gamemode_cp->GetBool())
|
||||
return std::nullopt;
|
||||
|
||||
// Map team to 0-1 and check If Valid
|
||||
int team_idx = team - TEAM_RED;
|
||||
if (team_idx < 0 || team_idx > 1)
|
||||
return std::nullopt;
|
||||
|
||||
// No controlpoints
|
||||
if (!GET_NUM_CONTROL_POINTS())
|
||||
return std::nullopt;
|
||||
|
||||
int ignore_index = -1;
|
||||
// Do the points need checking because of the map?
|
||||
auto levelname = GetLevelName();
|
||||
for (auto &ignore : ignore_points)
|
||||
{
|
||||
// Try to find map name in bad point array
|
||||
if (levelname.find(ignore.mapname) != levelname.npos)
|
||||
ignore_index = ignore.point_idx;
|
||||
}
|
||||
|
||||
// Find the best and closest control point
|
||||
std::optional<Vector> best_cp;
|
||||
float best_distance = FLT_MAX;
|
||||
for (auto &cp : controlpoint_data)
|
||||
{
|
||||
// Ignore this point
|
||||
if (cp.cp_index == ignore_index)
|
||||
continue;
|
||||
// They can cap
|
||||
if (cp.can_cap.at(team_idx))
|
||||
{
|
||||
// Is it closer?
|
||||
if (cp.position && (*cp.position).DistTo(source) < best_distance)
|
||||
{
|
||||
best_distance = (*cp.position).DistTo(source);
|
||||
best_cp = cp.position;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return best_cp;
|
||||
}
|
||||
|
||||
void LevelInit()
|
||||
{
|
||||
for (auto &cp : controlpoint_data)
|
||||
cp = cp_info();
|
||||
objective_resource = nullptr;
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
UpdateControlPoints();
|
||||
UpdateObjectiveResource();
|
||||
}
|
||||
} // namespace cpcontroller
|
||||
|
||||
// Main handlers
|
||||
void CreateMove()
|
||||
{
|
||||
flagcontroller::Update();
|
||||
plcontroller::Update();
|
||||
cpcontroller::Update();
|
||||
}
|
||||
|
||||
void LevelInit()
|
||||
{
|
||||
flagcontroller::LevelInit();
|
||||
plcontroller::LevelInit();
|
||||
cpcontroller::LevelInit();
|
||||
}
|
||||
|
||||
static InitRoutine init([]() {
|
||||
EC::Register(EC::CreateMove, CreateMove, "capturelogic_update");
|
||||
EC::Register(EC::LevelInit, LevelInit, "capturelogic_levelinit");
|
||||
});
|
259
src/controlpointcontroller.cpp
Normal file
259
src/controlpointcontroller.cpp
Normal file
@ -0,0 +1,259 @@
|
||||
#include "common.hpp"
|
||||
#include "controlpointcontroller.hpp"
|
||||
namespace cpcontroller
|
||||
{
|
||||
|
||||
std::array<cp_info, MAX_CONTROL_POINTS> controlpoint_data;
|
||||
CachedEntity *objective_resource = nullptr;
|
||||
|
||||
struct point_ignore
|
||||
{
|
||||
std::string mapname;
|
||||
int point_idx;
|
||||
point_ignore(std::string str, int idx) : mapname{ str }, point_idx{ idx } {};
|
||||
};
|
||||
|
||||
// TODO: Find a way to fix these edge-cases.
|
||||
// clang-format off
|
||||
std::array<point_ignore, 1> ignore_points
|
||||
{
|
||||
point_ignore("cp_steel", 4)
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
// This function updates the Entity used for the Object resource
|
||||
void UpdateObjectiveResource()
|
||||
{
|
||||
// Already set and valid
|
||||
if (CE_GOOD(objective_resource) && objective_resource->m_iClassID() == CL_CLASS(CTFObjectiveResource))
|
||||
return;
|
||||
// Find ObjectiveResource and gamerules
|
||||
for (int i = g_IEngine->GetMaxClients() + 1; i < MAX_ENTITIES; i++)
|
||||
{
|
||||
CachedEntity *ent = ENTITY(i);
|
||||
if (CE_BAD(ent) || ent->m_iClassID() != CL_CLASS(CTFObjectiveResource))
|
||||
continue;
|
||||
// Found it
|
||||
objective_resource = ent;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// A Bunch of defines for netvars that don't deserve their own function
|
||||
#define GET_NUM_CONTROL_POINTS() (CE_INT(objective_resource, netvar.m_iNumControlPoints))
|
||||
#define GET_OWNING_TEAM(index) ((&CE_INT(objective_resource, netvar.m_iOwningTeam))[index])
|
||||
#define GET_BASE_CONTROL_POINT_FOR_TEAM(team) ((&CE_INT(objective_resource, netvar.m_iBaseControlPoints))[team])
|
||||
#define GET_CP_LOCKED(index) ((&CE_VAR(objective_resource, netvar.m_bCPLocked, bool))[index])
|
||||
#define IN_MINI_ROUND(index) ((&CE_VAR(objective_resource, netvar.m_bInMiniRound, bool))[index])
|
||||
|
||||
bool TeamCanCapPoint(int index, int team)
|
||||
{
|
||||
int arr_index = index + team * MAX_CONTROL_POINTS;
|
||||
return (&CE_VAR(objective_resource, netvar.m_bTeamCanCap, bool))[arr_index];
|
||||
}
|
||||
|
||||
int GetPreviousPointForPoint(int index, int team, int previndex)
|
||||
{
|
||||
int iIntIndex = previndex + (index * MAX_PREVIOUS_POINTS) + (team * MAX_CONTROL_POINTS * MAX_PREVIOUS_POINTS);
|
||||
return (&CE_INT(objective_resource, netvar.m_iPreviousPoints))[iIntIndex];
|
||||
}
|
||||
|
||||
int GetFarthestOwnedControlPoint(int team)
|
||||
{
|
||||
int iOwnedEnd = GET_BASE_CONTROL_POINT_FOR_TEAM(team);
|
||||
if (iOwnedEnd == -1)
|
||||
return -1;
|
||||
|
||||
int iNumControlPoints = GET_NUM_CONTROL_POINTS();
|
||||
int iWalk = 1;
|
||||
int iEnemyEnd = iNumControlPoints - 1;
|
||||
if (iOwnedEnd != 0)
|
||||
{
|
||||
iWalk = -1;
|
||||
iEnemyEnd = 0;
|
||||
}
|
||||
|
||||
// Walk towards the other side, and find the farthest owned point
|
||||
int iFarthestPoint = iOwnedEnd;
|
||||
for (int iPoint = iOwnedEnd; iPoint != iEnemyEnd; iPoint += iWalk)
|
||||
{
|
||||
// If we've hit a point we don't own, we're done
|
||||
if (GET_OWNING_TEAM(iPoint) != team)
|
||||
break;
|
||||
|
||||
iFarthestPoint = iPoint;
|
||||
}
|
||||
|
||||
return iFarthestPoint;
|
||||
}
|
||||
|
||||
// Can we cap this point?
|
||||
bool isPointUseable(int index, int team)
|
||||
{
|
||||
// We Own it, can't cap it
|
||||
if (GET_OWNING_TEAM(index) == team)
|
||||
return false;
|
||||
|
||||
// Can we cap the point?
|
||||
if (!TeamCanCapPoint(index, team))
|
||||
return false;
|
||||
|
||||
// We are playing a sectioned map, check if the CP is in it
|
||||
if (CE_VAR(objective_resource, netvar.m_bPlayingMiniRounds, bool) && !IN_MINI_ROUND(index))
|
||||
return false;
|
||||
|
||||
// Is the point locked?
|
||||
if (GET_CP_LOCKED(index))
|
||||
return false;
|
||||
|
||||
// Linear cap means that it won't require previous points, bail
|
||||
static auto tf_caplinear = g_ICvar->FindVar("tf_caplinear");
|
||||
if (tf_caplinear && !tf_caplinear->GetBool())
|
||||
return true;
|
||||
|
||||
// Any previous points necessary?
|
||||
int iPointNeeded = GetPreviousPointForPoint(index, team, 0);
|
||||
|
||||
// Points set to require themselves are always cappable
|
||||
if (iPointNeeded == index)
|
||||
return true;
|
||||
|
||||
// No required points specified? Require all previous points.
|
||||
if (iPointNeeded == -1)
|
||||
{
|
||||
// No Mini rounds
|
||||
if (!CE_VAR(objective_resource, netvar.m_bPlayingMiniRounds, bool))
|
||||
{
|
||||
// No custom previous point, team must own all previous points
|
||||
int iFarthestPoint = GetFarthestOwnedControlPoint(team);
|
||||
return (abs(iFarthestPoint - index) <= 1);
|
||||
}
|
||||
// We got a section map
|
||||
else
|
||||
{
|
||||
// Tf2 itself does not seem to have any more code for this, so here goes
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Loop through each previous point and see if the team owns it
|
||||
for (int iPrevPoint = 0; iPrevPoint < MAX_PREVIOUS_POINTS; iPrevPoint++)
|
||||
{
|
||||
iPointNeeded = GetPreviousPointForPoint(index, team, iPrevPoint);
|
||||
if (iPointNeeded != -1)
|
||||
{
|
||||
// We don't own the needed points
|
||||
if (GET_OWNING_TEAM(iPointNeeded) != team)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Don't constantly update the cap status
|
||||
static Timer capstatus_update{};
|
||||
// Update the control points
|
||||
void UpdateControlPoints()
|
||||
{
|
||||
// No objective ressource, can't run
|
||||
if (!objective_resource)
|
||||
return;
|
||||
int num_cp = CE_INT(objective_resource, netvar.m_iNumControlPoints);
|
||||
// No control points
|
||||
if (!num_cp)
|
||||
return;
|
||||
// Clear the invalid controlpoints
|
||||
if (num_cp <= MAX_CONTROL_POINTS)
|
||||
for (int i = num_cp; i < MAX_CONTROL_POINTS; i++)
|
||||
controlpoint_data.at(i) = cp_info();
|
||||
|
||||
for (int i = 0; i < num_cp; i++)
|
||||
{
|
||||
auto &data = controlpoint_data.at(i);
|
||||
data.cp_index = i;
|
||||
|
||||
// Update position (m_vCPPositions[index])
|
||||
data.position = (&CE_VAR(objective_resource, netvar.m_vCPPositions, Vector))[i];
|
||||
}
|
||||
|
||||
if (capstatus_update.test_and_set(1000))
|
||||
for (int i = 0; i < num_cp; i++)
|
||||
{
|
||||
auto &data = controlpoint_data.at(i);
|
||||
// Check accessibility for both teams, requires alot of checks
|
||||
data.can_cap.at(0) = isPointUseable(i, TEAM_RED);
|
||||
data.can_cap.at(1) = isPointUseable(i, TEAM_BLU);
|
||||
}
|
||||
}
|
||||
|
||||
// Get the closest controlpoint to cap
|
||||
std::optional<Vector> getClosestControlPoint(Vector source, int team)
|
||||
{
|
||||
// No resource for it
|
||||
if (!objective_resource)
|
||||
return std::nullopt;
|
||||
// Check if it's a cp map
|
||||
static auto tf_gamemode_cp = g_ICvar->FindVar("tf_gamemode_cp");
|
||||
if (!tf_gamemode_cp)
|
||||
{
|
||||
tf_gamemode_cp = g_ICvar->FindVar("tf_gamemode_cp");
|
||||
return std::nullopt;
|
||||
}
|
||||
if (!tf_gamemode_cp->GetBool())
|
||||
return std::nullopt;
|
||||
|
||||
// Map team to 0-1 and check If Valid
|
||||
int team_idx = team - TEAM_RED;
|
||||
if (team_idx < 0 || team_idx > 1)
|
||||
return std::nullopt;
|
||||
|
||||
// No controlpoints
|
||||
if (!GET_NUM_CONTROL_POINTS())
|
||||
return std::nullopt;
|
||||
|
||||
int ignore_index = -1;
|
||||
// Do the points need checking because of the map?
|
||||
auto levelname = GetLevelName();
|
||||
for (auto &ignore : ignore_points)
|
||||
{
|
||||
// Try to find map name in bad point array
|
||||
if (levelname.find(ignore.mapname) != levelname.npos)
|
||||
ignore_index = ignore.point_idx;
|
||||
}
|
||||
|
||||
// Find the best and closest control point
|
||||
std::optional<Vector> best_cp;
|
||||
float best_distance = FLT_MAX;
|
||||
for (auto &cp : controlpoint_data)
|
||||
{
|
||||
// Ignore this point
|
||||
if (cp.cp_index == ignore_index)
|
||||
continue;
|
||||
// They can cap
|
||||
if (cp.can_cap.at(team_idx))
|
||||
{
|
||||
// Is it closer?
|
||||
if (cp.position && (*cp.position).DistTo(source) < best_distance)
|
||||
{
|
||||
best_distance = (*cp.position).DistTo(source);
|
||||
best_cp = cp.position;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return best_cp;
|
||||
}
|
||||
|
||||
void LevelInit()
|
||||
{
|
||||
for (auto &cp : controlpoint_data)
|
||||
cp = cp_info();
|
||||
objective_resource = nullptr;
|
||||
}
|
||||
|
||||
static InitRoutine init([]() {
|
||||
EC::Register(EC::CreateMove, UpdateObjectiveResource, "cpcontroller_updateent");
|
||||
EC::Register(EC::CreateMove, UpdateControlPoints, "cpcontroller_updatecp");
|
||||
EC::Register(EC::LevelInit, LevelInit, "levelinit_cocontroller");
|
||||
});
|
||||
} // namespace cpcontroller
|
@ -68,9 +68,8 @@ void logging::Info(const char *fmt, ...)
|
||||
// Fill buffer
|
||||
int size = vsnprintf(result, 512, fmt, list);
|
||||
va_end(list);
|
||||
if(size < 0)
|
||||
if (size < 0)
|
||||
return;
|
||||
|
||||
Log(result, false);
|
||||
#endif
|
||||
}
|
||||
@ -88,7 +87,7 @@ void logging::File(const char *fmt, ...)
|
||||
// Fill buffer
|
||||
int size = vsnprintf(result, 512, fmt, list);
|
||||
va_end(list);
|
||||
if(size < 0)
|
||||
if (size < 0)
|
||||
return;
|
||||
|
||||
Log(result, true);
|
||||
|
@ -111,6 +111,17 @@ void NetVars::Init()
|
||||
this->m_bMiniBuilding = gNetvars.get_offset("DT_BaseObject", "m_bMiniBuilding");
|
||||
this->m_bPlasmaDisable = gNetvars.get_offset("DT_BaseObject", "m_bPlasmaDisable");
|
||||
|
||||
// any building
|
||||
this->iUpgradeLevel = gNetvars.get_offset("DT_BaseObject", "m_iUpgradeLevel");
|
||||
this->m_hBuilder = gNetvars.get_offset("DT_BaseObject", "m_hBuilder");
|
||||
this->m_bCanPlace = gNetvars.get_offset("DT_BaseObject", "m_bServerOverridePlacement");
|
||||
this->m_bBuilding = gNetvars.get_offset("DT_BaseObject", "m_bBuilding");
|
||||
this->m_bCarryDeploy = gNetvars.get_offset("DT_BaseObject", "m_bCarryDeploy");
|
||||
this->m_iObjectType = gNetvars.get_offset("DT_BaseObject", "m_iObjectType");
|
||||
this->m_bHasSapper = gNetvars.get_offset("DT_BaseObject", "m_bHasSapper");
|
||||
this->m_bPlacing = gNetvars.get_offset("DT_BaseObject", "m_bPlacing");
|
||||
this->m_bMiniBuilding = gNetvars.get_offset("DT_BaseObject", "m_bMiniBuilding");
|
||||
|
||||
// teleporter
|
||||
this->m_iTeleState = gNetvars.get_offset("DT_ObjectTeleporter", "m_iState");
|
||||
this->m_flTeleRechargeTime = gNetvars.get_offset("DT_ObjectTeleporter", "m_flRechargeTime");
|
||||
@ -119,6 +130,21 @@ void NetVars::Init()
|
||||
this->m_flTeleYawToExit = gNetvars.get_offset("DT_ObjectTeleporter", "m_flYawToExit");
|
||||
this->m_bMatchBuilding = gNetvars.get_offset("DT_ObjectTeleporter", "m_bMatchBuilding");
|
||||
|
||||
// CTF Flag
|
||||
this->m_nFlagType = gNetvars.get_offset("DT_CaptureFlag", "m_nType");
|
||||
this->m_nFlagStatus = gNetvars.get_offset("DT_CaptureFlag", "m_nFlagStatus");
|
||||
|
||||
// ObjectiveResource
|
||||
this->m_bTeamCanCap = gNetvars.get_offset("DT_BaseTeamObjectiveResource", "m_bTeamCanCap");
|
||||
this->m_iNumControlPoints = gNetvars.get_offset("DT_BaseTeamObjectiveResource", "m_iNumControlPoints");
|
||||
this->m_vCPPositions = gNetvars.get_offset("DT_BaseTeamObjectiveResource", "m_vCPPositions[0]");
|
||||
this->m_iOwningTeam = gNetvars.get_offset("DT_BaseTeamObjectiveResource", "m_iOwner");
|
||||
this->m_bCPLocked = gNetvars.get_offset("DT_BaseTeamObjectiveResource", "m_bCPLocked");
|
||||
this->m_bPlayingMiniRounds = gNetvars.get_offset("DT_BaseTeamObjectiveResource", "m_bPlayingMiniRounds");
|
||||
this->m_bInMiniRound = gNetvars.get_offset("DT_BaseTeamObjectiveResource", "m_bInMiniRound");
|
||||
this->m_iPreviousPoints = gNetvars.get_offset("DT_BaseTeamObjectiveResource", "m_iPreviousPoints");
|
||||
this->m_iBaseControlPoints = gNetvars.get_offset("DT_BaseTeamObjectiveResource", "m_iBaseControlPoints");
|
||||
|
||||
this->m_DmgRadius = gNetvars.get_offset("DT_BaseGrenade", "m_DmgRadius");
|
||||
this->iPipeType = gNetvars.get_offset("DT_TFProjectile_Pipebomb", "m_iType");
|
||||
this->iBuildingHealth = gNetvars.get_offset("DT_BaseObject", "m_iHealth");
|
||||
|
156
src/flagcontroller.cpp
Normal file
156
src/flagcontroller.cpp
Normal file
@ -0,0 +1,156 @@
|
||||
#include "flagcontroller.hpp"
|
||||
#include "common.hpp"
|
||||
|
||||
namespace flagcontroller
|
||||
{
|
||||
|
||||
std::array<flag_info, 2> flags;
|
||||
bool is_ctf = true;
|
||||
|
||||
// Check if a flag is good or not
|
||||
bool isGoodFlag(CachedEntity *flag)
|
||||
{
|
||||
if (CE_INVALID(flag) || flag->m_iClassID() != CL_CLASS(CCaptureFlag))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
// Not ctf, no need to update
|
||||
if (!is_ctf)
|
||||
return;
|
||||
// Find flags if missing
|
||||
if (!flags[0].ent || !flags[1].ent)
|
||||
for (int i = g_IEngine->GetMaxClients() + 1; i < MAX_ENTITIES; i++)
|
||||
{
|
||||
CachedEntity *ent = ENTITY(i);
|
||||
// We cannot identify a bad entity as a flag due to the unreliability of it
|
||||
if (CE_BAD(ent) || ent->m_iClassID() != CL_CLASS(CCaptureFlag))
|
||||
continue;
|
||||
|
||||
// Store flags
|
||||
if (!flags[0].ent)
|
||||
flags[0].ent = ent;
|
||||
else if (ent != flags[0].ent)
|
||||
flags[1].ent = ent;
|
||||
}
|
||||
// Update flag data
|
||||
for (auto &flag : flags)
|
||||
{
|
||||
// Not inited
|
||||
if (!flag.ent)
|
||||
continue;
|
||||
|
||||
// Bad Flag, reset
|
||||
if (!isGoodFlag(flag.ent))
|
||||
{
|
||||
flag = flag_info();
|
||||
continue;
|
||||
}
|
||||
|
||||
// Cannot use "bad" flag, but it is still potentially valid
|
||||
if (CE_BAD(flag.ent))
|
||||
continue;
|
||||
|
||||
int flag_type = CE_INT(flag.ent, netvar.m_nFlagType);
|
||||
|
||||
// Only CTF support for now
|
||||
if (flag_type != TF_FLAGTYPE_CTF)
|
||||
continue;
|
||||
|
||||
// Assign team if missing
|
||||
if (flag.team == TEAM_UNK)
|
||||
flag.team = flag.ent->m_iTeam();
|
||||
|
||||
// Assign spawn point if it is missing and the flag is at spawn
|
||||
if (!flag.spawn_pos)
|
||||
{
|
||||
int flag_status = CE_INT(flag.ent, netvar.m_nFlagStatus);
|
||||
|
||||
// Flag is home
|
||||
if (flag_status == TF_FLAGINFO_HOME)
|
||||
flag.spawn_pos = flag.ent->m_vecOrigin();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LevelInit()
|
||||
{
|
||||
// Resez everything
|
||||
for (auto &flag : flags)
|
||||
flag = flag_info();
|
||||
is_ctf = true;
|
||||
}
|
||||
|
||||
// Get the info for the flag
|
||||
flag_info getFlag(int team)
|
||||
{
|
||||
for (auto &flag : flags)
|
||||
{
|
||||
if (flag.team == team)
|
||||
return flag;
|
||||
}
|
||||
// None found
|
||||
return flag_info();
|
||||
}
|
||||
|
||||
// Get the Position of a flag on a specific team
|
||||
Vector getPosition(CachedEntity *flag)
|
||||
{
|
||||
return flag->m_vecOrigin();
|
||||
}
|
||||
|
||||
std::optional<Vector> getPosition(int team)
|
||||
{
|
||||
auto flag = getFlag(team);
|
||||
if (isGoodFlag(flag.ent))
|
||||
return getPosition(flag.ent);
|
||||
// No good flag
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
// Get the person carrying the flag
|
||||
CachedEntity *getCarrier(CachedEntity *flag)
|
||||
{
|
||||
int entidx = HandleToIDX(CE_INT(flag, netvar.m_hOwnerEntity));
|
||||
// None/Invalid
|
||||
if (IDX_BAD(entidx))
|
||||
return nullptr;
|
||||
CachedEntity *carrier = ENTITY(entidx);
|
||||
// Carrier is invalid
|
||||
if (CE_BAD(carrier) || carrier->m_Type() != ENTITY_PLAYER)
|
||||
return nullptr;
|
||||
return carrier;
|
||||
}
|
||||
|
||||
// Wrapper for when you don't have the entity
|
||||
CachedEntity *getCarrier(int team)
|
||||
{
|
||||
auto flag = getFlag(team);
|
||||
// Only use good flags
|
||||
if (isGoodFlag(flag.ent))
|
||||
return getCarrier(flag.ent);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Get the status of the flag (Home, being carried, dropped)
|
||||
ETFFlagStatus getStatus(CachedEntity *flag)
|
||||
{
|
||||
return (ETFFlagStatus) CE_INT(flag, netvar.m_nFlagStatus);
|
||||
}
|
||||
|
||||
ETFFlagStatus getStatus(int team)
|
||||
{
|
||||
auto flag = getFlag(team);
|
||||
// Only use good flags
|
||||
if (isGoodFlag(flag.ent))
|
||||
return getStatus(flag.ent);
|
||||
// Mark as home if nothing is found
|
||||
return TF_FLAGINFO_HOME;
|
||||
}
|
||||
static InitRoutine init([]() {
|
||||
EC::Register(EC::CreateMove, Update, "flagcontroller_update");
|
||||
EC::Register(EC::LevelInit, LevelInit, "flagcontroller_levelinit");
|
||||
});
|
||||
} // namespace flagcontroller
|
@ -217,6 +217,7 @@ static void doAutoZoom(bool target_found)
|
||||
|
||||
// Current Entity
|
||||
CachedEntity *target_last = 0;
|
||||
bool aimed_this_tick = false;
|
||||
|
||||
// If slow aimbot allows autoshoot
|
||||
bool slow_can_shoot = false;
|
||||
@ -237,6 +238,8 @@ static void CreateMove()
|
||||
if (CE_BAD(LOCAL_E) || !LOCAL_E->m_bAlivePlayer() || CE_BAD(LOCAL_W))
|
||||
enable = false;
|
||||
|
||||
aimed_this_tick = false;
|
||||
|
||||
if (!enable)
|
||||
{
|
||||
target_last = nullptr;
|
||||
@ -982,6 +985,7 @@ void Aim(CachedEntity *entity)
|
||||
if (data)
|
||||
hacks::tf2::backtrack::SetBacktrackData(entity, *data);
|
||||
}
|
||||
aimed_this_tick = true;
|
||||
// Finish function
|
||||
return;
|
||||
}
|
||||
@ -1515,6 +1519,12 @@ float EffectiveTargetingRange()
|
||||
return (float) max_range;
|
||||
}
|
||||
|
||||
// Used mostly by navbot to not accidentally look at path when aiming
|
||||
bool isAiming()
|
||||
{
|
||||
return aimed_this_tick;
|
||||
}
|
||||
|
||||
// A function used by gui elements to determine the current target
|
||||
CachedEntity *CurrentTarget()
|
||||
{
|
||||
|
@ -369,6 +369,9 @@ void ProcessUserCmd(CUserCmd *cmd)
|
||||
return;
|
||||
if (!ShouldAA(cmd))
|
||||
return;
|
||||
// Not running
|
||||
if (!pitch && !yaw)
|
||||
return;
|
||||
static bool keepmode = true;
|
||||
keepmode = !keepmode;
|
||||
float &p = cmd->viewangles.x;
|
||||
|
@ -327,7 +327,7 @@ Upgradeinfo PickUpgrade()
|
||||
}
|
||||
static std::vector<Posinfo> spot_list;
|
||||
// Upgrade Navigation
|
||||
void NavUpgrade()
|
||||
/*void NavUpgrade()
|
||||
{
|
||||
std::string lvlname = g_IEngine->GetLevelName();
|
||||
std::vector<Posinfo> potential_spots{};
|
||||
@ -359,6 +359,7 @@ void NavUpgrade()
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static bool run = false;
|
||||
static Timer run_delay;
|
||||
static Timer buy_upgrade;
|
||||
@ -479,16 +480,17 @@ void MvM_Autoupgrade(KeyValues *event)
|
||||
run_delay.update();
|
||||
}
|
||||
}
|
||||
|
||||
*/
|
||||
void SendNetMsg(INetMessage &msg)
|
||||
{
|
||||
/*
|
||||
if (!strcmp(msg.GetName(), "clc_CmdKeyValues"))
|
||||
{
|
||||
if ((KeyValues *) (((unsigned *) &msg)[4]))
|
||||
MvM_Autoupgrade((KeyValues *) (((unsigned *) &msg)[4]));
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
/*
|
||||
class CatBotEventListener : public IGameEventListener2
|
||||
{
|
||||
void FireGameEvent(IGameEvent *event) override
|
||||
@ -509,7 +511,7 @@ CatBotEventListener &listener()
|
||||
{
|
||||
static CatBotEventListener object{};
|
||||
return object;
|
||||
}
|
||||
}*/
|
||||
|
||||
class CatBotEventListener2 : public IGameEventListener2
|
||||
{
|
||||
@ -912,7 +914,7 @@ void update()
|
||||
|
||||
void init()
|
||||
{
|
||||
g_IEventManager2->AddListener(&listener(), "player_death", false);
|
||||
// g_IEventManager2->AddListener(&listener(), "player_death", false);
|
||||
g_IEventManager2->AddListener(&listener2(), "vote_maps_changed", false);
|
||||
}
|
||||
|
||||
@ -924,7 +926,7 @@ void level_init()
|
||||
|
||||
void shutdown()
|
||||
{
|
||||
g_IEventManager2->RemoveListener(&listener());
|
||||
// g_IEventManager2->RemoveListener(&listener());
|
||||
g_IEventManager2->RemoveListener(&listener2());
|
||||
}
|
||||
|
||||
|
@ -37,8 +37,6 @@ static settings::Boolean ignore_textmode{ "follow-bot.ignore-textmode", "true" }
|
||||
static settings::Boolean mimic_crouch{ "follow-bot.mimic-crouch", "true" };
|
||||
static settings::Boolean autozoom_if_idle{ "follow-bot.autozoom-if-idle", "true" };
|
||||
|
||||
namespace nb = hacks::tf2::NavBot;
|
||||
|
||||
static Timer navBotInterval{};
|
||||
static unsigned steamid = 0x0;
|
||||
|
||||
@ -270,7 +268,7 @@ static bool startFollow(CachedEntity *entity, bool useNavbot)
|
||||
}
|
||||
if (useNavbot)
|
||||
{
|
||||
if (nav::navTo(entity->m_vecOrigin(), 8, true, false))
|
||||
if (navparser::NavEngine::navTo(entity->m_vecOrigin(), Priority_list::followbot, true, false))
|
||||
{
|
||||
navtarget = true;
|
||||
return true;
|
||||
@ -310,14 +308,14 @@ static void cm()
|
||||
if (!enable || CE_BAD(LOCAL_E) || !LOCAL_E->m_bAlivePlayer() || CE_BAD(LOCAL_W))
|
||||
{
|
||||
follow_target = 0;
|
||||
if (nb::task::current_task == nb::task::followbot)
|
||||
nb::task::current_task = nb::task::none;
|
||||
if (navparser::NavEngine::current_priority == Priority_list::followbot)
|
||||
navparser::NavEngine::cancelPath();
|
||||
return;
|
||||
}
|
||||
if (!inited)
|
||||
init();
|
||||
|
||||
if (nb::task::current_task == nb::task::health || nb::task::current_task == nb::task::ammo)
|
||||
if (navparser::NavEngine::current_priority > Priority_list::followbot)
|
||||
{
|
||||
follow_target = 0;
|
||||
return;
|
||||
@ -343,7 +341,7 @@ static void cm()
|
||||
crouch_timer.update();
|
||||
}
|
||||
|
||||
bool isNavBotCM = navBotInterval.test_and_set(3000) && nav::prepare();
|
||||
bool isNavBotCM = navBotInterval.test_and_set(3000) && navparser::NavEngine::isReady();
|
||||
bool foundPreferredTarget = false;
|
||||
|
||||
// Target Selection
|
||||
@ -467,18 +465,6 @@ static void cm()
|
||||
}
|
||||
if (entity->m_bEnemy())
|
||||
continue;
|
||||
// const model_t *model = ENTITY(follow_target)->InternalEntity()->GetModel();
|
||||
// FIXME follow cart/point
|
||||
/*if (followcart && model &&
|
||||
(lagexploit::pointarr[0] || lagexploit::pointarr[1] ||
|
||||
lagexploit::pointarr[2] || lagexploit::pointarr[3] ||
|
||||
lagexploit::pointarr[4]) &&
|
||||
(model == lagexploit::pointarr[0] ||
|
||||
model == lagexploit::pointarr[1] ||
|
||||
model == lagexploit::pointarr[2] ||
|
||||
model == lagexploit::pointarr[3] ||
|
||||
model == lagexploit::pointarr[4]))
|
||||
follow_target = entity->m_IDX;*/
|
||||
// favor closer entitys
|
||||
if (CE_GOOD(entity))
|
||||
{
|
||||
@ -512,7 +498,7 @@ static void cm()
|
||||
if (navtarget)
|
||||
{
|
||||
auto ent = ENTITY(follow_target);
|
||||
if (!nav::prepare())
|
||||
if (!navparser::NavEngine::isReady())
|
||||
{
|
||||
follow_target = 0;
|
||||
navtarget = 0;
|
||||
@ -531,7 +517,7 @@ static void cm()
|
||||
}
|
||||
if (pos && navtimer.test_and_set(800))
|
||||
{
|
||||
if (nav::navTo(*pos, 8, true, false))
|
||||
if (navparser::NavEngine::navTo(*pos, Priority_list::followbot, true, false))
|
||||
navinactivity.update();
|
||||
}
|
||||
}
|
||||
@ -539,7 +525,6 @@ static void cm()
|
||||
{
|
||||
follow_target = 0;
|
||||
}
|
||||
nb::task::current_task = nb::task::followbot;
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -547,13 +532,11 @@ static void cm()
|
||||
// last check for entity before we continue
|
||||
if (!follow_target)
|
||||
{
|
||||
if (nb::task::current_task == nb::task::followbot)
|
||||
nb::task::current_task = nb::task::none;
|
||||
if (navparser::NavEngine::current_priority == Priority_list::followbot)
|
||||
navparser::NavEngine::cancelPath();
|
||||
return;
|
||||
}
|
||||
|
||||
nb::task::current_task = nb::task::followbot;
|
||||
nav::clearInstructions();
|
||||
navparser::NavEngine::cancelPath();
|
||||
|
||||
CachedEntity *followtar = ENTITY(follow_target);
|
||||
// wtf is this needed
|
||||
|
@ -638,7 +638,7 @@ void DumpRecvTable(CachedEntity *ent, RecvTable *table, int depth, const char *f
|
||||
logging::Info("TABLE %s IN DEPTH %d: %s [0x%04x] = %i | %u | %hd | %hu", table ? table->GetName() : "none", depth, prop->GetName(), prop->GetOffset(), CE_INT(ent, acc_offset + prop->GetOffset()), CE_VAR(ent, acc_offset + prop->GetOffset(), unsigned int), CE_VAR(ent, acc_offset + prop->GetOffset(), short), CE_VAR(ent, acc_offset + prop->GetOffset(), unsigned short));
|
||||
break;
|
||||
case SendPropType::DPT_String:
|
||||
logging::Info("TABLE %s IN DEPTH %d: %s [0x%04x] = %s", table ? table->GetName() : "none", depth, prop->GetName(), prop->GetOffset(), CE_VAR(ent, prop->GetOffset(), char *));
|
||||
logging::Info("TABLE %s IN DEPTH %d: %s [0x%04x] = 'not yet supported'", table ? table->GetName() : "none", depth, prop->GetName(), prop->GetOffset());
|
||||
break;
|
||||
case SendPropType::DPT_Vector:
|
||||
logging::Info("TABLE %s IN DEPTH %d: %s [0x%04x] = (%f, %f, %f)", table ? table->GetName() : "none", depth, prop->GetName(), prop->GetOffset(), CE_FLOAT(ent, acc_offset + prop->GetOffset()), CE_FLOAT(ent, acc_offset + prop->GetOffset() + 4), CE_FLOAT(ent, acc_offset + prop->GetOffset() + 8));
|
||||
|
2246
src/hacks/NavBot.cpp
2246
src/hacks/NavBot.cpp
File diff suppressed because it is too large
Load Diff
@ -120,8 +120,9 @@ void WalkTo(const Vector &vector)
|
||||
// Calculate how to get to a vector
|
||||
auto result = ComputeMove(LOCAL_E->m_vecOrigin(), vector);
|
||||
// Push our move to usercmd
|
||||
current_user_cmd->forwardmove = result.first;
|
||||
current_user_cmd->sidemove = result.second;
|
||||
current_user_cmd->forwardmove = result.x;
|
||||
current_user_cmd->sidemove = result.y;
|
||||
current_user_cmd->upmove = result.z;
|
||||
}
|
||||
|
||||
// Function to get the corner location that a vischeck to an entity is possible
|
||||
@ -436,7 +437,6 @@ bool canReachVector(Vector loc, Vector dest)
|
||||
|
||||
std::string GetLevelName()
|
||||
{
|
||||
|
||||
std::string name(g_IEngine->GetLevelName());
|
||||
size_t slash = name.find('/');
|
||||
if (slash == std::string::npos)
|
||||
@ -465,21 +465,30 @@ std::pair<float, float> ComputeMovePrecise(const Vector &a, const Vector &b)
|
||||
return { cos(yaw) * speed, -sin(yaw) * speed };
|
||||
}
|
||||
|
||||
std::pair<float, float> ComputeMove(const Vector &a, const Vector &b)
|
||||
Vector ComputeMove(const Vector &a, const Vector &b)
|
||||
{
|
||||
Vector diff = (b - a);
|
||||
if (diff.Length() == 0.0f)
|
||||
return { 0, 0 };
|
||||
return Vector(0.0f);
|
||||
const float x = diff.x;
|
||||
const float y = diff.y;
|
||||
Vector vsilent(x, y, 0);
|
||||
float speed = sqrt(vsilent.x * vsilent.x + vsilent.y * vsilent.y);
|
||||
Vector ang;
|
||||
VectorAngles(vsilent, ang);
|
||||
float yaw = DEG2RAD(ang.y - current_user_cmd->viewangles.y);
|
||||
float yaw = DEG2RAD(ang.y - current_user_cmd->viewangles.y);
|
||||
float pitch = DEG2RAD(ang.x - current_user_cmd->viewangles.x);
|
||||
if (g_pLocalPlayer->bUseSilentAngles)
|
||||
yaw = DEG2RAD(ang.y - g_pLocalPlayer->v_OrigViewangles.y);
|
||||
return { cos(yaw) * 450.0f, -sin(yaw) * 450.0f };
|
||||
{
|
||||
yaw = DEG2RAD(ang.y - g_pLocalPlayer->v_OrigViewangles.y);
|
||||
pitch = DEG2RAD(ang.x - g_pLocalPlayer->v_OrigViewangles.x);
|
||||
}
|
||||
Vector move = { cos(yaw) * 450.0f, -sin(yaw) * 450.0f, -cos(pitch) * 450.0f };
|
||||
|
||||
// Only apply upmove in water
|
||||
if (!(g_ITrace->GetPointContents(g_pLocalPlayer->v_Eye) & CONTENTS_WATER))
|
||||
move.z = current_user_cmd->upmove;
|
||||
return move;
|
||||
}
|
||||
|
||||
ConCommand *CreateConCommand(const char *name, FnCommandCallback_t callback, const char *help)
|
||||
@ -1462,7 +1471,6 @@ Vector GetForwardVector(Vector origin, Vector viewangles, float distance, Cached
|
||||
// Compensate for punch angle
|
||||
if (punch_entity && should_correct_punch)
|
||||
angle += VectorToQAngle(CE_VECTOR(punch_entity, netvar.vecPunchAngle));
|
||||
trace_t trace;
|
||||
|
||||
sy = sinf(DEG2RAD(angle[1]));
|
||||
cy = cosf(DEG2RAD(angle[1]));
|
||||
|
@ -252,10 +252,6 @@ DEFINE_HOOKED_METHOD(CreateMove, bool, void *this_, float input_sample_time, CUs
|
||||
if (firstcm)
|
||||
{
|
||||
DelayTimer.update();
|
||||
// hacks::tf2::NavBot::Init();
|
||||
// hacks::tf2::NavBot::initonce();
|
||||
nav::status = nav::off;
|
||||
hacks::tf2::NavBot::init(true);
|
||||
if (identify)
|
||||
{
|
||||
sendIdentifyMessage(false);
|
||||
|
@ -88,14 +88,23 @@ void LocalPlayer::Update()
|
||||
holding_sniper_rifle = false;
|
||||
holding_sapper = false;
|
||||
weapon_melee_damage_tick = false;
|
||||
bRevving = false;
|
||||
bRevved = false;
|
||||
wep = weapon();
|
||||
if (CE_GOOD(wep))
|
||||
{
|
||||
weapon_mode = GetWeaponModeloc();
|
||||
if (wep->m_iClassID() == CL_CLASS(CTFSniperRifle) || wep->m_iClassID() == CL_CLASS(CTFSniperRifleDecap))
|
||||
holding_sniper_rifle = true;
|
||||
if (wep->m_iClassID() == CL_CLASS(CTFWeaponBuilder) || wep->m_iClassID() == CL_CLASS(CTFWeaponSapper))
|
||||
else if (wep->m_iClassID() == CL_CLASS(CTFWeaponBuilder) || wep->m_iClassID() == CL_CLASS(CTFWeaponSapper))
|
||||
holding_sapper = true;
|
||||
else if (wep->m_iClassID() == CL_CLASS(CTFMinigun))
|
||||
{
|
||||
if (CE_INT(LOCAL_W, netvar.iWeaponState) == 2 || CE_INT(LOCAL_W, netvar.iWeaponState) == 1)
|
||||
bRevving = true;
|
||||
else if (CE_INT(LOCAL_W, netvar.iWeaponState) == 3)
|
||||
bRevved = true;
|
||||
}
|
||||
// Detect when a melee hit will result in damage, useful for aimbot and antiaim
|
||||
if (CE_FLOAT(wep, netvar.flNextPrimaryAttack) > g_GlobalVars->curtime && weapon_mode == weapon_melee)
|
||||
{
|
||||
|
1633
src/navparser.cpp
1633
src/navparser.cpp
File diff suppressed because it is too large
Load Diff
69
src/payloadcontroller.cpp
Normal file
69
src/payloadcontroller.cpp
Normal file
@ -0,0 +1,69 @@
|
||||
#include "payloadcontroller.hpp"
|
||||
#include "common.hpp"
|
||||
|
||||
namespace plcontroller
|
||||
{
|
||||
|
||||
// Array that controls all the payloads for each team. Red team is first, then comes blue team.
|
||||
static std::array<std::vector<CachedEntity *>, 2> payloads;
|
||||
static Timer update_payloads{};
|
||||
|
||||
void Update()
|
||||
{
|
||||
// We should update the payload list
|
||||
if (update_payloads.test_and_set(3000))
|
||||
{
|
||||
// Reset entries
|
||||
for (auto &entry : payloads)
|
||||
entry.clear();
|
||||
|
||||
for (int i = g_IEngine->GetMaxClients() + 1; i < MAX_ENTITIES; i++)
|
||||
{
|
||||
CachedEntity *ent = ENTITY(i);
|
||||
// Not the object we need or invalid (team)
|
||||
if (CE_BAD(ent) || ent->m_iClassID() != CL_CLASS(CObjectCartDispenser) || ent->m_iTeam() < TEAM_RED || ent->m_iTeam() > TEAM_BLU)
|
||||
continue;
|
||||
int team = ent->m_iTeam();
|
||||
|
||||
// Add new entry for the team
|
||||
payloads.at(team - TEAM_RED).push_back(ent);
|
||||
}
|
||||
}
|
||||
}
|
||||
std::optional<Vector> getClosestPayload(Vector source, int team)
|
||||
{
|
||||
// Invalid team
|
||||
if (team < TEAM_RED || team > TEAM_BLU)
|
||||
return std::nullopt;
|
||||
// Convert to index
|
||||
int index = team - TEAM_RED;
|
||||
auto entry = payloads[index];
|
||||
|
||||
float best_distance = FLT_MAX;
|
||||
std::optional<Vector> best_pos;
|
||||
|
||||
// Find best payload
|
||||
for (auto payload : entry)
|
||||
{
|
||||
if (CE_BAD(payload) || payload->m_iClassID() != CL_CLASS(CObjectCartDispenser))
|
||||
continue;
|
||||
if (payload->m_vecOrigin().DistTo(source) < best_distance)
|
||||
{
|
||||
best_pos = payload->m_vecOrigin();
|
||||
best_distance = payload->m_vecOrigin().DistTo(source);
|
||||
}
|
||||
}
|
||||
return best_pos;
|
||||
}
|
||||
|
||||
void LevelInit()
|
||||
{
|
||||
for (auto &entry : payloads)
|
||||
entry.clear();
|
||||
}
|
||||
|
||||
static InitRoutine init([]() {
|
||||
EC::Register(EC::CreateMove, Update, "plcreatemove");
|
||||
EC::Register(EC::LevelInit, LevelInit, "levelinit_plcontroller");
|
||||
});
|
||||
} // namespace plcontroller
|
@ -226,11 +226,15 @@ struct migration_struct
|
||||
};
|
||||
/* clang-format off */
|
||||
// Use one per line, from -> to
|
||||
static std::array<migration_struct, 4> migrations({
|
||||
static std::array<migration_struct, 8> migrations({
|
||||
migration_struct{ "misc.semi-auto", "misc.full-auto" },
|
||||
migration_struct{ "cat-bot.abandon-if.bots-gte", "cat-bot.abandon-if.ipc-bots-gte" },
|
||||
migration_struct{ "votelogger.partysay-casts", "votelogger.chat.casts" },
|
||||
migration_struct{ "votelogger.partysay-casts.f1-only", "votelogger.chat.casts.f1-only" }
|
||||
migration_struct{ "votelogger.partysay-casts.f1-only", "votelogger.chat.casts.f1-only" },
|
||||
migration_struct{ "misc.pathing", "nav.enabled" },
|
||||
migration_struct{ "misc.pathing.draw", "nav.draw" },
|
||||
migration_struct{ "misc.pathing.log", "nav.log"},
|
||||
migration_struct{ "misc.pathing.look-at-path", "nav.look-at-path"}
|
||||
});
|
||||
/* clang-format on */
|
||||
void settings::SettingsReader::finishString(bool complete)
|
||||
|
@ -22,11 +22,22 @@ int GetScoreForEntity(CachedEntity *entity)
|
||||
{
|
||||
if (!entity)
|
||||
return 0;
|
||||
// TODO
|
||||
|
||||
if (entity->m_Type() == ENTITY_BUILDING)
|
||||
{
|
||||
if (entity->m_iClassID() == CL_CLASS(CObjectSentrygun))
|
||||
{
|
||||
bool is_strong_class = g_pLocalPlayer->clazz == tf_heavy || g_pLocalPlayer->clazz == tf_soldier;
|
||||
|
||||
if (is_strong_class)
|
||||
{
|
||||
float distance = (g_pLocalPlayer->v_Origin - entity->m_vecOrigin()).Length();
|
||||
if (distance < 400.0f)
|
||||
return 120;
|
||||
else if (distance < 1100.0f)
|
||||
return 60;
|
||||
return 30;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
@ -94,7 +105,7 @@ int GetScoreForEntity(CachedEntity *entity)
|
||||
total = 999;
|
||||
if (IsSentryBuster(entity))
|
||||
total = 0;
|
||||
if (clazz == tf_medic)
|
||||
total = 999; // TODO only for mvm
|
||||
if (clazz == tf_medic && g_pGameRules->isPVEMode)
|
||||
total = 999;
|
||||
return total;
|
||||
}
|
||||
|
Reference in New Issue
Block a user