PopRiotTarget.Visuals.cs
using Sandbox;
using System;
namespace PaintballBaddies;
public sealed partial class PopRiotTarget
{
private const string IndustrialPath="models/pop_riot/industrial/";
private GameObject shell,launcher;
private ModelRenderer skin;
private SkinnedModelRenderer drone;
private LineRenderer warningRing;
private readonly List<ModelRenderer> liquid=new(),lamps=new(),glass=new(),shutters=new();
private float shutterOpen=1;
private bool wasCharging;
private ModelRenderer Part(string name,GameObject parent,Vector3 position,float scale=1,Color? tint=null)
{
var go=new GameObject(parent,true,name){NetworkMode=NetworkMode.Never,LocalPosition=position,LocalScale=new Vector3(scale),LocalRotation=Rotation.FromYaw(-90)};
var renderer=go.Components.Create<ModelRenderer>();renderer.Model=Model.Load(IndustrialPath+name+".vmdl");
renderer.Tint=tint ?? Color.White;return renderer;
}
private void Capsule(GameObject parent,Vector3 position,float scale,int index,bool armored)
{
var assembly=new GameObject(parent,true,"Pressure chamber"){NetworkMode=NetworkMode.Never,LocalPosition=position,LocalScale=new Vector3(scale)};
if(Kind==PopKind.Giant)assembly.LocalRotation=Rotation.FromYaw(index*120);
Part("capsule_frame",assembly,Vector3.Zero);
glass.Add(Part("capsule_glass",assembly,Vector3.Zero));
liquid.Add(Part("capsule_paint",assembly,Vector3.Zero,1,PaintTint));
lamps.Add(Part("capsule_light",assembly,Vector3.Zero,1,PaintTint));
if(armored)shutters.Add(Part("shutter",assembly,Vector3.Zero));
if(Kind==PopKind.Giant)
{
var hit=assembly.Components.Create<BoxCollider>();hit.Scale=new Vector3(25,25,34);hit.Static=false;
}
}
private void BuildIndustrialVisuals()
{
shell=new GameObject(GameObject,true,"Industrial pressure target"){NetworkMode=NetworkMode.Never};
if(Kind==PopKind.Glob)
{
skin=Sphere(shell,Vector3.Zero,Radius,PaintTint,false);
Sphere(shell,Vector3.Forward*(Radius*.25f),Radius*.55f,PaintTint*1.35f,true);
return;
}
if(Kind==PopKind.Giant)
{
Part("machine_base",shell,Vector3.Zero);
for(int i=0;i<3;i++)Capsule(shell,SpotOffset(i),1.6f,i,true);
}
else if(Kind==PopKind.Blob)
{
var airframe=new GameObject(shell,true,"Rust quadcopter"){NetworkMode=NetworkMode.Never,LocalScale=new Vector3(.88f)};
drone=airframe.Components.Create<SkinnedModelRenderer>();drone.Model=RiotDroneAssets.Drone;drone.UseAnimGraph=false;
if(drone.Model.IsError)LoadAirframe();
Capsule(shell,Vector3.Down*15,.65f,0,false);
launcher=new GameObject(GameObject,true,"Drone paint launcher"){NetworkMode=NetworkMode.Never,LocalPosition=Vector3.Down*12};
var barrel=Part("capsule_frame",launcher,Vector3.Forward*12,.48f);
barrel.LocalRotation=Rotation.FromPitch(90)*Rotation.FromYaw(-90);
var bore=Sphere(launcher,Vector3.Forward*20,4.8f,new Color(.018f,.02f,.022f),false);
bore.GameObject.LocalScale=new Vector3(.012f,.15f,.15f);
warningRing=ArenaGlow.Ring(GameObject,"Drone attack warning",43,1.4f,new Color(1,.38f,.055f),32);
warningRing.LocalRotation=Rotation.FromPitch(90);warningRing.Enabled=false;
}
else
{
Capsule(shell,Vector3.Zero,Kind==PopKind.Chain ? .92f : .8f,0,false);
if(Kind==PopKind.Chain)
{
// Twin cartridges distinguish chain reactors by shape as well as colour.
Capsule(shell,new Vector3(0,-15,-2),.5f,1,false);
Capsule(shell,new Vector3(0,15,-2),.5f,2,false);
}
}
}
private async void LoadAirframe()
{
var model=await RiotDroneAssets.LoadAsync();
if(drone.IsValid() && model.IsValid() && !model.IsError)drone.Model=model;
}
protected override void OnPreRender()
{
if(!drone.IsValid())return;
int i=0;
foreach(var bone in drone.Model.Bones.AllBones)
{
if(!drone.TryGetBoneTransformAnimation(bone,out var pose))continue;
var local=drone.WorldTransform.ToLocal(pose);
local.Rotation*=Rotation.FromYaw(age*(Crashing ? 450 : 1800)*(i++%2==0 ? 1 : -1));
drone.SetBoneTransform(bone,local);
}
}
private void UpdateIndustrialVisuals()
{
if(!shell.IsValid())return;
if(Charging && !wasCharging)DroneAudio.Play("charge",WorldPosition);
wasCharging=Charging;
if(Kind==PopKind.Glob)
{
shell.LocalRotation=Rotation.LookAt(GlobVelocity.Length>1 ? GlobVelocity.Normal : Vector3.Forward);
shell.LocalScale=new Vector3(1.12f,.94f,.94f);return;
}
if(Kind==PopKind.Blob)
{
var facing=Charging ? AttackAim-WorldPosition : FlightVelocity;
if(launcher.IsValid())
{
launcher.LocalRotation=Charging ? Rotation.LookAt(AttackAim-launcher.WorldPosition) : shell.LocalRotation;
launcher.Enabled=!Crashing;
}
float yaw=facing.WithZ(0).Length>1 ? Rotation.LookAt(facing.WithZ(0)).Yaw() : shell.LocalRotation.Yaw();
float damage=1-(float)Health/MaximumHealth;
var bank=Rotation.FromRoll(MathF.Sin(age*1.6f+Seed)*4+MathF.Sin(age*9)*damage*13+MathF.Sin(age*31)*hitPulse*70);
if(Crashing)bank=Rotation.FromRoll(18+CrashSeconds*280)*Rotation.FromPitch(CrashSeconds*110);
shell.LocalRotation=Rotation.Lerp(shell.LocalRotation,Rotation.FromYaw(yaw)*bank,1-MathF.Exp(-6*Time.Delta));
if(warningRing.IsValid())
{
warningRing.Enabled=!Crashing && (Charging || Entering);
if(Scene.Camera.IsValid())warningRing.WorldRotation=Rotation.LookAt(Scene.Camera.WorldPosition-WorldPosition)*Rotation.FromPitch(90);
warningRing.LocalScale=Vector3.One*(Charging ? .9f+.35f*ChargeRemaining/ChargeDuration : 1);
var warning=(Entering ? new Color(.15f,.85f,.8f) : new Color(1,.25f,.04f))*1.5f;
warningRing.Color=Gradient.FromColors(warning,warning);
}
}
else if(Kind!=PopKind.Giant)shell.LocalRotation=Rotation.FromYaw(Seed*47+age*12)*Rotation.FromRoll(MathF.Sin(age*1.2f)*2);
float goal=Kind==PopKind.Giant ? (WeakSpotsExposed ? 1 : 0) : (3-Health)*.38f;
shutterOpen=MathX.Lerp(shutterOpen,goal,1-MathF.Exp(-12*Time.Delta));
for(int i=0;i<liquid.Count;i++)
{
bool intact=Kind!=PopKind.Giant || ChamberHealth(i)>0;
liquid[i].Enabled=glass[i].Enabled=intact;
float pulse=Charging ? 1.7f+MathF.Sin(age*19)*.5f : 1;
lamps[i].Tint=intact ? (Kind==PopKind.Blob && (Charging || Health<=2) ? new Color(1,.32f,.06f) : PaintTint)*pulse : new Color(.025f,.025f,.025f);
liquid[i].Tint=Color.Lerp(PaintTint,Color.White,hitPulse*.9f);
float fill=Kind==PopKind.Giant ? (float)ChamberHealth(i)/(MaximumHealth/3) : 1;
liquid[i].GameObject.LocalScale=new Vector3(1,1,.5f+fill*.5f);
liquid[i].GameObject.LocalPosition=Vector3.Down*(1-fill)*7;
}
foreach(var shutter in shutters)
{
shutter.GameObject.LocalRotation=Rotation.FromYaw(-90);
shutter.GameObject.LocalPosition=Kind==PopKind.Giant ? Vector3.Down*(38*shutterOpen) : Vector3.Up*(5-22*shutterOpen);
}
}
}