Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of PizzaTowerEscapeMusic ForkForMe v2.5.11
BepInEx/plugins/PizzaTowerEscapeMusic.dll
Decompiled 2 weeks ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Text; using System.Threading; using System.Threading.Tasks; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using LethalConfig; using LethalConfig.ConfigItems; using LethalConfig.ConfigItems.Options; using Microsoft.CodeAnalysis; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using PizzaTowerEscapeMusic.Networking; using PizzaTowerEscapeMusic.Scripting; using PizzaTowerEscapeMusic.Scripting.Conditions; using PizzaTowerEscapeMusic.Scripting.ScriptEvents; using Unity.Netcode; using UnityEngine; using UnityEngine.Networking; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyCompany("PizzaTowerEscapeMusic")] [assembly: AssemblyDescription("Plays music from Pizza Tower when the early ship leave alert appears")] [assembly: AssemblyFileVersion("2.5.11.0")] [assembly: AssemblyInformationalVersion("2.5.11")] [assembly: AssemblyProduct("PizzaTowerEscapeMusic")] [assembly: AssemblyTitle("PizzaTowerEscapeMusic")] [assembly: TargetFramework(".NETFramework,Version=v4.8.1", FrameworkDisplayName = ".NET Framework 4.8.1")] [assembly: AssemblyVersion("2.5.11.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace PizzaTowerEscapeMusic { [HarmonyPatch] internal static class ApparatusPatch { private static readonly ManualLogSource logger = Logger.CreateLogSource("PizzaTowerEscapeMusic ApparatusPatch"); [HarmonyPrefix] [HarmonyPatch(typeof(LungProp), "EquipItem")] private static void ApparatusTaken_Prefix(LungProp __instance) { if (__instance.isLungDocked) { logger.LogDebug((object)"Apparatus was taken"); GameEventListener.CheckApparatusTaken(__instance); } } internal static void ApplyPatches() { //IL_0005: Unknown result type (might be due to invalid IL or missing references) try { new Harmony("com.pizzatowerescapemusic.apparatus").PatchAll(typeof(ApparatusPatch)); logger.LogInfo((object)"Apparatus Harmony patches applied successfully"); } catch (Exception arg) { logger.LogError((object)$"Failed to apply Apparatus Harmony patches: {arg}"); } } internal static void RemovePatches() { //IL_0005: Unknown result type (might be due to invalid IL or missing references) try { new Harmony("com.pizzatowerescapemusic.apparatus").UnpatchSelf(); logger.LogInfo((object)"Apparatus Harmony patches removed"); } catch (Exception arg) { logger.LogError((object)$"Failed to remove Apparatus Harmony patches: {arg}"); } } } [HarmonyPatch] internal static class ChainloaderStartupPatch { private static readonly ManualLogSource logger = Logger.CreateLogSource("PizzaTowerEscapeMusic ChainloaderStartupPatch"); private static bool chainloaderStartupCompleted = false; [HarmonyPrefix] [HarmonyPatch(typeof(Logger), "LogMessage")] private static void LogMessagePrefix(object data) { if (data is string text && text == "Chainloader startup complete" && !chainloaderStartupCompleted) { chainloaderStartupCompleted = true; logger.LogDebug((object)"Chainloader startup complete detected"); PizzaTowerEscapeMusicManager.OnChainloaderStartupComplete(); } } internal static void ApplyPatches() { //IL_0005: Unknown result type (might be due to invalid IL or missing references) try { new Harmony("com.pizzatowerescapemusic.chainloaderstartup").PatchAll(typeof(ChainloaderStartupPatch)); logger.LogInfo((object)"Chainloader startup patch applied successfully"); } catch (Exception arg) { logger.LogError((object)$"Failed to apply Chainloader startup patch: {arg}"); } } } public class Configuration { private readonly ConfigFile config; internal ConfigEntry<bool> useRandomMapSeed; internal ConfigEntry<bool> dontQueue; internal ConfigEntry<string> scriptingScripts; internal ConfigEntry<float> volumeMaster; internal ConfigEntry<string> selectLabelManually; public Configuration(ConfigFile config) { //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Expected O, but got Unknown //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Expected O, but got Unknown //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Expected O, but got Unknown //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: Expected O, but got Unknown //IL_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: Expected O, but got Unknown this.config = config; useRandomMapSeed = config.Bind<bool>("General", "UseRandomMapSeed", false, new ConfigDescription("Whether to use the game's random map seed for randomization", (AcceptableValueBase)null, Array.Empty<object>())); dontQueue = config.Bind<bool>("General", "DontQueue", true, new ConfigDescription("Whether to not queue randomization events even RandomMapSeed not fully ready, UseRandomMapSeed required", (AcceptableValueBase)null, Array.Empty<object>())); scriptingScripts = config.Bind<string>("Scripting", "Scripts", "Default", new ConfigDescription("The names of the JSON script files that will be loaded (Separated by commas, do not put a space after the commas)", (AcceptableValueBase)null, Array.Empty<object>())); volumeMaster = config.Bind<float>("Volume", "Master", 0.5f, new ConfigDescription("The volume of the music as a whole, all volumes are scaled by this value", (AcceptableValueBase)null, Array.Empty<object>())); selectLabelManually = config.Bind<string>("LabelRandom", "SelectLabelManually", "", new ConfigDescription("Manually select label for groups. Format: Group1:Label1,Group2:Label2 (empty to skip)", (AcceptableValueBase)null, Array.Empty<object>())); volumeMaster.SettingChanged += delegate { }; selectLabelManually.SettingChanged += delegate { PizzaTowerEscapeMusicManager.ScriptManager?.ApplySelectedLabels(); }; RemoveObsoleteEntries(); } private void RemoveObsoleteEntry(string section, string key) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Expected O, but got Unknown ConfigDefinition val = new ConfigDefinition(section, key); config.Bind<string>(val, "", (ConfigDescription)null); config.Remove(val); } private void ReplaceObsoleteEntry<T>(string section, string key, ConfigEntry<T> replacement) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Expected O, but got Unknown ConfigDefinition val = new ConfigDefinition(section, key); ConfigEntry<T> val2 = config.Bind<T>(val, (T)((ConfigEntryBase)replacement).DefaultValue, (ConfigDescription)null); if (!EqualityComparer<T>.Default.Equals(val2.Value, (T)((ConfigEntryBase)replacement).DefaultValue)) { replacement.Value = val2.Value; } config.Remove(val); } private void RemoveObsoleteEntries() { RemoveObsoleteEntry("Volume", "InsideFacility"); RemoveObsoleteEntry("Volume", "OutsideFacility"); RemoveObsoleteEntry("Volume", "InsideShip"); RemoveObsoleteEntry("Volume", "CrouchingScale"); RemoveObsoleteEntry("Music", "InsideFacility"); RemoveObsoleteEntry("Music", "OutsideFacility"); RemoveObsoleteEntry("Music", "HeavyWeather"); ReplaceObsoleteEntry<string>("Scripting", "Script", scriptingScripts); config.Save(); } } internal static class CustomManager { public static string GetFilePath(string path, string fallbackPath) { string[] directories = Directory.GetDirectories(Paths.PluginPath); for (int i = 0; i < directories.Length; i++) { string text = directories[i] + "/BGN-PizzaTowerEscapeMusic/" + path; if (File.Exists(text)) { return text; } } string text2 = Paths.PluginPath + "/BGN-PizzaTowerEscapeMusic_Custom/" + path; if (File.Exists(text2)) { return text2; } return Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) + "/" + fallbackPath; } } [HarmonyPatch] internal static class EndOfGamePatches { private static readonly ManualLogSource logger = Logger.CreateLogSource("PizzaTowerEscapeMusic EndOfGamePatches"); [HarmonyPostfix] [HarmonyPatch(typeof(StartOfRound), "EndOfGame")] private static void EndOfGame_Postfix(int bodiesInsured, int connectedPlayersOnServer, int scrapCollected) { logger.LogDebug((object)$"EndOfGame called with bodiesInsured={bodiesInsured}, connectedPlayersOnServer={connectedPlayersOnServer}, scrapCollected={scrapCollected}"); GameEventListener.EndOfGameCalled = true; } internal static void ApplyPatches() { //IL_0005: Unknown result type (might be due to invalid IL or missing references) try { new Harmony("com.pizzatowerescapemusic.endofgame").PatchAll(typeof(EndOfGamePatches)); logger.LogInfo((object)"EndOfGame Harmony patches applied successfully"); } catch (Exception arg) { logger.LogError((object)$"Failed to apply EndOfGame Harmony patches: {arg}"); } } internal static void RemovePatches() { //IL_0005: Unknown result type (might be due to invalid IL or missing references) try { new Harmony("com.pizzatowerescapemusic.endofgame").UnpatchSelf(); logger.LogInfo((object)"EndOfGame Harmony patches removed"); } catch (Exception arg) { logger.LogError((object)$"Failed to remove EndOfGame Harmony patches: {arg}"); } } } public class FacilityMeltdownIntegration : MonoBehaviour { private ManualLogSource logger; private GameEventListener gameEventListener; private Action registeredCallback; public void Initialize(ManualLogSource logger, GameEventListener gameEventListener) { this.logger = logger; this.gameEventListener = gameEventListener; TryHookIntoFacilityMeltdown(); } private void TryHookIntoFacilityMeltdown() { try { if (Type.GetType("FacilityMeltdown.MeltdownPlugin, FacilityMeltdown") == null) { logger.LogInfo((object)"Could not find FacilityMeltdown mod, skipping"); return; } logger.LogInfo((object)"FacilityMeltdown detected, hooking into meltdown events..."); Type type = Type.GetType("FacilityMeltdown.API.MeltdownAPI, FacilityMeltdown"); if (type == null) { logger.LogWarning((object)"Could not find MeltdownAPI type"); return; } MethodInfo method = type.GetMethod("RegisterMeltdownListener", BindingFlags.Static | BindingFlags.Public); if (method == null) { logger.LogWarning((object)"Could not find RegisterMeltdownListener method in MeltdownAPI"); return; } logger.LogInfo((object)"Found RegisterMeltdownListener method in MeltdownAPI"); Action action = OnFacilityMeltdownStarted; method.Invoke(null, new object[1] { action }); registeredCallback = action; logger.LogInfo((object)"Successfully registered as a meltdown listener!"); } catch (Exception ex) { logger.LogError((object)("Failed to hook into FacilityMeltdown: " + ex.Message)); logger.LogDebug((object)("Exception details: " + ex.ToString())); } } private void OnFacilityMeltdownStarted() { logger.LogInfo((object)"FacilityMeltdown meltdown event detected! Triggering music..."); if ((Object)(object)gameEventListener != (Object)null) { gameEventListener.OnMeltdownStarted?.Invoke(); } } private void OnDestroy() { GC.KeepAlive(registeredCallback); logger.LogDebug((object)"FacilityMeltdown integration being destroyed"); } } public class GameEventListener : MonoBehaviour { private ManualLogSource logger; public Action OnFrameUpdate = delegate { }; public Action OnSoundManagerCreated = delegate { }; public Action OnSoundManagerDestroyed = delegate { }; public Action OnDungeonDoneGenerating = delegate { }; public Action OnLevelLoaded = delegate { }; public Action OnEndOfGame = delegate { }; public Action OnShipLanded = delegate { }; public Action OnShipTakeOff = delegate { }; public Action OnShipInOrbit = delegate { }; public Action OnShipLeavingAlertCalled = delegate { }; public Action OnPlayerDamaged = delegate { }; public Action OnPlayerDeath = delegate { }; public Action OnPlayerEnteredFacility = delegate { }; public Action OnPlayerExitedFacility = delegate { }; public Action OnPlayerEnteredShip = delegate { }; public Action OnPlayerExitedShip = delegate { }; public Action OnApparatusTaken = delegate { }; public Action OnMeltdownStarted = delegate { }; public Action OnShipNotInOrbit = delegate { }; public Action OnFiringPlayers = delegate { }; public Action OnGameOver = delegate { }; public Action<SelectableLevel> OnCurrentMoonChanged = delegate { }; private int localSeed; private bool syncedrandomMapSeed; private readonly Dictionary<string, object> previousValues = new Dictionary<string, object>(); private static readonly List<LungProp> dockedApparatuses = new List<LungProp>(); public static GameEventListener Instance { get; private set; } public static bool SyncedrandomMapSeed { get { if ((Object)(object)Instance != (Object)null) { return Instance.syncedrandomMapSeed; } return false; } } public static bool EndOfGameCalled { get; set; } public static bool ApparatusTaked { get; set; } private void Awake() { logger = Logger.CreateLogSource("PizzaTowerEscapeMusic GameEventListener"); Instance = this; OnShipLanded = (Action)Delegate.Combine(OnShipLanded, new Action(FindDockedApparatus)); } private void OnDestroy() { Instance = null; } private void FindDockedApparatus() { dockedApparatuses.Clear(); logger.LogDebug((object)"Checking for docked Apparatus..."); LungProp[] array = Object.FindObjectsOfType<LungProp>(); foreach (LungProp val in array) { if (val.isLungDocked) { dockedApparatuses.Add(val); logger.LogDebug((object)"Found docked Apparatus"); } } if (dockedApparatuses.Count == 0) { logger.LogDebug((object)"Could not find docked Apparatus"); } } public static bool IsApparatusDocked() { return dockedApparatuses.Count > 0; } private void StartSyncedrandomMapSeed() { if (!((Object)(object)StartOfRound.Instance != (Object)null) || !SeedSyncService.SeedReceived || syncedrandomMapSeed) { return; } int randomMapSeed = StartOfRound.Instance.randomMapSeed; if (randomMapSeed != localSeed) { localSeed = randomMapSeed; logger.LogDebug((object)$"StartOfRound randomMapSeed updated: {randomMapSeed}"); int capturedSeed = SeedSyncService.CapturedSeed; if (capturedSeed != -1 && randomMapSeed == capturedSeed) { logger.LogDebug((object)$"Seed match: RPC seed {capturedSeed} equals StartOfRound seed {randomMapSeed}"); syncedrandomMapSeed = true; } } } private void ResetSyncedrandomMapSeed() { if (syncedrandomMapSeed) { localSeed = 0; syncedrandomMapSeed = false; logger.LogDebug((object)"SyncedrandomMapSeed flag reset"); } } private void Update() { if ((Object)(object)SoundManager.Instance != (Object)null) { OnFrameUpdate(); } CheckSoundManager(); CheckDungeonDoneGenerating(); CheckLevelLoaded(); CheckEndOfGame(); CheckShipLanded(); CheckShipIsLeaving(); CheckShipReturnToOrbit(); CheckShipInOrbit(); CheckShipNotInOrbit(); CheckFiringPlayers(); CheckGameOver(); CheckShipLeavingAlertCalled(); CheckPlayerDamaged(); CheckPlayerDeath(); CheckPlayerInsideFacility(); CheckPlayerInsideShip(); CheckCurrentMoonChanged(); CheckStartOfRoundNull(); StartSyncedrandomMapSeed(); } private T UpdateCached<T>(string key, T currentValue, T defaultValue) { if (!previousValues.TryGetValue(key, out var value)) { value = defaultValue; } previousValues[key] = currentValue; return (T)value; } private void CheckSoundManager() { bool flag = (Object)(object)SoundManager.Instance != (Object)null; if (UpdateCached("SoundManager", flag, defaultValue: false) != flag) { if (flag) { logger.LogDebug((object)"Sound Manager created"); OnSoundManagerCreated(); } else { logger.LogDebug((object)"Sound Manager destroyed"); OnSoundManagerDestroyed(); } } } private void CheckDungeonDoneGenerating() { bool flag = (Object)(object)RoundManager.Instance != (Object)null && RoundManager.Instance.dungeonCompletedGenerating; bool flag2 = UpdateCached("DungeonDoneGenerating", flag, defaultValue: false); if (flag != flag2 && flag) { logger.LogDebug((object)"Dungeon done generating"); OnDungeonDoneGenerating(); } } private void CheckLevelLoaded() { bool flag = (Object)(object)RoundManager.Instance != (Object)null && RoundManager.Instance.dungeonFinishedGeneratingForAllPlayers; bool flag2 = UpdateCached("LevelLoaded", flag, defaultValue: false); if (flag != flag2 && flag) { logger.LogDebug((object)"Level loaded"); OnLevelLoaded(); } } private void CheckEndOfGame() { bool flag = (Object)(object)StartOfRound.Instance != (Object)null && EndOfGameCalled; bool flag2 = UpdateCached("EndOfGame", flag, defaultValue: false); if (flag != flag2 && flag) { logger.LogDebug((object)"End of game"); OnEndOfGame(); EndOfGameCalled = false; } } private void CheckShipLanded() { bool flag = (Object)(object)StartOfRound.Instance != (Object)null && StartOfRound.Instance.shipHasLanded; bool flag2 = UpdateCached("ShipLanded", flag, defaultValue: true); if (flag != flag2 && !((Object)(object)StartOfRound.Instance == (Object)null)) { if (flag) { logger.LogDebug((object)"Ship landed"); OnShipLanded(); } else { logger.LogDebug((object)"Ship takeoff"); OnShipTakeOff(); } } } private void CheckShipIsLeaving() { bool flag = (Object)(object)StartOfRound.Instance != (Object)null && StartOfRound.Instance.shipIsLeaving; bool flag2 = UpdateCached("ShipIsLeaving", flag, defaultValue: false); if (flag != flag2 && flag) { logger.LogDebug((object)"Ship is leaving"); } } private void CheckShipReturnToOrbit() { bool flag = (Object)(object)StartOfRound.Instance == (Object)null || (!StartOfRound.Instance.shipHasLanded && !StartOfRound.Instance.shipIsLeaving); bool flag2 = UpdateCached("ShipReturnToOrbit", flag, defaultValue: true); if (flag != flag2 && flag) { logger.LogDebug((object)"Ship returning to orbit"); } } private void CheckShipInOrbit() { bool flag = (Object)(object)StartOfRound.Instance != (Object)null && StartOfRound.Instance.inShipPhase; bool flag2 = UpdateCached("ShipInOrbit", flag, defaultValue: false); if (flag != flag2 && flag) { logger.LogDebug((object)"Ship is in orbit"); OnShipInOrbit(); EndOfGameCalled = false; ApparatusTaked = false; dockedApparatuses.Clear(); } } private void CheckShipNotInOrbit() { bool flag = (Object)(object)StartOfRound.Instance != (Object)null && !StartOfRound.Instance.inShipPhase; bool flag2 = UpdateCached("ShipNotInOrbit", flag, defaultValue: true); if (flag != flag2 && flag) { logger.LogDebug((object)"Ship not in orbit"); OnShipNotInOrbit(); } } private void CheckShipLeavingAlertCalled() { bool flag = (Object)(object)TimeOfDay.Instance != (Object)null && TimeOfDay.Instance.shipLeavingAlertCalled; bool flag2 = UpdateCached("ShipLeavingAlertCalled", flag, defaultValue: false); if (flag != flag2 && flag) { logger.LogDebug((object)"Ship leaving alert called"); OnShipLeavingAlertCalled(); } } private void CheckPlayerDamaged() { if (!((Object)(object)GameNetworkManager.Instance == (Object)null) && !((Object)(object)GameNetworkManager.Instance.localPlayerController == (Object)null)) { int health = GameNetworkManager.Instance.localPlayerController.health; int num = UpdateCached("PlayerDamaged", health, 100); if (health < num) { logger.LogDebug((object)$"Player took damage (Health: {GameNetworkManager.Instance.localPlayerController.health})"); OnPlayerDamaged(); } } } private void CheckPlayerDeath() { bool flag = (Object)(object)GameNetworkManager.Instance != (Object)null && (Object)(object)GameNetworkManager.Instance.localPlayerController != (Object)null && GameNetworkManager.Instance.localPlayerController.isPlayerDead; bool flag2 = UpdateCached("PlayerDeath", flag, defaultValue: false); if (flag != flag2 && flag) { logger.LogDebug((object)"Player has died"); OnPlayerDeath(); } } private void CheckPlayerInsideFacility() { bool flag = (Object)(object)GameNetworkManager.Instance != (Object)null && (Object)(object)GameNetworkManager.Instance.localPlayerController != (Object)null && GameNetworkManager.Instance.localPlayerController.isInsideFactory; bool flag2 = UpdateCached("PlayerInsideFacility", flag, defaultValue: false); if (flag != flag2) { if (flag) { logger.LogDebug((object)"Player entered the facility"); OnPlayerEnteredFacility(); } else { logger.LogDebug((object)"Player exited the facility"); OnPlayerExitedFacility(); } } } private void CheckPlayerInsideShip() { bool flag = (Object)(object)GameNetworkManager.Instance != (Object)null && (Object)(object)GameNetworkManager.Instance.localPlayerController != (Object)null && GameNetworkManager.Instance.localPlayerController.isInHangarShipRoom; bool flag2 = UpdateCached("PlayerInsideShip", flag, defaultValue: false); if (flag != flag2) { if (flag) { logger.LogDebug((object)"Player entered the ship"); OnPlayerEnteredShip(); } else { logger.LogDebug((object)"Player exited the ship"); OnPlayerExitedShip(); } } } internal static void CheckApparatusTaken(LungProp lungProp) { if ((Object)(object)lungProp != (Object)null) { dockedApparatuses.Remove(lungProp); for (int num = dockedApparatuses.Count - 1; num >= 0; num--) { if ((Object)(object)dockedApparatuses[num] == (Object)null) { dockedApparatuses.RemoveAt(num); } } } ApparatusTaked = true; Instance?.OnApparatusTaken(); } private void CheckCurrentMoonChanged() { if (!((Object)(object)StartOfRound.Instance == (Object)null) && !((Object)(object)TimeOfDay.Instance == (Object)null)) { SelectableLevel currentLevel = TimeOfDay.Instance.currentLevel; SelectableLevel val = UpdateCached<SelectableLevel>("CurrentMoon", currentLevel, null); if (!((Object)(object)currentLevel == (Object)(object)val) && !((Object)(object)currentLevel == (Object)null) && !((Object)(object)val == (Object)null)) { logger.LogDebug((object)("Level has changed to " + (((Object)(object)currentLevel != (Object)null) ? currentLevel.PlanetName : null))); OnCurrentMoonChanged(currentLevel); } } } private void CheckFiringPlayers() { bool flag = (Object)(object)StartOfRound.Instance != (Object)null && StartOfRound.Instance.firingPlayersCutsceneRunning; bool flag2 = UpdateCached("FiringPlayers", flag, defaultValue: false); if (flag != flag2 && flag) { logger.LogDebug((object)"Firing players cutscene running"); OnFiringPlayers(); } } private void CheckGameOver() { bool flag = (Object)(object)StartOfRound.Instance != (Object)null && StartOfRound.Instance.suckingPlayersOutOfShip; bool flag2 = UpdateCached("GameOver", flag, defaultValue: false); if (flag != flag2 && flag) { logger.LogDebug((object)"Game over"); OnGameOver(); } } private void CheckStartOfRoundNull() { bool flag = (Object)(object)StartOfRound.Instance == (Object)null; bool flag2 = UpdateCached("StartOfRoundNull", flag, defaultValue: false); if (flag != flag2 && flag) { logger.LogDebug((object)"StartOfRound instance became null"); ResetSyncedrandomMapSeed(); SeedSyncService.ResetSeedReceived(); ScriptEvent_LabelRandom.ClearQueueAndFlags(); previousValues.Remove("CurrentMoon"); } } } internal static class LethalConfigIntegration { internal static void Initialize() { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Expected O, but got Unknown //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Expected O, but got Unknown //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Expected O, but got Unknown //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Expected O, but got Unknown //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Expected O, but got Unknown //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Expected O, but got Unknown LethalConfigManager.SkipAutoGen(); LethalConfigManager.SetModDescription("PizzaTowerEscapeMusic"); ConfigEntry<float> volumeMaster = PizzaTowerEscapeMusicManager.Configuration.volumeMaster; FloatStepSliderOptions val = new FloatStepSliderOptions { Name = "Master Volume", RequiresRestart = false }; ((BaseRangeOptions<float>)val).Min = 0f; ((BaseRangeOptions<float>)val).Max = 1f; val.Step = 0.01f; LethalConfigManager.AddConfigItem((BaseConfigItem)new FloatSliderConfigItem(volumeMaster, (FloatSliderOptions)val)); LethalConfigManager.AddConfigItem((BaseConfigItem)new TextInputFieldConfigItem(PizzaTowerEscapeMusicManager.Configuration.selectLabelManually, new TextInputFieldOptions { Name = "Select Label Manually", RequiresRestart = false, CharacterLimit = 200 })); } } public class MusicManager : MonoBehaviour { private class MusicInstance { private readonly MusicManager manager; public Script script; public ScriptEvent_PlayMusic musicEvent; public AudioSource introAudioSource; public AudioSource mainAudioSource; public Script.VolumeGroup volumeGroup; private bool isStopping; private readonly AudioClip introClip; private readonly AudioClip mainClip; private bool isIntroPlaying; private bool mainScheduled; private bool introSwitchToMain; private float volume; public float FadeSpeed { get; private set; } public MusicInstance(MusicManager manager, Script script, ScriptEvent_PlayMusic musicEvent, AudioSource audioSource, AudioClip musicClip, AudioClip introClip = null) { this.manager = manager; this.script = script; this.musicEvent = musicEvent; introAudioSource = audioSource; this.introClip = introClip; mainClip = musicClip; isIntroPlaying = (Object)(object)introClip != (Object)null; if (isIntroPlaying) { audioSource.clip = introClip; audioSource.loop = false; audioSource.bypassEffects = musicEvent.bypassEffects; audioSource.bypassListenerEffects = musicEvent.bypassEffects; audioSource.bypassReverbZones = musicEvent.bypassEffects; mainAudioSource = manager.GetAudioSource(); mainAudioSource.clip = mainClip; mainAudioSource.loop = musicEvent.loop; mainAudioSource.bypassEffects = musicEvent.bypassEffects; mainAudioSource.bypassListenerEffects = musicEvent.bypassEffects; mainAudioSource.bypassReverbZones = musicEvent.bypassEffects; mainScheduled = false; audioSource.Play(); } else { introAudioSource = null; mainAudioSource = audioSource; mainAudioSource.clip = mainClip; mainAudioSource.loop = musicEvent.loop; audioSource.bypassEffects = musicEvent.bypassEffects; audioSource.bypassListenerEffects = musicEvent.bypassEffects; audioSource.bypassReverbZones = musicEvent.bypassEffects; mainAudioSource.Play(); } musicInstances.Add(this); if (musicEvent.tag != null) { if (!musicInstancesByTag.TryGetValue(musicEvent.tag, out var value)) { value = new List<MusicInstance>(1); musicInstancesByTag.Add(musicEvent.tag, value); } value.Add(this); } volumeGroup = script.TryGetVolumeGroupOrDefault(musicEvent.tag); volume = volumeGroup.GetVolume(script); if (!isIntroPlaying) { manager.OnMainMusicStarted?.Invoke(musicEvent.tag); } } public void Update(float deltaTime) { bool flag = introSwitchToMain; introSwitchToMain = false; if (isIntroPlaying) { if ((Object)(object)introAudioSource != (Object)null && (Object)(object)mainAudioSource != (Object)null && !mainScheduled) { int num = introClip.samples - introAudioSource.timeSamples; int num2 = (int)(0.5f * (float)introClip.frequency); if (num <= num2) { double num3 = (double)num / (double)introClip.frequency; double num4 = AudioSettings.dspTime + num3; mainAudioSource.PlayScheduled(num4); mainScheduled = true; } } if ((Object)(object)introAudioSource != (Object)null && !introAudioSource.isPlaying) { isIntroPlaying = false; introSwitchToMain = true; manager.OnMainMusicStarted?.Invoke(musicEvent.tag); } } float num5 = (isStopping ? 0f : volumeGroup.GetVolume(script)); float num6 = (isStopping ? volumeGroup.stoppingVolumeLerpSpeed : volumeGroup.volumeLerpSpeed); float num7 = (isStopping ? volumeGroup.GetStoppingVolumeLerpSpeedScale(script) : volumeGroup.GetVolumeLerpSpeedScale(script)); float num8 = num6 * num7; volume = Mathf.Lerp(volume, num5, num8 * deltaTime); float value = PizzaTowerEscapeMusicManager.Configuration.volumeMaster.Value; if ((Object)(object)introAudioSource != (Object)null) { introAudioSource.volume = volume * value; } if ((Object)(object)mainAudioSource != (Object)null) { mainAudioSource.volume = volume * value; } AudioSource val = (isIntroPlaying ? introAudioSource : (mainAudioSource ?? introAudioSource)); if (((!((Object)(object)val != (Object)null) || !val.isPlaying) && !introSwitchToMain && !flag) || (isStopping && (Object)(object)val != (Object)null && val.volume < 0.005f)) { StopCompletely(); } } public void FadeStop() { if (!isStopping) { isStopping = true; float stoppingVolumeLerpSpeedScale = volumeGroup.GetStoppingVolumeLerpSpeedScale(script); FadeSpeed = volumeGroup.stoppingVolumeLerpSpeed * stoppingVolumeLerpSpeedScale; } } public void StopCompletely() { if ((Object)(object)introAudioSource != (Object)null) { introAudioSource.Stop(); audioSourcePool.Push(introAudioSource); } if ((Object)(object)mainAudioSource != (Object)null) { mainAudioSource.Stop(); audioSourcePool.Push(mainAudioSource); } musicInstances.Remove(this); if (musicEvent.tag != null && musicInstancesByTag.TryGetValue(musicEvent.tag, out var value)) { value.Remove(this); } mainScheduled = false; } } private readonly Dictionary<string, float> lastGetIsMusicPlayingLogTimeByTag = new Dictionary<string, float>(); private readonly bool enablelogCooldown = true; private static readonly SemaphoreSlim _loadConcurrencySemaphore = new SemaphoreSlim(16, 16); private ManualLogSource logger; private static readonly List<MusicInstance> musicInstances = new List<MusicInstance>(); private static readonly Dictionary<string, List<MusicInstance>> musicInstancesByTag = new Dictionary<string, List<MusicInstance>>(); private static readonly Stack<AudioSource> audioSourcePool = new Stack<AudioSource>(); private readonly Dictionary<string, AudioClip> loadedMusic = new Dictionary<string, AudioClip>(); public Action<string> OnMainMusicStarted = delegate { }; private void Awake() { logger = Logger.CreateLogSource("PizzaTowerEscapeMusic MusicManager"); } private void Update() { if ((Object)(object)StartOfRound.Instance == (Object)null) { return; } for (int num = musicInstances.Count - 1; num >= 0; num--) { musicInstances[num].Update(Time.deltaTime); } bool flag = false; foreach (MusicInstance musicInstance in musicInstances) { if (musicInstance.musicEvent.silenceGameMusic) { flag = true; break; } } if (flag) { if (SoundManager.Instance.playingOutsideMusic && GetIsMusicPlaying()) { SoundManager.Instance.playingOutsideMusic = false; logger.LogInfo((object)"Silenced the outside music because alternate music is playing"); } if (TimeOfDay.Instance.TimeOfDayMusic.isPlaying && GetIsMusicPlaying()) { TimeOfDay.Instance.TimeOfDayMusic.Stop(); logger.LogInfo((object)"Silenced the time of day music because alternate music is playing"); } } } public bool GetIsMusicPlaying(string tag = null) { if (tag == null) { return musicInstances.Count > 0; } if (musicInstancesByTag.TryGetValue(tag, out var value)) { bool flag = true; if (enablelogCooldown) { if (!lastGetIsMusicPlayingLogTimeByTag.TryGetValue(tag, out var value2)) { value2 = -30f; } if (Time.time - value2 >= 30f) { lastGetIsMusicPlayingLogTimeByTag[tag] = Time.time; } else { flag = false; } } if (flag) { logger.LogDebug((object)$"GetIsMusicPlaying says there's {value.Count} music instance(s) with the tag \"{tag}\""); } return value.Count > 0; } bool flag2 = true; if (enablelogCooldown) { if (!lastGetIsMusicPlayingLogTimeByTag.TryGetValue(tag, out var value3)) { value3 = -30f; } if (Time.time - value3 >= 30f) { lastGetIsMusicPlayingLogTimeByTag[tag] = Time.time; } else { flag2 = false; } } if (flag2) { logger.LogDebug((object)("GetIsMusicPlaying says there was no music instance list for tag \"" + tag + "\"")); } return false; } public void PlayMusic(Script script, ScriptEvent_PlayMusic musicEvent) { logger.LogDebug((object)("PlayMusic called\nTag: " + musicEvent.tag + $"\nOverlap handling: {musicEvent.overlapHandling}" + $"\nAny music playing?: {GetIsMusicPlaying()}" + $"\nAny music playing with tag?: {GetIsMusicPlaying(musicEvent.tag)}")); string text = musicEvent.musicNames[Random.Range(0, musicEvent.musicNames.Length)]; string text2 = null; if (musicEvent.introMusicNames != null && musicEvent.introMusicNames.Length != 0) { text2 = musicEvent.introMusicNames[Random.Range(0, musicEvent.introMusicNames.Length)]; } if (musicEvent.overlapHandling == ScriptEvent_PlayMusic.OverlapHandling.IgnoreAll && GetIsMusicPlaying()) { logger.LogDebug((object)"PlayMusic canceled because other music was playing"); return; } if (musicEvent.overlapHandling == ScriptEvent_PlayMusic.OverlapHandling.IgnoreTag && GetIsMusicPlaying(musicEvent.tag)) { logger.LogDebug((object)("PlayMusic canceled because other music with the tag \"" + musicEvent.tag + "\" was playing")); return; } (musicEvent.overlapHandling switch { ScriptEvent_PlayMusic.OverlapHandling.OverrideAll => delegate { StopMusic(); }, ScriptEvent_PlayMusic.OverlapHandling.OverrideTag => delegate { StopMusic(musicEvent.tag); }, ScriptEvent_PlayMusic.OverlapHandling.OverrideFadeAll => delegate { FadeStopMusic(); }, ScriptEvent_PlayMusic.OverlapHandling.OverrideFadeTag => delegate { FadeStopMusic(musicEvent.tag); }, _ => delegate { }, })(); loadedMusic.TryGetValue(text, out var value); AudioClip value2 = null; if (text2 != null) { loadedMusic.TryGetValue(text2, out value2); } if ((Object)(object)value != (Object)null) { new MusicInstance(this, script, musicEvent, GetAudioSource(), value, value2); logger.LogInfo((object)("Playing music (" + text + ")" + ((text2 != null) ? (" with intro (" + text2 + ")") : ""))); } else { logger.LogWarning((object)("Music (" + text + ") is null, cannot play. Maybe it wasn't loaded correctly?")); } } public void StopMusic(string targetTag = null) { foreach (MusicInstance item in new List<MusicInstance>(musicInstances)) { if (targetTag == null || !(item.musicEvent.tag != targetTag)) { item.StopCompletely(); } } } public void FadeStopMusic(string targetTag = null) { foreach (MusicInstance item in new List<MusicInstance>(musicInstances)) { if (targetTag == null || !(item.musicEvent.tag != targetTag)) { item.FadeStop(); } } } private AudioSource GetAudioSource() { if (audioSourcePool.Count > 0) { return audioSourcePool.Pop(); } return ((Component)this).gameObject.AddComponent<AudioSource>(); } public async void LoadNecessaryMusicClips() { if (PizzaTowerEscapeMusicManager.ScriptManager.loadedScripts.Count == 0) { logger.LogError((object)"No scripts are loaded, addon scripts may not work, please report this issue"); return; } if (string.IsNullOrWhiteSpace(PizzaTowerEscapeMusicManager.Configuration?.scriptingScripts?.Value)) { logger.LogInfo((object)"No scripts configured, skipping music loading"); return; } HashSet<string> musicToLoad = new HashSet<string>(); foreach (Script loadedScript in PizzaTowerEscapeMusicManager.ScriptManager.loadedScripts) { ScriptEvent[] scriptEvents = loadedScript.scriptEvents; for (int i = 0; i < scriptEvents.Length; i++) { if (!(scriptEvents[i] is ScriptEvent_PlayMusic scriptEvent_PlayMusic)) { continue; } string[] musicNames; if (scriptEvent_PlayMusic.musicNames != null) { musicNames = scriptEvent_PlayMusic.musicNames; foreach (string text in musicNames) { if (!loadedMusic.ContainsKey(text)) { musicToLoad.Add(text); } } } if (scriptEvent_PlayMusic.introMusicNames == null) { continue; } musicNames = scriptEvent_PlayMusic.introMusicNames; foreach (string text2 in musicNames) { if (!loadedMusic.ContainsKey(text2)) { musicToLoad.Add(text2); } } } } if (musicToLoad.Count == 0) { logger.LogInfo((object)"All music clips already loaded"); return; } logger.LogInfo((object)$"Loading {musicToLoad.Count} music clips..."); List<Task<AudioClip>> list = new List<Task<AudioClip>>(); foreach (string item in musicToLoad) { list.Add(LoadMusicClip(item)); } AudioClip[] array = await Task.WhenAll(list); int num = 0; int num2 = 0; foreach (string item2 in musicToLoad) { AudioClip val = array[num2++]; if ((Object)(object)val != (Object)null) { loadedMusic[item2] = val; num++; } } num2 = 0; foreach (string item3 in musicToLoad) { AudioClip val2 = array[num2++]; if ((Object)(object)val2 != (Object)null) { try { val2.LoadAudioData(); } catch (Exception arg) { logger.LogError((object)$"Failed to load audio data for {item3}: {arg}"); } } } logger.LogInfo((object)$"Music clips done loading. Successfully loaded {num} out of {musicToLoad.Count}"); } private Task<AudioClip> LoadMusicClip(string musicFileName) { //IL_005b: Unknown result type (might be due to invalid IL or missing references) InterpretMusicFileName(musicFileName, out var audioType, out var finalFileName); string path = "file:///" + CustomManager.GetFilePath("Music/" + finalFileName, "DefaultMusic/" + finalFileName); UnityWebRequest request = UnityWebRequestMultimedia.GetAudioClip(path, audioType); UnityWebRequestAsyncOperation obj = request.SendWebRequest(); TaskCompletionSource<AudioClip> tcs = new TaskCompletionSource<AudioClip>(); ((AsyncOperation)obj).completed += delegate { Task.Run(async delegate { await _loadConcurrencySemaphore.WaitAsync(); try { if ((int)request.result == 1) { AudioClip content = DownloadHandlerAudioClip.GetContent(request); if ((Object)(object)content != (Object)null) { ((Object)content).name = musicFileName; logger.LogInfo((object)("Loaded music (" + musicFileName + ") from file")); tcs.SetResult(content); } else { logger.LogError((object)("DownloadHandlerAudioClip.GetContent returned null for " + musicFileName)); tcs.SetResult(null); } } else { logger.LogError((object)($"Failed to load music ({musicFileName}) from file as audio type {audioType}, if the file extension and the audio type do not match the file extension may not be supported" + "\n- Path: " + path + "\n- Error: " + request.error)); tcs.SetResult(null); } } finally { request.Dispose(); _loadConcurrencySemaphore.Release(); } }); }; return tcs.Task; } private void InterpretMusicFileName(string musicFileName, out AudioType audioType, out string finalFileName) { //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Expected I4, but got Unknown //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) if (!Enumerable.Contains(musicFileName, '.')) { audioType = (AudioType)20; finalFileName = musicFileName + ".wav"; return; } string text = musicFileName.Split(new char[1] { '.' }).Last().ToLower(); AudioType val = ((text == "ogg") ? ((AudioType)14) : ((text == "mp3") ? ((AudioType)13) : ((AudioType)20))); audioType = (AudioType)(int)val; finalFileName = musicFileName; } } public class PizzaTowerEscapeMusicManager : MonoBehaviour { private GameEventListener gameEventListener; public static Configuration Configuration { get; private set; } public static ScriptManager ScriptManager { get; private set; } public static MusicManager MusicManager { get; private set; } public void Initialise(ManualLogSource logger, ConfigFile config) { Configuration = new Configuration(config); MusicManager = ((Component)this).gameObject.AddComponent<MusicManager>(); gameEventListener = ((Component)this).gameObject.AddComponent<GameEventListener>(); GameEventListener obj = gameEventListener; obj.OnSoundManagerDestroyed = (Action)Delegate.Combine(obj.OnSoundManagerDestroyed, (Action)delegate { MusicManager.StopMusic(); }); ScriptManager = new ScriptManager(Configuration.scriptingScripts.Value.Split(new char[1] { ',' }), gameEventListener); GameEventListener obj2 = gameEventListener; obj2.OnSoundManagerDestroyed = (Action)Delegate.Combine(obj2.OnSoundManagerDestroyed, new Action(ScriptManager.ClearAllScriptTimers)); GameEventListener obj3 = gameEventListener; obj3.OnSoundManagerDestroyed = (Action)Delegate.Combine(obj3.OnSoundManagerDestroyed, new Action(ScriptManager.ClearAllScriptCounters)); try { ((Component)this).gameObject.AddComponent<FacilityMeltdownIntegration>().Initialize(logger, gameEventListener); } catch (Exception) { logger.LogInfo((object)"Could not initialize FacilityMeltdown integration, skipping"); } try { LethalConfigIntegration.Initialize(); } catch (Exception) { logger.LogInfo((object)"Could not initialize LethalConfig integration, skipping"); } logger.LogInfo((object)"Plugin pizzatowerescapemusic is loaded!"); } private void Update() { ScriptManager.UpdateAllScriptTimers(Time.deltaTime); } public static void OnChainloaderStartupComplete() { if ((Object)(object)MusicManager != (Object)null) { MusicManager.LoadNecessaryMusicClips(); } } } [BepInPlugin("bgn.pizzatowerescapemusic", "PizzaTowerEscapeMusic", "2.5.11")] [BepInProcess("Lethal Company.exe")] public class Plugin : BaseUnityPlugin { private void Awake() { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Expected O, but got Unknown SeedSyncPatches.ApplyPatches(); EndOfGamePatches.ApplyPatches(); ChainloaderStartupPatch.ApplyPatches(); ApparatusPatch.ApplyPatches(); GameObject val = new GameObject("PizzaTowerEscapeMusic Manager") { hideFlags = (HideFlags)61 }; Object.DontDestroyOnLoad((Object)val); val.AddComponent<PizzaTowerEscapeMusicManager>().Initialise(((BaseUnityPlugin)this).Logger, ((BaseUnityPlugin)this).Config); } } public static class PluginInfo { public const string PLUGIN_GUID = "bgn.pizzatowerescapemusic"; public const string PLUGIN_NAME = "PizzaTowerEscapeMusic"; public const string PLUGIN_VERSION = "2.5.11"; public const string PLUGIN_VERSION_FULL = "2.5.11.0"; } } namespace PizzaTowerEscapeMusic.Scripting { public class Script { public class VolumeRule { public string comment = string.Empty; [JsonRequired] public float volume; public Condition condition; } public class VolumeModifier { public string comment = string.Empty; [JsonRequired] public float volumeScale; public float volumeLerpSpeedScale = 1f; public float stoppingVolumeLerpSpeedScale = 1f; public Condition condition; } public class VolumeGroup { public string comment = string.Empty; public string tag = string.Empty; public float volumeLerpSpeed = 1f; public float stoppingVolumeLerpSpeed = 1f; public float masterVolume = 1f; public VolumeRule[] volumeRules = Array.Empty<VolumeRule>(); public VolumeModifier[] volumeModifiers = Array.Empty<VolumeModifier>(); public float GetVolume(Script script) { float num = 1f; VolumeRule[] array = volumeRules; foreach (VolumeRule volumeRule in array) { if (volumeRule.condition == null || volumeRule.condition.Check(script)) { num = volumeRule.volume; break; } } VolumeModifier[] array2 = volumeModifiers; foreach (VolumeModifier volumeModifier in array2) { if (volumeModifier.condition == null || volumeModifier.condition.Check(script)) { num *= volumeModifier.volumeScale; } } return num * masterVolume; } public float GetVolumeLerpSpeedScale(Script script) { float num = 1f; VolumeModifier[] array = volumeModifiers; foreach (VolumeModifier volumeModifier in array) { if (volumeModifier.condition == null || volumeModifier.condition.Check(script)) { num *= volumeModifier.volumeLerpSpeedScale; } } return num; } public float GetStoppingVolumeLerpSpeedScale(Script script) { float num = 1f; VolumeModifier[] array = volumeModifiers; foreach (VolumeModifier volumeModifier in array) { if (volumeModifier.condition == null || volumeModifier.condition.Check(script)) { num *= volumeModifier.stoppingVolumeLerpSpeedScale; } } return num; } } public class Timer { public string name; public float time; public Timer(string name) { this.name = name; } } public class Counter { public string name; public int count; public Counter(string name) { this.name = name; } } public string comment = string.Empty; public bool isAddon; public VolumeGroup[] volumeGroups = Array.Empty<VolumeGroup>(); [JsonRequired] public ScriptEvent[] scriptEvents = Array.Empty<ScriptEvent>(); [JsonIgnore] public readonly Dictionary<ScriptEvent.GameEventType, List<ScriptEvent>> loadedScriptEvents = new Dictionary<ScriptEvent.GameEventType, List<ScriptEvent>>(); [JsonIgnore] public readonly Dictionary<string, VolumeGroup> loadedScriptVolumeGroups = new Dictionary<string, VolumeGroup>(); [JsonIgnore] public readonly Dictionary<string, Timer> activeTimers = new Dictionary<string, Timer>(); [JsonIgnore] public readonly Dictionary<string, Counter> activeCounters = new Dictionary<string, Counter>(); [JsonIgnore] public readonly Dictionary<string, string> selectedLabelsByGroup = new Dictionary<string, string>(); [JsonIgnore] public static VolumeGroup DefaultVolumeGroup { get; private set; } = new VolumeGroup(); [JsonIgnore] public string selectedLabel { get { if (selectedLabelsByGroup.TryGetValue("", out var value)) { return value; } return string.Empty; } set { selectedLabelsByGroup[""] = value; } } public void Initialise(ManualLogSource logger) { ScriptEvent[] array = scriptEvents; foreach (ScriptEvent scriptEvent in array) { if (!loadedScriptEvents.TryGetValue(scriptEvent.gameEventType, out var value)) { value = new List<ScriptEvent>(1); loadedScriptEvents.Add(scriptEvent.gameEventType, value); } value.Add(scriptEvent); } VolumeGroup[] array2 = volumeGroups; foreach (VolumeGroup volumeGroup in array2) { if (!loadedScriptVolumeGroups.ContainsKey(volumeGroup.tag)) { loadedScriptVolumeGroups.Add(volumeGroup.tag, volumeGroup); } else { logger.LogError((object)("Volume group tag \"" + volumeGroup.tag + "\" was already declared, you cannot have two volume groups with the same tag")); } } } public VolumeGroup TryGetVolumeGroupOrDefault(string tag) { if (tag != null && loadedScriptVolumeGroups.TryGetValue(tag, out var value)) { return value; } return DefaultVolumeGroup; } public bool TryGetVolumeGroup(string tag, out VolumeGroup volumeGroup) { if (tag != null && loadedScriptVolumeGroups.TryGetValue(tag, out volumeGroup)) { return true; } volumeGroup = null; return false; } public void UpdateTimers(float deltaTime) { foreach (Timer value in activeTimers.Values) { value.time += deltaTime; } } public void ClearTimers() { activeTimers.Clear(); } internal void ClearTimer(string timerName) { activeTimers.Remove(timerName); } public void ClearCounters() { activeCounters.Clear(); } internal void ClearCounter(string counterName) { activeCounters.Remove(counterName); } } public class ScriptManager { private bool pendingManualLabelSelection; private readonly Dictionary<ScriptEvent.GameEventType, float> lastLogTimeByEvent = new Dictionary<ScriptEvent.GameEventType, float>(); private readonly bool enablelogCooldown = true; public readonly List<Script> loadedScripts = new List<Script>(); private static readonly char[] commaSeparator = new char[1] { ',' }; private static readonly char[] colonSeparator = new char[1] { ':' }; public bool SelectLabelManuallyValid { get; private set; } = true; public ManualLogSource Logger { get; private set; } public ScriptManager(string[] scriptNames, GameEventListener gameEventListener) { Logger = Logger.CreateLogSource("PizzaTowerEscapeMusic ScriptManager"); Script script = new Script(); loadedScripts.Add(script); foreach (string text in scriptNames) { if (string.IsNullOrWhiteSpace(text)) { Logger.LogDebug((object)"Skipping empty script name"); continue; } Script script2 = DeserializeScript(text); if (script2 == null) { continue; } script2.Initialise(Logger); if (script2.isAddon) { Script script3 = script; Script.VolumeGroup[] volumeGroups = script.volumeGroups; Script.VolumeGroup[] volumeGroups2 = script2.volumeGroups; int num = 0; Script.VolumeGroup[] array = new Script.VolumeGroup[volumeGroups.Length + volumeGroups2.Length]; Script.VolumeGroup[] array2 = volumeGroups; foreach (Script.VolumeGroup volumeGroup in array2) { array[num] = volumeGroup; num++; } array2 = volumeGroups2; foreach (Script.VolumeGroup volumeGroup in array2) { array[num] = volumeGroup; num++; } script3.volumeGroups = array; script3 = script; ScriptEvent[] scriptEvents = script.scriptEvents; ScriptEvent[] scriptEvents2 = script2.scriptEvents; num = 0; ScriptEvent[] array3 = new ScriptEvent[scriptEvents.Length + scriptEvents2.Length]; ScriptEvent[] array4 = scriptEvents; foreach (ScriptEvent scriptEvent in array4) { array3[num] = scriptEvent; num++; } array4 = scriptEvents2; foreach (ScriptEvent scriptEvent in array4) { array3[num] = scriptEvent; num++; } script3.scriptEvents = array3; } else { loadedScripts.Add(script2); } if (script2.isAddon) { Logger.LogInfo((object)("Script (" + text + ") loaded as addon")); } else { Logger.LogInfo((object)("Script (" + text + ") loaded")); } } script.Initialise(Logger); gameEventListener.OnFrameUpdate = (Action)Delegate.Combine(gameEventListener.OnFrameUpdate, (Action)delegate { CheckScriptEvents(ScriptEvent.GameEventType.FrameUpdated); }); gameEventListener.OnShipLanded = (Action)Delegate.Combine(gameEventListener.OnShipLanded, (Action)delegate { CheckScriptEvents(ScriptEvent.GameEventType.ShipLanded); }); gameEventListener.OnShipTakeOff = (Action)Delegate.Combine(gameEventListener.OnShipTakeOff, (Action)delegate { CheckScriptEvents(ScriptEvent.GameEventType.ShipTakeOff); }); gameEventListener.OnShipInOrbit = (Action)Delegate.Combine(gameEventListener.OnShipInOrbit, (Action)delegate { CheckScriptEvents(ScriptEvent.GameEventType.ShipInOrbit); }); gameEventListener.OnShipInOrbit = (Action)Delegate.Combine(gameEventListener.OnShipInOrbit, (Action)delegate { if (pendingManualLabelSelection) { pendingManualLabelSelection = false; ApplySelectedLabels(); } }); gameEventListener.OnShipLeavingAlertCalled = (Action)Delegate.Combine(gameEventListener.OnShipLeavingAlertCalled, (Action)delegate { CheckScriptEvents(ScriptEvent.GameEventType.ShipLeavingAlertCalled); }); gameEventListener.OnPlayerDamaged = (Action)Delegate.Combine(gameEventListener.OnPlayerDamaged, (Action)delegate { CheckScriptEvents(ScriptEvent.GameEventType.PlayerDamaged); }); gameEventListener.OnPlayerDeath = (Action)Delegate.Combine(gameEventListener.OnPlayerDeath, (Action)delegate { CheckScriptEvents(ScriptEvent.GameEventType.PlayerDied); }); gameEventListener.OnPlayerEnteredFacility = (Action)Delegate.Combine(gameEventListener.OnPlayerEnteredFacility, (Action)delegate { CheckScriptEvents(ScriptEvent.GameEventType.PlayerEnteredFacility); }); gameEventListener.OnPlayerExitedFacility = (Action)Delegate.Combine(gameEventListener.OnPlayerExitedFacility, (Action)delegate { CheckScriptEvents(ScriptEvent.GameEventType.PlayerExitedFacility); }); gameEventListener.OnPlayerEnteredShip = (Action)Delegate.Combine(gameEventListener.OnPlayerEnteredShip, (Action)delegate { CheckScriptEvents(ScriptEvent.GameEventType.PlayerEnteredShip); }); gameEventListener.OnPlayerExitedShip = (Action)Delegate.Combine(gameEventListener.OnPlayerExitedShip, (Action)delegate { CheckScriptEvents(ScriptEvent.GameEventType.PlayerExitedShip); }); gameEventListener.OnApparatusTaken = (Action)Delegate.Combine(gameEventListener.OnApparatusTaken, (Action)delegate { CheckScriptEvents(ScriptEvent.GameEventType.ApparatusTaken); }); gameEventListener.OnMeltdownStarted = (Action)Delegate.Combine(gameEventListener.OnMeltdownStarted, (Action)delegate { CheckScriptEvents(ScriptEvent.GameEventType.MeltdownStarted); }); gameEventListener.OnLevelLoaded = (Action)Delegate.Combine(gameEventListener.OnLevelLoaded, (Action)delegate { CheckScriptEvents(ScriptEvent.GameEventType.LevelLoaded); }); gameEventListener.OnEndOfGame = (Action)Delegate.Combine(gameEventListener.OnEndOfGame, (Action)delegate { CheckScriptEvents(ScriptEvent.GameEventType.EndOfGame); }); gameEventListener.OnFiringPlayers = (Action)Delegate.Combine(gameEventListener.OnFiringPlayers, (Action)delegate { CheckScriptEvents(ScriptEvent.GameEventType.FiringPlayers); }); gameEventListener.OnGameOver = (Action)Delegate.Combine(gameEventListener.OnGameOver, (Action)delegate { CheckScriptEvents(ScriptEvent.GameEventType.GameOver); }); gameEventListener.OnShipNotInOrbit = (Action)Delegate.Combine(gameEventListener.OnShipNotInOrbit, (Action)delegate { CheckScriptEvents(ScriptEvent.GameEventType.ShipNotInOrbit); }); gameEventListener.OnCurrentMoonChanged = (Action<SelectableLevel>)Delegate.Combine(gameEventListener.OnCurrentMoonChanged, (Action<SelectableLevel>)delegate { CheckScriptEvents(ScriptEvent.GameEventType.CurrentMoonChanged); }); Logger.LogInfo((object)"Done loading scripts"); ApplySelectedLabels(); } private void CheckScriptEvents(ScriptEvent.GameEventType eventType) { foreach (Script loadedScript in loadedScripts) { if (!loadedScript.loadedScriptEvents.TryGetValue(eventType, out var value)) { continue; } foreach (ScriptEvent item in value) { if (!item.CheckConditions(loadedScript)) { continue; } bool flag = true; if (enablelogCooldown) { if (!lastLogTimeByEvent.TryGetValue(eventType, out var value2)) { value2 = -15f; } if (Time.time - value2 >= 15f) { lastLogTimeByEvent[eventType] = Time.time; } else { flag = false; } } if (flag) { Logger.LogDebug((object)("Conditions for a script event have been met!\n Script Event Type: " + item.scriptEventType + $"\n Game Event Type: {item.gameEventType}" + "\n Comment: " + item.comment)); } item.Run(loadedScript); } } } private Script DeserializeScript(string name) { string filePath = CustomManager.GetFilePath("Scripts/" + name + ".json", "DefaultScripts/" + name + ".json"); if (!File.Exists(filePath)) { Logger.LogError((object)("Script \"" + name + "\" does not exist! Make sure you spelt it right the config, and make sure its file extension is \".json\"")); return null; } string text = File.ReadAllText(filePath); try { return JsonConvert.DeserializeObject<Script>(text); } catch (Exception ex) { Logger.LogError((object)("Failed to deserialize script \"" + name + "\":\n" + ex.Message)); return null; } } public void UpdateAllScriptTimers(float deltaTime) { foreach (Script loadedScript in loadedScripts) { loadedScript.UpdateTimers(deltaTime); } } public void ClearAllScriptTimers() { foreach (Script loadedScript in loadedScripts) { loadedScript.ClearTimers(); } } public void ClearAllScriptCounters() { foreach (Script loadedScript in loadedScripts) { loadedScript.ClearCounters(); } } public void ApplySelectedLabels() { if ((Object)(object)StartOfRound.Instance != (Object)null && !StartOfRound.Instance.inShipPhase) { pendingManualLabelSelection = true; Logger.LogInfo((object)"Cannot apply manual label selection when not in ship phase, Changes pending"); return; } pendingManualLabelSelection = false; string text = PizzaTowerEscapeMusicManager.Configuration?.selectLabelManually?.Value; if (string.IsNullOrWhiteSpace(text)) { SelectLabelManuallyValid = true; return; } string[] array = text.Split(commaSeparator, StringSplitOptions.RemoveEmptyEntries); Dictionary<string, string> dictionary = new Dictionary<string, string>(); bool selectLabelManuallyValid = true; string[] array2 = array; foreach (string text2 in array2) { string[] array3 = text2.Split(colonSeparator, 2); if (array3.Length != 2) { Logger.LogWarning((object)("Invalid selectLabelManually entry: '" + text2 + "', expected Group:Label")); selectLabelManuallyValid = false; continue; } string text3 = array3[0].Trim(); string text4 = array3[1].Trim(); if (string.IsNullOrEmpty(text3) || string.IsNullOrEmpty(text4)) { Logger.LogWarning((object)("Empty group or label in entry: '" + text2 + "'")); selectLabelManuallyValid = false; continue; } if (dictionary.TryGetValue(text3, out var value)) { Logger.LogWarning((object)("Duplicate group '" + text3 + "' in selectLabelManually configuration, will use label '" + text4 + "' (previous label '" + value + "')")); } dictionary[text3] = text4; } SelectLabelManuallyValid = selectLabelManuallyValid; foreach (KeyValuePair<string, string> item in dictionary) { string key = item.Key; string value2 = item.Value; foreach (Script loadedScript in loadedScripts) { loadedScript.selectedLabelsByGroup[key] = value2; } Logger.LogDebug((object)("Applied manual label selection: group='" + key + "', label='" + value2 + "'")); } } } } namespace PizzaTowerEscapeMusic.Scripting.ScriptEvents { [JsonConverter(typeof(ScriptEventConverter))] public abstract class ScriptEvent { public enum GameEventType { FrameUpdated, ShipLanded, ShipTakeOff, ShipLeavingAlertCalled, PlayerDamaged, PlayerDied, PlayerEnteredFacility, PlayerExitedFacility, PlayerEnteredShip, PlayerExitedShip, ApparatusTaken, CurrentMoonChanged, MeltdownStarted, ShipInOrbit, ShipNotInOrbit, LevelLoaded, EndOfGame, FiringPlayers, GameOver } public string comment = string.Empty; [JsonRequired] public string scriptEventType = string.Empty; [JsonRequired] public GameEventType gameEventType; public Condition[] conditions = Array.Empty<Condition>(); public bool CheckConditions(Script script) { return !conditions.Any((Condition c) => !c.Check(script)); } public abstract void Run(Script script); } public class ScriptEventConverter : JsonConverter<ScriptEvent> { public override bool CanWrite => false; public override ScriptEvent ReadJson(JsonReader reader, Type objectType, ScriptEvent existingValue, bool hasExistingValue, JsonSerializer serializer) { JObject val = JObject.Load(reader); JToken val2 = default(JToken); if (!val.TryGetValue("scriptEventType", ref val2)) { throw new Exception("scriptEventType type is null!"); } ScriptEvent scriptEvent = Extensions.Value<string>((IEnumerable<JToken>)val2) switch { "SetVolumeGroupMasterVolume" => new ScriptEvent_SetVolumeGroupMasterVolume(), "LabelRandom" => new ScriptEvent_LabelRandom(), "ResetCounters" => new ScriptEvent_ResetCounters(), "ResetTimers" => new ScriptEvent_ResetTimers(), "StopMusic" => new ScriptEvent_StopMusic(), "PlayMusic" => new ScriptEvent_PlayMusic(), _ => throw new Exception($"Condition type \"{val2}\" does not exist"), }; serializer.Populate(((JToken)val).CreateReader(), (object)scriptEvent); return scriptEvent; } public override void WriteJson(JsonWriter writer, ScriptEvent value, JsonSerializer serializer) { throw new NotImplementedException(); } } public class ScriptEvent_LabelRandom : ScriptEvent { private struct QueuedLabelRandom { public Script script; public string group; public string[] labels; public List<(string label, float weight)> entries; public float totalWeight; } private static readonly Queue<QueuedLabelRandom> pendingEvents = new Queue<QueuedLabelRandom>(); private static bool queueProcessing = false; private static bool subscribedToSeedReceived = false; private static readonly char[] commaSeparator = new char[1] { ',' }; private static readonly char[] colonSeparator = new char[1] { ':' }; [JsonRequired] public string group = string.Empty; [JsonRequired] public string[] labels = Array.Empty<string>(); public override void Run(Script script) { if (string.IsNullOrEmpty(group)) { PizzaTowerEscapeMusicManager.ScriptManager.Logger.LogError((object)"LabelRandom: group must be specified and non-empty"); } else { if (labels.Length == 0) { return; } List<(string, float)> list = new List<(string, float)>(); float num = 0f; string[] array = labels; foreach (string text in array) { string[] array2 = text.Split(new char[1] { ':' }); if (array2.Length != 2) { PizzaTowerEscapeMusicManager.ScriptManager.Logger.LogError((object)("LabelRandom: malformed entry '" + text + "', expected 'label:weight'")); continue; } string text2 = array2[0].Trim(); if (string.IsNullOrEmpty(text2)) { PizzaTowerEscapeMusicManager.ScriptManager.Logger.LogError((object)("LabelRandom: label is empty '" + text + "'")); continue; } if (!float.TryParse(array2[1], out var result)) { PizzaTowerEscapeMusicManager.ScriptManager.Logger.LogError((object)("LabelRandom: weight is not a number '" + text + "'")); continue; } if (result <= 0f) { PizzaTowerEscapeMusicManager.ScriptManager.Logger.LogError((object)("LabelRandom: weight must be positive '" + text + "'")); continue; } list.Add((text2, result)); num += result; } if (list.Count == 0) { return; } if (PizzaTowerEscapeMusicManager.Configuration != null && PizzaTowerEscapeMusicManager.Configuration.useRandomMapSeed != null && PizzaTowerEscapeMusicManager.Configuration.useRandomMapSeed.Value) { if ((Object)(object)StartOfRound.Instance == (Object)null) { PizzaTowerEscapeMusicManager.ScriptManager.Logger.LogDebug((object)"LabelRandom: StartOfRound instance is null, skipping"); } else if ((((NetworkBehaviour)StartOfRound.Instance).IsHost && ((NetworkBehaviour)StartOfRound.Instance).IsServer) || (SeedSyncService.SeedReceived && GameEventListener.SyncedrandomMapSeed) || (PizzaTowerEscapeMusicManager.Configuration.dontQueue != null && PizzaTowerEscapeMusicManager.Configuration.dontQueue.Value)) { ExecuteWithDelay(script, group, labels, list, num); } else { EnqueueEvent(script, group, labels, list, num); } } else { float randomValue = Random.Range(0f, num); SelectLabel(script, group, list, num, randomValue); } } } private static void EnqueueEvent(Script script, string group, string[] labels, List<(string label, float weight)> entries, float totalWeight) { QueuedLabelRandom item = new QueuedLabelRandom { script = script, group = group, labels = labels, entries = entries, totalWeight = totalWeight }; pendingEvents.Enqueue(item); PizzaTowerEscapeMusicManager.ScriptManager.Logger.LogDebug((object)$"LabelRandom: event queued (waiting for seed). Queue size: {pendingEvents.Count}"); if (!subscribedToSeedReceived) { SeedSyncService.OnSeedReceived += OnSeedReceived; subscribedToSeedReceived = true; } } private static void OnSeedReceived() { PizzaTowerEscapeMusicManager.ScriptManager.Logger.LogDebug((object)"LabelRandom: OnSeedReceived"); if (GameEventListener.SyncedrandomMapSeed) { ProcessQueue(); return; } GameEventListener gameEventListener = GameEventListener.Instance ?? Object.FindObjectOfType<GameEventListener>(); if ((Object)(object)gameEventListener == (Object)null) { PizzaTowerEscapeMusicManager.ScriptManager.Logger.LogError((object)"LabelRandom: cannot find GameEventListener instance, cannot wait for sync"); } else { ((MonoBehaviour)gameEventListener).StartCoroutine(WaitForSyncedThenProcess()); } } private static IEnumerator WaitForSyncedThenProcess() { while (!GameEventListener.SyncedrandomMapSeed) { yield return (object)new WaitForSeconds(0.2f); } PizzaTowerEscapeMusicManager.ScriptManager.Logger.LogDebug((object)"LabelRandom: SyncedrandomMapSeed"); ProcessQueue(); } private static void ProcessQueue() { if (!queueProcessing) { GameEventListener gameEventListener = GameEventListener.Instance ?? Object.FindObjectOfType<GameEventListener>(); if ((Object)(object)gameEventListener == (Object)null) { PizzaTowerEscapeMusicManager.ScriptManager.Logger.LogError((object)"LabelRandom: cannot find GameEventListener instance, cannot start delay coroutine"); } else { ((MonoBehaviour)gameEventListener).StartCoroutine(ProcessQueueWithDelay()); } } } private static IEnumerator ProcessQueueWithDelay() { queueProcessing = true; yield return (object)new WaitForSeconds(0.2f); while (pendingEvents.Count > 0) { QueuedLabelRandom queuedLabelRandom = pendingEvents.Dequeue(); ExecuteWithDelay(queuedLabelRandom.script, queuedLabelRandom.group, queuedLabelRandom.labels, queuedLabelRandom.entries, queuedLabelRandom.totalWeight); } queueProcessing = false; PizzaTowerEscapeMusicManager.ScriptManager.Logger.LogDebug((object)"LabelRandom: queue processed"); } private static void ExecuteWithDelay(Script script, string group, string[] labels, List<(string label, float weight)> entries, float totalWeight) { GameEventListener gameEventListener = GameEventListener.Instance ?? Object.FindObjectOfType<GameEventListener>(); if ((Object)(object)gameEventListener == (Object)null) { PizzaTowerEscapeMusicManager.ScriptManager.Logger.LogError((object)"LabelRandom: cannot find GameEventListener to start coroutine, falling back to immediate selection"); SelectLabelWithSeed(script, group, labels, entries, totalWeight); } else { ((MonoBehaviour)gameEventListener).StartCoroutine(DelayedSelection(script, group, labels, entries, totalWeight)); } } private static IEnumerator DelayedSelection(Script script, string group, string[] labels, List<(string label, float weight)> entries, float totalWeight) { yield return (object)new WaitForSeconds(0.2f); SelectLabelWithSeed(script, group, labels, entries, totalWeight); } private static void SelectLabelWithSeed(Script script, string group, string[] labels, List<(string label, float weight)> entries, float totalWeight) { int randomMapSeed = StartOfRound.Instance.randomMapSeed; int num = group.GetHashCode(); foreach (string text in labels) { num ^= text.GetHashCode(); } float randomValue = (float)(new Random(randomMapSeed ^ num).NextDouble() * (double)totalWeight); SelectLabel(script, group, entries, totalWeight, randomValue); } private static void SelectLabel(Script script, string group, List<(string label, float weight)> entries, float totalWeight, float randomValue) { string text = PizzaTowerEscapeMusicManager.Configuration?.selectLabelManually?.Value; if (!string.IsNullOrWhiteSpace(text)) { ScriptManager scriptManager = PizzaTowerEscapeMusicManager.ScriptManager; if (scriptManager != null && scriptManager.SelectLabelManuallyValid) { string[] array = text.Split(commaSeparator, StringSplitOptions.RemoveEmptyEntries); for (int i = 0; i < array.Length; i++) { string[] array2 = array[i].Split(colonSeparator, 2); if (array2.Length == 2) { string text2 = array2[0].Trim(); string text3 = array2[1].Trim(); if (text2.Equals(group)) { string text4 = (string.IsNullOrEmpty(group) ? "" : group); script.selectedLabelsByGroup[text4] = text3; PizzaTowerEscapeMusicManager.ScriptManager.Logger.LogDebug((object)("LabelRandom: using manually selected label '" + text3 + "' for group '" + text4 + "'")); return; } } } } } float num = 0f; string text5 = null; foreach (var entry in entries) { string item = entry.label; float item2 = entry.weight; num += item2; if (randomValue <= num) { text5 = item; break; } } if (text5 != null) { string text6 = (string.IsNullOrEmpty(group) ? "" : group); script.selectedLabelsByGroup[text6] = text5; PizzaTowerEscapeMusicManager.ScriptManager.Logger.LogDebug((object)("LabelRandom: selected label '" + text5 + "' for group '" + text6 + "'")); } } public static void ClearQueueAndFlags() { pendingEvents.Clear(); queueProcessing = false; subscribedToSeedReceived = false; SeedSyncService.OnSeedReceived -= OnSeedReceived; PizzaTowerEscapeMusicManager.ScriptManager.Logger.LogDebug((object)"LabelRandom: queue and flags cleared"); } } public class ScriptEvent_PlayMusic : ScriptEvent { public enum OverlapHandling { IgnoreAll, IgnoreTag, OverrideAll, OverrideTag, OverrideFadeAll, OverrideFadeTag, Overlap } public bool loop; public bool bypassEffects; public bool silenceGameMusic = true; [JsonRequired] public OverlapHandling overlapHandling; public string tag; [JsonRequired] public string[] musicNames = Array.Empty<string>(); public string[] introMusicNames = Array.Empty<string>(); public override void Run(Script script) { if (musicNames.Length != 0) { PizzaTowerEscapeMusicManager.MusicManager.PlayMusic(script, this); } } } public class ScriptEvent_ResetCounters : ScriptEvent { public string[] targetCounterNames; public override void Run(Script script) { if (targetCounterNames != null) { string[] array = targetCounterNames; foreach (string counterName in array) { script.ClearCounter(counterName); } } } } public class ScriptEvent_ResetTimers : ScriptEvent { public string[] targetTimerNames; public override void Run(Script script) { if (targetTimerNames != null) { string[] array = targetTimerNames; foreach (string timerName in array) { script.ClearTimer(timerName); } } } } public class ScriptEvent_SetVolumeGroupMasterVolume : ScriptEvent { public string[] targetTags = Array.Empty<string>(); [JsonRequired] public float masterVolume; public override void Run(Script script) { if (targetTags.Length == 0) { Script.DefaultVolumeGroup.masterVolume = masterVolume; return; } string[] array = targetTags; foreach (string text in array) { if (!script.loadedScriptVolumeGroups.TryGetValue(text, out var value)) { PizzaTowerEscapeMusicManager.ScriptManager.Logger.LogError((object)("Script Event SetVolumeGroupMasterVolume was called for volume group with tag \"" + text + "\", but there is no volume group of that tag")); } else { value.masterVolume = masterVolume; } } } } public class ScriptEvent_StopMusic : ScriptEvent { public string[] targetTags; public bool instant; public override void Run(Script script) { if (targetTags != null) { string[] array = targetTags; foreach (string targetTag in array) { if (instant) { PizzaTowerEscapeMusicManager.MusicManager.StopMusic(targetTag); } else { PizzaTowerEscapeMusicManager.MusicManager.FadeStopMusic(targetTag); } } } else if (instant) { PizzaTowerEscapeMusicManager.MusicManager.StopMusic(); } else { PizzaTowerEscapeMusicManager.MusicManager.FadeStopMusic(); } } } } namespace PizzaTowerEscapeMusic.Scripting.Conditions { [JsonConverter(typeof(ConditionConverter))] public abstract class Condition { [JsonRequired] public string conditionType = string.Empty; public abstract bool Check(Script script); } public abstract class ConditionComparableNumber : Condition { public enum ComparisonType { Equals, NotEquals, GreaterThan, LessThan, GreaterThanOrEquals, LessThanOrEquals } [JsonRequired] public ComparisonType comparisonType; } public class ConditionConverter : JsonConverter<Condition> { public override bool CanWrite => false; public override Condition ReadJson(JsonReader reader, Type objectType, Condition existingValue, bool hasExistingValue, JsonSerializer serializer) { JObject val = JObject.Load(reader); JToken val2 = default(JToken); if (!val.TryGetValue("conditionType", ref val2)) { throw new Exception("Condition type is null!"); } Condition condition = Extensions.Value<string>((IEnumerable<JToken>)val2) switch { "And" => new Condition_And(), "Or" => new Condition_Or(), "Not" => new Condition_Not(), "Weather" => new Condition_Weather(), "PlayerLocation" => new Condition_PlayerLocation(), "PlayerAlive" => new Condition_PlayerAlive(), "AllPlayersDead" => new Condition_AllPlayersDead(), "PlayerHealth" => new Condition_PlayerHealth(), "PlayerCrouching" => new Condition_PlayerCrouching(), "PlayerSprinting" => new Condition_PlayerSprinting(), "PlayerStamina" => new Condition_PlayerStamina(), "PlayerInsanity" => new Condition_PlayerInsanity(), "PlayerHasItem" => new Condition_PlayerHasItem(), "PlayerHoldingItem" => new Condition_PlayerHoldingItem(), "PlayerFearLevel" => new Condition_PlayerFearLevel(), "PlayerAlone" => new Condition_PlayerAlone(), "FiringPlayers" => new Condition_FiringPlayers(), "ShipLanded" => new Condition_ShipLanded(), "ShipInOrbit" => new Condition_ShipInOrbit(), "ShipLeavingAlertCalled" => new Condition_ShipLeavingAlertCalled(), "ShipIsLeaving" => new Condition_ShipIsLeaving(), "MusicWithTagPlaying" => new Condition_MusicWithTagPlaying(), "CurrentMoon" => new Condition_CurrentMoon(), "Timer" => new Condition_Timer(), "Counter" => new Condition_Counter(), "Random" => new Condition_Random(), "ApparatusDocked" => new Condition_ApparatusDocked(), "ApparatusTaked" => new Condition_ApparatusTaked(), "TimeOfDay" => new Condition_TimeOfDay(), "FacilityInterior" => new Condition_FacilityInterior(), "PlayerCount" => new Condition_PlayerCount(), "PlayersAlivePercent" => new Condition_PlayersAlivePercent(), "SelectedLabel" => new Condition_SelectedLabel(), _ => throw new Exception($"Condition type \"{val2}\" does not exist"), }; serializer.Populate(((JToken)val).CreateReader(), (object)condition); return condition; } public override void WriteJson(JsonWriter writer, Condition value, JsonSerializer serializer) { throw new NotImplementedException(); } } public class Condition_AllPlayersDead : Condition { public override bool Check(Script script) { if ((Object)(object)StartOfRound.Instance != (Object)null) { return StartOfRound.Instance.allPlayersDead; } return false; } } public class Condition_And : Condition { [JsonRequired] public Condition[] conditions = Array.Empty<Condition>(); public override bool Check(Script script) { return !conditions.Any((Condition c) => !c.Check(script)); } } public class Condition_ApparatusDocked : Condition { public override bool Check(Script script) { return GameEventListener.IsApparatusDocked(); } } public class Condition_ApparatusTaked : Condition { public override bool Check(Script script) { return GameEventListener.ApparatusTaked; } } public class Condition_Counter : Condition { [JsonRequired] public string counterName = string.Empty; [JsonRequired] public int counterGoal; public ConditionComparableNumber.ComparisonType? counterComparisonType; public override bool Check(Script script) { if (!script.activeCounters.TryGetValue(counterName, out var value)) { value = new Script.Counter(counterName); script.activeCounters.Add(counterName, value); } value.count++; return (counterComparisonType ?? ConditionComparableNumber.ComparisonType.GreaterThanOrEquals) switch { ConditionComparableNumber.ComparisonType.Equals => value.count == counterGoal, ConditionComparableNumber.ComparisonType.NotEquals => value.count != counterGoal, ConditionComparableNumber.ComparisonType.GreaterThan => value.count > counterGoal, ConditionComparableNumber.ComparisonType.LessThan => value.count < counterGoal, ConditionComparableNumber.ComparisonType.GreaterThanOrEquals => value.count >= counterGoal, ConditionComparableNumber.ComparisonType.LessThanOrEquals => value.count <= counterGoal, _ => false, }; } } public class Condition_CurrentMoon : Condition { private static readonly Dictionary<string, int> moonNameToId = new Dictionary<string, int>(); [JsonRequired] public string moonName = string.Empty; private bool isDisabled; public override bool Check(Script script) { if ((Object)(object)TimeOfDay.Instance == (Object)null) { return false; } if ((Object)(object)StartOfRound.Instance == (Object)null) { return false; } if (isDisabled) { return false; } if (!moonNameToId.TryGetValue(moonName, out var value)) { SelectableLevel[] levels = StartOfRound.Instance.levels; foreach (SelectableLevel val in levels) { if (!moonNameToId.ContainsKey(val.PlanetName)) { moonNameToId.Add(val.PlanetName, val.levelID); } } if (!moonNameToId.TryGetValue(moonName, out value)) { PizzaTowerEscapeMusicManager.ScriptManager.Logger.LogError((object)("From CurrentMoon condition: Found no existing level with the name \"" + moonName + "\"")); isDisabled = true; return false; } } return TimeOfDay.Instance.currentLevel.levelID == value; } } public class Condition_FacilityInterior : Condition { [JsonRequired] public string interiorName = string.Empty; private readonly List<int> interiorIds = new List<int>(); private bool isDisabled; private static readonly Dictionary<string, List<string>> ShorthandNames = new Dictionary<string, List<string>> { { "Factory any", new List<string> { "Level1Flow", "Level1FlowExtraLarge", "Level1Flow3Exits" } }, { "Factory normal", new List<string> { "Level1Flow" } }, { "Factory large", new List<string> { "Level1FlowExtraLarge" } }, { "Factory 3 exits", new List<string> { "Level1Flow3Exits" } }, { "Mansion", new List<string> { "Level2Flow" } }, { "Mineshaft", new List<string> { "Level3Flow" } } }; public override bool Check(Script script) { if (isDisabled) { return false; } RoundManager roundManager = RoundManager.Instance; if ((Object)(object)roundManager == (Object)null) { return false; } if (!TryInitialize(roundManager)) { return false; } return interiorIds.Any((int x) => x == roundManager.currentDungeonType); } private bool TryInitialize(RoundManager rm) { if (interiorIds.Count > 0) { return true; } if (ShorthandNames.TryGetValue(interiorName, out var value)) { for (int i = 0; i < rm.dungeonFlowTypes.Length; i++) { if (value.Contains(((Object)rm.dungeonFlowTypes[i].dungeonFlow).name)) { interiorIds.Add(i); } } } else { for (int j = 0; j < rm.dungeonFlowTypes.Length; j++) { if (((Object)rm.dungeonFlowTypes[j].dungeonFlow).name == interiorName) { interiorIds.Add(j); break; } } } if (interiorIds.Count > 0) { return true; } StringBuilder stringBuilder = new StringBuilder("From FacilityInterior condition: Found no existing interior with the name \""); stringBuilder.Append(interiorName).AppendLine("\". Valid names:"); foreach (string key in ShorthandNames.Keys) { stringBuilder.Append(" - \"").Append(key).AppendLine("\""); } IndoorMapType[] dungeonFlowTypes = rm.dungeonFlowTypes; foreach (IndoorMapType val in dungeonFlowTypes) { stringBuilder.Append(" - \"").Append(((Object)val.dungeonFlow).name).AppendLine("\""); } PizzaTowerEscapeMusicManager.ScriptManager.Logger.LogError((object)stringBuilder.ToString()); isDisabled = true; return false; } } public class Condition_FiringPlayers : Condition { public override bool Check(Script script) { if (!((Object)(object)StartOfRound.Instance == (Object)null)) { return StartOfRound.Instance.firingPlayersCutsceneRunning; } return false; } } public class Condition_MusicWithTagPlaying : Condition { [JsonRequired] public string tag = string.Empty; public override bool Check(Script script) { return PizzaTowerEscapeMusicManager.MusicManager.GetIsMusicPlaying(tag); } } public class Condition_Not : Condition { [JsonRequired] public Condition condition; public override bool Check(Script script) { if (condition != null) { return !condition.Check(script); } return true; } } public class Condition_Or : Condition { [JsonRequired] public Condition[] conditions = Array.Empty<Condition>(); public override bool Check(Script script) { return conditions.Any((Condition c) => c.Check(script)); } } public class Condition_PlayerAlive : Condition { public override bool Check(Script script) { if (!((Object)(object)GameNetworkManager.Instance == (Object)null) && !((Object)(object)GameNetworkManager.Instance.localPlayerController == (Object)null)) { return !GameNetworkManager.Instance.localPlayerController.isPlayerDead; } return false; } } public class Condition_PlayerAlone : Condition { public override bool Check(Script script) { if (!((Object)(object)GameNetworkManager.Instance == (Object)null) && !((Object)(object)GameNetworkManager.Instance.localPlayerController == (Object)null)) { return GameNetworkManager.Instance.localPlayerController.isPlayerAlone; } return false; } } public class Condition_PlayerCount : ConditionComparableNumber { public enum PlayerQueryType { Total, Alive, Dead } [JsonRequired] public PlayerQueryType queryType; [JsonRequired] public int count; public override bool Check(Script script) { StartOfRound instance = StartOfRound.Instance; if ((Object)(object)instance == (Object)null) { return false; } int num; switch (queryType) { case PlayerQueryType.Total: num = instance.connectedPlayersAmount + 1; break; case PlayerQueryType.Alive: num = instance.livingPlayers; break; case PlayerQueryType.Dead: num = instance.connectedPlayersAmount + 1 - instance.livingPlayers; break; default: return false; } return comparisonType switch { ComparisonType.Equals => num == count, ComparisonType.NotEquals => num != count, ComparisonType.GreaterThan => num > count, ComparisonType.LessThan => num < count, ComparisonType.GreaterThanOrEquals => num >= count, ComparisonType.LessThanOrEquals => num <= count, _ => false, }; } } public class Condition_PlayerCrouching : Condition { public override bool Check(Script script) { if (!((Object)(object)GameNetworkManager.Instance == (Object)null) && !((Object)(object)GameNetworkManager.Instance.localPlayerController == (Object)null)) { return GameNetworkManager.Instance.localPlayerController.isCrouching; } return false; } } public class Condition_PlayerFearLevel : ConditionComparableNumber { [JsonRequired] public float level; public override bool Check(Script script) { if ((Object)(object)StartOfRound.Instance == (Object)null) { return false; } float fearLevel = StartOfRound.Instance.fearLevel; return comparisonType switch { ComparisonType.Equals => fearLevel == level, ComparisonType.NotEquals => fearLevel != level, ComparisonType.GreaterThan => fearLevel > level, ComparisonType.LessThan => fearLevel < level, ComparisonType.GreaterThanOrEquals => fearLevel >= level, ComparisonType.LessThanOrEquals => fearLevel <= level, _ => false, }; } } public class Condition_PlayerHasItem : Condition { [JsonRequired] public string itemName = string.Empty; public int[] checkNormalSlots = new int[4] { 0, 1, 2, 3 }; public int[] checkBagsInNormalSlots = new int[4] { 0, 1, 2, 3 }; public bool checkBeltSlot = true; public bool checkBagInBeltSlot = true; public bool checkBagsInBagSlots = true; public override bool Check(Script script) { GameNetworkManager instance = GameNetworkManager.Instance; if ((Object)(object)instance == (Object)null) { return false; } if (CheckItem(instance.localPlayerController.ItemOnlySlot, itemName, checkBeltSlot, checkBagInBeltSlot)) { return true; } GrabbableObject[] itemSlots = instance.localPlayerController.ItemSlots; for (int i = 0; i < itemSlots.Length; i++) { if (CheckItem(itemSlots[i], itemName, checkNormalSlots.Contains(i), checkBagsInNormalSlots.Contains(i))) { return true; } } return false; } public static bool CheckItem(GrabbableObject item, string itemName, bool checkItem, bool checkBag) { if ((Object)(object)item == (Object)null) { return false; } if (checkItem && DoesNameMatch(item, itemName)) { return true; } if (checkBag) { BeltBagItem val = (BeltBagItem)(object)((item is BeltBagItem) ? item : null); if ((Object)(object)val != (Object)null && CheckBag(val, itemName, checkBagsInBagSlots: true)) { return true; } } return false; } private static bool DoesNameMatch(GrabbableObject item, string itemName) { return item.itemProperties.itemName == itemName; } private static bool CheckBag(BeltBagItem bag, string itemName, bool checkBagsInBagSlots) { foreach (GrabbableObject item in bag.objectsInBag) { if (CheckItem(item, itemName, checkItem: true, checkBagsInBagSlots)) { return true; } } return false; } } public class Condition_PlayerHealth : ConditionComparableNumber { [JsonRequired] public int value; public override bool Check(Script script) { if ((Object)(object)GameNetworkManager.Instance == (Object)null) { return false; } if ((Object)(object)GameNetworkManager.Instance.localPlayerController == (Object)null) { return false; } int health = GameNetworkManager.Instance.localPlayerController.health; return comparisonType switch { ComparisonType.Equals => health == value, ComparisonType.NotEquals => health != value, ComparisonType.GreaterThan => health > value, ComparisonType.LessThan => health < value, ComparisonType.GreaterThanOrEquals => health >= value, ComparisonType.LessThanOrEquals => health <= value, _ => false, }; } } public class Condition_PlayerHoldingItem : Condition { [JsonRequired] public string itemName = string.Empty; public bool checkBags; public override bool Check(Script script) { GameNetworkManager instance = GameNetworkManager.Instance; if ((Object)(object)instance == (Object)null) { return false; } return Condition_PlayerHasItem.CheckItem(instance.localPlayerController.currentlyHeldObjectServer, itemName, checkItem: true, checkBags); } } public class Condition_PlayerInsanity : ConditionComparableNumber { [JsonRequired] public float level; public override bool Check(Script script) { if ((Object)(object)GameNetworkManager.Instance == (Object)null) { return false; } if ((Object)(object)GameNetworkManager.Instance.localPlayerController == (Object)null) { return false; } float num = GameNetworkManager.Instance.localPlayerController.insanityLevel / GameNetworkManager.Instance.localPlayerController.maxInsanityLevel; return comparisonType switch { ComparisonType.Equals => num == level, ComparisonType.NotEquals => num != level, ComparisonType.GreaterThan => num > level, ComparisonType.LessThan => num < level, ComparisonType.GreaterThanOrEquals => num >= level, ComparisonType.LessThanOrEquals => num <= level, _ => false, }; } } public class Condition_PlayerLocation : Condition { public enum Location { Ship, Facility } [JsonRequired] public Location location; public override bool Check(Script script) { if ((Object)(object)GameNetworkManager.Instance == (Object)null) { return false; } if ((Object)(object)GameNetworkManager.Instance.localPlayerController == (Object)null) { return false; } Location location = this.location; if (location != Location.Ship) { return location == Location.Facility && GameNetworkManager.Instance.localPlayerController.isInsideFactory; } return GameNetworkManager.Instance.localPlayerController.isInHangarShipRoom; } } public class Condition_PlayersAlivePercent : ConditionComparableNumber { [JsonRequired] public float percent; public override bool Check(Script script) { if ((Object)(object)StartOfRound.Instance == (Object)null) { return false; } float num = (float)StartOfRound.Instance.livingPlayers / (float)(StartOfRound.Instance.connectedPlayersAmount + 1); return comparisonType switch { ComparisonType.Equals => num == percent, ComparisonType.NotEquals => num != percent, ComparisonType.GreaterThan => num > percent, ComparisonType.LessThan => num < percent, ComparisonType.GreaterThanOrEquals => num >= percent, ComparisonType.LessThanOrEquals => num <= percent, _ => false, }; } } public class Condition_PlayerSprinting : Condition { public override bool Check(Script script) { if ((Object)(object)GameNetworkManager.Instance == (Object)null) { return false; } if ((Object)(object)GameNetworkManager.Instance.localPlayerController == (Object)null) { return false; } return GameNetworkManager.Instance.localPlayerController.isSprinting; } } public class Condition_PlayerStamina : ConditionComparableNumber { [JsonRequired] public float value; public override bool Check(Script script) { if ((Object)(object)GameNetworkManager.Instance == (Object)null) { return false; } if ((Object)(object)GameNetworkManager.Instance.localPlayerController == (Object)null) { return false; } float sprintMeter = GameNetworkManager.Instance.localPlayerController.sprintMeter; return comparisonType switch { ComparisonType.Equals => sprintMeter == value, ComparisonType.NotEquals => sprintMeter != value, ComparisonType.GreaterThan => sprintMeter > value, ComparisonType.LessThan => sprintMeter < value, ComparisonType.GreaterThanOrEquals => sprintMeter >= value, ComparisonType.LessThanOrEquals => sprintMeter <= value, _ => false, }; } } public class Condition_Random : Condition { [JsonRequired] public float chance; public override bool Check(Script script) { return Random.Range(0f, 1f) <= chance; } } public class Condition_SelectedLabel : Condition { [JsonRequired] public string label = string.Empty; [JsonRequired] public string group = string.Empty; public override bool Check(Script script) { if (string.IsNullOrEmpty(group)) { PizzaTowerEscapeMusicManager.ScriptManager.Logger.LogError((object)"Condition_SelectedLabel: group must be specified and non-empty"); return false; } if (script.selectedLabelsByGroup.TryGetValue(group, out var value)) { return value == label; } return false; } } public class Condition_ShipInOrbit : Condition { public override bool Check(Script script) { if (!((Object)(object)StartOfRound.Instance == (Object)null)) { return StartOfRound.Instance.inShipPhase; } return false; } } public class Condition_ShipIsLeaving : Condition { public override bool Check(Script script) { if (!((Object)(object)StartOfRound.Instance == (Object)null)) { return StartOfRound.Instance.shipIsLeaving; } return false; } } public class Condition_ShipLanded : Condition { public override bool Check(Script script) { if (!((Object)(object)StartOfRound.Instance == (Object)null)) { return StartOfRound.Instance.shipHasLanded; } return false; } } public class Condition_ShipLeavingAlertCalled : Condition { public override bool Check(Script script) { if (!((Object)(object)TimeOfDay.Instance == (Object)null)) { return TimeOfDay.Instance.shipLeavingAlertCalled; } return false; } } public class Condition_TimeOfDay : ConditionComparableNumber { [JsonRequired] public float time; public override bool Check(Script script) { if ((Object)(object)TimeOfDay.Instance == (Object)null) { return false; } float num = TimeOfDay.Instance.currentDayTime / TimeOfDay.Instance.totalTime; return comparisonType switch { ComparisonType.Equals => num == time, ComparisonType.NotEquals => num != time, ComparisonType.GreaterThan => num > time, ComparisonType.LessThan => num < time, ComparisonType.GreaterThanOrEquals => num >= time, ComparisonType.LessThanOrEquals => num <= time, _ => false, }; } } public class Condition_Timer : Condition { [JsonRequired] public string timerName = string.Empty; [JsonRequired] public float timeGoal; public ConditionComparableNumber.ComparisonType? timerComparisonType; public override bool Check(Script script) { if (!script.activeTimers.TryGetValue(timerName, out var value)) { value = new Script.Timer(timerName); script.activeTimers.Add(timerName, value); } return (timerComparisonType ?? ConditionComparableNumber.ComparisonType.GreaterThanOrEquals) switch { ConditionComparableNumber.ComparisonType.Equals => value.time == timeGoal, ConditionComparableNumber.ComparisonType.NotEquals => value.time != timeGoal, ConditionComparableNumber.ComparisonType.GreaterThan => value.time > timeGoal, ConditionComparableNumber.ComparisonType.LessThan => value.time < timeGoal, ConditionComparableNumber.ComparisonType.GreaterThanOrEquals => value.time >= timeGoal, ConditionComparableNumber.ComparisonType.LessThanOrEquals => value.time <= timeGoal, _ => false, }; } } public class Condition_Weather : Condition { [JsonRequired] public object weather; private static readonly Type _weatherConfigHelperType; private static readonly MethodInfo _resolveWeatherMethod; private static readonly PropertyInfo _vanillaWeatherTypeProp; public override bool Check(Script script) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)TimeOfDay.Instance == (Object)null) { return false; } LevelWeatherType currentLevelWeather = TimeOfDay.Instance.currentLevelWeather; if (weather is LevelWeatherType val) { return currentLevelWeather == val; } if (!(weather is string text) || _weatherConfigHelperType == null || _resolveWeatherMethod == null || _vanillaWeatherTypeProp == null) { return false; } try { object obj = _resolveWeatherMethod.Invoke(null, new object[1] { text }); if (obj == null) { return false; } LevelWeatherType val2 = (LevelWeatherType)_vanillaWeatherTypeProp.GetValue(obj); return currentLevelWeather == val2; } catch (Exception) { return false; } } static Condition_Weather() { try { _weatherConfigHelperType = Type.GetType("WeatherRegistry.ConfigHelper, WeatherRegistry"); if (_weatherConfigHelperType != null) { _resolveWeatherMethod = _weatherCo