Defines MysteryBoxSkin record and a static MysteryBoxSkins class that lists available box skins (Original and Origins), holds current selection from config, provides lookup by name, console commands to change skin and tune offer lift/yaw, and rebuilds boxes via MysteryBoxManager.
using Sandbox;
using System.Linq;
namespace NZombies;
/// <summary>
/// One look for the mystery box: its crate, the base under it, where the offer rises, and the sounds that belong to it.
/// </summary>
/// <param name="Name">What `Gameplay.BoxSkin` calls it.</param>
/// <param name="Model">The crate, with its idle / open / close / arrive / leave.</param>
/// <param name="Platform">What stands at a spot the box is not at (`MysteryBoxManager.BuildPlatform`).</param>
/// <param name="PlatformYaw">That platform's turn from the spot's yaw: the original's footlockers are authored across the opening.</param>
/// <param name="BaseUnderBox">Does the box stand ON its platform? The Origins crate rises out of its base and sinks back into it.</param>
/// <param name="OfferLift">How much higher the weapon rises than out of the original crate — the Origins chest sits 17 up, and
/// its lid 26 above the original's rim.</param>
/// <param name="OfferYaw">The weapon's turn from the original's pose: GMod's `WEAPONPANG` for Origins is −90 (random_box:115).</param>
public sealed record MysteryBoxSkin( string Name, string Model, string Platform, float PlatformYaw, bool BaseUnderBox,
float OfferLift, float OfferYaw,
string OpenSound, string CloseSound, string ArriveSound, string LeaveSound, string TeddySound, string HumSound )
{
/// <summary>The box the game has always had — every other field is what the code already did.</summary>
public bool IsOriginal => Name == MysteryBoxSkins.OriginalName;
}
/// <summary>
/// THE MYSTERY BOX'S SKINS — `Gameplay.BoxSkin` chooses one per map. Asked for as *"I want to get the box skin from origins in
/// Gmod"* (2026-09-28): the Origins stone chest on its pedestal, from the user's `nz_moo_misc.gma`
/// (`models/moo/_codz_ports_props/t6/zm/p6_zm_tm_magic_box/`), decompiled, converted to `models/nz/magicbox_origins/`, with its
/// own sounds (`sound/nz_moo/mysterybox/tomb/`). Basalt wears it.
///
/// ⛔ ORIGINS' BASE IS PART OF THE BOX, NOT A PLATFORM ONLY. Its chest (Z 17..45) nests into the base (Z −9..25), and the base's two
/// doors open as the chest rises out of it and sinks back in — so the box builds its own base and plays `arrive`/`leave` on both
/// (`MysteryBox.PlayClip`), while the spots it is not at show the same base, shut.
///
/// ⚠️ THE OFFER'S LIFT AND TURN ARE A STARTING POINT, TO BE TUNED BY EYE: `nz_box_skin_offer lift yaw` moves them live.
/// </summary>
public static class MysteryBoxSkins
{
public const string OriginalName = "original";
public const string OriginsName = "origins";
/// <summary>Every name `Gameplay.BoxSkin` can take.</summary>
public static string[] Names => new[] { OriginalName, OriginsName };
public static MysteryBoxSkin Original => new( OriginalName,
"models/nz/magicbox/magic_box.vmdl", "models/nz/magicbox/magic_box_platform.vmdl", 90f, false,
0f, 0f,
"", "", "", "", "", "" );
public static MysteryBoxSkin Origins => new( OriginsName,
"models/nz/magicbox_origins/magic_box_origins.vmdl", "models/nz/magicbox_origins/magic_box_origins_base.vmdl", 0f, true,
_liftOverride ?? 22f, _yawOverride ?? -90f,
"nz.box.tomb.open", "nz.box.tomb.close", "nz.box.tomb.arrive", "nz.box.tomb.leave", "nz.box.tomb.bear", "nz.box.tomb.hum" );
static float? _liftOverride, _yawOverride;
/// <summary>A skin by name; anything unknown or blank is the original.</summary>
public static MysteryBoxSkin For( string name ) => (name ?? "").Trim().ToLowerInvariant() switch
{
OriginsName or "tomb" => Origins,
_ => Original,
};
/// <summary>This map's: its config's `Gameplay.BoxSkin`.</summary>
public static MysteryBoxSkin Current => For( ActiveConfig.Current?.Gameplay?.BoxSkin );
/// <summary>Rebuild every box and platform in the current skin — after a skin or an offer change.</summary>
static void Rebuild()
{
var m = MysteryBoxManager.Instance;
if ( m.IsValid() ) m.Rebuild();
}
/// <summary>
/// `nz_box_skin [original|origins]` — this map's mystery box. Bare, which it is and what each is. A name switches it (the config in
/// memory — `nz_save` keeps it) and rebuilds every box and platform.
/// </summary>
[ConCmd( "nz_box_skin" )]
public static void Cmd( string name = "" )
{
var cfg = ActiveConfig.Current;
if ( !string.IsNullOrWhiteSpace( name ) && cfg?.Gameplay is not null )
{
var skin = For( name );
cfg.Gameplay.BoxSkin = skin.IsOriginal ? "" : skin.Name;
Rebuild();
}
var now = Current;
Log.Info( $"[box] skin '{now.Name}' — {now.Model} on {now.Platform}{(now.BaseUnderBox ? " (the box stands on its base)" : "")}"
+ $" · offer lift {now.OfferLift:0.#}, turn {now.OfferYaw:0.#}° · {string.Join( ", ", Names )} · nz_save keeps it" );
}
/// <summary>
/// `nz_box_skin_offer [lift] [yaw]` — tune the Origins box's offer by eye: how much higher than the original's the weapon rises,
/// and its turn. For this session; say the numbers and they become the defaults. Rebuilds the boxes.
/// </summary>
[ConCmd( "nz_box_skin_offer" )]
public static void OfferCmd( float lift = float.NaN, float yaw = float.NaN )
{
if ( !float.IsNaN( lift ) ) _liftOverride = lift;
if ( !float.IsNaN( yaw ) ) _yawOverride = yaw;
Rebuild();
Log.Info( $"[box] Origins offer: lift {Origins.OfferLift:0.#}, turn {Origins.OfferYaw:0.#}°"
+ (Current.Name == OriginsName ? "" : " — this map's box is not Origins (nz_box_skin origins)") );
}
}