summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/esp.cpp136
-rw-r--r--src/hl2h.cpp3
-rw-r--r--src/hl2h.h7
-rw-r--r--src/menu.cpp41
4 files changed, 174 insertions, 13 deletions
diff --git a/src/esp.cpp b/src/esp.cpp
index 47df57d..0117d27 100644
--- a/src/esp.cpp
+++ b/src/esp.cpp
@@ -1042,6 +1042,142 @@ bool melee_aimbot_apply(CUserCmd *cmd) {
1042 return false; 1042 return false;
1043} 1043}
1044 1044
1045// ---------------------------------------------------------------------------
1046// weapon spread control
1047// ---------------------------------------------------------------------------
1048//
1049// HL2's CBaseEntity::FireBullets uses CBaseEntity::GetPredictionRandomSeed()
1050// (the client usercmd's random_seed) unless a weapon opts into
1051// m_bUseServerRandomSeed. HL2 weapons do not, so the client can choose the
1052// 8-bit seed and with it the random cone offset. CShotManipulator::ApplySpread
1053// draws four uniform floats per attempt; we precompute the best seed for one
1054// shot and for the shotgun's pellet windows with the engine's own RNG.
1055
1056static bool g_spread_ready = false;
1057static int g_spread_seed1 = 0;
1058static int g_spread_seed8 = 0; // first pellet exact, 7 spread
1059static int g_spread_seed12 = 0; // all 12 spread
1060
1061static void spread_compute() {
1062 using SeedFn = void (*)(int);
1063 using FloatFn = float (*)(float, float);
1064 SeedFn seed = (SeedFn)dlsym(RTLD_DEFAULT, "RandomSeed");
1065 FloatFn rf = (FloatFn)dlsym(RTLD_DEFAULT, "RandomFloat");
1066 if (!seed || !rf) {
1067 size_t slash = g_engine.path.find_last_of('/');
1068 if (slash != std::string::npos) {
1069 std::string path = g_engine.path.substr(0, slash + 1) + "libvstdlib.so";
1070 void *h = dlopen(path.c_str(), RTLD_NOLOAD | RTLD_LAZY | RTLD_GLOBAL);
1071 if (!h)
1072 h = dlopen(path.c_str(), RTLD_LAZY | RTLD_GLOBAL);
1073 if (h) {
1074 seed = (SeedFn)dlsym(h, "RandomSeed");
1075 rf = (FloatFn)dlsym(h, "RandomFloat");
1076 }
1077 }
1078 }
1079 if (!seed || !rf) {
1080 logf("spread: RandomSeed/RandomFloat unavailable");
1081 return;
1082 }
1083
1084 auto draw = [&](int s, float &x, float &y) {
1085 seed(s);
1086 int it = 0;
1087 do {
1088 // CShotManipulator::ApplySpread with the default bias of 1.0:
1089 // shotBias = 1.0, flatness = 0.5.
1090 x = rf(-1.0f, 1.0f) * 0.5f + rf(-1.0f, 1.0f) * 0.5f;
1091 y = rf(-1.0f, 1.0f) * 0.5f + rf(-1.0f, 1.0f) * 0.5f;
1092 it++;
1093 } while (x * x + y * y > 1.0f && it < 64);
1094 };
1095
1096 float best1 = 1e9f;
1097 for (int s = 0; s < 256; s++) {
1098 float x, y;
1099 draw(s, x, y);
1100 float r2 = x * x + y * y;
1101 if (r2 < best1) {
1102 best1 = r2;
1103 g_spread_seed1 = s;
1104 }
1105 }
1106
1107 auto window = [&](int n, int first) {
1108 int best_s = 0;
1109 float best = 1e9f;
1110 for (int s = 0; s < 256; s++) {
1111 float score = 0.0f;
1112 for (int i = first; i < n; i++) {
1113 float x, y;
1114 draw(s + i, x, y);
1115 score += x * x + y * y;
1116 }
1117 if (score < best) {
1118 best = score;
1119 best_s = s;
1120 }
1121 }
1122 return best_s;
1123 };
1124 g_spread_seed8 = window(8, 1);
1125 g_spread_seed12 = window(12, 0);
1126 seed(0);
1127
1128 logf("spread: seeds single=%d shotgun8=%d shotgun12=%d", g_spread_seed1,
1129 g_spread_seed8, g_spread_seed12);
1130 g_spread_ready = true;
1131}
1132
1133static bool active_weapon_is_shotgun(void *local_ent) {
1134 if (!local_ent || g_net.activeweapon < 0)
1135 return false;
1136 uint32_t h = *(uint32_t *)((uintptr_t)local_ent + g_net.activeweapon);
1137 if (h == 0xFFFFFFFFu)
1138 return false;
1139 int idx = (int)(h & 0xFFFF);
1140 if (idx <= 0 || idx > 4096)
1141 return false;
1142 void *wep = entitylist_get(idx);
1143 void *net = entity_networkable(idx);
1144 const char *cls = net ? entity_class_name(net, nullptr) : nullptr;
1145 const char *model = wep ? entity_model_name(wep) : nullptr;
1146 return (cls && strstr(cls, "Shotgun")) ||
1147 (model && strstr(model, "shotgun"));
1148}
1149
1150bool spread_control_apply(CUserCmd *cmd, void *local_ent) {
1151 if (!feature_active(FEAT_SPREAD) || !spread_no_spread_enabled())
1152 return false;
1153 if (!(cmd->buttons & (IN_ATTACK | IN_ATTACK2)))
1154 return false;
1155 if (!g_spread_ready) {
1156 static bool tried = false;
1157 if (!tried) {
1158 tried = true;
1159 spread_compute();
1160 }
1161 }
1162 if (!g_spread_ready)
1163 return false;
1164
1165 bool shotgun = active_weapon_is_shotgun(local_ent);
1166 int seed = g_spread_seed1;
1167 if (shotgun)
1168 seed = (cmd->buttons & IN_ATTACK2) ? g_spread_seed12 : g_spread_seed8;
1169 if (cmd->random_seed == seed)
1170 return false;
1171 cmd->random_seed = seed;
1172
1173 static int logs = 0;
1174 if (logs < 10) {
1175 logs++;
1176 logf("spread: seed=%d (%s)", seed, shotgun ? "shotgun" : "single");
1177 }
1178 return true;
1179}
1180
1045bool triggerbot_apply(CUserCmd *cmd) { 1181bool triggerbot_apply(CUserCmd *cmd) {
1046 if (!g_iface.enginetrace || !g_iface.entitylist) 1182 if (!g_iface.enginetrace || !g_iface.entitylist)
1047 return false; 1183 return false;
diff --git a/src/hl2h.cpp b/src/hl2h.cpp
index ee2e990..dddcbdc 100644
--- a/src/hl2h.cpp
+++ b/src/hl2h.cpp
@@ -532,6 +532,9 @@ static void do_move(int seq, float frametime) {
532 note_modified(cmd, flags, vel); 532 note_modified(cmd, flags, vel);
533 } 533 }
534 } 534 }
535
536 if (spread_control_apply(cmd, ent))
537 note_modified(cmd, flags, vel);
535} 538}
536 539
537// --------------------------------------------------------------------------- 540// ---------------------------------------------------------------------------
diff --git a/src/hl2h.h b/src/hl2h.h
index 2680591..ef8e8d6 100644
--- a/src/hl2h.h
+++ b/src/hl2h.h
@@ -129,7 +129,7 @@ struct CUserCmd {
129// engine constants 129// engine constants
130// --------------------------------------------------------------------------- 130// ---------------------------------------------------------------------------
131 131
132enum { IN_ATTACK = 1 << 0, IN_JUMP = 1 << 1, IN_DUCK = 1 << 2, IN_USE = 1 << 5 }; 132enum { IN_ATTACK = 1 << 0, IN_JUMP = 1 << 1, IN_DUCK = 1 << 2, IN_USE = 1 << 5, IN_ATTACK2 = 1 << 11 };
133enum { FL_ONGROUND = 1 << 0, FL_DUCKING = 1 << 1, FL_INWATER = 1 << 9 }; 133enum { FL_ONGROUND = 1 << 0, FL_DUCKING = 1 << 1, FL_INWATER = 1 << 9 };
134enum { MOVETYPE_WALK = 2, MOVETYPE_NOCLIP = 8, MOVETYPE_LADDER = 9 }; 134enum { MOVETYPE_WALK = 2, MOVETYPE_NOCLIP = 8, MOVETYPE_LADDER = 9 };
135 135
@@ -150,6 +150,7 @@ bool triggerbot_apply(CUserCmd *cmd);
150bool silent_aim_apply(CUserCmd *cmd); 150bool silent_aim_apply(CUserCmd *cmd);
151bool melee_weapon_active(void *local_ent); 151bool melee_weapon_active(void *local_ent);
152bool melee_aimbot_apply(CUserCmd *cmd); 152bool melee_aimbot_apply(CUserCmd *cmd);
153bool spread_control_apply(CUserCmd *cmd, void *local_ent);
153enum FeatureId { 154enum FeatureId {
154 FEAT_BHOP = 0, 155 FEAT_BHOP = 0,
155 FEAT_ABH = 1, 156 FEAT_ABH = 1,
@@ -158,7 +159,8 @@ enum FeatureId {
158 FEAT_TRIGGERBOT = 4, 159 FEAT_TRIGGERBOT = 4,
159 FEAT_SILENTAIM = 5, 160 FEAT_SILENTAIM = 5,
160 FEAT_JUMPBUG = 6, 161 FEAT_JUMPBUG = 6,
161 FEAT_MELEE = 7 162 FEAT_MELEE = 7,
163 FEAT_SPREAD = 8
162}; 164};
163enum EspOption { 165enum EspOption {
164 ESP_OPT_SHOW_NEUTRAL = 0, 166 ESP_OPT_SHOW_NEUTRAL = 0,
@@ -193,6 +195,7 @@ bool feature_bind_held(int feature);
193bool esp_option(int opt); 195bool esp_option(int opt);
194bool bhop_autostrafe_enabled(); 196bool bhop_autostrafe_enabled();
195bool jumpbug_assist_enabled(); 197bool jumpbug_assist_enabled();
198bool spread_no_spread_enabled();
196unsigned aimbot_bone_mask(); 199unsigned aimbot_bone_mask();
197int aimbot_smooth_step(); 200int aimbot_smooth_step();
198bool aimbot_vischeck_enabled(); 201bool aimbot_vischeck_enabled();
diff --git a/src/menu.cpp b/src/menu.cpp
index f590d69..9dffc9e 100644
--- a/src/menu.cpp
+++ b/src/menu.cpp
@@ -40,7 +40,7 @@ struct MenuNode {
40 const char *label; 40 const char *label;
41 bool expanded; // for root/feature: whether children are visible 41 bool expanded; // for root/feature: whether children are visible
42 int child_count; 42 int child_count;
43 MenuNode *children[8]; // max children per node 43 MenuNode *children[12]; // max children per node
44 44
45 // leaf data 45 // leaf data
46 bool *active_ptr; // NODE_TOGGLE: pointer to the active flag 46 bool *active_ptr; // NODE_TOGGLE: pointer to the active flag
@@ -65,6 +65,8 @@ static FeatureState g_abh{true, 0};
65static FeatureState g_jumpbug{true, 0}; 65static FeatureState g_jumpbug{true, 0};
66static bool g_jumpbug_assist = false; 66static bool g_jumpbug_assist = false;
67static FeatureState g_melee{true, 0}; 67static FeatureState g_melee{true, 0};
68static FeatureState g_spread{true, 0};
69static bool g_spread_no_spread = true;
68static FeatureState g_esp{true, 0}; 70static FeatureState g_esp{true, 0};
69static FeatureState g_aimbot{true, 604}; // default Mouse5, rebindable in menu 71static FeatureState g_aimbot{true, 604}; // default Mouse5, rebindable in menu
70static FeatureState g_triggerbot{true, 603}; // default Mouse4 72static FeatureState g_triggerbot{true, 603}; // default Mouse4
@@ -104,6 +106,9 @@ static MenuNode g_jumpbug_active{NODE_TOGGLE, "Active", false, 0, {}, &g_jumpbug
104static MenuNode g_jumpbug_assist_node{NODE_TOGGLE, "Assist timing", false, 0, {}, &g_jumpbug_assist, nullptr, nullptr}; 106static MenuNode g_jumpbug_assist_node{NODE_TOGGLE, "Assist timing", false, 0, {}, &g_jumpbug_assist, nullptr, nullptr};
105static MenuNode g_melee_feat{NODE_FEATURE, "Melee killbot", false, 1, {}, nullptr, nullptr, nullptr}; 107static MenuNode g_melee_feat{NODE_FEATURE, "Melee killbot", false, 1, {}, nullptr, nullptr, nullptr};
106static MenuNode g_melee_active{NODE_TOGGLE, "Active", false, 0, {}, &g_melee.active, nullptr, nullptr}; 108static MenuNode g_melee_active{NODE_TOGGLE, "Active", false, 0, {}, &g_melee.active, nullptr, nullptr};
109static MenuNode g_spread_feat{NODE_FEATURE, "Spread control", false, 1, {}, nullptr, nullptr, nullptr};
110static MenuNode g_spread_active{NODE_TOGGLE, "Active", false, 0, {}, &g_spread.active, nullptr, nullptr};
111static MenuNode g_spread_no_spread_node{NODE_TOGGLE, "No spread", false, 0, {}, &g_spread_no_spread, nullptr, nullptr};
107static MenuNode g_esp_feat{NODE_FEATURE, "ESP", false, 1, {}, nullptr, nullptr, nullptr}; 112static MenuNode g_esp_feat{NODE_FEATURE, "ESP", false, 1, {}, nullptr, nullptr, nullptr};
108static MenuNode g_esp_active{NODE_TOGGLE, "Active", false, 0, {}, &g_esp.active, nullptr, nullptr}; 113static MenuNode g_esp_active{NODE_TOGGLE, "Active", false, 0, {}, &g_esp.active, nullptr, nullptr};
109static MenuNode g_esp_opt_nodes[ESP_OPT_COUNT] = { 114static MenuNode g_esp_opt_nodes[ESP_OPT_COUNT] = {
@@ -161,6 +166,9 @@ static void build_tree() {
161 g_jumpbug_feat.child_count = 2; 166 g_jumpbug_feat.child_count = 2;
162 g_melee_feat.children[0] = &g_melee_active; 167 g_melee_feat.children[0] = &g_melee_active;
163 g_melee_feat.child_count = 1; 168 g_melee_feat.child_count = 1;
169 g_spread_feat.children[0] = &g_spread_active;
170 g_spread_feat.children[1] = &g_spread_no_spread_node;
171 g_spread_feat.child_count = 2;
164 g_esp_feat.children[0] = &g_esp_active; 172 g_esp_feat.children[0] = &g_esp_active;
165 g_aimbot_feat.children[0] = &g_aimbot_active; 173 g_aimbot_feat.children[0] = &g_aimbot_active;
166 g_aimbot_feat.children[1] = &g_aimbot_bind; 174 g_aimbot_feat.children[1] = &g_aimbot_bind;
@@ -187,11 +195,12 @@ static void build_tree() {
187 g_root.children[1] = &g_abh_feat; 195 g_root.children[1] = &g_abh_feat;
188 g_root.children[2] = &g_jumpbug_feat; 196 g_root.children[2] = &g_jumpbug_feat;
189 g_root.children[3] = &g_melee_feat; 197 g_root.children[3] = &g_melee_feat;
190 g_root.children[4] = &g_esp_feat; 198 g_root.children[4] = &g_spread_feat;
191 g_root.children[5] = &g_aimbot_feat; 199 g_root.children[5] = &g_esp_feat;
192 g_root.children[6] = &g_triggerbot_feat; 200 g_root.children[6] = &g_aimbot_feat;
193 g_root.children[7] = &g_silentaim_feat; 201 g_root.children[7] = &g_triggerbot_feat;
194 g_root.child_count = 8; 202 g_root.children[8] = &g_silentaim_feat;
203 g_root.child_count = 9;
195} 204}
196 205
197static int g_depth[48]; // depth of each visible row (for indentation) 206static int g_depth[48]; // depth of each visible row (for indentation)
@@ -316,6 +325,8 @@ static void config_save() {
316 fprintf(f, "[jumpbug]\nactive=%d\nassist=%d\n", g_jumpbug.active, 325 fprintf(f, "[jumpbug]\nactive=%d\nassist=%d\n", g_jumpbug.active,
317 (int)g_jumpbug_assist); 326 (int)g_jumpbug_assist);
318 fprintf(f, "[melee]\nactive=%d\n", g_melee.active); 327 fprintf(f, "[melee]\nactive=%d\n", g_melee.active);
328 fprintf(f, "[spread]\nactive=%d\nno_spread=%d\n", g_spread.active,
329 (int)g_spread_no_spread);
319 fprintf(f, "[aimbot]\nactive=%d\nbind=%d\nsmooth=%d\nvischeck=%d\n" 330 fprintf(f, "[aimbot]\nactive=%d\nbind=%d\nsmooth=%d\nvischeck=%d\n"
320 "fov=%d\nfov_circle=%d\n" 331 "fov=%d\nfov_circle=%d\n"
321 "bone_head=%d\nbone_torso=%d\nbone_larm=%d\nbone_rarm=%d\n" 332 "bone_head=%d\nbone_torso=%d\nbone_larm=%d\nbone_rarm=%d\n"
@@ -346,7 +357,7 @@ static void config_load() {
346 char line[256]; 357 char line[256];
347 FeatureState *cur = nullptr; 358 FeatureState *cur = nullptr;
348 bool in_esp = false, in_bhop = false, in_aim = false, in_silent = false, 359 bool in_esp = false, in_bhop = false, in_aim = false, in_silent = false,
349 in_jumpbug = false; 360 in_jumpbug = false, in_spread = false;
350 while (fgets(line, sizeof(line), f)) { 361 while (fgets(line, sizeof(line), f)) {
351 line[strcspn(line, "\r\n")] = 0; 362 line[strcspn(line, "\r\n")] = 0;
352 if (line[0] == '[') { 363 if (line[0] == '[') {
@@ -358,6 +369,8 @@ static void config_load() {
358 cur = &g_jumpbug; 369 cur = &g_jumpbug;
359 else if (strstr(line, "[melee]")) 370 else if (strstr(line, "[melee]"))
360 cur = &g_melee; 371 cur = &g_melee;
372 else if (strstr(line, "[spread]"))
373 cur = &g_spread;
361 else if (strstr(line, "[esp]")) 374 else if (strstr(line, "[esp]"))
362 cur = &g_esp; 375 cur = &g_esp;
363 else if (strstr(line, "[aimbot]")) 376 else if (strstr(line, "[aimbot]"))
@@ -373,6 +386,7 @@ static void config_load() {
373 in_aim = (cur == &g_aimbot); 386 in_aim = (cur == &g_aimbot);
374 in_silent = (cur == &g_silentaim); 387 in_silent = (cur == &g_silentaim);
375 in_jumpbug = (cur == &g_jumpbug); 388 in_jumpbug = (cur == &g_jumpbug);
389 in_spread = (cur == &g_spread);
376 } else if (cur) { 390 } else if (cur) {
377 char *eq = strchr(line, '='); 391 char *eq = strchr(line, '=');
378 if (!eq) 392 if (!eq)
@@ -385,6 +399,9 @@ static void config_load() {
385 if (in_jumpbug && strcmp(key, "assist") == 0) { 399 if (in_jumpbug && strcmp(key, "assist") == 0) {
386 g_jumpbug_assist = atoi(val) != 0; 400 g_jumpbug_assist = atoi(val) != 0;
387 } 401 }
402 if (in_spread && strcmp(key, "no_spread") == 0) {
403 g_spread_no_spread = atoi(val) != 0;
404 }
388 if (in_aim) { 405 if (in_aim) {
389 if (strcmp(key, "smooth") == 0) { 406 if (strcmp(key, "smooth") == 0) {
390 int v = atoi(val); 407 int v = atoi(val);
@@ -546,10 +563,10 @@ static bool key_pressed(int sc) {
546// feature gate queried from hl2h.cpp do_move(): feature must be Active AND 563// feature gate queried from hl2h.cpp do_move(): feature must be Active AND
547// its bind key held (always-on when unbound). 564// its bind key held (always-on when unbound).
548static FeatureState *feature_state(int feature) { 565static FeatureState *feature_state(int feature) {
549 static FeatureState *feats[8] = {&g_bhop, &g_abh, &g_esp, 566 static FeatureState *feats[9] = {&g_bhop, &g_abh, &g_esp,
550 &g_aimbot, &g_triggerbot, &g_silentaim, 567 &g_aimbot, &g_triggerbot, &g_silentaim,
551 &g_jumpbug, &g_melee}; 568 &g_jumpbug, &g_melee, &g_spread};
552 if (feature < 0 || feature > 7) 569 if (feature < 0 || feature > 8)
553 return nullptr; 570 return nullptr;
554 return feats[feature]; 571 return feats[feature];
555} 572}
@@ -579,6 +596,8 @@ bool bhop_autostrafe_enabled() { return g_bhop_autostrafe; }
579 596
580bool jumpbug_assist_enabled() { return g_jumpbug_assist; } 597bool jumpbug_assist_enabled() { return g_jumpbug_assist; }
581 598
599bool spread_no_spread_enabled() { return g_spread_no_spread; }
600
582unsigned aimbot_bone_mask() { 601unsigned aimbot_bone_mask() {
583 unsigned m = 0; 602 unsigned m = 0;
584 if (g_aim_bones[AIM_BONE_HEAD]) 603 if (g_aim_bones[AIM_BONE_HEAD])