Core/ChargerReviewStage.cs
using System;
using System.Collections.Generic;
namespace Prototype;
/// <summary>Only attached to scenes/review/charger_review.scene; never spawns gameplay enemies.</summary>
public sealed class ChargerReviewStage : Component
{
[Property] public string Clip { get; set; } = "idle";
private readonly List<SkinnedModelRenderer> _models = new();
private string _lastClip;
protected override void OnStart()
{
var model = Model.Load( "models/review/charger_relic_v001/charger.vmdl" );
var fillObject = new GameObject( true, "Review fill light" );
fillObject.WorldPosition = new Vector3( 120, -80, 145 );
var fill = fillObject.Components.Create<PointLight>();
fill.Radius = 500; fill.LightColor = new Color( 1.8f, 1.65f, 1.45f ); fill.Shadows = false;
var size = model.Bounds.Size;
Log.Info( $"CHARGER_REVIEW imported size={size}, bones={model.BoneCount}, bounds={model.Bounds}" );
if ( size.z < 60 || size.z > 90 || size.x > 105 || size.y > 105 )
{
Log.Error( "CHARGER_REVIEW: unsafe import dimensions; preview spawn rejected" );
return;
}
PrototypeFactory.Box( "Review floor", new Vector3( 0, 0, -3 ), new Vector3( 440, 440, 6 ), new Color( .22f, .23f, .25f ), true );
for ( int n = -5; n <= 5; n++ )
{
float p = n * 39.37008f;
PrototypeFactory.Box( "1 metre grid X", new Vector3( p, 0, .04f ), new Vector3( .22f, 400, .08f ), new Color( .48f, .45f, .35f ), false );
PrototypeFactory.Box( "1 metre grid Y", new Vector3( 0, p, .04f ), new Vector3( 400, .22f, .08f ), new Color( .48f, .45f, .35f ), false );
}
for ( int i = 0; i < 3; i++ )
{
var go = new GameObject( true, $"Charger {i}" );
go.WorldPosition = new Vector3( 0, (i - 1) * 76, 0 );
go.WorldRotation = Rotation.FromYaw( i == 1 ? 0 : i == 0 ? 90 : 180 );
var renderer = go.Components.Create<SkinnedModelRenderer>();
renderer.Model = model; renderer.UseAnimGraph = false;
renderer.Sequence.Name = Clip; renderer.Sequence.Looping = true;
_models.Add( renderer );
// Gameplay-sized proxy is explicit, separate from decorative mesh bounds.
var proxy = go.Components.Create<CapsuleCollider>();
proxy.Radius = 10; proxy.Start = new Vector3( 0, 0, 10 ); proxy.End = new Vector3( 0, 0, 59 );
}
var reference = new GameObject( true, "Citizen scale reference" );
reference.WorldPosition = new Vector3( 0, 150, 0 );
var citizen = reference.Components.Create<SkinnedModelRenderer>();
citizen.Model = Model.Load( "models/citizen/citizen.vmdl" ); citizen.UseAnimGraph = false;
PrototypeFactory.Box( "1.8 metre ruler", new Vector3( 0, 174, 35.433f ), new Vector3( .8f, .8f, 70.866f ), new Color( .2f, .8f, .7f ), false );
for ( int i = 0; i <= 18; i++ )
PrototypeFactory.Box( "10 cm tick", new Vector3( 0, 174, i * 3.937f ), new Vector3( .8f, i % 5 == 0 ? 6 : 3, .35f ), Color.White, false );
_lastClip = Clip;
}
protected override void OnUpdate()
{
if ( _lastClip == Clip ) return;
foreach ( var renderer in _models )
{
renderer.Sequence.Name = Clip; renderer.Sequence.Time = 0;
renderer.Sequence.Looping = Clip is "idle" or "walk" or "run";
}
_lastClip = Clip;
}
}