using NewHorizons.External.Modules; using NewHorizons.Utility; using NewHorizons.Utility.OWMLUtilities; using NewHorizons.Utility.OWUtilities; using OWML.Common; using OWML.Utils; using System.Collections.Generic; using UnityEngine; using Logger = NewHorizons.Utility.Logger; namespace NewHorizons.Builder.Props { public static class SignalBuilder { private static AnimationCurve _customCurve = null; private static Dictionary _customSignalNames; private static Dictionary _customFrequencyNames; public static int NumberOfFrequencies; private static List _qmSignals; private static List _cloakedSignals; public static bool Initialized; public static void Init() { Logger.LogVerbose($"Initializing SignalBuilder"); _customSignalNames = new Dictionary(); _customFrequencyNames = new Dictionary() { { SignalFrequency.Statue, "FREQ_STATUE" }, { SignalFrequency.Default, "FREQ_UNKNOWN" }, { SignalFrequency.WarpCore, "FREQ_WARP_CORE" } }; NumberOfFrequencies = EnumUtils.GetValues().Length; _qmSignals = new List() { SignalName.Quantum_QM }; _cloakedSignals = new List(); Initialized = true; } public static bool IsCloaked(this SignalName signalName) { return _cloakedSignals.Contains(signalName); } public static bool IsOnQuantumMoon(this SignalName signalName) { return _qmSignals.Contains(signalName); } public static SignalFrequency AddFrequency(string str) { if (_customFrequencyNames == null) Init(); var freq = CollectionUtilities.KeyByValue(_customFrequencyNames, str); if (freq != default) return freq; Logger.Log($"Registering new frequency name [{str}]"); if (NumberOfFrequencies == 31) { Logger.LogWarning($"Can't store any more frequencies, skipping [{str}]"); return SignalFrequency.Default; } freq = EnumUtilities.Create(str); _customFrequencyNames.Add(freq, str); NumberOfFrequencies = EnumUtils.GetValues().Length; // This stuff happens after the signalscope is Awake so we have to change the number of frequencies now GameObject.FindObjectOfType()._strongestSignals = new AudioSignal[NumberOfFrequencies + 1]; return freq; } public static string GetCustomFrequencyName(SignalFrequency frequencyName) { if (_customFrequencyNames == null) Init(); _customFrequencyNames.TryGetValue(frequencyName, out string name); return name; } public static SignalName AddSignalName(string str) { if (_customSignalNames == null) Init(); var name = CollectionUtilities.KeyByValue(_customSignalNames, str); if (name != default) return name; Logger.Log($"Registering new signal name [{str}]"); name = EnumUtilities.Create(str); _customSignalNames.Add(name, str); return name; } public static string GetCustomSignalName(SignalName signalName) { if (_customSignalNames == null) Init(); _customSignalNames.TryGetValue(signalName, out string name); return name; } public static GameObject Make(GameObject planetGO, Sector sector, SignalModule.SignalInfo info, IModBehaviour mod) { var signalGO = GeneralPropBuilder.MakeNew($"Signal_{info.name}", planetGO, sector, info); signalGO.layer = Layer.AdvancedEffectVolume; var source = signalGO.AddComponent(); var owAudioSource = signalGO.AddComponent(); owAudioSource._audioSource = source; var audioSignal = signalGO.AddComponent(); audioSignal._owAudioSource = owAudioSource; var frequency = StringToFrequency(info.frequency); var name = StringToSignalName(info.name); audioSignal.SetSector(sector); if (name == SignalName.Default) audioSignal._preventIdentification = true; audioSignal._frequency = frequency; audioSignal._name = name; audioSignal._sourceRadius = info.sourceRadius; audioSignal._revealFactID = info.reveals; audioSignal._onlyAudibleToScope = info.onlyAudibleToScope; audioSignal._identificationDistance = info.identificationRadius; audioSignal._canBePickedUpByScope = true; audioSignal._outerFogWarpVolume = planetGO.GetComponentInChildren(); // shouldn't break non-bramble signals source.loop = true; source.minDistance = 0; source.maxDistance = 30; source.velocityUpdateMode = AudioVelocityUpdateMode.Fixed; source.rolloffMode = AudioRolloffMode.Custom; if (_customCurve == null) { _customCurve = new AnimationCurve( new Keyframe(0.0333f, 1f, -30.012f, -30.012f, 0.3333f, 0.3333f), new Keyframe(0.0667f, 0.5f, -7.503f, -7.503f, 0.3333f, 0.3333f), new Keyframe(0.1333f, 0.25f, -1.8758f, -1.8758f, 0.3333f, 0.3333f), new Keyframe(0.2667f, 0.125f, -0.4689f, -0.4689f, 0.3333f, 0.3333f), new Keyframe(0.5333f, 0.0625f, -0.1172f, -0.1172f, 0.3333f, 0.3333f), new Keyframe(1f, 0f, -0.0333f, -0.0333f, 0.3333f, 0.3333f)); } source.SetCustomCurve(AudioSourceCurveType.CustomRolloff, _customCurve); // If it can be heard regularly then we play it immediately source.playOnAwake = !info.onlyAudibleToScope; source.spatialBlend = 1f; source.volume = 0.5f; source.dopplerLevel = 0; owAudioSource.SetTrack(OWAudioMixer.TrackName.Signal); AudioUtilities.SetAudioClip(owAudioSource, info.audio, mod); // Frequency detection trigger volume var sphereShape = signalGO.AddComponent(); var owTriggerVolume = signalGO.AddComponent(); var audioSignalDetectionTrigger = signalGO.AddComponent(); sphereShape.radius = info.detectionRadius == 0 ? info.sourceRadius + 30 : info.detectionRadius; audioSignalDetectionTrigger._signal = audioSignal; audioSignalDetectionTrigger._trigger = owTriggerVolume; signalGO.SetActive(true); // Track certain special signal things if (planetGO.GetComponent()?.GetAstroObjectName() == AstroObject.Name.QuantumMoon) _qmSignals.Add(name); if (info.insideCloak) _cloakedSignals.Add(name); return signalGO; } private static SignalFrequency StringToFrequency(string str) { return EnumUtils.TryParse(str, out SignalFrequency frequency) ? frequency : AddFrequency(str); } public static SignalName StringToSignalName(string str) { return EnumUtils.TryParse(str, out SignalName name) ? name : AddSignalName(str); } } }