diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/hl2h.cpp | 27 |
1 files changed, 22 insertions, 5 deletions
diff --git a/src/hl2h.cpp b/src/hl2h.cpp index 02bf584..8ab1a3e 100644 --- a/src/hl2h.cpp +++ b/src/hl2h.cpp | |||
| @@ -482,6 +482,8 @@ static void (*g_real_random_seed)(int) = nullptr; | |||
| 482 | static uintptr_t g_srv_base = 0; | 482 | static uintptr_t g_srv_base = 0; |
| 483 | static uintptr_t g_local_server_player = 0; | 483 | static uintptr_t g_local_server_player = 0; |
| 484 | static bool g_seed_hook_installed = false; | 484 | static bool g_seed_hook_installed = false; |
| 485 | // Pellet-spread window armed by the player's FireBullets RandomSeed call. | ||
| 486 | static volatile int g_spread_rand_left = 0; | ||
| 485 | 487 | ||
| 486 | static void hkdSrvRandomSeed(int seed) { | 488 | static void hkdSrvRandomSeed(int seed) { |
| 487 | uintptr_t ret = (uintptr_t)__builtin_return_address(0); | 489 | uintptr_t ret = (uintptr_t)__builtin_return_address(0); |
| @@ -502,6 +504,7 @@ static void hkdSrvRandomSeed(int seed) { | |||
| 502 | 504 | ||
| 503 | if (local && g_server.contains(ret) && feature_active(FEAT_SPREAD) && | 505 | if (local && g_server.contains(ret) && feature_active(FEAT_SPREAD) && |
| 504 | spread_no_spread_enabled()) { | 506 | spread_no_spread_enabled()) { |
| 507 | g_spread_rand_left = 8; | ||
| 505 | int pellets = g_spread_pellets; | 508 | int pellets = g_spread_pellets; |
| 506 | if (pellets < 1) | 509 | if (pellets < 1) |
| 507 | pellets = 1; | 510 | pellets = 1; |
| @@ -590,19 +593,33 @@ static void install_seed_hook() { | |||
| 590 | 593 | ||
| 591 | static float (*g_orig_uniform_float)(void *, float, float) = nullptr; | 594 | static float (*g_orig_uniform_float)(void *, float, float) = nullptr; |
| 592 | static bool g_uniform_hook_installed = false; | 595 | static bool g_uniform_hook_installed = false; |
| 596 | // g_spread_rand_left is set for a few draws right after the player's | ||
| 597 | // FireBullets RandomSeed. The ApplySpread frame is not always the player's | ||
| 598 | // (the compiler may outline it), so this window is the reliable signal. | ||
| 593 | 599 | ||
| 594 | static float hkdUniformRandomFloat(void *self, float mn, float mx) { | 600 | static float hkdUniformRandomFloat(void *self, float mn, float mx) { |
| 595 | if (g_local_server_player && feature_active(FEAT_SPREAD) && | 601 | bool enabled = g_local_server_player && feature_active(FEAT_SPREAD) && |
| 596 | spread_no_spread_enabled()) { | 602 | spread_no_spread_enabled(); |
| 603 | bool hit = false; | ||
| 604 | void *who = nullptr; | ||
| 605 | if (enabled) { | ||
| 597 | void *frame = nullptr; | 606 | void *frame = nullptr; |
| 598 | __asm__ volatile("movl %%ebp, %0" : "=r"(frame)); | 607 | __asm__ volatile("movl %%ebp, %0" : "=r"(frame)); |
| 599 | if (frame) { | 608 | if (frame) { |
| 600 | frame = *(void **)frame; // caller's ebp (CBaseEntity::FireBullets) | 609 | frame = *(void **)frame; // caller's ebp |
| 601 | void *who = frame ? *(void **)((char *)frame + 8) : nullptr; | 610 | who = frame ? *(void **)((char *)frame + 8) : nullptr; |
| 602 | if (who && (uintptr_t)who == g_local_server_player) | 611 | if (who && (uintptr_t)who == g_local_server_player) |
| 603 | return 0.0f; | 612 | hit = true; |
| 613 | } | ||
| 614 | if (!hit && g_spread_rand_left > 0) { | ||
| 615 | // The next few draws after the player's FireBullets RandomSeed are the | ||
| 616 | // pellet spread, regardless of which function emits them. | ||
| 617 | hit = true; | ||
| 618 | g_spread_rand_left--; | ||
| 604 | } | 619 | } |
| 605 | } | 620 | } |
| 621 | if (hit) | ||
| 622 | return 0.0f; | ||
| 606 | return g_orig_uniform_float ? g_orig_uniform_float(self, mn, mx) : mn; | 623 | return g_orig_uniform_float ? g_orig_uniform_float(self, mn, mx) : mn; |
| 607 | } | 624 | } |
| 608 | 625 | ||
