Partial NZPlayer class holding per-class weapon-tech state for a player body. Stores adrenaline stacks, lifeline-applied health, follow-through shot id and leftover damage, and provides TechOrNull(prefab) to return the owned tech node list or null.
namespace NZombies;
/// <summary>
/// The per-class weapon tech's state that belongs to the BODY rather than to a gun (2026-10-04,
/// `Sbox nzombies/Docs/WEAPON_TECH_BY_CLASS.md`).
///
/// ⚠️ NOT `[Sync]`. Each is set and read on the owner's own machine; what they change (move speed, max health)
/// replicates the way every other source of it does.
/// </summary>
public sealed partial class NZPlayer
{
/// <summary>
/// ADRENALINE ROUNDS (`t5_adrenaline`): hits stacked since the last one-second gap. Each is +1% damage and +1% aiming
/// walk speed, up to the node's cap. Read together with `AdrenalineUntil`, which ends them.
/// </summary>
public int AdrenalineStacks { get; set; }
/// <summary>
/// LIFELINE (`t5_hg_lifeline`): the max health the gun in hand added at the last `JuggAugments.RefreshHealth`, so a
/// switch can tell its own share of a change from Juggernog's. Lifeline's share raises the ceiling and heals nothing.
/// </summary>
public float LifelineApplied { get; set; }
/// <summary>
/// FOLLOW-THROUGH (`t3_br_followthrough`, 2026-10-04): the bullet (`ShotId`) whose kill left
/// <see cref="FollowThroughLeft"/> over, and that leftover, waiting for the same bullet's next zombie
/// (`ClassTech.FollowThroughCarry`).
///
/// ⚠️ THE HOST'S, NOT THE OWNER'S — the exception in this file: only the host knows a kill, so it keeps these on its
/// copy of the shooter. One slot: a newer kill replaces it, and a bullet that stops leaves it unmatched.
/// </summary>
public System.Guid FollowThroughShot { get; set; }
/// <summary>FOLLOW-THROUGH: the leftover damage waiting for <see cref="FollowThroughShot"/>'s next zombie. 0 when none.</summary>
public float FollowThroughLeft { get; set; }
/// <summary>
/// The nodes this prefab owns, or null when it owns none — `TechFor` without its fresh empty list.
///
/// ⚠️ FOR THE PER-FRAME STAT READS (`TechStats`): `EffectiveFiringType` alone asks three switches several times a frame,
/// and `TechFor` allocates a new list for every gun that has no tech. Same rules as `TechFor`: the wonder weapon owns
/// nothing, and the host reads a client's tree off the wire (`TechStore`).
/// </summary>
public System.Collections.Generic.List<string> TechOrNull( string prefab )
=> !string.IsNullOrEmpty( prefab ) && !BuildParts.IsWonderWeapon( prefab )
&& TechStore.TryGetValue( prefab, out var l ) && l.Count > 0
? l
: null;
}