using System; using UnityEngine; namespace ProjectI.Enemies { [Serializable] public struct EncounterPacingBeat { public string name; public float duration, spawnIntervalMultiplier; public int aliveCap; public EncounterPacingBeat(string name,float duration,float multiplier,int cap) {this.name=name;this.duration=duration;spawnIntervalMultiplier=multiplier;aliveCap=cap;} } public readonly struct EncounterPressure { public readonly int BeatIndex, AliveCap; public readonly float SpawnInterval; public EncounterPressure(int index,int cap,float interval) {BeatIndex=index;AliveCap=cap;SpawnInterval=interval;} } public static class EncounterPacing { private static readonly EncounterPacingBeat[] defaults=CreateDefaults(); private static readonly float[] earlyStageDefaults=CreateEarlyStageDefaults(); public static float[] CreateEarlyStageDefaults()=>new[]{2f,1.6f,1.3f}; public static float StageMultiplier(int stage,float[] authored) { var scales=authored??earlyStageDefaults; int index=Math.Max(1,stage)-1; if(index>=scales.Length)return 1; return Finite(scales[index])?Mathf.Clamp(scales[index],1,4):1; } public static EncounterPressure SampleForStage(double elapsed,float baseInterval,int maximumAlive,EncounterPacingBeat[] authored,int stage,float[] stageScales) { var pressure=Sample(elapsed,baseInterval,maximumAlive,authored); return new EncounterPressure(pressure.BeatIndex,pressure.AliveCap,pressure.SpawnInterval*StageMultiplier(stage,stageScales)); } public static EncounterPacingBeat[] CreateDefaults()=>new[] { new EncounterPacingBeat("Build pressure",20,.8f,10), new EncounterPacingBeat("High pressure",25,.36f,16), new EncounterPacingBeat("Recovery",15,1.6f,5) }; public static EncounterPressure Sample(double elapsed,float baseInterval,int maximumAlive,EncounterPacingBeat[] authored) { var beats=authored==null||authored.Length==0?defaults:authored; int count=Mathf.Min(16,beats.Length),cap=Mathf.Clamp(maximumAlive,1,16); float interval=Finite(baseInterval)?Mathf.Clamp(baseInterval,.25f,30):2.5f; double total=0; for(int i=0;iFinite(beat.duration)?Mathf.Clamp(beat.duration,0,600):0; private static bool Finite(float value)=>!float.IsNaN(value)&&!float.IsInfinity(value); } }