diff options
Diffstat (limited to '')
| -rw-r--r-- | src/hl2h.cpp | 56 | ||||
| -rw-r--r-- | src/hl2h.h | 1 | ||||
| -rw-r--r-- | src/menu.cpp | 21 |
3 files changed, 73 insertions, 5 deletions
diff --git a/src/hl2h.cpp b/src/hl2h.cpp index a451a18..b666585 100644 --- a/src/hl2h.cpp +++ b/src/hl2h.cpp | |||
| @@ -114,6 +114,60 @@ void *entitylist_get(int idx) { | |||
| 114 | return vfunc<Fn>(g_iface.entitylist, 3)(g_iface.entitylist, idx); | 114 | return vfunc<Fn>(g_iface.entitylist, 3)(g_iface.entitylist, idx); |
| 115 | } | 115 | } |
| 116 | 116 | ||
| 117 | // Source air-strafe. The movement code caps the *wishspeed* used for the | ||
| 118 | // acceleration delta to GetAirSpeedCap() (30) but scales accelspeed by the | ||
| 119 | // full wishspeed, then clamps to the delta. Putting wishdir perpendicular to | ||
| 120 | // the horizontal velocity makes the delta maximal every tick. We express that | ||
| 121 | // world-space direction in the current view basis so the camera is untouched. | ||
| 122 | // | ||
| 123 | // The perpendicular is chosen so the velocity turns toward the direction the | ||
| 124 | // player is actually asking for (W/S/A/D relative to the view), which keeps | ||
| 125 | // the feature useful in every direction instead of only forward. | ||
| 126 | static void apply_autostrafe(CUserCmd *cmd, const float *vel) { | ||
| 127 | float vx = vel[0], vy = vel[1]; | ||
| 128 | float speed = sqrtf(vx * vx + vy * vy); | ||
| 129 | if (speed < 1.0f) | ||
| 130 | return; | ||
| 131 | |||
| 132 | float yaw = cmd->viewangles[1] * PI_F / 180.0f; | ||
| 133 | float cy = cosf(yaw), sy = sinf(yaw); | ||
| 134 | float fx = cy, fy = sy; // view forward on the XY plane | ||
| 135 | float rx = sy, ry = -cy; // view right on the XY plane | ||
| 136 | |||
| 137 | // Intended ground-plane direction from the raw movement keys (before we | ||
| 138 | // overwrite them). No keys held -> keep accelerating along current travel. | ||
| 139 | float tx, ty; | ||
| 140 | if (fabsf(cmd->forwardmove) > 0.01f || fabsf(cmd->sidemove) > 0.01f) { | ||
| 141 | tx = fx * cmd->forwardmove + rx * cmd->sidemove; | ||
| 142 | ty = fy * cmd->forwardmove + ry * cmd->sidemove; | ||
| 143 | float tl = sqrtf(tx * tx + ty * ty); | ||
| 144 | tx /= tl; | ||
| 145 | ty /= tl; | ||
| 146 | } else { | ||
| 147 | // No movement keys held: accelerate along the crosshair (a velocity- | ||
| 148 | // relative target would keep rotating with the velocity and circle). | ||
| 149 | tx = fx; | ||
| 150 | ty = fy; | ||
| 151 | } | ||
| 152 | |||
| 153 | // +90 degrees from horizontal velocity ("left" in Source's XY convention); | ||
| 154 | // the other perpendicular is its negation. Pick the side that rotates the | ||
| 155 | // velocity toward the intended direction. | ||
| 156 | float px = -vy / speed, py = vx / speed; | ||
| 157 | float cross = vx * ty - vy * tx; // > 0 => target is left of velocity | ||
| 158 | static int last_side = -1; | ||
| 159 | int side = (cross >= 0.0f) ? -1 : 1; | ||
| 160 | if (fabsf(cross) < 1e-6f) // exactly aligned/opposite: keep previous side | ||
| 161 | side = last_side; | ||
| 162 | last_side = side; | ||
| 163 | |||
| 164 | float dx = (side < 0) ? px : -px; | ||
| 165 | float dy = (side < 0) ? py : -py; | ||
| 166 | // 450 saturates the usercmd move clamps and the engine's air-accel cap. | ||
| 167 | cmd->forwardmove = (dx * fx + dy * fy) * 450.0f; | ||
| 168 | cmd->sidemove = (dx * rx + dy * ry) * 450.0f; | ||
| 169 | } | ||
| 170 | |||
| 117 | static void do_move(int seq) { | 171 | static void do_move(int seq) { |
| 118 | static bool g_echo_sent = false; | 172 | static bool g_echo_sent = false; |
| 119 | if (!g_input || !g_net.ok()) | 173 | if (!g_input || !g_net.ok()) |
| @@ -177,6 +231,8 @@ static void do_move(int seq) { | |||
| 177 | if (!onground) { | 231 | if (!onground) { |
| 178 | lastground = false; | 232 | lastground = false; |
| 179 | cmd->buttons &= ~IN_JUMP; | 233 | cmd->buttons &= ~IN_JUMP; |
| 234 | if (!inwater && bhop_autostrafe_enabled()) | ||
| 235 | apply_autostrafe(cmd, vel); | ||
| 180 | note_modified(cmd, flags, vel); | 236 | note_modified(cmd, flags, vel); |
| 181 | } else if (!lastground) { | 237 | } else if (!lastground) { |
| 182 | lastground = true; | 238 | lastground = true; |
| @@ -161,6 +161,7 @@ void find_modules(); | |||
| 161 | void init_conmsg(); | 161 | void init_conmsg(); |
| 162 | bool feature_active(int feature); | 162 | bool feature_active(int feature); |
| 163 | bool esp_option(int opt); | 163 | bool esp_option(int opt); |
| 164 | bool bhop_autostrafe_enabled(); | ||
| 164 | void *entitylist_get(int idx); | 165 | void *entitylist_get(int idx); |
| 165 | int engine_get_local_player(); | 166 | int engine_get_local_player(); |
| 166 | void draw_text_col(int x, int y, const char *s, int r, int g, int b); | 167 | void draw_text_col(int x, int y, const char *s, int r, int g, int b); |
diff --git a/src/menu.cpp b/src/menu.cpp index 2caf0aa..c8dffc9 100644 --- a/src/menu.cpp +++ b/src/menu.cpp | |||
| @@ -52,6 +52,7 @@ struct FeatureState { | |||
| 52 | }; | 52 | }; |
| 53 | 53 | ||
| 54 | static FeatureState g_bhop{true, 0}; | 54 | static FeatureState g_bhop{true, 0}; |
| 55 | static bool g_bhop_autostrafe = true; | ||
| 55 | 56 | ||
| 56 | static FeatureState g_abh{true, 0}; | 57 | static FeatureState g_abh{true, 0}; |
| 57 | static FeatureState g_esp{true, 0}; | 58 | static FeatureState g_esp{true, 0}; |
| @@ -64,6 +65,7 @@ static bool g_esp_opt[ESP_OPT_COUNT] = {true, true, true, true}; | |||
| 64 | static MenuNode g_root{NODE_ROOT, "HL2hake", true, 0, {}, nullptr, nullptr, nullptr}; | 65 | static MenuNode g_root{NODE_ROOT, "HL2hake", true, 0, {}, nullptr, nullptr, nullptr}; |
| 65 | static MenuNode g_bhop_feat{NODE_FEATURE, "Bunnyhop", true, 1, {}, nullptr, nullptr, nullptr}; | 66 | static MenuNode g_bhop_feat{NODE_FEATURE, "Bunnyhop", true, 1, {}, nullptr, nullptr, nullptr}; |
| 66 | static MenuNode g_bhop_active{NODE_TOGGLE, "Active", false, 0, {}, &g_bhop.active, nullptr, nullptr}; | 67 | static MenuNode g_bhop_active{NODE_TOGGLE, "Active", false, 0, {}, &g_bhop.active, nullptr, nullptr}; |
| 68 | static MenuNode g_bhop_autostrafe_node{NODE_TOGGLE, "Uni-directional auto-strafe", false, 0, {}, &g_bhop_autostrafe, nullptr, nullptr}; | ||
| 67 | static MenuNode g_abh_feat{NODE_FEATURE, "ABH", true, 1, {}, nullptr, nullptr, nullptr}; | 69 | static MenuNode g_abh_feat{NODE_FEATURE, "ABH", true, 1, {}, nullptr, nullptr, nullptr}; |
| 68 | static MenuNode g_abh_active{NODE_TOGGLE, "Active", false, 0, {}, &g_abh.active, nullptr, nullptr}; | 70 | static MenuNode g_abh_active{NODE_TOGGLE, "Active", false, 0, {}, &g_abh.active, nullptr, nullptr}; |
| 69 | static MenuNode g_esp_feat{NODE_FEATURE, "ESP", true, 1, {}, nullptr, nullptr, nullptr}; | 71 | static MenuNode g_esp_feat{NODE_FEATURE, "ESP", true, 1, {}, nullptr, nullptr, nullptr}; |
| @@ -83,6 +85,8 @@ bool g_menu_open = false; | |||
| 83 | static bool g_bind_mode = false; | 85 | static bool g_bind_mode = false; |
| 84 | static void build_tree() { | 86 | static void build_tree() { |
| 85 | g_bhop_feat.children[0] = &g_bhop_active; | 87 | g_bhop_feat.children[0] = &g_bhop_active; |
| 88 | g_bhop_feat.children[1] = &g_bhop_autostrafe_node; | ||
| 89 | g_bhop_feat.child_count = 2; | ||
| 86 | g_abh_feat.children[0] = &g_abh_active; | 90 | g_abh_feat.children[0] = &g_abh_active; |
| 87 | g_esp_feat.children[0] = &g_esp_active; | 91 | g_esp_feat.children[0] = &g_esp_active; |
| 88 | for (int i = 0; i < ESP_OPT_COUNT; i++) | 92 | for (int i = 0; i < ESP_OPT_COUNT; i++) |
| @@ -151,7 +155,8 @@ static void config_save() { | |||
| 151 | FILE *f = fopen(config_path().c_str(), "w"); | 155 | FILE *f = fopen(config_path().c_str(), "w"); |
| 152 | if (!f) | 156 | if (!f) |
| 153 | return; | 157 | return; |
| 154 | fprintf(f, "[bhop]\nactive=%d\nbind=%d\n", g_bhop.active, g_bhop.bind); | 158 | fprintf(f, "[bhop]\nactive=%d\nbind=%d\nautostrafe=%d\n", g_bhop.active, |
| 159 | g_bhop.bind, g_bhop_autostrafe); | ||
| 155 | fprintf(f, "[abh]\nactive=%d\nbind=%d\n", g_abh.active, g_abh.bind); | 160 | fprintf(f, "[abh]\nactive=%d\nbind=%d\n", g_abh.active, g_abh.bind); |
| 156 | fprintf(f, "[esp]\nactive=%d\nbind=%d\nneutral=%d\nhealthbar=%d\n" | 161 | fprintf(f, "[esp]\nactive=%d\nbind=%d\nneutral=%d\nhealthbar=%d\n" |
| 157 | "healthnum=%d\nname=%d\n", | 162 | "healthnum=%d\nname=%d\n", |
| @@ -167,7 +172,7 @@ static void config_load() { | |||
| 167 | return; | 172 | return; |
| 168 | char line[256]; | 173 | char line[256]; |
| 169 | FeatureState *cur = nullptr; | 174 | FeatureState *cur = nullptr; |
| 170 | bool in_esp = false; | 175 | bool in_esp = false, in_bhop = false; |
| 171 | while (fgets(line, sizeof(line), f)) { | 176 | while (fgets(line, sizeof(line), f)) { |
| 172 | line[strcspn(line, "\r\n")] = 0; | 177 | line[strcspn(line, "\r\n")] = 0; |
| 173 | if (line[0] == '[') { | 178 | if (line[0] == '[') { |
| @@ -180,12 +185,16 @@ static void config_load() { | |||
| 180 | else | 185 | else |
| 181 | cur = nullptr; | 186 | cur = nullptr; |
| 182 | in_esp = (cur == &g_esp); | 187 | in_esp = (cur == &g_esp); |
| 188 | in_bhop = (cur == &g_bhop); | ||
| 183 | } else if (cur) { | 189 | } else if (cur) { |
| 184 | char *eq = strchr(line, '='); | 190 | char *eq = strchr(line, '='); |
| 185 | if (!eq) | 191 | if (!eq) |
| 186 | continue; | 192 | continue; |
| 187 | *eq = 0; | 193 | *eq = 0; |
| 188 | const char *key = line, *val = eq + 1; | 194 | const char *key = line, *val = eq + 1; |
| 195 | if (in_bhop && strcmp(key, "autostrafe") == 0) { | ||
| 196 | g_bhop_autostrafe = atoi(val) != 0; | ||
| 197 | } | ||
| 189 | if (in_esp) { | 198 | if (in_esp) { |
| 190 | if (strcmp(key, "neutral") == 0) | 199 | if (strcmp(key, "neutral") == 0) |
| 191 | g_esp_opt[ESP_OPT_SHOW_NEUTRAL] = atoi(val) != 0; | 200 | g_esp_opt[ESP_OPT_SHOW_NEUTRAL] = atoi(val) != 0; |
| @@ -319,6 +328,8 @@ bool esp_option(int opt) { | |||
| 319 | return opt >= 0 && opt < ESP_OPT_COUNT && g_esp_opt[opt]; | 328 | return opt >= 0 && opt < ESP_OPT_COUNT && g_esp_opt[opt]; |
| 320 | } | 329 | } |
| 321 | 330 | ||
| 331 | bool bhop_autostrafe_enabled() { return g_bhop_autostrafe; } | ||
| 332 | |||
| 322 | static void menu_handle_input() { | 333 | static void menu_handle_input() { |
| 323 | poll_keyboard(); | 334 | poll_keyboard(); |
| 324 | 335 | ||
| @@ -557,10 +568,10 @@ void outer_draw() { | |||
| 557 | draw_text(x, 10 + i * 20, line); | 568 | draw_text(x, 10 + i * 20, line); |
| 558 | // right-aligned state | 569 | // right-aligned state |
| 559 | if (n->type == NODE_TOGGLE) { | 570 | if (n->type == NODE_TOGGLE) { |
| 560 | draw_text(200, 10 + i * 20, *n->active_ptr ? "[on]" : "[off]"); | 571 | draw_text(270, 10 + i * 20, *n->active_ptr ? "[on]" : "[off]"); |
| 561 | } else if (n->type == NODE_BIND) { | 572 | } else if (n->type == NODE_BIND) { |
| 562 | if (g_bind_mode && i == g_selected) | 573 | if (g_bind_mode && i == g_selected) |
| 563 | draw_text(200, 10 + i * 20, "[press key]"); | 574 | draw_text(270, 10 + i * 20, "[press key]"); |
| 564 | else { | 575 | else { |
| 565 | /* stable name for current bind */ | 576 | /* stable name for current bind */ |
| 566 | static char bn[2][32]; | 577 | static char bn[2][32]; |
| @@ -570,7 +581,7 @@ void outer_draw() { | |||
| 570 | if (n->bind_ptr == &feats[k]->bind) | 581 | if (n->bind_ptr == &feats[k]->bind) |
| 571 | fi = k; | 582 | fi = k; |
| 572 | snprintf(bn[fi], 32, "[%s]", scancode_name(*n->bind_ptr)); | 583 | snprintf(bn[fi], 32, "[%s]", scancode_name(*n->bind_ptr)); |
| 573 | draw_text(200, 10 + i * 20, bn[fi]); | 584 | draw_text(270, 10 + i * 20, bn[fi]); |
| 574 | } | 585 | } |
| 575 | } | 586 | } |
| 576 | } | 587 | } |
