summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorsalmonik <salmonik@tuta.io>2026-11-04 16:11:28 +0100
committersalmonik <salmonik@tuta.io>2026-11-04 16:11:28 +0100
commit4019880cf113a2a13460ec8ea5bb30a5c8ed50f3 (patch)
tree5c13148671afd7d294273cff431c0ef373d862a3
parentClip transition and radius lines at the near plane (diff)
downloadhl2h-4019880cf113a2a13460ec8ea5bb30a5c8ed50f3.tar.gz
hl2h-4019880cf113a2a13460ec8ea5bb30a5c8ed50f3.zip
Items: hide full ammo pickups; robust close-target projection
- Resolve m_iAmmo and m_hMyWeapons arrays from the client recv tables. - "Only if usable" now compares m_iAmmo[type] against sk_max_* (stock caps as fallback: RPG rockets 3, AR2 60, ...). Full ammo hides the pickup, including RPG rockets and fallen weapons converted to ammo. - Inventory now comes from m_hMyWeapons directly, so fallen weapons are ammo before the player equips the matching weapon. - Projection: fall back to local math when ScreenPosition claims "behind" for a point with positive view depth, and build NPC boxes from vertical samples so feet behind the near plane no longer drop the whole target. Log the first 8 near-target projection failures for diagnosis.
-rw-r--r--CONTEXT.md18
-rw-r--r--src/esp.cpp236
-rw-r--r--src/hl2h.h2
-rw-r--r--src/netvars.cpp13
4 files changed, 233 insertions, 36 deletions
diff --git a/CONTEXT.md b/CONTEXT.md
index acdab2f..839d340 100644
--- a/CONTEXT.md
+++ b/CONTEXT.md
@@ -232,7 +232,11 @@ vocabulary / decisions.
232 (>1e7). A point on the view axis (e.g. directly below the player's feet) 232 (>1e7). A point on the view axis (e.g. directly below the player's feet)
233 can make `IVDebugOverlay::ScreenPosition` return NaN/huge values; casting 233 can make `IVDebugOverlay::ScreenPosition` return NaN/huge values; casting
234 those to int corrupted the ISurface clip state and made the whole overlay 234 those to int corrupted the ISurface clip state and made the whole overlay
235 disappear for that frame. 235 disappear for that frame. If the overlay reports "behind" for a point whose
236 view-space depth is actually positive, a local projection is used instead.
237- NPC boxes are built from several vertical samples, so a target whose feet
238 are behind the near plane (standing over it) still gets a box from the
239 visible span instead of being dropped.
236- Projectile radius rings are drawn independently of the centre marker, so a 240- Projectile radius rings are drawn independently of the centre marker, so a
237 grenade behind the camera/off-screen still shows its blast circle when any 241 grenade behind the camera/off-screen still shows its blast circle when any
238 part of the ring projects. 242 part of the ring projects.
@@ -606,10 +610,14 @@ vocabulary / decisions.
606- A world weapon whose type is already in the local player's inventory is 610- A world weapon whose type is already in the local player's inventory is
607 reclassified as ammo (`SMG ammo`, `AR2 ammo`, ...). Owner handles are 611 reclassified as ammo (`SMG ammo`, `AR2 ammo`, ...). Owner handles are
608 unreliable on this client (`m_hOwnerEntity`/`m_hOwner` resolve to -1), so 612 unreliable on this client (`m_hOwnerEntity`/`m_hOwner` resolve to -1), so
609 the inventory mask is accumulated from every weapon type the player has 613 the inventory is read directly from the local `m_hMyWeapons[48]` handle
610 held (client `m_hActiveWeapon`, with the server handle as fallback) since 614 array (and remembered active types as a fallback). NPC-held weapons are
611 the current local entity appeared. NPC-held weapons are therefore ignored. 615 therefore ignored. Weapons the player does not own stay under the Weapons
612 Weapons the player does not own stay under the Weapons category. 616 category.
617- Ammo pickups also honour "Only if usable": the reserve count from
618 `m_iAmmo[type]` is compared with the `sk_max_*` cvar (stock caps as fallback,
619 e.g. RPG rockets = 3). Full ammo hides the pickup; if either value cannot
620 be read the item stays visible.
613- Scans the client entity list every 100 ms and tags health, ammo, armor/suit, 621- Scans the client entity list every 100 ms and tags health, ammo, armor/suit,
614 world weapon pickups, the two supply-crate models and generic items. 622 world weapon pickups, the two supply-crate models and generic items.
615- Each tag is a colored marker with a name and optional distance, filtered by 623- Each tag is a colored marker with a name and optional distance, filtered by
diff --git a/src/esp.cpp b/src/esp.cpp
index 715dbc8..1d4a6a5 100644
--- a/src/esp.cpp
+++ b/src/esp.cpp
@@ -52,27 +52,11 @@ static double esp_now() {
52 return (double)ts.tv_sec + (double)ts.tv_nsec * 1e-9; 52 return (double)ts.tv_sec + (double)ts.tv_nsec * 1e-9;
53} 53}
54 54
55bool world_to_screen(const Vector &w, float &sx, float &sy) { 55// Local perspective projection used when the engine's debug-overlay
56 // Preferred: the engine's own transform. Uses the real view setup (FOV, 56// projection refuses a point that is actually in front of the camera.
57 // aspect, roll), so boxes do not drift at the screen edges. 57static bool project_manual(const Vector &w, float &sx, float &sy) {
58 if (g_iface.debugoverlay) { 58 if (!g_scr_w || !g_scr_h)
59 using Fn = int (*)(void *, const Vector *, Vector *); 59 return false;
60 Vector s;
61 int behind =
62 vfunc<Fn>(g_iface.debugoverlay, 9)(g_iface.debugoverlay, &w, &s);
63 if (behind)
64 return false;
65 // A point on the view axis (e.g. directly below the feet) can produce
66 // NaN/inf or enormous coordinates; drawing those as ints corrupts the
67 // surface clip state and hides the rest of the overlay.
68 if (!std::isfinite(s.x) || !std::isfinite(s.y) || fabsf(s.x) > 1e7f ||
69 fabsf(s.y) > 1e7f)
70 return false;
71 sx = s.x;
72 sy = s.y;
73 return true;
74 }
75 // Fallback: local math with the default HL2 FOV.
76 float pitch = g_cam_view.x * PI_F / 180.0f; 60 float pitch = g_cam_view.x * PI_F / 180.0f;
77 float yaw = g_cam_view.y * PI_F / 180.0f; 61 float yaw = g_cam_view.y * PI_F / 180.0f;
78 float sp = sinf(pitch), cp = cosf(pitch); 62 float sp = sinf(pitch), cp = cosf(pitch);
@@ -82,7 +66,8 @@ bool world_to_screen(const Vector &w, float &sx, float &sy) {
82 float up[3] = {sp * cy, sp * syy, cp}; 66 float up[3] = {sp * cy, sp * syy, cp};
83 float dx = w.x - g_cam_eye.x, dy = w.y - g_cam_eye.y, dz = w.z - g_cam_eye.z; 67 float dx = w.x - g_cam_eye.x, dy = w.y - g_cam_eye.y, dz = w.z - g_cam_eye.z;
84 float z = dx * fwd[0] + dy * fwd[1] + dz * fwd[2]; 68 float z = dx * fwd[0] + dy * fwd[1] + dz * fwd[2];
85 if (z < 1.0f) return false; 69 if (z < 1.0f)
70 return false;
86 float x = dx * right[0] + dy * right[1] + dz * right[2]; 71 float x = dx * right[0] + dy * right[1] + dz * right[2];
87 float y = dx * up[0] + dy * up[1] + dz * up[2]; 72 float y = dx * up[0] + dy * up[1] + dz * up[2];
88 float tanfov = tanf(75.0f * 0.5f * PI_F / 180.0f); 73 float tanfov = tanf(75.0f * 0.5f * PI_F / 180.0f);
@@ -92,6 +77,42 @@ bool world_to_screen(const Vector &w, float &sx, float &sy) {
92 fabsf(sy) < 1e7f; 77 fabsf(sy) < 1e7f;
93} 78}
94 79
80bool world_to_screen(const Vector &w, float &sx, float &sy) {
81 // Preferred: the engine's own transform. Uses the real view setup (FOV,
82 // aspect, roll), so boxes do not drift at the screen edges.
83 if (g_iface.debugoverlay) {
84 using Fn = int (*)(void *, const Vector *, Vector *);
85 Vector s;
86 int behind =
87 vfunc<Fn>(g_iface.debugoverlay, 9)(g_iface.debugoverlay, &w, &s);
88 if (behind) {
89 // The overlay transform can report "behind" for points that are in
90 // front but near the view axis/extremes (e.g. something directly below
91 // the player). Use the local projection in that case.
92 float pitch = g_cam_view.x * PI_F / 180.0f;
93 float yaw = g_cam_view.y * PI_F / 180.0f;
94 float cp = cosf(pitch), sp = sinf(pitch);
95 float fwd[3] = {cp * cosf(yaw), cp * sinf(yaw), -sp};
96 float z = (w.x - g_cam_eye.x) * fwd[0] +
97 (w.y - g_cam_eye.y) * fwd[1] +
98 (w.z - g_cam_eye.z) * fwd[2];
99 if (z > 4.0f)
100 return project_manual(w, sx, sy);
101 return false;
102 }
103 // A point on the view axis can produce NaN/inf or enormous coordinates;
104 // drawing those as ints corrupts the surface clip state and hides the
105 // rest of the overlay.
106 if (!std::isfinite(s.x) || !std::isfinite(s.y) || fabsf(s.x) > 1e7f ||
107 fabsf(s.y) > 1e7f)
108 return false;
109 sx = s.x;
110 sy = s.y;
111 return true;
112 }
113 return project_manual(w, sx, sy);
114}
115
95// --------------------------------------------------------------------------- 116// ---------------------------------------------------------------------------
96// entity helpers (IClientEntityList / IClientNetworkable, header-documented) 117// entity helpers (IClientEntityList / IClientNetworkable, header-documented)
97// --------------------------------------------------------------------------- 118// ---------------------------------------------------------------------------
@@ -431,8 +452,6 @@ static void esp_collect(int local_idx) {
431 } 452 }
432 Vector origin{*(float *)(e + g_net.origin), *(float *)(e + g_net.origin + 4), 453 Vector origin{*(float *)(e + g_net.origin), *(float *)(e + g_net.origin + 4),
433 *(float *)(e + g_net.origin + 8)}; 454 *(float *)(e + g_net.origin + 8)};
434 Vector bottom{origin.x, origin.y, origin.z + minz};
435 Vector top{origin.x, origin.y, origin.z + maxz};
436 bool neutral = false; 455 bool neutral = false;
437 bool friendly = npc && npc_is_friendly(idx, model, local_idx, neutral); 456 bool friendly = npc && npc_is_friendly(idx, model, local_idx, neutral);
438 // Arrows are collected before projection: a hostile behind the camera 457 // Arrows are collected before projection: a hostile behind the camera
@@ -443,12 +462,47 @@ static void esp_collect(int local_idx) {
443 a.head = Vector{origin.x, origin.y, origin.z + maxz * 0.7f}; 462 a.head = Vector{origin.x, origin.y, origin.z + maxz * 0.7f};
444 a.neutral = neutral; 463 a.neutral = neutral;
445 } 464 }
446 float sx, sy, tx, ty; 465 // Project several points along the vertical axis. Requiring both feet and
447 if (!world_to_screen(bottom, sx, sy) || !world_to_screen(top, tx, ty)) 466 // head to project dropped the target when the feet were behind the near
467 // plane (common when standing over/next to something).
468 float min_sy = 1e9f, max_sy = -1e9f, low_x = 0.0f;
469 bool projected = false;
470 const int VSAMPLES = 6;
471 for (int k = 0; k <= VSAMPLES; k++) {
472 float z = origin.z + minz +
473 (maxz - minz) * (float)k / (float)VSAMPLES;
474 float px, py;
475 if (!world_to_screen(Vector{origin.x, origin.y, z}, px, py))
476 continue;
477 if (px < -2.0f * (float)g_scr_w || px > 3.0f * (float)g_scr_w)
478 continue;
479 projected = true;
480 if (py < min_sy)
481 min_sy = py;
482 if (py > max_sy) {
483 max_sy = py;
484 low_x = px;
485 }
486 }
487 if (!projected) {
488 static int fail_logs = 0;
489 float ddx = origin.x - g_cam_eye.x;
490 float ddy = origin.y - g_cam_eye.y;
491 float ddz = origin.z - g_cam_eye.z;
492 if (fail_logs < 8 && ddx * ddx + ddy * ddy + ddz * ddz < 400.0f * 400.0f) {
493 fail_logs++;
494 logf("ESP: close target %d model=%s failed projection at "
495 "(%.1f %.1f %.1f)",
496 idx, model ? model : "?", origin.x, origin.y, origin.z);
497 }
498 continue;
499 }
500 float h = max_sy - min_sy;
501 if (h < 3.0f || max_sy < 0 || min_sy > (float)g_scr_h)
502 continue; // behind / offscreen
503 if (low_x < -(float)g_scr_w || low_x > 2.0f * (float)g_scr_w)
448 continue; 504 continue;
449 float h = sy - ty; 505 float sx = low_x, sy = max_sy;
450 if (h < 3.0f || sy < 0 || ty > (float)g_scr_h) continue; // behind / offscreen
451 if (sx < -(float)g_scr_w || sx > 2.0f * (float)g_scr_w) continue;
452 506
453 EspTarget &t = g_targets[g_ntargets++]; 507 EspTarget &t = g_targets[g_ntargets++];
454 t.idx = idx; 508 t.idx = idx;
@@ -2088,6 +2142,7 @@ enum ItemKind {
2088struct ItemTarget { 2142struct ItemTarget {
2089 int idx; 2143 int idx;
2090 int kind; 2144 int kind;
2145 int ammo_type; // m_iAmmo index for IK_AMMO, -1 otherwise
2091 Vector origin; 2146 Vector origin;
2092 char label[128]; 2147 char label[128];
2093}; 2148};
@@ -2235,6 +2290,117 @@ static int weapon_type_id(const char *model, const char *cls) {
2235 return WT_NONE; 2290 return WT_NONE;
2236} 2291}
2237 2292
2293static int weapon_ammo_type(int wt) {
2294 switch (wt) {
2295 case WT_PISTOL: return 2;
2296 case WT_357: return 4;
2297 case WT_SMG: return 3;
2298 case WT_AR2: return 0;
2299 case WT_SHOTGUN: return 6;
2300 case WT_CROSSBOW: return 5;
2301 case WT_RPG: return 7;
2302 case WT_GRENADE: return 11;
2303 case WT_SNIPER: return 9;
2304 default: return -1;
2305 }
2306}
2307
2308// Ammo type index used by CBasePlayer::m_iAmmo (order of AddAmmoType in
2309// hl2_gamerules.cpp).
2310static int item_ammo_type(const char *model) {
2311 if (!model)
2312 return -1;
2313 if (item_icontains(model, "boxsrounds") ||
2314 item_icontains(model, "ammocrate_pistol") ||
2315 item_icontains(model, "w_pistol"))
2316 return 2;
2317 if (item_icontains(model, "boxmrounds") ||
2318 item_icontains(model, "ammocrate_smg1"))
2319 return 3;
2320 if (item_icontains(model, "boxlrounds") ||
2321 item_icontains(model, "combine_rifle") ||
2322 item_icontains(model, "ammocrate_ar2") ||
2323 item_icontains(model, "w_ar2") || item_icontains(model, "w_irifle"))
2324 return 0;
2325 if (item_icontains(model, "357ammo") ||
2326 item_icontains(model, "357ammobox") ||
2327 item_icontains(model, "w_357"))
2328 return 4;
2329 if (item_icontains(model, "crossbowrounds") ||
2330 item_icontains(model, "w_crossbow"))
2331 return 5;
2332 if (item_icontains(model, "boxbuckshot") ||
2333 item_icontains(model, "ammocrate_buckshot") ||
2334 item_icontains(model, "w_shotgun"))
2335 return 6;
2336 if (item_icontains(model, "w_missile_closed") ||
2337 item_icontains(model, "ammocrate_rockets") ||
2338 item_icontains(model, "w_rocket_launcher"))
2339 return 7;
2340 if (item_icontains(model, "ar2_grenade") ||
2341 item_icontains(model, "ammocrate_smg2"))
2342 return 8;
2343 if (item_icontains(model, "ammocrate_grenade") ||
2344 item_icontains(model, "w_grenade") || item_icontains(model, "w_frag"))
2345 return 11;
2346 if (item_icontains(model, "w_smg1") || item_icontains(model, "w_smg2"))
2347 return 3;
2348 return -1;
2349}
2350
2351static int convar_int(const char *name) {
2352 if (!g_iface.cvar || !name)
2353 return -1;
2354 using FindFn = void *(*)(void *, const char *);
2355 void *v = vfunc<FindFn>(g_iface.cvar, 12)(g_iface.cvar, name);
2356 if (!v)
2357 return -1;
2358 return (int)*(float *)((uintptr_t)v + 0x2c); // ConVar m_Value.f
2359}
2360
2361// Maximum reserve ammo for an m_iAmmo index. Prefers the sk_max_* cvar and
2362// falls back to the stock HL2 cap so the RPG's 3-rocket limit is honoured
2363// even when server cvars are not visible from the client.
2364static int ammo_max(int type) {
2365 static int cache[16];
2366 static bool init = false;
2367 if (type < 0 || type >= 16)
2368 return -1;
2369 if (!init) {
2370 for (int i = 0; i < 16; i++)
2371 cache[i] = -2;
2372 init = true;
2373 }
2374 if (cache[type] != -2)
2375 return cache[type];
2376 const char *name = nullptr;
2377 int stock = -1;
2378 switch (type) {
2379 case 0: name = "sk_max_ar2"; stock = 60; break;
2380 case 2: name = "sk_max_pistol"; stock = 150; break;
2381 case 3: name = "sk_max_smg1"; stock = 225; break;
2382 case 4: name = "sk_max_357"; stock = 12; break;
2383 case 5: name = "sk_max_crossbow"; stock = 10; break;
2384 case 6: name = "sk_max_buckshot"; stock = 30; break;
2385 case 7: name = "sk_max_rpg_round"; stock = 3; break;
2386 case 8: name = "sk_max_smg1_grenade"; stock = 3; break;
2387 case 9: name = "sk_max_sniper_round"; stock = 30; break;
2388 case 11: name = "sk_max_grenade"; stock = 5; break;
2389 default: break;
2390 }
2391 int v = convar_int(name);
2392 if (v <= 0)
2393 v = stock;
2394 cache[type] = v;
2395 return v;
2396}
2397
2398static int local_ammo(void *local_ent, int type) {
2399 if (!local_ent || g_net.ammo < 0 || type < 0 || type >= 32)
2400 return -1;
2401 return *(int *)((uintptr_t)local_ent + g_net.ammo + type * 4);
2402}
2403
2238static int classify_item(const char *model, const char *cls, char *label, 2404static int classify_item(const char *model, const char *cls, char *label,
2239 size_t outn) { 2405 size_t outn) {
2240 if (!model && !cls) 2406 if (!model && !cls)
@@ -2535,6 +2701,12 @@ static void items_collect(int local_idx) {
2535 ItemTarget &t = g_item_targets[g_nitems++]; 2701 ItemTarget &t = g_item_targets[g_nitems++];
2536 t.idx = idx; 2702 t.idx = idx;
2537 t.kind = kind; 2703 t.kind = kind;
2704 t.ammo_type = -1;
2705 if (kind == IK_AMMO) {
2706 t.ammo_type = item_ammo_type(model);
2707 if (t.ammo_type < 0)
2708 t.ammo_type = weapon_ammo_type(weapon_type_id(model, cls));
2709 }
2538 t.origin = origin; 2710 t.origin = origin;
2539 snprintf(t.label, sizeof(t.label), "%s", label); 2711 snprintf(t.label, sizeof(t.label), "%s", label);
2540 if (dbg_lines < 8) { 2712 if (dbg_lines < 8) {
@@ -2605,6 +2777,12 @@ void esp_draw_items() {
2605 continue; 2777 continue;
2606 if (t.kind == IK_ARMOR && vit_armor >= 0 && vit_armor >= 100) 2778 if (t.kind == IK_ARMOR && vit_armor >= 0 && vit_armor >= 100)
2607 continue; 2779 continue;
2780 if (t.kind == IK_AMMO && t.ammo_type >= 0) {
2781 int maxa = ammo_max(t.ammo_type);
2782 int cura = local_ammo(entitylist_get(local), t.ammo_type);
2783 if (maxa > 0 && cura >= 0 && cura >= maxa)
2784 continue;
2785 }
2608 } 2786 }
2609 float sx, sy; 2787 float sx, sy;
2610 if (!world_to_screen(t.origin, sx, sy)) 2788 if (!world_to_screen(t.origin, sx, sy))
diff --git a/src/hl2h.h b/src/hl2h.h
index 0c8ffb5..4f3552e 100644
--- a/src/hl2h.h
+++ b/src/hl2h.h
@@ -100,6 +100,8 @@ struct NetVars {
100 int punch = -1; // client m_vecPunchAngle (aim punch) 100 int punch = -1; // client m_vecPunchAngle (aim punch)
101 int default_fov = -1; // client m_iDefaultFOV (camera fov) 101 int default_fov = -1; // client m_iDefaultFOV (camera fov)
102 int dmg_radius = -1; // client C_BaseGrenade::m_DmgRadius 102 int dmg_radius = -1; // client C_BaseGrenade::m_DmgRadius
103 int my_weapons = -1; // client m_hMyWeapons[48] array base
104 int ammo = -1; // client m_iAmmo[] array base
103 // ponytail: mins/maxs may be absent from some HL2 netvar tables; esp.cpp falls back to h=72 105 // ponytail: mins/maxs may be absent from some HL2 netvar tables; esp.cpp falls back to h=72
104 bool ok() const { return flags >= 0 && velocity >= 0 && movetype >= 0; } 106 bool ok() const { return flags >= 0 && velocity >= 0 && movetype >= 0; }
105 // ponytail: m_iMaxHealth isn't a netvar in HL2 SP; esp.cpp falls back to 100. 107 // ponytail: m_iMaxHealth isn't a netvar in HL2 SP; esp.cpp falls back to 100.
diff --git a/src/netvars.cpp b/src/netvars.cpp
index ef564cd..2747c29 100644
--- a/src/netvars.cpp
+++ b/src/netvars.cpp
@@ -112,6 +112,15 @@ static void collect_netvars(uintptr_t table, uintptr_t base_off, int depth) {
112 int off = (int)(base_off + (uint32_t)poff); 112 int off = (int)(base_off + (uint32_t)poff);
113 if (off >= 0x20 && off <= 0x2000) 113 if (off >= 0x20 && off <= 0x2000)
114 g_net.dmg_radius = off; 114 g_net.dmg_radius = off;
115 } else if (strcmp(pname2, "m_hMyWeapons") == 0 &&
116 g_net.my_weapons < 0) {
117 int off = (int)(base_off + (uint32_t)poff);
118 if (off >= 0x20 && off <= 0x2000)
119 g_net.my_weapons = off;
120 } else if (strcmp(pname2, "m_iAmmo") == 0 && g_net.ammo < 0) {
121 int off = (int)(base_off + (uint32_t)poff);
122 if (off >= 0x20 && off <= 0x2000)
123 g_net.ammo = off;
115 } else if (strcmp(pname2, "m_iTeamNum") == 0 && g_net.teamnum < 0) { 124 } else if (strcmp(pname2, "m_iTeamNum") == 0 && g_net.teamnum < 0) {
116 g_net.teamnum = (int)(base_off + (uint32_t)poff); 125 g_net.teamnum = (int)(base_off + (uint32_t)poff);
117 } else if (strcmp(pname2, "m_vecOrigin") == 0 && g_net.origin < 0) { 126 } else if (strcmp(pname2, "m_vecOrigin") == 0 && g_net.origin < 0) {
@@ -294,11 +303,11 @@ void resolve_netvars() {
294 "teamnum=%d origin=%d viewoffset=%d mins=%d maxs=%d lifeste=%d " 303 "teamnum=%d origin=%d viewoffset=%d mins=%d maxs=%d lifeste=%d "
295 "modelindex=%d absvelocity=%d activeweapon=%d owner=%d " 304 "modelindex=%d absvelocity=%d activeweapon=%d owner=%d "
296 "weapon_owner=%d clr_render=%d punch=%d default_fov=%d " 305 "weapon_owner=%d clr_render=%d punch=%d default_fov=%d "
297 "dmg_radius=%d", 306 "dmg_radius=%d my_weapons=%d ammo=%d",
298 g_net.flags, g_net.velocity, g_net.movetype, g_net.health, 307 g_net.flags, g_net.velocity, g_net.movetype, g_net.health,
299 g_net.maxhealth, g_net.teamnum, g_net.origin, g_net.viewoffset, 308 g_net.maxhealth, g_net.teamnum, g_net.origin, g_net.viewoffset,
300 g_net.mins, g_net.maxs, g_net.lifestate, g_net.modelindex, 309 g_net.mins, g_net.maxs, g_net.lifestate, g_net.modelindex,
301 g_net.absvelocity, g_net.activeweapon, g_net.owner, 310 g_net.absvelocity, g_net.activeweapon, g_net.owner,
302 g_net.weapon_owner, g_net.clr_render, g_net.punch, 311 g_net.weapon_owner, g_net.clr_render, g_net.punch,
303 g_net.default_fov, g_net.dmg_radius); 312 g_net.default_fov, g_net.dmg_radius, g_net.my_weapons, g_net.ammo);
304} 313}