diff options
Diffstat (limited to '')
| -rw-r--r-- | src/esp.cpp | 158 |
1 files changed, 153 insertions, 5 deletions
diff --git a/src/esp.cpp b/src/esp.cpp index d32a8bc..594a8fa 100644 --- a/src/esp.cpp +++ b/src/esp.cpp | |||
| @@ -320,7 +320,8 @@ static int npc_damage_class(int idx, const char *model) { | |||
| 320 | if (td == 0 || td == 1) // DAMAGE_NO / DAMAGE_EVENTS_ONLY | 320 | if (td == 0 || td == 1) // DAMAGE_NO / DAMAGE_EVENTS_ONLY |
| 321 | return NPC_DMG_IMMUNE; | 321 | return NPC_DMG_IMMUNE; |
| 322 | if (model_has(model, "gunship") || model_has(model, "combine_strider") || | 322 | if (model_has(model, "gunship") || model_has(model, "combine_strider") || |
| 323 | model_has(model, "dropship")) | 323 | model_has(model, "dropship") || model_has(model, "helicopter") || |
| 324 | model_has(model, "chopper")) | ||
| 324 | return NPC_DMG_ARMORED; | 325 | return NPC_DMG_ARMORED; |
| 325 | if (model_has(model, "headcrab") || model_has(model, "antlion") || | 326 | if (model_has(model, "headcrab") || model_has(model, "antlion") || |
| 326 | model_has(model, "manhack")) | 327 | model_has(model, "manhack")) |
| @@ -822,6 +823,12 @@ static bool select_aim_target(const QAngle &view, unsigned bone_mask, | |||
| 822 | *(int *)((uintptr_t)local_ent + g_net.health) <= 0) | 823 | *(int *)((uintptr_t)local_ent + g_net.health) <= 0) |
| 823 | return false; | 824 | return false; |
| 824 | 825 | ||
| 826 | // With the RPG equipped, armoured units (striders, gunships, dropships, | ||
| 827 | // hunter-choppers) are the ones ordinary shots cannot hurt, so prefer them | ||
| 828 | // over normal NPCs when acquiring. | ||
| 829 | bool rpg = active_weapon_contains(local_ent, "rocket_launcher") || | ||
| 830 | active_weapon_contains(local_ent, "rpg"); | ||
| 831 | |||
| 825 | auto try_target = [&](int idx, bool enforce_fov, Vector &pt, | 832 | auto try_target = [&](int idx, bool enforce_fov, Vector &pt, |
| 826 | float &fov) -> bool { | 833 | float &fov) -> bool { |
| 827 | if (idx <= 0 || idx == local) | 834 | if (idx <= 0 || idx == local) |
| @@ -899,6 +906,8 @@ static bool select_aim_target(const QAngle &view, unsigned bone_mask, | |||
| 899 | int idx; | 906 | int idx; |
| 900 | float fov; | 907 | float fov; |
| 901 | Vector approx; | 908 | Vector approx; |
| 909 | bool armored; | ||
| 910 | float key; | ||
| 902 | }; | 911 | }; |
| 903 | Candidate cands[16]; | 912 | Candidate cands[16]; |
| 904 | int ncands = 0; | 913 | int ncands = 0; |
| @@ -928,6 +937,7 @@ static bool select_aim_target(const QAngle &view, unsigned bone_mask, | |||
| 928 | continue; | 937 | continue; |
| 929 | if (!npc_can_be_damaged(idx, model)) | 938 | if (!npc_can_be_damaged(idx, model)) |
| 930 | continue; | 939 | continue; |
| 940 | bool armored = npc_damage_class(idx, model) == NPC_DMG_ARMORED; | ||
| 931 | 941 | ||
| 932 | float maxz = g_net.maxs >= 0 ? *(float *)(e + g_net.maxs + 8) : 72.0f; | 942 | float maxz = g_net.maxs >= 0 ? *(float *)(e + g_net.maxs + 8) : 72.0f; |
| 933 | if (!(maxz > 4.0f && maxz < 512.0f)) | 943 | if (!(maxz > 4.0f && maxz < 512.0f)) |
| @@ -940,16 +950,17 @@ static bool select_aim_target(const QAngle &view, unsigned bone_mask, | |||
| 940 | float fov = getfov(view, angle_to(g_cam_eye, approx)); | 950 | float fov = getfov(view, angle_to(g_cam_eye, approx)); |
| 941 | if (fov > max_fov) | 951 | if (fov > max_fov) |
| 942 | continue; | 952 | continue; |
| 953 | float key = (rpg && armored) ? fov - 1000.0f : fov; | ||
| 943 | 954 | ||
| 944 | int pos = ncands; | 955 | int pos = ncands; |
| 945 | while (pos > 0 && cands[pos - 1].fov > fov) | 956 | while (pos > 0 && cands[pos - 1].key > key) |
| 946 | pos--; | 957 | pos--; |
| 947 | if (ncands < 16) | 958 | if (ncands < 16) |
| 948 | ncands++; | 959 | ncands++; |
| 949 | for (int j = ncands - 1; j > pos; j--) | 960 | for (int j = ncands - 1; j > pos; j--) |
| 950 | cands[j] = cands[j - 1]; | 961 | cands[j] = cands[j - 1]; |
| 951 | if (pos < 16) | 962 | if (pos < 16) |
| 952 | cands[pos] = {idx, fov, approx}; | 963 | cands[pos] = {idx, fov, approx, armored, key}; |
| 953 | } | 964 | } |
| 954 | 965 | ||
| 955 | if (ncands == 0) { | 966 | if (ncands == 0) { |
| @@ -1309,6 +1320,26 @@ bool gravity_gun_active(void *local_ent) { | |||
| 1309 | (model && strcasestr(model, "physcannon")); | 1320 | (model && strcasestr(model, "physcannon")); |
| 1310 | } | 1321 | } |
| 1311 | 1322 | ||
| 1323 | // The citadel supercharges the gravity gun (d3_citadel_03 onward). It can then | ||
| 1324 | // punt any NPC, so the melee aimbot should not restrict itself to | ||
| 1325 | // physics-vulnerable units. | ||
| 1326 | static bool supercharged_gravity_gun() { | ||
| 1327 | if (!g_iface.engine) | ||
| 1328 | return false; | ||
| 1329 | using Fn = const char *(*)(void *); | ||
| 1330 | const char *m = vfunc<Fn>(g_iface.engine, 51)(g_iface.engine); | ||
| 1331 | if (!m) | ||
| 1332 | return false; | ||
| 1333 | bool supe = strstr(m, "d3_citadel_03") || strstr(m, "d3_citadel_04") || | ||
| 1334 | strstr(m, "d3_breen_01"); | ||
| 1335 | static const char *logged_map = nullptr; | ||
| 1336 | if (logged_map != m) { | ||
| 1337 | logged_map = m; | ||
| 1338 | logf("melee: gravity gun map=%s supercharged=%d", m, (int)supe); | ||
| 1339 | } | ||
| 1340 | return supe; | ||
| 1341 | } | ||
| 1342 | |||
| 1312 | bool melee_aimbot_apply(CUserCmd *cmd, bool gravity) { | 1343 | bool melee_aimbot_apply(CUserCmd *cmd, bool gravity) { |
| 1313 | if (!g_iface.entitylist || g_net.origin < 0) | 1344 | if (!g_iface.entitylist || g_net.origin < 0) |
| 1314 | return false; | 1345 | return false; |
| @@ -1324,6 +1355,7 @@ bool melee_aimbot_apply(CUserCmd *cmd, bool gravity) { | |||
| 1324 | 1355 | ||
| 1325 | // The punted object can travel much farther than the crowbar. | 1356 | // The punted object can travel much farther than the crowbar. |
| 1326 | float max_range = gravity ? 1200.0f : MELEE_RANGE; | 1357 | float max_range = gravity ? 1200.0f : MELEE_RANGE; |
| 1358 | bool supercharged = gravity && supercharged_gravity_gun(); | ||
| 1327 | 1359 | ||
| 1328 | using Fn = int (*)(void *); | 1360 | using Fn = int (*)(void *); |
| 1329 | int hi = vfunc<Fn>(g_iface.entitylist, 6)(g_iface.entitylist); | 1361 | int hi = vfunc<Fn>(g_iface.entitylist, 6)(g_iface.entitylist); |
| @@ -1363,8 +1395,10 @@ bool melee_aimbot_apply(CUserCmd *cmd, bool gravity) { | |||
| 1363 | continue; | 1395 | continue; |
| 1364 | if (!npc_can_be_damaged(idx, model)) | 1396 | if (!npc_can_be_damaged(idx, model)) |
| 1365 | continue; | 1397 | continue; |
| 1366 | // The gravity gun is only the tool for physics-vulnerable units. | 1398 | // The normal gravity gun is only the tool for physics-vulnerable units; |
| 1367 | if (gravity && npc_damage_class(idx, model) != NPC_DMG_VULNERABLE) | 1399 | // the citadel version behaves like a normal weapon. |
| 1400 | if (gravity && !supercharged && | ||
| 1401 | npc_damage_class(idx, model) != NPC_DMG_VULNERABLE) | ||
| 1368 | continue; | 1402 | continue; |
| 1369 | 1403 | ||
| 1370 | Vector origin{*(float *)(e + g_net.origin), | 1404 | Vector origin{*(float *)(e + g_net.origin), |
| @@ -2747,6 +2781,11 @@ static void items_collect(int local_idx) { | |||
| 2747 | int kind = classify_item(model, cls, label, sizeof(label)); | 2781 | int kind = classify_item(model, cls, label, sizeof(label)); |
| 2748 | if (kind < 0) | 2782 | if (kind < 0) |
| 2749 | continue; | 2783 | continue; |
| 2784 | // Health/suit chargers are dispensers that stay useful after a refill, but | ||
| 2785 | // an empty one cannot give anything. m_iJuice is 0 when depleted (until it | ||
| 2786 | // recharges); only hide the tag once the server value is readable. | ||
| 2787 | if (strcasestr(label, "charger") && server_item_juice(idx) == 0) | ||
| 2788 | continue; | ||
| 2750 | 2789 | ||
| 2751 | Vector origin{*(float *)((uintptr_t)ent + g_net.origin), | 2790 | Vector origin{*(float *)((uintptr_t)ent + g_net.origin), |
| 2752 | *(float *)((uintptr_t)ent + g_net.origin + 4), | 2791 | *(float *)((uintptr_t)ent + g_net.origin + 4), |
| @@ -3045,6 +3084,114 @@ static void projs_collect(int local_idx) { | |||
| 3045 | } | 3084 | } |
| 3046 | } | 3085 | } |
| 3047 | 3086 | ||
| 3087 | // Frag-grenade path preview: throw velocity from weapon_frag.cpp (eye/right | ||
| 3088 | // offset, forward*1200 + 0.1 z), gravity 600, and a simple bounce model. | ||
| 3089 | // Shows the bounces and the first landing with the blast-radius ring. | ||
| 3090 | static void draw_grenade_trajectory(int local_idx) { | ||
| 3091 | if (!g_proj_traj || !g_iface.entitylist) | ||
| 3092 | return; | ||
| 3093 | void *le = entitylist_get(local_idx); | ||
| 3094 | if (!le) | ||
| 3095 | return; | ||
| 3096 | if (!active_weapon_contains(le, "frag") && | ||
| 3097 | !active_weapon_contains(le, "w_grenade")) | ||
| 3098 | return; | ||
| 3099 | |||
| 3100 | QAngle va = engine_view_angles(); | ||
| 3101 | float pitch = va.x * PI_F / 180.0f; | ||
| 3102 | float yaw = va.y * PI_F / 180.0f; | ||
| 3103 | float cp = cosf(pitch), sp = sinf(pitch); | ||
| 3104 | float cy = cosf(yaw), sy = sinf(yaw); | ||
| 3105 | Vector fwd{cp * cy, cp * sy, -sp}; | ||
| 3106 | Vector right{sy, -cy, 0.0f}; | ||
| 3107 | |||
| 3108 | Vector src{g_cam_eye.x + fwd.x * 18.0f + right.x * 8.0f, | ||
| 3109 | g_cam_eye.y + fwd.y * 18.0f + right.y * 8.0f, | ||
| 3110 | g_cam_eye.z + fwd.z * 18.0f}; | ||
| 3111 | Vector vel{}; | ||
| 3112 | if (g_net.velocity >= 0) { | ||
| 3113 | const float *pv = (const float *)((uintptr_t)le + g_net.velocity); | ||
| 3114 | vel = Vector{pv[0], pv[1], pv[2]}; | ||
| 3115 | } | ||
| 3116 | vel.x += fwd.x * 1200.0f; | ||
| 3117 | vel.y += fwd.y * 1200.0f; | ||
| 3118 | vel.z += fwd.z * 1200.0f + 120.0f; // vForward[2] += 0.1 | ||
| 3119 | |||
| 3120 | const float gravity = 600.0f; | ||
| 3121 | const float dt = 0.02f; | ||
| 3122 | const float restitution = 0.35f; | ||
| 3123 | const float friction = 0.35f; | ||
| 3124 | |||
| 3125 | Vector pts[128]; | ||
| 3126 | int n = 0; | ||
| 3127 | Vector pos = src; | ||
| 3128 | pts[n++] = pos; | ||
| 3129 | bool landed = false; | ||
| 3130 | for (int step = 0; step < 240 && n < 127; step++) { | ||
| 3131 | Vector nv = vel; | ||
| 3132 | nv.z -= gravity * dt; | ||
| 3133 | Vector next{pos.x + nv.x * dt, pos.y + nv.y * dt, pos.z + nv.z * dt}; | ||
| 3134 | Vector hit_end{}, normal{}; | ||
| 3135 | if (trace_solid_segment(pos, next, le, hit_end, normal)) { | ||
| 3136 | pts[n++] = hit_end; | ||
| 3137 | float vn = vel.x * normal.x + vel.y * normal.y + vel.z * normal.z; | ||
| 3138 | Vector vt{vel.x - vn * normal.x, vel.y - vn * normal.y, | ||
| 3139 | vel.z - vn * normal.z}; | ||
| 3140 | float keep = 1.0f - friction; | ||
| 3141 | vel.x = vt.x * keep - normal.x * vn * restitution; | ||
| 3142 | vel.y = vt.y * keep - normal.y * vn * restitution; | ||
| 3143 | vel.z = vt.z * keep - normal.z * vn * restitution; | ||
| 3144 | float vlen2 = vel.x * vel.x + vel.y * vel.y + vel.z * vel.z; | ||
| 3145 | pos.x = hit_end.x + normal.x * 1.0f; | ||
| 3146 | pos.y = hit_end.y + normal.y * 1.0f; | ||
| 3147 | pos.z = hit_end.z + normal.z * 1.0f; | ||
| 3148 | if (normal.z > 0.6f && (vn > -80.0f || vlen2 < 2500.0f)) { | ||
| 3149 | landed = true; | ||
| 3150 | break; | ||
| 3151 | } | ||
| 3152 | } else { | ||
| 3153 | pos = next; | ||
| 3154 | vel = nv; | ||
| 3155 | pts[n++] = pos; | ||
| 3156 | } | ||
| 3157 | } | ||
| 3158 | |||
| 3159 | surf_color(255, 210, 90, 200); | ||
| 3160 | for (int i = 0; i + 1 < n; i++) { | ||
| 3161 | int x0, y0, x1, y1; | ||
| 3162 | if (project_segment(pts[i], pts[i + 1], x0, y0, x1, y1)) | ||
| 3163 | surf_line(x0, y0, x1, y1); | ||
| 3164 | } | ||
| 3165 | |||
| 3166 | Vector land = landed ? pos : pts[n - 1]; | ||
| 3167 | float ssx, ssy; | ||
| 3168 | if (world_to_screen(land, ssx, ssy)) { | ||
| 3169 | int x = (int)ssx, y = (int)ssy; | ||
| 3170 | surf_color(255, 210, 90, 230); | ||
| 3171 | surf_rect(0, x - 3, y - 3, x + 3, y + 3); | ||
| 3172 | surf_line(x - 9, y, x - 4, y); | ||
| 3173 | surf_line(x + 4, y, x + 9, y); | ||
| 3174 | surf_line(x, y - 9, x, y - 4); | ||
| 3175 | surf_line(x, y + 4, x, y + 9); | ||
| 3176 | } | ||
| 3177 | if (landed) { | ||
| 3178 | const int SEG = 24; | ||
| 3179 | const float radius = 300.0f; // CBaseGrenade m_DmgRadius | ||
| 3180 | surf_color(255, 120, 40, 120); | ||
| 3181 | for (int k = 0; k < SEG; k++) { | ||
| 3182 | float a0 = (float)k * 2.0f * PI_F / (float)SEG; | ||
| 3183 | float a1 = (float)(k + 1) * 2.0f * PI_F / (float)SEG; | ||
| 3184 | Vector p0{land.x + cosf(a0) * radius, land.y + sinf(a0) * radius, | ||
| 3185 | land.z + 1.0f}; | ||
| 3186 | Vector p1{land.x + cosf(a1) * radius, land.y + sinf(a1) * radius, | ||
| 3187 | land.z + 1.0f}; | ||
| 3188 | int x0, y0, x1, y1; | ||
| 3189 | if (project_segment(p0, p1, x0, y0, x1, y1)) | ||
| 3190 | surf_line(x0, y0, x1, y1); | ||
| 3191 | } | ||
| 3192 | } | ||
| 3193 | } | ||
| 3194 | |||
| 3048 | void esp_draw_projectiles() { | 3195 | void esp_draw_projectiles() { |
| 3049 | if (!g_surface || !g_iface.entitylist || g_net.origin < 0) | 3196 | if (!g_surface || !g_iface.entitylist || g_net.origin < 0) |
| 3050 | return; | 3197 | return; |
| @@ -3055,6 +3202,7 @@ void esp_draw_projectiles() { | |||
| 3055 | return; | 3202 | return; |
| 3056 | } | 3203 | } |
| 3057 | projs_collect(engine_get_local_player()); | 3204 | projs_collect(engine_get_local_player()); |
| 3205 | draw_grenade_trajectory(engine_get_local_player()); | ||
| 3058 | for (int i = 0; i < g_nprojs; i++) { | 3206 | for (int i = 0; i < g_nprojs; i++) { |
| 3059 | const ProjTarget &p = g_projs[i]; | 3207 | const ProjTarget &p = g_projs[i]; |
| 3060 | int r = 255, g = 170, b = 60; | 3208 | int r = 255, g = 170, b = 60; |
