Host-side death hook for ammo-mod effects. When a ZombieAI dies (before its status effects are cleared) this calls SilkShot.OnWebbedDeath and Bloodhound.OnMarkedDeath and logs any exceptions so one mod failing does not abort the whole death handling.
using Sandbox;
using System;
namespace NZombies;
/// <summary>
/// THE AMMO MODS' DEATH HOOK, ON THE HOST (2026-10-06, `Sbox nzombies/Docs/AMMO_MODS.md` "Tiers IV and V"): a zombie died, and a
/// mod that left something ON it passes it on.
///
/// | mod | upgrade | the hook is for |
/// |---|---|---|
/// | **Silk Shot** | V Brood | a webbed zombie that dies webs up to 3 within 140u (`SilkShot.OnWebbedDeath`) |
/// | **Bloodhound** | V Blood Trail | a marked zombie's mark jumps to the nearest unmarked one (`Bloodhound.OnMarkedDeath`) |
///
/// ⛔ CALLED FROM `ZombieAI.Die`, ON THE HOST (OR SOLO), BEFORE THE CORPSE'S STATUSES ARE CLEARED — beside `PrismaChain.OnDied`,
/// for its reason: what is on the body (the web, the mark, and who put them there: `StatusEffects.SourceOf`) is read off it, and
/// after `StatusEffects.ClearAll` there is nothing left to read. A puppet never reaches `Die`, so this runs once a death, on the
/// machine whose statuses the AI obeys.
///
/// ⚠️ NOT `AmmoMods.OnZombieKilled`, which runs on the KILLER'S machine, relayed there after the fact when the corpse's statuses
/// are gone, and is about who killed it. These are about what the zombie WORE, whoever killed it — a grenade, a bleed, a
/// teammate.
///
/// ⚠️ EACH HOOK IS FENCED: an exception thrown inside `Die` before `ClearAll` would end the whole death there — no points, no
/// corpse on the other screens (`NZNet.ZombieDied`) — so one mod's fault costs that mod's effect and a warning, nothing else.
/// </summary>
public static class AmmoModDeaths
{
/// <summary>A zombie died. THE HOST, from `ZombieAI.Die`, before `StatusEffects.ClearAll`.</summary>
public static void Died( ZombieAI zombie )
{
// ⚠️ A CLIENT NEVER GETS HERE (`Die` is the host's alone); the test says so where the next caller would read it.
if ( !zombie.IsValid() || NZGame.IsClient ) return;
try { SilkShot.OnWebbedDeath( zombie ); }
catch ( Exception e ) { Log.Warning( $"[nz-ammo] silk shot's death hook threw on {zombie.GameObject?.Name}: {e.Message}" ); }
try { Bloodhound.OnMarkedDeath( zombie ); }
catch ( Exception e ) { Log.Warning( $"[nz-ammo] bloodhound's death hook threw on {zombie.GameObject?.Name}: {e.Message}" ); }
}
}