RestaurantBathroomEntrance.cs
using Sandbox;
using System;
namespace PaintballBaddies;
// A one-way enemy entrance. Native collision rules block the squad while
// allowing sausages out; the opaque swinging leaf conceals their arrival.
public sealed class RestaurantBathroomEntrance : Component
{
public const string BarrierTag="sausage_entry_clip";
public static readonly Vector3 Threshold=new(448,793,33);
private GameObject root,hinge;
private float open,linger;
public float OpenAmount=>open;
protected override void OnStart()
{
root=new GameObject(true,"Restroom enemy entrance"){NetworkMode=NetworkMode.Never};
Scene.NavMesh.ExcludedBodies.Add(BarrierTag);
var barrier=new GameObject(root,false,"Restroom exit-only player barrier")
{NetworkMode=NetworkMode.Never,WorldPosition=Threshold+Vector3.Up*56};
barrier.Tags.Add(BarrierTag);
var clip=barrier.Components.Create<BoxCollider>();clip.Scale=new Vector3(12,64,116);clip.Static=true;
// This is a physical player clip, never invisible cover or bullet cover.
clip.ColliderFlags=ColliderFlags.IgnoreTraces;barrier.Enabled=true;
hinge=new GameObject(root,true,"Restroom outward door hinge")
{NetworkMode=NetworkMode.Never,WorldPosition=new Vector3(447,817,33)};
var wood="models/foundry/foundry_factory_door/foundry_factory_door.vmat";
Panel(hinge,"Restroom door leaf",new Vector3(0,-24,51),new Vector3(3.5f,48,102),new Color(.27f,.21f,.14f),wood);
foreach(float y in new[]{-43f,-5f})Panel(hinge,"Restroom door raised stile",new Vector3(-2.2f,y,51),new Vector3(1.4f,3.5f,96),new Color(.20f,.15f,.1f),wood);
foreach(float z in new[]{7f,51f,96f})Panel(hinge,"Restroom door raised rail",new Vector3(-2.2f,-24,z),new Vector3(1.4f,39,4),new Color(.2f,.15f,.1f),wood);
Panel(hinge,"Restroom push plate",new Vector3(-3,-39,44),new Vector3(.9f,6,14),new Color(.46f,.43f,.35f),"materials/foundry/metalplates006/metalplates006.vmat");
Label(hinge,"EXIT ONLY",new Vector3(-3.4f,-24,74),.13f,new Color(1,.81f,.43f));
Label(hinge,"NO ENTRY",new Vector3(-3.4f,-24,63),.115f,new Color(1,.81f,.43f));
Panel(root,"Restroom out of order sign",new Vector3(436,793,150),new Vector3(2,92,18),new Color(.14f,.1f,.075f),"materials/foundry/metalplates006/metalplates006.vmat");
Label(root,"RESTROOM · OUT OF ORDER",new Vector3(434.5f,793,151),.12f,new Color(1,.8f,.45f));
Scene.NavMesh.SetDirty();
}
protected override void OnUpdate()
{
if(!hinge.IsValid())return;
bool exiting=Scene.GetAllComponents<OverdriveEnemy>().Any(e=>!e.Dead && e.GameObject.Active
&& e.WorldPosition.x>380 && e.WorldPosition.x<570 && MathF.Abs(e.WorldPosition.y-793)<72);
if(exiting)linger=.5f;else linger=MathF.Max(0,linger-Time.Delta);
float target=linger>0 ? 1 : 0;
open+=(target-open)*(1-MathF.Exp(-10*Time.Delta));
hinge.WorldRotation=Rotation.FromYaw(-100*open);
}
private static GameObject Panel(GameObject parent,string name,Vector3 at,Vector3 size,Color tint,string material)
{
var model=Model.Load("models/dev/box.vmdl");
var go=new GameObject(parent,true,name){NetworkMode=NetworkMode.Never,LocalPosition=at};
go.LocalScale=size/model.Bounds.Size;go.LocalPosition-=model.Bounds.Center*go.LocalScale;
var render=go.Components.Create<ModelRenderer>();render.Model=model;render.Tint=tint;render.MaterialOverride=Material.Load(material);
return go;
}
private static void Label(GameObject parent,string text,Vector3 at,float scale,Color color)
{
var go=new GameObject(parent,true,"Restroom entrance notice"){NetworkMode=NetworkMode.Never,LocalPosition=at};
var label=go.Components.Create<TextRenderer>();label.Text=text;label.FontFamily="Arial";label.FontWeight=800;label.FontSize=36;label.Scale=scale;
label.Color=color;label.HorizontalAlignment=TextRenderer.HAlignment.Center;label.VerticalAlignment=TextRenderer.VAlignment.Center;
}
protected override void OnDestroy(){if(root.IsValid())root.Destroy();}
}