Add autoparty (#1183)
This commit is contained in:
parent
d2b3547605
commit
13a0c43b4e
@ -27,7 +27,7 @@
|
||||
<Option name="Random" value="1"/>
|
||||
<Option name="Medic" value="2"/>
|
||||
<Option name="Thanks" value="3"/>
|
||||
<Option name="Nice shot" value="4"/>
|
||||
<Option name="Nice shot" value="4"/>
|
||||
<Option name="Cheers" value="5"/>
|
||||
<Option name="Jeers" value="6"/>
|
||||
</Select>
|
||||
|
@ -6,6 +6,7 @@
|
||||
<Include path="nullifiedcat/misc/spyalert.xml"/>
|
||||
<Include path="nullifiedcat/misc/collective.xml"/>
|
||||
<Include path="nullifiedcat/misc/catbot.xml"/>
|
||||
<Include path="nullifiedcat/misc/autoparty.xml"/>
|
||||
<Include path="nullifiedcat/misc/autoload.xml"/>
|
||||
<Include path="nullifiedcat/misc/datacenters.xml"/>
|
||||
</TabContainer>
|
||||
|
17
data/menu/nullifiedcat/misc/autoparty.xml
Executable file
17
data/menu/nullifiedcat/misc/autoparty.xml
Executable file
@ -0,0 +1,17 @@
|
||||
<Tab name="Auto Party" padding="4 4 4 4">
|
||||
<Box name="Auto Party" width="content" height="content" padding="12 6 6 6">
|
||||
<List width="400">
|
||||
<AutoVariable width="fill" target="autoparty.enable" label="Enable auto party"/>
|
||||
<AutoVariable width="fill" target="autoparty.run-frequency" label="Run every N seconds"/>
|
||||
<AutoVariable width="fill" target="autoparty.max-party-size" label="Max party members allowed"/>
|
||||
<AutoVariable width="fill" target="autoparty.kick-rage" label="Automatically kick raged players from the party"/>
|
||||
<AutoVariable width="fill" target="autoparty.auto-leave" label="Leave the party when a member goes offline"/>
|
||||
<AutoVariable width="fill" target="autoparty.auto-lock" label="Lock the party when max party size is reached"/>
|
||||
<AutoVariable width="fill" target="autoparty.auto-unlock" label="Unlock the party when max party size has not been reached"/>
|
||||
<AutoVariable width="fill" target="autoparty.party-hosts" label="Comma-separated list of Steam32 IDs to use as party hosts"/>
|
||||
<AutoVariable width="fill" target="autoparty.log" label="Log party leaves and member kicks"/>
|
||||
<AutoVariable width="fill" target="autoparty.message-kicks" label="Log kick notifications to party chat"/>
|
||||
<AutoVariable width="fill" target="autoparty.debug" label="Log party locks and unlocks"/>
|
||||
</List>
|
||||
</Box>
|
||||
</Tab>
|
@ -1,38 +1,38 @@
|
||||
<Tab name="Auto Pyro" padding="4 4 4 4">
|
||||
<Box padding="12 6 6 6" width="content" height="content" name="Auto reflect">
|
||||
<List width="202">
|
||||
<AutoVariable width="fill" target="autoreflect.enable" label="Enable auto reflect"/>
|
||||
<AutoVariable width="fill" target="autoreflect.button" label="Reflect button"/>
|
||||
<AutoVariable width="fill" target="autoreflect.idle-only" label="Only reflect when able" tooltip="Don't try to reflect when using primary fire."/>
|
||||
<AutoVariable width="fill" target="autoreflect.teammate" label="Teammate projectiles" tooltip="Attempt to reflect teammate projectiles."/>
|
||||
<AutoVariable width="fill" target="autoreflect.dodgeball" label="Dodgeball mode" tooltip="Disable vischeck"/>
|
||||
<AutoVariable width="fill" target="autoreflect.legit" label="Legit mode" tooltip="Don't move the mouse to reflect. Spectator safe."/>
|
||||
</List>
|
||||
<Box padding="12 6 6 6" name="Targets" width="content" height="content" y="100">
|
||||
<Box padding="12 6 6 6" name="Big" width="content" height="content">
|
||||
<List width="95">
|
||||
<AutoVariable width="fill" target="autoreflect.rockets" label="Rockets"/>
|
||||
<AutoVariable width="fill" target="autoreflect.pipes" label="Pipes"/>
|
||||
<AutoVariable width="fill" target="autoreflect.stickies" label="Stickies"/>
|
||||
<AutoVariable width="fill" target="autoreflect.sentryrockets" label="Sentry rockets"/>
|
||||
</List>
|
||||
</Box>
|
||||
<Box padding="12 6 6 6" name="Small" width="content" height="content" x="105">
|
||||
<List width="85">
|
||||
<AutoVariable width="fill" target="autoreflect.flares" label="Flares"/>
|
||||
<AutoVariable width="fill" target="autoreflect.arrows" label="Arrows"/>
|
||||
<AutoVariable width="fill" target="autoreflect.jars" label="Jars"/>
|
||||
<AutoVariable width="fill" target="autoreflect.healingbolts" label="Healing bolts"/>
|
||||
<AutoVariable width="fill" target="autoreflect.cleavers" label="Cleavers"/>
|
||||
</List>
|
||||
</Box>
|
||||
<AutoVariable width="196" y="95" target="autoreflect.default" label="Default" tooltip="If a projectile is not known, should autoreflect still try to reflect it?"/>
|
||||
</Box>
|
||||
</Box>
|
||||
<Box padding="12 6 6 6" width="content" height="content" name="Auto Detonator" x="235">
|
||||
<List width="150">
|
||||
<AutoVariable width="fill" target="auto-detonator.enable" label="Enable auto detonator" tooltip="Auto explode flares"/>
|
||||
<AutoVariable width="fill" target="auto-detonator.ignore-cloaked" label="Ignore cloaked"/>
|
||||
</List>
|
||||
</Box>
|
||||
<Box padding="12 6 6 6" width="content" height="content" name="Auto reflect">
|
||||
<List width="202">
|
||||
<AutoVariable width="fill" target="autoreflect.enable" label="Enable auto reflect"/>
|
||||
<AutoVariable width="fill" target="autoreflect.button" label="Reflect button"/>
|
||||
<AutoVariable width="fill" target="autoreflect.idle-only" label="Only reflect when able" tooltip="Don't try to reflect when using primary fire."/>
|
||||
<AutoVariable width="fill" target="autoreflect.teammate" label="Teammate projectiles" tooltip="Attempt to reflect teammate projectiles."/>
|
||||
<AutoVariable width="fill" target="autoreflect.dodgeball" label="Dodgeball mode" tooltip="Disable vischeck"/>
|
||||
<AutoVariable width="fill" target="autoreflect.legit" label="Legit mode" tooltip="Don't move the mouse to reflect. Spectator safe."/>
|
||||
</List>
|
||||
<Box padding="12 6 6 6" name="Targets" width="content" height="content" y="100">
|
||||
<Box padding="12 6 6 6" name="Big" width="content" height="content">
|
||||
<List width="95">
|
||||
<AutoVariable width="fill" target="autoreflect.rockets" label="Rockets"/>
|
||||
<AutoVariable width="fill" target="autoreflect.pipes" label="Pipes"/>
|
||||
<AutoVariable width="fill" target="autoreflect.stickies" label="Stickies"/>
|
||||
<AutoVariable width="fill" target="autoreflect.sentryrockets" label="Sentry rockets"/>
|
||||
</List>
|
||||
</Box>
|
||||
<Box padding="12 6 6 6" name="Small" width="content" height="content" x="105">
|
||||
<List width="85">
|
||||
<AutoVariable width="fill" target="autoreflect.flares" label="Flares"/>
|
||||
<AutoVariable width="fill" target="autoreflect.arrows" label="Arrows"/>
|
||||
<AutoVariable width="fill" target="autoreflect.jars" label="Jars"/>
|
||||
<AutoVariable width="fill" target="autoreflect.healingbolts" label="Healing bolts"/>
|
||||
<AutoVariable width="fill" target="autoreflect.cleavers" label="Cleavers"/>
|
||||
</List>
|
||||
</Box>
|
||||
<AutoVariable width="196" y="95" target="autoreflect.default" label="Default" tooltip="If a projectile is not known, should autoreflect still try to reflect it?"/>
|
||||
</Box>
|
||||
</Box>
|
||||
<Box padding="12 6 6 6" width="content" height="content" name="Auto Detonator" x="235">
|
||||
<List width="150">
|
||||
<AutoVariable width="fill" target="auto-detonator.enable" label="Enable auto detonator" tooltip="Auto explode flares"/>
|
||||
<AutoVariable width="fill" target="auto-detonator.ignore-cloaked" label="Ignore cloaked"/>
|
||||
</List>
|
||||
</Box>
|
||||
</Tab>
|
||||
|
@ -40,7 +40,7 @@
|
||||
</Tab>
|
||||
<Include path="nullifiedcat/trigger/autopyro.xml"/>
|
||||
<Include path="nullifiedcat/trigger/autosticky.xml"/>
|
||||
<Include path="nullifiedcat/trigger/autoheal.xml"/>
|
||||
<Include path="nullifiedcat/trigger/autoheal.xml"/>
|
||||
<Include path="nullifiedcat/trigger/autospy.xml"/>
|
||||
</TabContainer>
|
||||
</Tab>
|
||||
|
@ -2,13 +2,13 @@
|
||||
<Box padding="12 6 6 6" width="content" height="content" name="Radar">
|
||||
<List width="150">
|
||||
<AutoVariable width="fill" target="radar.enable" label="Enable" tooltip="Shows a highly customizable radar."/>
|
||||
<LabeledObject width="fill" label="Radar Shape" tooltip="Sets the radar's shape">
|
||||
<Select target="radar.shape">
|
||||
<Option name="Square" value="0"/>
|
||||
<Option name="Circle" value="1"/>
|
||||
</Select>
|
||||
</LabeledObject>
|
||||
<AutoVariable width="fill" target="radar.show-cross" label="Show Cross" tooltip="Show cross in the center of the radar."/>
|
||||
<LabeledObject width="fill" label="Radar Shape" tooltip="Sets the radar's shape">
|
||||
<Select target="radar.shape">
|
||||
<Option name="Square" value="0"/>
|
||||
<Option name="Circle" value="1"/>
|
||||
</Select>
|
||||
</LabeledObject>
|
||||
<AutoVariable width="fill" target="radar.show-cross" label="Show Cross" tooltip="Show cross in the center of the radar."/>
|
||||
<AutoVariable width="fill" target="radar.enemies-over-teammates" label="Enemies on top"/>
|
||||
<AutoVariable width="fill" target="radar.healthbar" label="Health bar size" min="0" max="5" step="1"/>
|
||||
<AutoVariable width="fill" target="radar.use-icons" label="Use icons"/>
|
||||
@ -25,7 +25,7 @@
|
||||
<AutoVariable width="fill" target="radar.show.ammo" label="Ammo packs"/>
|
||||
<AutoVariable width="fill" target="radar.show.health" label="Health packs"/>
|
||||
<AutoVariable width="fill" target="radar.show.teammates" label="Teammates"/>
|
||||
<AutoVariable width="fill" target="radar.show.team.buildings" label="Team buildings"/>
|
||||
<AutoVariable width="fill" target="radar.show.team.buildings" label="Team buildings"/>
|
||||
<AutoVariable width="fill" target="radar.hide-invis" label="Hide invisible"/>
|
||||
</List>
|
||||
</Box>
|
||||
|
@ -14,9 +14,9 @@
|
||||
<Box padding="12 6 6 6" width="content" height="content" name="Thirdperson" y="110">
|
||||
<List width="180">
|
||||
<AutoVariable width="fill" target="visual.thirdperson.enable" label="Enable Thirdperson"/>
|
||||
<AutoVariable width="fill" target="visual.thirdperson-button" label="Thirdperson Button" tooltip="Set a Button to Toggle Thirdperson"/>
|
||||
<AutoVariable width="fill" target="visual.thirdperson-button" label="Thirdperson Button" tooltip="Set a Button to Toggle Thirdperson"/>
|
||||
<AutoVariable width="fill" target="visual.thirdperson.real-angles" label="Show Angles in Thirdperson" tooltip="Show Real Antiaim Angles in Third Person"/>
|
||||
<AutoVariable width="fill" target="visual.thirdperson.disable-zoomed" label="Disable When Zoomed" tooltip="Disables Thirdperson When Zoomed In"/>
|
||||
<AutoVariable width="fill" target="visual.thirdperson.disable-zoomed" label="Disable When Zoomed" tooltip="Disables Thirdperson When Zoomed In"/>
|
||||
</List>
|
||||
</Box>
|
||||
<Box padding="12 6 6 6" width="content" height="content" name="Remove" x="195">
|
||||
|
257
src/hacks/AutoParty.cpp
Normal file
257
src/hacks/AutoParty.cpp
Normal file
@ -0,0 +1,257 @@
|
||||
/*
|
||||
* AutoParty.cpp
|
||||
*
|
||||
* Created on: Nov 27, 2020
|
||||
* Author: delimeats-ch
|
||||
*/
|
||||
|
||||
#include "common.hpp"
|
||||
#include "hack.hpp"
|
||||
|
||||
namespace hacks::tf2::autoparty
|
||||
{
|
||||
// Enable auto-party?
|
||||
static settings::Boolean enabled{ "autoparty.enable", "false" };
|
||||
// Max number of party members before locking the party (and kicking members if there are too many)
|
||||
static settings::Int max_size{ "autoparty.max-party-size", "6" };
|
||||
// Comma-separated list of Steam32 IDs that should accept party requests
|
||||
static settings::String host_list{ "autoparty.party-hosts", "" };
|
||||
// Whether to automatically kick raged players from the party
|
||||
static settings::Boolean kick_rage{ "autoparty.kick-rage", "true" };
|
||||
// Automatically leave the party when a member goes offline
|
||||
static settings::Boolean auto_leave{ "autoparty.auto-leave", "false" };
|
||||
// Automatically lock the party when max party size is reached
|
||||
static settings::Boolean auto_lock{ "autoparty.auto-lock", "true" };
|
||||
// Automatically unlock the party when max party size has not been reached
|
||||
static settings::Boolean auto_unlock{ "autoparty.auto-unlock", "true" };
|
||||
// Actions like leaving the party or kicking members
|
||||
static settings::Boolean autoparty_log{ "autoparty.log", "true" };
|
||||
// Log kick notifications to party chat
|
||||
static settings::Boolean message_kicks{ "autoparty.message-kicks", "true" };
|
||||
// Extra debugging information like locking/unlocking the party
|
||||
static settings::Boolean autoparty_debug{ "autoparty.debug", "false" };
|
||||
// How often to run the autoparty routine, in seconds
|
||||
static settings::Int timeout{ "autoparty.run-frequency", "60" };
|
||||
// Only run the autoparty routine once every N seconds
|
||||
static Timer routine_timer{};
|
||||
// Populated by the routine when empty and by configuration changes
|
||||
static std::vector<uint32> party_hosts = {};
|
||||
|
||||
// ha ha macros go brr
|
||||
#define log(...) \
|
||||
if (*autoparty_log) \
|
||||
logging::Info("AutoParty: " __VA_ARGS__)
|
||||
|
||||
#define log_debug(...) \
|
||||
if (*autoparty_debug) \
|
||||
logging::Info("AutoParty (debug): " __VA_ARGS__)
|
||||
|
||||
// Re-populates party_hosts from the current or new configuration
|
||||
void repopulate(std::string str)
|
||||
{
|
||||
// Empty previous values
|
||||
party_hosts.clear();
|
||||
|
||||
// Add Steam32 IDs to party_hosts
|
||||
std::stringstream ss(str);
|
||||
for (uint32 id; ss >> id;)
|
||||
{
|
||||
party_hosts.push_back(id);
|
||||
if (ss.peek() == ',' or ss.peek() == ' ')
|
||||
{
|
||||
ss.ignore();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Is this bot a designated party host?
|
||||
bool is_host()
|
||||
{
|
||||
uint32 id = g_ISteamUser->GetSteamID().GetAccountID();
|
||||
for (int i = 0; i < party_hosts.size(); i++)
|
||||
{
|
||||
if (party_hosts.at(i) == id)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Tries to join every party host
|
||||
void find_party()
|
||||
{
|
||||
log_debug("No party members and not a party host; requesting to join with each party host");
|
||||
for (int i = 0; i < party_hosts.size(); i++)
|
||||
{
|
||||
hack::ExecuteCommand("tf_party_request_join_user " + std::to_string(party_hosts[i]));
|
||||
}
|
||||
}
|
||||
|
||||
// Locks the party, prevents more members from joining
|
||||
void lock_party()
|
||||
{
|
||||
// "Friends must be invited"
|
||||
hack::ExecuteCommand("tf_party_join_request_mode 2");
|
||||
}
|
||||
|
||||
// Unlocks the party, yeah?
|
||||
void unlock_party()
|
||||
{
|
||||
// "Friends can freely join"
|
||||
hack::ExecuteCommand("tf_party_join_request_mode 0");
|
||||
}
|
||||
|
||||
// Leaves the party, called when a member is offline
|
||||
// If we were the party leader, also unlock the party
|
||||
void leave_party(re::CTFPartyClient *client, bool was_leader)
|
||||
{
|
||||
log("Leaving the party because %d/%d members are offline", client->GetNumMembers() - client->GetNumOnlineMembers(), client->GetNumMembers());
|
||||
hack::ExecuteCommand("tf_party_leave");
|
||||
}
|
||||
|
||||
// Automatically join/leave parties and kick bad members
|
||||
void party_routine()
|
||||
{
|
||||
// Is this thing on?
|
||||
if (!*enabled)
|
||||
return;
|
||||
|
||||
// Only run every N seconds
|
||||
if (!routine_timer.test_and_set(*timeout * 1000))
|
||||
return;
|
||||
|
||||
// Ignore bad settings
|
||||
if (*max_size < 1 or *max_size > 6)
|
||||
{
|
||||
log("Can't have %d members, max-party-size has been reset to 6", *max_size);
|
||||
max_size = 6;
|
||||
}
|
||||
|
||||
// Populate party_hosts from the current configuration
|
||||
if (party_hosts.size() == 0)
|
||||
{
|
||||
repopulate(*host_list);
|
||||
}
|
||||
|
||||
re::CTFPartyClient *client = re::CTFPartyClient::GTFPartyClient();
|
||||
if (client)
|
||||
{
|
||||
int members = client->GetNumMembers();
|
||||
// Are we in a party?
|
||||
if (members == 1)
|
||||
{
|
||||
// We're the only player in this party, so not really
|
||||
// If we're a host, allow access, otherwise find a party to join
|
||||
if (is_host())
|
||||
{
|
||||
// We are a party host but have no members; allow access to the party
|
||||
log_debug("No members; unlocking the party");
|
||||
unlock_party();
|
||||
}
|
||||
else
|
||||
{
|
||||
find_party();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// We are in a party!
|
||||
// Get a list of party members, then check each one to determine the leader
|
||||
std::vector<unsigned> members = client->GetPartySteamIDs();
|
||||
uint32 leader_id = 0;
|
||||
for (int i = 0; i < members.size(); i++)
|
||||
{
|
||||
CSteamID id = CSteamID(members[i], EUniverse::k_EUniversePublic, EAccountType::k_EAccountTypeIndividual);
|
||||
// Are you my mummy?
|
||||
if (client->GetCurrentPartyLeader(id))
|
||||
{
|
||||
leader_id = members[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Are we the leader of the current party?
|
||||
// If so, manage it
|
||||
if (leader_id == g_ISteamUser->GetSteamID().GetAccountID())
|
||||
{
|
||||
// If a member is offline, just leave the party and allow new join requests
|
||||
if (*auto_leave and client->GetNumMembers() > client->GetNumOnlineMembers())
|
||||
{
|
||||
leave_party(client, true);
|
||||
return;
|
||||
}
|
||||
|
||||
// If enabled, check for any raged players who may have joined our party and kick them
|
||||
// If there are any, return so we don't kick other members in the event we're also over the set size limit
|
||||
if (*kick_rage)
|
||||
{
|
||||
bool should_ret = false;
|
||||
for (int i = 0; i < members.size(); i++)
|
||||
{
|
||||
auto &pl = playerlist::AccessData(members[i]);
|
||||
if (pl.state == playerlist::k_EState::RAGE)
|
||||
{
|
||||
std::string message = "Kicking Steam32 ID " + std::to_string(members[i]) + " from the party because they are set to RAGE";
|
||||
logging::Info("AutoParty: %s", message);
|
||||
if (*message_kicks)
|
||||
client->SendPartyChat(message.c_str());
|
||||
CSteamID id = CSteamID(members[i], EUniverse::k_EUniversePublic, EAccountType::k_EAccountTypeIndividual);
|
||||
client->KickPlayer(id);
|
||||
should_ret = true;
|
||||
}
|
||||
}
|
||||
if (should_ret)
|
||||
return;
|
||||
}
|
||||
|
||||
// If we are at or over the specified limit, lock the party so we auto-reject future join requests
|
||||
if (*auto_lock and members.size() >= *max_size)
|
||||
{
|
||||
log_debug("Locking the party because we have %d out of %d allowed members", members.size(), *max_size);
|
||||
lock_party();
|
||||
}
|
||||
|
||||
// Kick extra members from the party
|
||||
if (members.size() > *max_size)
|
||||
{
|
||||
int num_to_kick = members.size() - *max_size;
|
||||
std::string message = "Kicking " + std::to_string(num_to_kick) + " party members because there are " + std::to_string(members.size()) + " out of " + std::to_string(*max_size) + " allowed members";
|
||||
logging::Info("AutoParty: %s", message);
|
||||
if (*message_kicks)
|
||||
client->SendPartyChat(message.c_str());
|
||||
for (int i = 0; i < num_to_kick; i++)
|
||||
{
|
||||
CSteamID id = CSteamID(members[members.size() - (1 + i)], EUniverse::k_EUniversePublic, EAccountType::k_EAccountTypeIndividual);
|
||||
client->KickPlayer(id);
|
||||
}
|
||||
}
|
||||
|
||||
// Unlock the party if it's not full
|
||||
if (*auto_unlock and members.size() < *max_size)
|
||||
unlock_party();
|
||||
}
|
||||
else
|
||||
{
|
||||
// In a party, but not the leader
|
||||
if (*auto_lock)
|
||||
{
|
||||
log_debug("Locking our party join mode because we are not the leader of the current party");
|
||||
lock_party();
|
||||
}
|
||||
|
||||
// If a member is offline, leave the party
|
||||
if (*auto_leave and client->GetNumMembers() > client->GetNumOnlineMembers())
|
||||
{
|
||||
leave_party(client, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static InitRoutine init([]() {
|
||||
host_list.installChangeCallback([](settings::VariableBase<std::string> &var, std::string after) { repopulate(after); });
|
||||
EC::Register(EC::Paint, party_routine, "paint_autoparty", EC::average);
|
||||
});
|
||||
} // namespace hacks::tf2::autoparty
|
@ -15,6 +15,7 @@ set(files "${CMAKE_CURRENT_LIST_DIR}/AutoJoin.cpp"
|
||||
"${CMAKE_CURRENT_LIST_DIR}/AutoDeadringer.cpp"
|
||||
"${CMAKE_CURRENT_LIST_DIR}/AutoDetonator.cpp"
|
||||
"${CMAKE_CURRENT_LIST_DIR}/AutoHeal.cpp"
|
||||
"${CMAKE_CURRENT_LIST_DIR}/AutoParty.cpp"
|
||||
"${CMAKE_CURRENT_LIST_DIR}/AutoReflect.cpp"
|
||||
"${CMAKE_CURRENT_LIST_DIR}/AutoSticky.cpp"
|
||||
"${CMAKE_CURRENT_LIST_DIR}/AutoTaunt.cpp"
|
||||
|
Reference in New Issue
Block a user