-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathTriggerbot.h
More file actions
166 lines (139 loc) 路 4.43 KB
/
Copy pathTriggerbot.h
File metadata and controls
166 lines (139 loc) 路 4.43 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
#pragma once
/// @file
/// The Triggerbot feature: while the trigger key is held, fires (a synthetic left click) once the
/// crosshair is on an enemy, after a configurable delay. Reuses the shared ActorCache.
///
/// NOTE: "on target" is approximated by a body-bone being within TriggerFov pixels of the crosshair
/// (not a real trace), so the FOV/delay want in-game tuning.
#include "Feature.h"
#include "../ue/Engine.h"
#include "../cache/ActorCache.h"
#include "../native/WorldToScreen.h"
#include "../native/Visibility.h"
#include "../utils/Input.h"
#include <Windows.h>
#include <chrono>
#include <cmath>
class Triggerbot : public Feature
{
private:
std::chrono::steady_clock::time_point acquiredAt{}; ///< when the crosshair first landed on a target
std::chrono::steady_clock::time_point fireStart{}; ///< when the current synthetic click was pressed
bool onTarget = false; ///< currently on a target (edge tracking for the delay)
bool firing = false; ///< a synthetic left-button press is currently held
/// How long to hold the synthetic left button down before releasing it. A same-frame down+up is
/// often too fast for the game to register as a shot; a short hold makes it a real click.
static constexpr int HoldMs = 30;
static void MouseButton(DWORD flag)
{
INPUT input{};
input.type = INPUT_MOUSE;
input.mi.dwFlags = flag;
SendInput(1, &input, sizeof(INPUT));
}
void Press()
{
MouseButton(MOUSEEVENTF_LEFTDOWN);
firing = true;
fireStart = std::chrono::steady_clock::now();
}
void Release()
{
if (!firing) return;
MouseButton(MOUSEEVENTF_LEFTUP);
firing = false;
}
public:
Triggerbot()
{
Name = "Triggerbot";
UpdateEnabled();
Log("Created");
};
void UpdateEnabled()
{
Enabled = Settings.AIM.Triggerbot;
};
bool Check()
{
if (!Initialized) return false;
if (!Engine::PlayerController) return false;
if (!Engine::IsInGame) return false;
if (!Engine::Canvas) return false;
return true;
};
void Init()
{
Initialized = true;
Log("Initialized");
};
void Destroy()
{
Release(); // don't leave the button stuck down if the feature is disabled mid-click
};
void Run()
{
const auto& aim = Settings.AIM;
if (!Input::Down(aim.TriggerKey))
{
Release();
onTarget = false;
return;
}
auto* controller = Engine::PlayerController;
auto* localPawn = controller->AcknowledgedPawn;
if (!localPawn) return;
char localTeam = -1;
if (auto* localChar = reinterpret_cast<APortalWarsCharacter*>(controller->Character))
localTeam = localChar->GetTeamNum();
const FVector2D crosshair{Engine::Canvas->ClipX * 0.5f, Engine::Canvas->ClipY * 0.5f};
// Eye origin for the visibility line-of-sight trace.
FVector eye = localPawn->K2_GetActorLocation();
eye.Z += 80.f;
bool nowOnTarget = false;
for (const auto& cached : ActorCache::Players())
{
auto* character = cached.character;
if (reinterpret_cast<AActor*>(character) == reinterpret_cast<AActor*>(localPawn)) continue;
if (ActorCache::IsDead(cached)) continue; // don't fire at a dead body
if (aim.TriggerTeamCheck && localTeam >= 0 && cached.team == localTeam) continue;
if (aim.IgnoreBots && cached.isBot) continue; // fire only at real players
if (aim.AimVisibleCheck && !Visibility::IsVisible(character, eye)) continue; // only visible targets
auto* mesh = character->Mesh;
if (!mesh) continue;
for (const int bone : {(int)BoneFNames::head, (int)BoneFNames::spine_03, (int)BoneFNames::pelvis})
{
const FVector2D screen = Projection::Bone(mesh, bone);
if (!screen.X && !screen.Y) continue;
const float dx = screen.X - crosshair.X, dy = screen.Y - crosshair.Y;
if (sqrtf(dx * dx + dy * dy) <= aim.TriggerFov)
{
nowOnTarget = true;
break;
}
}
if (nowOnTarget) break;
}
const auto now = std::chrono::steady_clock::now();
// Release a held click after the hold window (so it reads as a real, separate shot).
if (firing && std::chrono::duration_cast<std::chrono::milliseconds>(now - fireStart).count() >= HoldMs)
Release();
if (!nowOnTarget)
{
Release();
onTarget = false;
return;
}
if (!onTarget)
{
onTarget = true;
acquiredAt = now;
}
// Press after the delay, once the previous click has been released (edge-triggered).
if (!firing && std::chrono::duration_cast<std::chrono::milliseconds>(now - acquiredAt).count() >= aim.TriggerDelay)
{
Press();
acquiredAt = now; // re-arm the delay before the next shot
}
};
};