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 VoidCoinFlip v1.0.1
VoidCoinFlip.dll
Decompiled a week agousing System; using System.Collections; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using EntityStates; using HarmonyLib; using Microsoft.CodeAnalysis; using RoR2; using RoR2.ExpansionManagement; using RoR2.UI; using UnityEngine; using UnityEngine.AddressableAssets; using UnityEngine.Events; using UnityEngine.Networking; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.0.0.0")] [module: UnverifiableCode] [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 VoidCoinFlip { internal static class FuelArrayDeath { private const string FuelArrayName = "QuestVolatileBattery"; private const string MonitorStateName = "EntityStates.QuestVolatileBattery.Monitor"; private const string CountDownStateName = "EntityStates.QuestVolatileBattery.CountDown"; public static IEnumerator Run(IEnumerable<CharacterBody> playerBodies) { if (!NetworkServer.active) { yield break; } List<CharacterBody> bodies = playerBodies.Where((CharacterBody b) => Object.op_Implicit((Object)(object)b) && Object.op_Implicit((Object)(object)b.inventory)).ToList(); EquipmentIndex val = EquipmentCatalog.FindEquipmentIndex("QuestVolatileBattery"); Type countDownType = AccessTools.TypeByName("EntityStates.QuestVolatileBattery.CountDown"); if ((int)val == -1 || countDownType == null) { VoidCoinFlipPlugin.Log.LogWarning((object)"Couldn't find the Fuel Array; falling back to a plain death."); KillAll(bodies); yield break; } Dictionary<Inventory, EquipmentIndex> previous = new Dictionary<Inventory, EquipmentIndex>(); foreach (CharacterBody item in bodies) { previous[item.inventory] = item.inventory.currentEquipmentIndex; item.inventory.SetEquipmentIndex(val); } yield return (object)new WaitForSeconds(0.5f); int num = 0; foreach (CharacterBody item2 in bodies) { if (Object.op_Implicit((Object)(object)item2)) { if (StartCountdown(item2, countDownType)) { num++; } else { ForceBelowThreshold(item2); } } } VoidCoinFlipPlugin.Log.LogInfo((object)$"Fuel Array countdown started on {num}/{bodies.Count} player(s)."); float num2 = ((AccessTools.Field(countDownType, "duration")?.GetValue(null) is float d && d > 0f) ? d : 3f); yield return (object)new WaitForSeconds(num2 + 1f); KillAll(bodies); foreach (KeyValuePair<Inventory, EquipmentIndex> item3 in previous) { if (Object.op_Implicit((Object)(object)item3.Key)) { item3.Key.SetEquipmentIndex(item3.Value); } } } private static bool StartCountdown(CharacterBody body, Type countDownType) { //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Expected O, but got Unknown try { NetworkedBodyAttachment[] array = Object.FindObjectsOfType<NetworkedBodyAttachment>(); foreach (NetworkedBodyAttachment val in array) { if (!Object.op_Implicit((Object)(object)val) || (Object)(object)val.attachedBody != (Object)(object)body) { continue; } EntityStateMachine[] components = ((Component)val).GetComponents<EntityStateMachine>(); foreach (EntityStateMachine val2 in components) { string text = ((object)val2.state)?.GetType().FullName; if (!(text != "EntityStates.QuestVolatileBattery.Monitor") || !(text != "EntityStates.QuestVolatileBattery.CountDown")) { if (text == "EntityStates.QuestVolatileBattery.Monitor") { val2.SetNextState((EntityState)Activator.CreateInstance(countDownType)); } return true; } } } } catch (Exception ex) { VoidCoinFlipPlugin.Log.LogWarning((object)("Couldn't start the Fuel Array countdown directly. " + ex.Message)); } return false; } private static void ForceBelowThreshold(CharacterBody body) { HealthComponent healthComponent = body.healthComponent; if (Object.op_Implicit((Object)(object)healthComponent) && healthComponent.alive) { healthComponent.Networkshield = 0f; healthComponent.Networkbarrier = 0f; healthComponent.Networkhealth = Mathf.Max(1f, healthComponent.fullHealth * 0.3f); } } private static void KillAll(IEnumerable<CharacterBody> bodies) { //IL_003f: Unknown result type (might be due to invalid IL or missing references) foreach (CharacterBody body in bodies) { if (Object.op_Implicit((Object)(object)body) && Object.op_Implicit((Object)(object)body.healthComponent) && body.healthComponent.alive) { body.healthComponent.Suicide((GameObject)null, (GameObject)null, DamageTypeCombo.op_Implicit((DamageType)65536)); } } } } internal static class MusicSilencer { [CompilerGenerated] private static class <>O { public static PickTrackDelegate <0>__OnPickTrack; } public static bool Enabled = true; public static bool WagerWon; private const string WardStateNamespace = "EntityStates.Missions.Arena.NullWard"; public static void Install() { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Expected O, but got Unknown object obj = <>O.<0>__OnPickTrack; if (obj == null) { PickTrackDelegate val = OnPickTrack; <>O.<0>__OnPickTrack = val; obj = (object)val; } MusicController.pickTrackHook += (PickTrackDelegate)obj; } public static void Uninstall() { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Expected O, but got Unknown object obj = <>O.<0>__OnPickTrack; if (obj == null) { PickTrackDelegate val = OnPickTrack; <>O.<0>__OnPickTrack = val; obj = (object)val; } MusicController.pickTrackHook -= (PickTrackDelegate)obj; } private static void OnPickTrack(MusicController controller, ref MusicTrackDef newTrack) { try { if (Enabled && ShouldBeSilent()) { newTrack = null; } } catch (Exception ex) { Enabled = false; VoidCoinFlipPlugin.Log.LogWarning((object)("Music silencing turned off after an error. " + ex.Message)); } } private static bool ShouldBeSilent() { ArenaMissionController instance = ArenaMissionController.instance; if (!Object.op_Implicit((Object)(object)instance) || instance.nullWards == null) { return false; } if (WagerWon) { return true; } int num = 0; int num2 = 0; int num3 = 0; GameObject[] nullWards = instance.nullWards; foreach (GameObject val in nullWards) { if (Object.op_Implicit((Object)(object)val)) { num3++; string text = WardState(val); if (text == "Active") { num++; } else if (text == "Complete") { num++; num2++; } } } if (!NetworkServer.active && num3 > 0 && num2 == num3) { return true; } return num == 0; } internal static string WardState(GameObject ward) { EntityStateMachine[] components = ward.GetComponents<EntityStateMachine>(); for (int i = 0; i < components.Length; i++) { EntityState state = components[i].state; if (state != null && ((object)state).GetType().Namespace == "EntityStates.Missions.Arena.NullWard") { return ((object)state).GetType().Name; } } return null; } } internal class VoiceLine { public string Name; public float[] Samples; public int SampleRate; public float Length { get { if (SampleRate <= 0) { return 0f; } return (float)Samples.Length / (float)SampleRate; } } } internal static class ShrineVoice { public static readonly List<VoiceLine> Lines = new List<VoiceLine>(); private const uint SND_ASYNC = 1u; private const uint SND_NODEFAULT = 2u; private const uint SND_MEMORY = 4u; private static GCHandle playing; private static bool unavailable; [DllImport("winmm.dll", SetLastError = true)] private static extern bool PlaySound(IntPtr sound, IntPtr module, uint flags); public static void LoadFrom(string folder) { Lines.Clear(); foreach (string item in from p in Directory.GetFiles(folder, "shrine_voice*") orderby p select p) { if (Path.GetExtension(item).ToLowerInvariant() != ".wav") { VoidCoinFlipPlugin.Log.LogWarning((object)("Skipping " + Path.GetFileName(item) + ": only .wav files are supported for the shrine voice.")); continue; } try { VoiceLine voiceLine = LoadWav(item); Lines.Add(voiceLine); VoidCoinFlipPlugin.Log.LogInfo((object)$"Loaded shrine voice {voiceLine.Name} ({voiceLine.Length:0.0}s)."); } catch (Exception ex) { VoidCoinFlipPlugin.Log.LogWarning((object)("Couldn't read " + Path.GetFileName(item) + ": " + ex.Message)); } } if (Lines.Count == 0) { VoidCoinFlipPlugin.Log.LogInfo((object)"No shrine_voice .wav files found; the shrine will stay silent."); } else { VoidCoinFlipPlugin.Log.LogInfo((object)$"Shrine has {Lines.Count} voice line(s)."); } } private static VoiceLine LoadWav(string path) { byte[] array = File.ReadAllBytes(path); if (array.Length < 12 || Encoding.ASCII.GetString(array, 0, 4) != "RIFF" || Encoding.ASCII.GetString(array, 8, 4) != "WAVE") { throw new InvalidDataException("not a WAV file"); } int num = 0; int num2 = 0; int num3 = 0; int num4 = 0; int num5 = -1; int num6 = 0; int num7 = 12; while (num7 + 8 <= array.Length) { string text = Encoding.ASCII.GetString(array, num7, 4); int num8 = BitConverter.ToInt32(array, num7 + 4); int num9 = num7 + 8; if (text == "fmt ") { num = BitConverter.ToUInt16(array, num9); num2 = BitConverter.ToUInt16(array, num9 + 2); num3 = BitConverter.ToInt32(array, num9 + 4); num4 = BitConverter.ToUInt16(array, num9 + 14); if (num == 65534 && num8 >= 26) { num = BitConverter.ToUInt16(array, num9 + 24); } } else if (text == "data") { num5 = num9; num6 = ((num8 < 0 || num9 + num8 > array.Length) ? (array.Length - num9) : num8); break; } if (num8 < 0) { break; } num7 = num9 + num8 + (num8 & 1); } if (num5 < 0 || num2 <= 0 || num3 <= 0 || num4 <= 0) { throw new InvalidDataException("missing format or audio data"); } if (num != 1 && num != 3) { throw new InvalidDataException($"unsupported WAV encoding ({num}); export as Linear PCM"); } int num10 = num4 / 8; int num11 = num6 / (num10 * num2); float[] array2 = new float[num11]; for (int i = 0; i < num11; i++) { float num12 = 0f; for (int j = 0; j < num2; j++) { int i2 = num5 + (i * num2 + j) * num10; num12 += ReadSample(array, i2, num4, num); } array2[i] = num12 / (float)num2; } return new VoiceLine { Name = Path.GetFileNameWithoutExtension(path), Samples = array2, SampleRate = num3 }; } private static float ReadSample(byte[] b, int i, int bits, int format) { if (format == 3 && bits == 32) { return BitConverter.ToSingle(b, i); } if (format == 3 && bits == 64) { return (float)BitConverter.ToDouble(b, i); } return bits switch { 8 => (float)(b[i] - 128) / 128f, 16 => (float)BitConverter.ToInt16(b, i) / 32768f, 24 => (float)(b[i] | (b[i + 1] << 8) | ((sbyte)b[i + 2] << 16)) / 8388608f, 32 => (float)BitConverter.ToInt32(b, i) / 2.1474836E+09f, _ => throw new InvalidDataException($"unsupported bit depth {bits}"), }; } public static void Play(VoiceLine line, float volume, float pan) { if (unavailable) { VoidCoinFlipPlugin.Log.LogWarning((object)"Shrine voice: Windows audio was unavailable earlier, not playing."); } else { if (line == null || line.Samples.Length == 0) { return; } float leftGain = volume * Math.Min(1f, 1f - pan); float rightGain = volume * Math.Min(1f, 1f + pan); byte[] value = BuildStereoWav(line, leftGain, rightGain); try { Stop(); playing = GCHandle.Alloc(value, GCHandleType.Pinned); if (PlaySound(playing.AddrOfPinnedObject(), IntPtr.Zero, 7u)) { VoidCoinFlipPlugin.Log.LogInfo((object)$"Shrine voice: playing {line.Name} (volume {volume:0.00}, pan {pan:0.00})."); } else { VoidCoinFlipPlugin.Log.LogWarning((object)$"Shrine voice: Windows refused to play {line.Name} (error {Marshal.GetLastWin32Error()})."); } } catch (Exception ex) { unavailable = true; VoidCoinFlipPlugin.Log.LogWarning((object)("Windows audio isn't available; the shrine will stay silent. " + ex.Message)); } } } public static void Stop() { if (!unavailable) { try { PlaySound(IntPtr.Zero, IntPtr.Zero, 0u); } catch { } if (playing.IsAllocated) { playing.Free(); } } } private static byte[] BuildStereoWav(VoiceLine line, float leftGain, float rightGain) { int num = line.Samples.Length; int num2 = num * 4; byte[] wav = new byte[44 + num2]; Str(0, "RIFF"); I(4, 36 + num2); Str(8, "WAVE"); Str(12, "fmt "); I(16, 16); I16(20, 1); I16(22, 2); I(24, line.SampleRate); I(28, line.SampleRate * 4); I16(32, 4); I16(34, 16); Str(36, "data"); I(40, num2); int num3 = 44; for (int i = 0; i < num; i++) { float num4 = line.Samples[i]; short num5 = (short)(Math.Max(-1f, Math.Min(1f, num4 * leftGain)) * 32767f); short num6 = (short)(Math.Max(-1f, Math.Min(1f, num4 * rightGain)) * 32767f); wav[num3++] = (byte)num5; wav[num3++] = (byte)(num5 >> 8); wav[num3++] = (byte)num6; wav[num3++] = (byte)(num6 >> 8); } return wav; void I(int at, int v) { BitConverter.GetBytes(v).CopyTo(wav, at); } void I16(int at, short v) { BitConverter.GetBytes(v).CopyTo(wav, at); } void Str(int at, string s) { Encoding.ASCII.GetBytes(s, 0, 4, wav, at); } } } [BepInPlugin("com.deadLeshy.VoidCoinFlip", "VoidCoinFlip", "1.0.1")] public class VoidCoinFlipPlugin : BaseUnityPlugin { private enum Rig { None, Win, Loss } internal enum Call { None, Heads, Tails } public enum LossOutcome { Die, SkipVoidFields } public const string GUID = "com.deadLeshy.VoidCoinFlip"; public const string PluginName = "VoidCoinFlip"; public const string Version = "1.0.1"; internal static ManualLogSource Log; internal static VoidCoinFlipPlugin Instance; private ConfigEntry<string> winRewards; private ConfigEntry<int> optionsPerPick; private ConfigEntry<bool> goldBonus; private ConfigEntry<int> goldChestsWorth; private ConfigEntry<float> callTimeout; private ConfigEntry<KeyCode> headsKey; private ConfigEntry<KeyCode> tailsKey; private ConfigEntry<KeyCode> voiceTestKey; private ConfigEntry<bool> debugKeys; private ConfigEntry<KeyCode> forceWinKey; private ConfigEntry<KeyCode> forceLossKey; private ConfigEntry<KeyCode> jumpToVoidKey; private ConfigEntry<KeyCode> chimeTestKey; private ConfigEntry<bool> winChimeEnabled; private Rig rigNextFlip; private ConfigEntry<LossOutcome> lossOutcome; private bool awaitingCall; private bool walkedAway; private Call pendingCall; private NetworkUser caller; private PurchaseInteraction shrine; private SimpleDialogBox dialog; private Coroutine flow; private bool wagerUsed; private bool exitMode; private static readonly Random rng = new Random(); private const string ShrineCardKey = "RoR2/Base/ShrineChance/iscShrineChance.asset"; private const string VoidFieldsScene = "arena"; private Coroutine clientDecorate; private static GameObject optionPickupPrefab; private const float PauseAfterWinMessage = 1.5f; private const float PauseAfterRewardMessage = 1f; private const float PauseBetweenItems = 0.35f; internal bool IsDialogOpen { get { if (Object.op_Implicit((Object)(object)dialog)) { return Object.op_Implicit((Object)(object)dialog.rootObject); } return false; } } private static GameObject OptionPickupPrefab { get { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) if (!Object.op_Implicit((Object)(object)optionPickupPrefab)) { try { optionPickupPrefab = Addressables.LoadAssetAsync<GameObject>((object)"RoR2/DLC1/OptionPickup/OptionPickup.prefab").WaitForCompletion(); } catch (Exception arg) { Log.LogWarning((object)$"Couldn't load the choice pickup; rewards will be single items. {arg}"); } } return optionPickupPrefab; } } private void Awake() { //IL_0335: Unknown result type (might be due to invalid IL or missing references) //IL_033b: Expected O, but got Unknown Log = ((BaseUnityPlugin)this).Logger; Instance = this; lossOutcome = ((BaseUnityPlugin)this).Config.Bind<LossOutcome>("General", "LossOutcome", LossOutcome.Die, "What happens on a wrong call. Die: everyone's Fuel Array detonates. SkipVoidFields: you're sent to the next stage with no rewards."); callTimeout = ((BaseUnityPlugin)this).Config.Bind<float>("General", "CallTimeoutSeconds", 60f, "If no call is made this long after the shrine is used, the wager is cancelled and the shrine can be used again."); winRewards = ((BaseUnityPlugin)this).Config.Bind<string>("Rewards", "WinRewards", "Tier1,Tier1,Tier1,Tier1,Tier2,Tier2,Tier2,Tier2,Tier3", "Reward pickups each player gets for a correct call, one per cell (vanilla: 4 white, 4 green, 1 red). Options: Tier1, Tier2, Tier3, Boss, Lunar, Void. Leave empty for no items."); optionsPerPick = ((BaseUnityPlugin)this).Config.Bind<int>("Rewards", "OptionsPerPick", 3, "How many items to choose between in each reward pickup."); goldBonus = ((BaseUnityPlugin)this).Config.Bind<bool>("Rewards", "GoldBonus", true, "Also give every player a lump sum of gold on a correct call."); goldChestsWorth = ((BaseUnityPlugin)this).Config.Bind<int>("Rewards", "GoldChestsWorth", 5, "Size of the gold bonus, measured in small chests at the current difficulty."); WagerShrineVisuals.VoiceEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Audio", "ShrineVoice", true, "Let the shrine speak when you're near it. Needs your own shrine_voice*.wav files next to the mod's .dll.").Value; WagerShrineVisuals.VoiceVolume = ((BaseUnityPlugin)this).Config.Bind<float>("Audio", "VoiceVolume", 1.5f, "Volume of the shrine's voice. 1 is the clip as recorded; above 1 boosts it (past ~2 may distort).").Value; WagerShrineVisuals.VoiceInterval = ((BaseUnityPlugin)this).Config.Bind<float>("Audio", "SecondsBetweenLines", 20f, "Pause between the shrine's lines while you're near it.").Value; WagerShrineVisuals.VoiceRange = ((BaseUnityPlugin)this).Config.Bind<float>("Audio", "HearingRange", 18f, "How close (in meters) you need to be to hear the shrine.").Value; winChimeEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Audio", "WinChime", true, "Play the Void Fields cell-complete sound when the coin flip is won."); MusicSilencer.Enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Audio", "QuietVoidFields", true, "No music in the Void Fields until someone activates a cell vent, and none after a winning flip, so the shrine can be heard.").Value; headsKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Controls", "HeadsKey", (KeyCode)104, "Key for the host to call heads (in case the popup doesn't take mouse input)."); tailsKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Controls", "TailsKey", (KeyCode)116, "Key for the host to call tails."); debugKeys = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "EnableDebugKeys", false, "Turn on the testing hotkeys below (host only). Leave off for normal play."); jumpToVoidKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Debug", "JumpToVoidFieldsKey", (KeyCode)288, "Load the Void Fields right now during a run. Press again inside it for a fresh one."); forceWinKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Debug", "ForceWinKey", (KeyCode)291, "Make the next coin flip a guaranteed win. Press again to cancel."); forceLossKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Debug", "ForceLossKey", (KeyCode)292, "Make the next coin flip a guaranteed loss. Press again to cancel."); voiceTestKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Debug", "VoiceTestKey", (KeyCode)290, "Play a random shrine voice line right away (works at the main menu)."); chimeTestKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Debug", "WinChimeTestKey", (KeyCode)289, "Play the win chime right away (works at the main menu)."); MusicSilencer.Install(); Chat.onChatChanged += OnChatChangedForChime; ShrineVoice.LoadFrom(Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location)); Stage.onServerStageBegin += OnServerStageBegin; Stage.onStageStartGlobal += OnStageStartGlobal; Harmony val = new Harmony("com.deadLeshy.VoidCoinFlip"); val.PatchAll(typeof(ChatCallPatch)); val.PatchAll(typeof(ShrineActivatePatch)); val.PatchAll(typeof(HideVentPromptPatch)); try { val.PatchAll(typeof(EscapeClosesCoinPopupPatch)); } catch (Exception ex) { Log.LogWarning((object)("Couldn't hook Escape for the coin popup; use the Walk away button. " + ex.Message)); } Log.LogInfo((object)"VoidCoinFlip 1.0.1 loaded."); } private void OnDestroy() { MusicSilencer.Uninstall(); Chat.onChatChanged -= OnChatChangedForChime; Stage.onServerStageBegin -= OnServerStageBegin; Stage.onStageStartGlobal -= OnStageStartGlobal; if ((Object)(object)Instance == (Object)(object)this) { Instance = null; } } private bool InTriggerScene() { SceneDef sceneDefForCurrentScene = SceneCatalog.GetSceneDefForCurrentScene(); return ((sceneDefForCurrentScene != null) ? sceneDefForCurrentScene.baseSceneName : null) == "arena"; } private void OnStageStartGlobal(Stage stage) { if (clientDecorate != null) { ((MonoBehaviour)this).StopCoroutine(clientDecorate); clientDecorate = null; } if (!NetworkServer.active && InTriggerScene()) { clientDecorate = ((MonoBehaviour)this).StartCoroutine(DecorateShrineAsClient()); } } private IEnumerator DecorateShrineAsClient() { for (float t = 0f; t < 120f; t += 1f) { if (!InTriggerScene()) { yield break; } PurchaseInteraction[] array = Object.FindObjectsOfType<PurchaseInteraction>(); foreach (PurchaseInteraction val in array) { if (Object.op_Implicit((Object)(object)val) && ((Object)((Component)val).gameObject).name.StartsWith("ShrineChance") && !Object.op_Implicit((Object)(object)((Component)val).GetComponent<WagerShrineVisuals>())) { val.displayNameToken = "Shrine of the Void's Wager"; val.contextToken = "Call the coin"; WagerShrineVisuals.Apply(((Component)val).gameObject); clientDecorate = null; yield break; } } yield return (object)new WaitForSeconds(1f); } clientDecorate = null; } private void OnServerStageBegin(Stage stage) { CloseDialog(); awaitingCall = false; wagerUsed = false; exitMode = false; MusicSilencer.WagerWon = false; shrine = null; caller = null; if (flow != null) { ((MonoBehaviour)this).StopCoroutine(flow); } if (InTriggerScene()) { Log.LogInfo((object)"Entered the Void Fields, spawning the wager shrine."); ((MonoBehaviour)this).StartCoroutine(SpawnShrineWhenReady()); } } private IEnumerator SpawnShrineWhenReady() { float timeout = 30f; while (timeout > 0f && !AllPlayerBodies().Any()) { timeout -= Time.deltaTime; yield return null; } yield return (object)new WaitForSeconds(1f); CharacterBody anchor = AllPlayerBodies().FirstOrDefault(); if (!Object.op_Implicit((Object)(object)anchor)) { Log.LogWarning((object)"No players found; not spawning the shrine."); yield break; } GameObject firstVent = null; for (float t = 0f; t < 10f; t += 0.5f) { GameObject val; firstVent = (val = FindReadyVent()); if (Object.op_Implicit((Object)(object)val)) { break; } yield return (object)new WaitForSeconds(0.5f); } GameObject val2 = (Object.op_Implicit((Object)(object)firstVent) ? SpawnShrineInVent(firstVent) : SpawnShrineNear(anchor.footPosition, 6f, 20f)); if (!Object.op_Implicit((Object)(object)firstVent)) { Log.LogWarning((object)"Couldn't find the first cell vent; spawning the shrine near the players instead."); } if (!Object.op_Implicit((Object)(object)val2)) { Log.LogError((object)"Couldn't spawn the wager shrine."); yield break; } shrine = val2.GetComponent<PurchaseInteraction>(); ConvertToWagerShrine(val2); Broadcast("<color=#c08cff>A <b>Shrine of the Void's Wager</b> has appeared by the first cell vent. Gamble on a coin flip, or activate the vent to face the trials. You can't do both.</color>"); ((MonoBehaviour)this).StartCoroutine(WithdrawShrineIfVentStarted()); } private static GameObject FindReadyVent() { ArenaMissionController instance = ArenaMissionController.instance; if (!Object.op_Implicit((Object)(object)instance) || instance.nullWards == null) { return null; } return ((IEnumerable<GameObject>)instance.nullWards).FirstOrDefault((Func<GameObject, bool>)((GameObject w) => Object.op_Implicit((Object)(object)w) && MusicSilencer.WardState(w) == "WardOnAndReady")); } private static float VentSafeRadius(GameObject vent) { SphereZone componentInChildren = vent.GetComponentInChildren<SphereZone>(); if (Object.op_Implicit((Object)(object)componentInChildren) && (AccessTools.Property(typeof(SphereZone), "radius")?.GetValue(componentInChildren) ?? AccessTools.Field(typeof(SphereZone), "radius")?.GetValue(componentInChildren)) is float num && num > 1f) { return num; } return 15f; } private GameObject SpawnShrineInVent(GameObject vent) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0012: 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_0023: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_017d: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_00c8: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: Unknown result type (might be due to invalid IL or missing references) //IL_00e0: Unknown result type (might be due to invalid IL or missing references) //IL_00e5: Unknown result type (might be due to invalid IL or missing references) //IL_00ea: Unknown result type (might be due to invalid IL or missing references) //IL_00fb: Unknown result type (might be due to invalid IL or missing references) //IL_010c: Unknown result type (might be due to invalid IL or missing references) //IL_010e: Unknown result type (might be due to invalid IL or missing references) //IL_0122: Unknown result type (might be due to invalid IL or missing references) //IL_0127: Unknown result type (might be due to invalid IL or missing references) //IL_012c: Unknown result type (might be due to invalid IL or missing references) //IL_0151: Unknown result type (might be due to invalid IL or missing references) //IL_0156: Unknown result type (might be due to invalid IL or missing references) float num = VentSafeRadius(vent); Vector3 position = vent.transform.position; List<CharacterBody> list = AllPlayerBodies().ToList(); Vector3 val = Vector3.forward; if (list.Count > 0) { Vector3 val2 = list.Aggregate(Vector3.zero, (Vector3 acc, CharacterBody b) => acc + b.footPosition) / (float)list.Count - position; val2.y = 0f; if (((Vector3)(ref val2)).sqrMagnitude > 0.25f) { val = ((Vector3)(ref val2)).normalized; } } RaycastHit val4 = default(RaycastHit); for (int num2 = 0; num2 < 12; num2++) { float num3 = (float)(((num2 % 2 == 0) ? 1 : (-1)) * ((num2 + 1) / 2)) * 30f; Vector3 val3 = Quaternion.Euler(0f, num3, 0f) * val; if (Physics.Raycast(position + val3 * num + Vector3.up * 15f, Vector3.down, ref val4, 40f, LayerMask.op_Implicit(((LayerIndex)(ref LayerIndex.world)).mask))) { Quaternion rotation = Quaternion.LookRotation(val3) * Quaternion.Euler(0f, 180f, 0f); Log.LogInfo((object)$"Placing the shrine on the edge of {((Object)vent).name}'s safe zone (radius {num:0.0}m)."); return SpawnShrineAt(((RaycastHit)(ref val4)).point, rotation); } } Log.LogWarning((object)"No ground at the vent's edge; using a nearby spot instead."); return SpawnShrineNear(position, num * 0.8f, num * 1.2f); } private GameObject SpawnShrineAt(Vector3 position, Quaternion rotation) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000a: 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) try { InteractableSpawnCard val = Addressables.LoadAssetAsync<InteractableSpawnCard>((object)"RoR2/Base/ShrineChance/iscShrineChance.asset").WaitForCompletion(); if (!Object.op_Implicit((Object)(object)val) || !Object.op_Implicit((Object)(object)((SpawnCard)val).prefab)) { return null; } GameObject obj = Object.Instantiate<GameObject>(((SpawnCard)val).prefab, position, rotation); NetworkServer.Spawn(obj); return obj; } catch (Exception ex) { Log.LogError((object)ex); return null; } } private GameObject SpawnShrineNear(Vector3 center, float minDistance, float maxDistance) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000a: 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_0035: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Expected O, but got Unknown //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Expected O, but got Unknown //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: Unknown result type (might be due to invalid IL or missing references) //IL_00dd: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: Unknown result type (might be due to invalid IL or missing references) //IL_00ec: Unknown result type (might be due to invalid IL or missing references) //IL_00f1: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: Unknown result type (might be due to invalid IL or missing references) //IL_0107: Unknown result type (might be due to invalid IL or missing references) //IL_0134: Unknown result type (might be due to invalid IL or missing references) //IL_0136: Unknown result type (might be due to invalid IL or missing references) //IL_011a: Unknown result type (might be due to invalid IL or missing references) //IL_011f: Unknown result type (might be due to invalid IL or missing references) try { InteractableSpawnCard val = Addressables.LoadAssetAsync<InteractableSpawnCard>((object)"RoR2/Base/ShrineChance/iscShrineChance.asset").WaitForCompletion(); if (!Object.op_Implicit((Object)(object)val) || !Object.op_Implicit((Object)(object)DirectorCore.instance)) { return null; } DirectorPlacementRule val2 = new DirectorPlacementRule { placementMode = (PlacementMode)1, position = center, minDistance = minDistance, maxDistance = maxDistance }; DirectorSpawnRequest val3 = new DirectorSpawnRequest((SpawnCard)(object)val, val2, Run.instance.stageRng); GameObject val4 = DirectorCore.instance.TrySpawnObject(val3); if (Object.op_Implicit((Object)(object)val4)) { return val4; } Log.LogWarning((object)"Placement failed; finding ground for the shrine manually."); float num = (minDistance + maxDistance) * 0.5f; Vector3 val5 = center + Vector3.forward * num; RaycastHit val6 = default(RaycastHit); for (int i = 0; i < 8; i++) { if (Physics.Raycast(center + Quaternion.Euler(0f, (float)i * 45f, 0f) * Vector3.forward * num + Vector3.up * 15f, Vector3.down, ref val6, 40f, LayerMask.op_Implicit(((LayerIndex)(ref LayerIndex.world)).mask))) { val5 = ((RaycastHit)(ref val6)).point; break; } } GameObject obj = Object.Instantiate<GameObject>(((SpawnCard)val).prefab, val5, Quaternion.identity); NetworkServer.Spawn(obj); return obj; } catch (Exception ex) { Log.LogError((object)ex); return null; } } private IEnumerator WithdrawShrineIfVentStarted() { while (Object.op_Implicit((Object)(object)shrine) && !wagerUsed) { ArenaMissionController instance = ArenaMissionController.instance; if (Object.op_Implicit((Object)(object)instance) && instance.nullWards != null && instance.nullWards.Any((GameObject w) => Object.op_Implicit((Object)(object)w) && MusicSilencer.WardState(w) == "Active")) { if (awaitingCall) { if (flow != null) { ((MonoBehaviour)this).StopCoroutine(flow); } awaitingCall = false; caller = null; CloseDialog(); } Broadcast("<color=#c08cff>A cell vent has been activated. The void's wager is withdrawn.</color>"); Log.LogInfo((object)"Cell vent started normally; removing the wager shrine."); NetworkServer.Destroy(((Component)shrine).gameObject); shrine = null; break; } yield return (object)new WaitForSeconds(0.5f); } } private void ConvertToWagerShrine(GameObject shrineObject) { //IL_0050: Unknown result type (might be due to invalid IL or missing references) ShrineChanceBehavior component = shrineObject.GetComponent<ShrineChanceBehavior>(); if (Object.op_Implicit((Object)(object)component)) { Object.Destroy((Object)(object)component); } if (Object.op_Implicit((Object)(object)shrine)) { shrine.displayNameToken = "Shrine of the Void's Wager"; shrine.contextToken = "Call the coin"; WagerShrineVisuals.Apply(shrineObject); shrine.costType = (CostTypeIndex)0; shrine.Networkcost = 0; } } internal bool IsWagerShrine(PurchaseInteraction pi) { if (Object.op_Implicit((Object)(object)pi)) { return (Object)(object)pi == (Object)(object)shrine; } return false; } internal void OnShrineActivated(Interactor interactor) { if (exitMode) { exitMode = false; if (Object.op_Implicit((Object)(object)shrine)) { shrine.SetAvailable(false); } Broadcast("<color=#c08cff>Leaving the void...</color>"); ((MonoBehaviour)this).StartCoroutine(LeaveAfter(2f)); } else { if (wagerUsed || awaitingCall) { return; } CharacterBody val = (Object.op_Implicit((Object)(object)interactor) ? ((Component)interactor).GetComponent<CharacterBody>() : null); NetworkUser val2 = ((Object.op_Implicit((Object)(object)val) && Object.op_Implicit((Object)(object)val.master) && Object.op_Implicit((Object)(object)val.master.playerCharacterMasterController)) ? val.master.playerCharacterMasterController.networkUser : null); if (Object.op_Implicit((Object)(object)val2)) { shrine.SetAvailable(false); if (flow != null) { ((MonoBehaviour)this).StopCoroutine(flow); } flow = ((MonoBehaviour)this).StartCoroutine(CoinFlipFlow(val2)); } } } private IEnumerator CoinFlipFlow(NetworkUser user) { caller = user; pendingCall = Call.None; walkedAway = false; awaitingCall = true; bool isLocalPlayer = ((NetworkBehaviour)user).isLocalPlayer; string name = user.userName; if (isLocalPlayer) { Broadcast("<color=#c08cff><b>" + name + "</b> accepts the void's wager and is calling the coin...</color>"); OpenDialog(); } else { Broadcast("<color=#c08cff><b>" + name + "</b> accepts the void's wager. <b>" + name + "</b>: type <b>heads</b> or <b>tails</b> in chat.</color>"); } float waited = 0f; while (pendingCall == Call.None && !walkedAway && waited < callTimeout.Value) { if (!NetworkServer.active) { yield break; } waited += Time.deltaTime; yield return null; } awaitingCall = false; CloseDialog(); if (pendingCall == Call.None) { Broadcast(walkedAway ? ("<color=#c08cff><b>" + name + "</b> walks away from the wager. The shrine waits for another taker.</color>") : "<color=#c08cff>No call was made. The shrine waits for another taker.</color>"); caller = null; if (Object.op_Implicit((Object)(object)shrine)) { shrine.SetAvailable(true); } yield break; } wagerUsed = true; Call result = ((rng.Next(2) == 0) ? Call.Heads : Call.Tails); if (rigNextFlip != Rig.None) { bool flag = rigNextFlip == Rig.Win; result = (flag ? pendingCall : ((pendingCall != Call.Heads) ? Call.Heads : Call.Tails)); Log.LogInfo((object)("[Debug] Forced " + (flag ? "win" : "loss") + " used.")); rigNextFlip = Rig.None; } Broadcast($"<color=#c08cff><b>{name}</b> calls <b>{pendingCall}</b>. The coin spins...</color>"); yield return (object)new WaitForSeconds(1.5f); if (result == pendingCall) { Broadcast(string.Format("<color=#7fff7f>It lands <b>{0}</b>! {1}.</color>", result, "The void trials are passed")); if (winChimeEnabled.Value) { WinChime.Play(); } MusicSilencer.WagerWon = true; bool completed = VoidFieldsCompletion.Finish(); ((MonoBehaviour)this).StartCoroutine(RelockVents()); ((MonoBehaviour)this).StartCoroutine(RemoveVentShortly()); yield return (object)new WaitForSeconds(1.5f); yield return DropRewards(); yield return (object)new WaitForSeconds(1f); ApplyWinBonus(); yield return (object)new WaitForSeconds(2f); if (completed) { Broadcast("<color=#c08cff>The void is beaten. Take a portal when you're ready.</color>"); yield break; } exitMode = true; if (Object.op_Implicit((Object)(object)shrine)) { shrine.contextToken = "Leave the void"; shrine.SetAvailable(true); } Broadcast("<color=#c08cff>The fog lifts. Use the shrine again when you're ready to leave.</color>"); } else if (lossOutcome.Value == LossOutcome.SkipVoidFields) { Broadcast($"<color=#ff5050>It lands <b>{result}</b>. The void casts you out empty-handed.</color>"); yield return (object)new WaitForSeconds(3f); AdvanceToNextStage(); } else { Broadcast($"<color=#ff5050>It lands <b>{result}</b>.</color>"); Broadcast("<color=#ff5050>You have lost the void's wager. Your soul is now forfeit.</color>"); yield return (object)new WaitForSeconds(0.5f); yield return FuelArrayDeath.Run(AllPlayerBodies().ToList()); } } internal void OnChatMessage(NetworkUser sender, string text) { if (awaitingCall && Object.op_Implicit((Object)(object)sender) && !((Object)(object)sender != (Object)(object)caller) && text != null) { switch (text.Trim().ToLowerInvariant()) { case "heads": case "h": pendingCall = Call.Heads; break; case "tails": case "t": pendingCall = Call.Tails; break; } } } private void ToggleRig(Rig rig) { rigNextFlip = ((rigNextFlip != rig) ? rig : Rig.None); Log.LogInfo((object)((rigNextFlip == Rig.None) ? "[Debug] Forced outcome cancelled; the next flip is random." : ("[Debug] Next coin flip will be a " + ((rigNextFlip == Rig.Win) ? "win" : "loss") + "."))); } private void JumpToVoidFields() { Run instance = Run.instance; if (!Object.op_Implicit((Object)(object)instance)) { Log.LogInfo((object)"[Debug] Start a run first, then press the jump key."); return; } SceneDef val = SceneCatalog.FindSceneDef("arena"); if (!Object.op_Implicit((Object)(object)val)) { Log.LogWarning((object)"[Debug] Couldn't find the Void Fields scene."); return; } Log.LogInfo((object)"[Debug] Jumping to the Void Fields."); instance.AdvanceStage(val); } private void OnChatChangedForChime() { if (winChimeEnabled.Value) { WinChime.OnChatChanged(); } } private void Update() { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_00e5: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_0166: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_0180: Unknown result type (might be due to invalid IL or missing references) if (debugKeys.Value && (int)chimeTestKey.Value != 0 && Input.GetKeyDown(chimeTestKey.Value)) { Log.LogInfo((object)"Win chime: test key pressed."); WinChime.Play(); } if (debugKeys.Value && NetworkServer.active) { if ((int)forceWinKey.Value != 0 && Input.GetKeyDown(forceWinKey.Value)) { ToggleRig(Rig.Win); } if ((int)forceLossKey.Value != 0 && Input.GetKeyDown(forceLossKey.Value)) { ToggleRig(Rig.Loss); } if ((int)jumpToVoidKey.Value != 0 && Input.GetKeyDown(jumpToVoidKey.Value)) { JumpToVoidFields(); } } if (debugKeys.Value && (int)voiceTestKey.Value != 0 && Input.GetKeyDown(voiceTestKey.Value) && WagerShrineVisuals.VoiceEnabled && ShrineVoice.Lines.Count > 0) { Log.LogInfo((object)"Shrine voice: test key pressed."); ShrineVoice.Play(ShrineVoice.Lines[Random.Range(0, ShrineVoice.Lines.Count)], WagerShrineVisuals.VoiceVolume, 0f); } if (awaitingCall && Object.op_Implicit((Object)(object)caller) && ((NetworkBehaviour)caller).isLocalPlayer) { if (Input.GetKeyDown(headsKey.Value)) { pendingCall = Call.Heads; } else if (Input.GetKeyDown(tailsKey.Value)) { pendingCall = Call.Tails; } } } private void OpenDialog() { //IL_015f: Unknown result type (might be due to invalid IL or missing references) //IL_016f: 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_0066: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Expected O, but got Unknown //IL_00c9: Unknown result type (might be due to invalid IL or missing references) //IL_00de: Expected O, but got Unknown //IL_00ec: Unknown result type (might be due to invalid IL or missing references) //IL_0101: Expected O, but got Unknown try { LocalUser firstLocalUser = LocalUserManager.GetFirstLocalUser(); dialog = SimpleDialogBox.Create((firstLocalUser != null) ? firstLocalUser.eventSystem : null); dialog.headerToken = new TokenParamsPair("THE VOID'S WAGER", Array.Empty<object>()); dialog.descriptionToken = new TokenParamsPair("Call the coin.\n\nRight: skip the void trials and claim their rewards.\n" + ((lossOutcome.Value == LossOutcome.Die) ? "Wrong: everyone dies.\n\n" : "Wrong: leave the Void Fields with nothing.\n\n") + $"(Or press {headsKey.Value} for heads, {tailsKey.Value} for tails. Escape to walk away.)", Array.Empty<object>()); dialog.AddActionButton((UnityAction)delegate { pendingCall = Call.Heads; }, "Heads", true, Array.Empty<object>()); dialog.AddActionButton((UnityAction)delegate { pendingCall = Call.Tails; }, "Tails", true, Array.Empty<object>()); dialog.AddActionButton((UnityAction)delegate { walkedAway = true; }, "Walk away", true, Array.Empty<object>()); if (Object.op_Implicit((Object)(object)dialog.rootObject) && !Object.op_Implicit((Object)(object)dialog.rootObject.GetComponent<CursorOpener>())) { dialog.rootObject.AddComponent<CursorOpener>(); } } catch (Exception arg) { Log.LogWarning((object)$"Couldn't open the popup, use the keys instead. {arg}"); Broadcast($"<color=#c08cff>Press <b>{headsKey.Value}</b> for heads or <b>{tailsKey.Value}</b> for tails, or type it in chat.</color>"); } } internal void WalkAwayFromDialog() { if (awaitingCall) { walkedAway = true; CloseDialog(); } } private void CloseDialog() { if (Object.op_Implicit((Object)(object)dialog) && Object.op_Implicit((Object)(object)dialog.rootObject)) { Object.Destroy((Object)(object)dialog.rootObject); } dialog = null; } private static IEnumerable<CharacterBody> AllPlayerBodies() { return from p in PlayerCharacterMasterController.instances where Object.op_Implicit((Object)(object)p) && Object.op_Implicit((Object)(object)p.master) select p.master.GetBody() into b where Object.op_Implicit((Object)(object)b) && Object.op_Implicit((Object)(object)b.healthComponent) && b.healthComponent.alive select b; } private IEnumerator DropRewards() { Run run = Run.instance; if (!Object.op_Implicit((Object)(object)run)) { yield break; } List<string> tiers = (from s in winRewards.Value.Split(',') select s.Trim() into s where s.Length > 0 select s).ToList(); if (tiers.Count == 0) { yield break; } GameObject prefab = OptionPickupPrefab; List<CharacterBody> bodies = AllPlayerBodies().ToList(); Dictionary<CharacterBody, Vector3> piles = PilePositions(bodies); for (int p = 0; p < bodies.Count; p++) { CharacterBody body = bodies[p]; if (!Object.op_Implicit((Object)(object)body)) { continue; } string text = ((Object.op_Implicit((Object)(object)body.master) && Object.op_Implicit((Object)(object)body.master.playerCharacterMasterController) && Object.op_Implicit((Object)(object)body.master.playerCharacterMasterController.networkUser)) ? body.master.playerCharacterMasterController.networkUser.userName : body.GetDisplayName()); Broadcast("<color=#c08cff>Here are <b>" + text + "</b>'s rewards</color>"); yield return (object)new WaitForSeconds(1f); Vector3 val = piles[body]; Vector3 origin = val + Vector3.up * 4f; for (int i = 0; i < tiers.Count; i++) { List<PickupIndex> list = DropListFor(run, tiers[i]); if (list != null && list.Count != 0) { PickupIndex[] array = list.OrderBy((PickupIndex _) => rng.Next()).Take(Math.Max(1, optionsPerPick.Value)).ToArray(); Vector3 val2 = Quaternion.AngleAxis(360f / (float)tiers.Count * (float)i, Vector3.up) * (Vector3.forward * 2.5f) + Vector3.up * 6f; if (Object.op_Implicit((Object)(object)prefab)) { CreatePickupInfo val3 = new CreatePickupInfo { pickerOptions = PickupPickerController.GenerateOptionsFromArray(array), prefabOverride = prefab, position = origin, rotation = Quaternion.identity }; ((CreatePickupInfo)(ref val3)).pickupIndex = PickupCatalog.FindPickupIndex(ItemTierFor(tiers[i])); PickupDropletController.CreatePickupDroplet(val3, origin, val2); } else { PickupDropletController.CreatePickupDroplet(array[0], origin, val2); } if (i < tiers.Count - 1) { yield return (object)new WaitForSeconds(0.35f); } } } if (p < bodies.Count - 1) { yield return (object)new WaitForSeconds(2f); } } } private Dictionary<CharacterBody, Vector3> PilePositions(List<CharacterBody> bodies) { //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0127: Unknown result type (might be due to invalid IL or missing references) //IL_012c: Unknown result type (might be due to invalid IL or missing references) //IL_0131: Unknown result type (might be due to invalid IL or missing references) //IL_0136: Unknown result type (might be due to invalid IL or missing references) //IL_013c: Unknown result type (might be due to invalid IL or missing references) //IL_0141: Unknown result type (might be due to invalid IL or missing references) //IL_0148: Unknown result type (might be due to invalid IL or missing references) //IL_014d: Unknown result type (might be due to invalid IL or missing references) Dictionary<CharacterBody, Vector3> dictionary = new Dictionary<CharacterBody, Vector3>(); if (bodies.Count == 0) { return dictionary; } Vector3 center = (Object.op_Implicit((Object)(object)shrine) ? ((Component)shrine).transform.position : bodies[0].footPosition); List<(CharacterBody, float)> list = (from x in bodies.Select(delegate(CharacterBody b) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_002c: 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) Vector3 val2 = b.footPosition - center; val2.y = 0f; float num3 = ((((Vector3)(ref val2)).sqrMagnitude < 0.01f) ? 0f : (Mathf.Atan2(val2.x, val2.z) * 57.29578f)); return (body: b, angle: (num3 + 360f) % 360f); }) orderby x.angle select x).ToList(); float num = Mathf.Min(70f, 360f / (float)bodies.Count); for (int num2 = 1; num2 < list.Count; num2++) { if (list[num2].Item2 - list[num2 - 1].Item2 < num) { list[num2] = (list[num2].Item1, list[num2 - 1].Item2 + num); } } foreach (var item3 in list) { CharacterBody item = item3.Item1; float item2 = item3.Item2; Vector3 val = Quaternion.Euler(0f, item2, 0f) * Vector3.forward; dictionary[item] = center + val * 6f; } return dictionary; } private static ItemTier ItemTierFor(string tier) { switch (tier.ToLowerInvariant()) { case "tier2": case "green": return (ItemTier)1; case "tier3": case "red": return (ItemTier)2; case "boss": case "yellow": return (ItemTier)4; case "lunar": case "blue": return (ItemTier)3; case "void": case "purple": return (ItemTier)6; default: return (ItemTier)0; } } private static List<PickupIndex> DropListFor(Run run, string tier) { switch (tier.ToLowerInvariant()) { case "tier1": case "white": return run.availableTier1DropList; case "tier2": case "green": return run.availableTier2DropList; case "tier3": case "red": return run.availableTier3DropList; case "boss": case "yellow": return run.availableBossDropList; case "lunar": case "blue": return run.availableLunarItemDropList; case "void": case "purple": return run.availableVoidTier1DropList.Concat(run.availableVoidTier2DropList).Concat(run.availableVoidTier3DropList).ToList(); default: Log.LogWarning((object)("Unknown reward tier '" + tier + "', skipping.")); return null; } } private IEnumerator RelockVents() { while (MusicSilencer.WagerWon && Object.op_Implicit((Object)(object)ArenaMissionController.instance)) { VoidFieldsCompletion.LockVents(); yield return (object)new WaitForSeconds(0.5f); } } private IEnumerator RemoveVentShortly() { yield return (object)new WaitForSeconds(1f); VoidFieldsCompletion.RemoveReadyVent(); } private IEnumerator LeaveAfter(float seconds) { yield return (object)new WaitForSeconds(seconds); AdvanceToNextStage(); } private void ApplyWinBonus() { Run instance = Run.instance; if (!Object.op_Implicit((Object)(object)instance) || !goldBonus.Value) { return; } int difficultyScaledCost = instance.GetDifficultyScaledCost(25); uint num = (uint)Math.Max(0, difficultyScaledCost * goldChestsWorth.Value); if (num == 0) { return; } foreach (PlayerCharacterMasterController item in PlayerCharacterMasterController.instances.Where((PlayerCharacterMasterController p) => Object.op_Implicit((Object)(object)p) && Object.op_Implicit((Object)(object)p.master))) { item.master.GiveMoney(num); } Broadcast($"<color=#ffd34d>The void pays out <b>${num}</b> to each survivor.</color>"); } private static void ConvertGoldToExperience() { ulong num = 0uL; foreach (PlayerCharacterMasterController item in PlayerCharacterMasterController.instances.Where((PlayerCharacterMasterController p) => Object.op_Implicit((Object)(object)p) && Object.op_Implicit((Object)(object)p.master))) { uint money = item.master.money; if (money != 0) { num += money; item.master.money = 0u; } } if (num != 0L) { if (Object.op_Implicit((Object)(object)TeamManager.instance)) { TeamManager.instance.GiveTeamExperience((TeamIndex)1, num); Log.LogInfo((object)$"Converted ${num} of unspent gold into experience."); } else { Log.LogWarning((object)"Couldn't find the team manager; unspent gold wasn't converted."); } } } private void AdvanceToNextStage() { Run instance = Run.instance; if (Object.op_Implicit((Object)(object)instance)) { ConvertGoldToExperience(); if (!Object.op_Implicit((Object)(object)instance.nextStageScene)) { Log.LogWarning((object)"No next stage queued; letting the game pick one."); instance.PickNextStageSceneFromCurrentSceneDestinations(); } if (Object.op_Implicit((Object)(object)instance.nextStageScene)) { instance.AdvanceStage(instance.nextStageScene); } else { Log.LogError((object)"Couldn't find a stage to move to. Use the normal exit."); } } } private static void Broadcast(string text) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Expected O, but got Unknown Chat.SendBroadcastChat((ChatMessageBase)new SimpleChatMessage { baseToken = text }); } } internal class WagerShrineVisuals : MonoBehaviour { private static readonly Color VoidPurple = new Color(0.66f, 0.24f, 1f); private Highlight outline; private Light glow; internal static bool VoiceEnabled = true; internal static float VoiceVolume = 1.5f; internal static float VoiceInterval = 20f; internal static float VoiceRange = 18f; private PurchaseInteraction purchase; private float nextVoiceTime; private VoiceLine lastLine; private bool silenced; internal static void Apply(GameObject shrine) { if (!Object.op_Implicit((Object)(object)shrine) || Object.op_Implicit((Object)(object)shrine.GetComponent<WagerShrineVisuals>())) { return; } try { shrine.AddComponent<WagerShrineVisuals>().Setup(); } catch (Exception arg) { VoidCoinFlipPlugin.Log.LogWarning((object)$"Couldn't add the shrine outline. {arg}"); } } private void Setup() { //IL_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: Expected O, but got Unknown //IL_00ef: Unknown result type (might be due to invalid IL or missing references) //IL_00f9: Unknown result type (might be due to invalid IL or missing references) //IL_0121: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Unknown result type (might be due to invalid IL or missing references) Renderer val = ((Component)this).GetComponent<Highlight>()?.targetRenderer; if (!Object.op_Implicit((Object)(object)val)) { val = (from r in ((Component)this).GetComponentsInChildren<Renderer>() where r is MeshRenderer || r is SkinnedMeshRenderer select r).OrderByDescending(delegate(Renderer r) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) Bounds bounds = r.bounds; Vector3 size = ((Bounds)(ref bounds)).size; return ((Vector3)(ref size)).sqrMagnitude; }).FirstOrDefault(); } if (Object.op_Implicit((Object)(object)val)) { outline = ((Component)this).gameObject.AddComponent<Highlight>(); outline.targetRenderer = val; outline.highlightColor = (HighlightColor)3; outline.CustomColor = VoidPurple; outline.strength = 1f; outline.isOn = true; } GameObject val2 = new GameObject("VoidWagerGlow"); val2.transform.SetParent(((Component)this).transform, false); val2.transform.localPosition = Vector3.up * 3f; glow = val2.AddComponent<Light>(); glow.type = (LightType)2; glow.color = VoidPurple; glow.range = 12f; glow.intensity = 3f; purchase = ((Component)this).GetComponent<PurchaseInteraction>(); nextVoiceTime = Time.time + 2f; VoidCoinFlipPlugin.Log.LogInfo((object)string.Format("Shrine voice: ready on {0} ({1} line(s), available={2}).", ((Object)((Component)this).gameObject).name, ShrineVoice.Lines.Count, Object.op_Implicit((Object)(object)purchase) ? purchase.available.ToString() : "no purchase component")); } private void UpdateVoice() { //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: Unknown result type (might be due to invalid IL or missing references) //IL_0102: Unknown result type (might be due to invalid IL or missing references) if (!VoiceEnabled || silenced || ShrineVoice.Lines.Count == 0) { return; } if (Object.op_Implicit((Object)(object)purchase) && !purchase.available) { VoidCoinFlipPlugin.Log.LogInfo((object)"Shrine voice: shrine no longer available, going quiet."); silenced = true; ShrineVoice.Stop(); } else { if (Time.time < nextVoiceTime) { return; } LocalUser firstLocalUser = LocalUserManager.GetFirstLocalUser(); CharacterBody val = ((firstLocalUser != null) ? firstLocalUser.cachedBody : null); if (!Object.op_Implicit((Object)(object)val)) { return; } Vector3 val2 = ((Component)this).transform.position - val.corePosition; float magnitude = ((Vector3)(ref val2)).magnitude; if (!(magnitude > VoiceRange)) { float num = Mathf.Clamp01(1f - (magnitude - 3f) / Mathf.Max(1f, VoiceRange - 3f)); float volume = VoiceVolume * num; float pan = 0f; Camera main = Camera.main; if (Object.op_Implicit((Object)(object)main) && magnitude > 0.5f) { pan = Mathf.Clamp(Vector3.Dot(((Vector3)(ref val2)).normalized, ((Component)main).transform.right), -1f, 1f) * 0.8f; } List<VoiceLine> list = ((ShrineVoice.Lines.Count > 1) ? ShrineVoice.Lines.Where((VoiceLine l) => l != lastLine).ToList() : ShrineVoice.Lines); VoiceLine voiceLine = (lastLine = list[Random.Range(0, list.Count)]); ShrineVoice.Play(voiceLine, volume, pan); nextVoiceTime = Time.time + voiceLine.Length + VoiceInterval; } } } private void OnDestroy() { if (!silenced) { ShrineVoice.Stop(); } } private void Update() { float num = 0.75f + 0.25f * Mathf.Sin(Time.time * 2.5f); if (Object.op_Implicit((Object)(object)outline)) { outline.isOn = true; outline.strength = num; } if (Object.op_Implicit((Object)(object)glow)) { glow.intensity = 2f + 1.5f * num; } UpdateVoice(); } } [HarmonyPatch(typeof(PurchaseInteraction), "OnInteractionBegin")] internal static class ShrineActivatePatch { private static bool Prefix(PurchaseInteraction __instance, Interactor activator) { VoidCoinFlipPlugin instance = VoidCoinFlipPlugin.Instance; if ((Object)(object)instance == (Object)null || !NetworkServer.active) { return true; } if (MusicSilencer.WagerWon && VoidFieldsCompletion.IsCellVent(__instance)) { __instance.SetAvailable(false); return false; } if (!instance.IsWagerShrine(__instance)) { return true; } try { instance.OnShrineActivated(activator); } catch (Exception ex) { VoidCoinFlipPlugin.Log.LogError((object)ex); } return false; } } [HarmonyPatch(typeof(PauseManager), "TogglePauseScreen")] internal static class EscapeClosesCoinPopupPatch { private static bool Prefix() { VoidCoinFlipPlugin instance = VoidCoinFlipPlugin.Instance; if ((Object)(object)instance == (Object)null || !instance.IsDialogOpen) { return true; } instance.WalkAwayFromDialog(); return false; } } [HarmonyPatch(typeof(PurchaseInteraction), "GetInteractability")] internal static class HideVentPromptPatch { private static void Postfix(PurchaseInteraction __instance, ref Interactability __result) { if (MusicSilencer.WagerWon && VoidFieldsCompletion.IsCellVent(__instance)) { __result = (Interactability)0; } } } [HarmonyPatch] internal static class ChatCallPatch { private static IEnumerable<MethodBase> TargetMethods() { return (from m in typeof(Chat).GetMethods(BindingFlags.Static | BindingFlags.Public) where m.Name == "SendBroadcastChat" select m).Where(delegate(MethodInfo m) { ParameterInfo[] parameters = m.GetParameters(); return parameters.Length >= 1 && parameters[0].ParameterType == typeof(ChatMessageBase); }).Cast<MethodBase>(); } private static void Prefix(ChatMessageBase __0) { try { if (NetworkServer.active && !((Object)(object)VoidCoinFlipPlugin.Instance == (Object)null)) { UserChatMessage val = (UserChatMessage)(object)((__0 is UserChatMessage) ? __0 : null); if (val != null && Object.op_Implicit((Object)(object)val.sender)) { NetworkUser component = val.sender.GetComponent<NetworkUser>(); VoidCoinFlipPlugin.Instance.OnChatMessage(component, val.text); } } } catch (Exception ex) { VoidCoinFlipPlugin.Log.LogWarning((object)ex); } } } internal static class VoidFieldsCompletion { private const string ArenaTypeName = "RoR2.ArenaMissionController"; public static GameObject ReadyVent; public static void RemoveReadyVent() { //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Expected O, but got Unknown if (!NetworkServer.active || !Object.op_Implicit((Object)(object)ReadyVent)) { return; } GameObject readyVent = ReadyVent; ReadyVent = null; try { ArenaMissionController instance = ArenaMissionController.instance; GameObject val = (GameObject)(Object.op_Implicit((Object)(object)instance) ? /*isinst with value type is only supported in some contexts*/: null); if (Object.op_Implicit((Object)(object)val)) { EffectManager.SpawnEffect(val, new EffectData { origin = readyVent.transform.position, scale = 10f }, true); } } catch (Exception ex) { VoidCoinFlipPlugin.Log.LogInfo((object)("Void Fields: no burst effect for the vent (" + ex.Message + ").")); } try { if (Object.op_Implicit((Object)(object)readyVent.GetComponent<NetworkIdentity>())) { NetworkServer.Destroy(readyVent); } else { Object.Destroy((Object)(object)readyVent); } VoidCoinFlipPlugin.Log.LogInfo((object)("Void Fields: removed the waiting vent " + ((Object)readyVent).name + ".")); } catch (Exception ex2) { VoidCoinFlipPlugin.Log.LogWarning((object)("Void Fields: couldn't remove the waiting vent. " + ex2.Message)); } } public static bool Finish() { if (!NetworkServer.active) { return false; } Type arenaType = AccessTools.TypeByName("RoR2.ArenaMissionController"); object obj = FindArena(arenaType); if (obj == null) { VoidCoinFlipPlugin.Log.LogWarning((object)"Couldn't find the Void Fields controller."); StopFog(); return false; } StopSpawning(arenaType, obj); ClearMonsters(); ReadyVent = ((Object.op_Implicit((Object)(object)ArenaMissionController.instance) && ArenaMissionController.instance.nullWards != null) ? ((IEnumerable<GameObject>)ArenaMissionController.instance.nullWards).FirstOrDefault((Func<GameObject, bool>)((GameObject w) => Object.op_Implicit((Object)(object)w) && MusicSilencer.WardState(w) == "WardOnAndReady")) : null); CompleteCells(arenaType, obj); LockVents(); SetRoundsCleared(arenaType, obj); bool result = EnterMissionCompleted(arenaType, obj); SpawnCompletionPortals(arenaType, obj); StopFog(); return result; } private static object FindArena(Type arenaType) { if (arenaType == null) { return null; } return AccessTools.Property(arenaType, "instance")?.GetValue(null) ?? Object.FindObjectOfType(arenaType); } private static void SetRoundsCleared(Type arenaType, object arena) { int num = ((AccessTools.Field(arenaType, "totalRoundsMax")?.GetValue(arena) is int num2) ? num2 : 9); try { MethodInfo methodInfo = AccessTools.PropertySetter(arenaType, "Network_clearedRounds") ?? AccessTools.PropertySetter(arenaType, "clearedRounds"); if (methodInfo != null) { methodInfo.Invoke(arena, new object[1] { num }); } else { AccessTools.Field(arenaType, "_clearedRounds")?.SetValue(arena, num); } AccessTools.PropertySetter(arenaType, "currentRound")?.Invoke(arena, new object[1] { num }); VoidCoinFlipPlugin.Log.LogInfo((object)$"Void Fields: rounds cleared set to {num}/{num}."); } catch (Exception ex) { VoidCoinFlipPlugin.Log.LogWarning((object)("Couldn't set the cleared-rounds counter. " + ex.Message)); } } private static bool EnterMissionCompleted(Type arenaType, object arena) { //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Expected O, but got Unknown try { Type type = AccessTools.Inner(arenaType, "MissionCompleted"); object? obj = AccessTools.Field(arenaType, "mainStateMachine")?.GetValue(arena); EntityStateMachine val = (EntityStateMachine)((obj is EntityStateMachine) ? obj : null); if (type == null || !Object.op_Implicit((Object)(object)val)) { VoidCoinFlipPlugin.Log.LogWarning((object)"Couldn't find the Void Fields 'mission completed' state."); return false; } if (val.state == null || ((object)val.state).GetType() != type) { val.SetNextState((EntityState)Activator.CreateInstance(type)); } VoidCoinFlipPlugin.Log.LogInfo((object)"Void Fields: switched to mission completed."); return true; } catch (Exception arg) { VoidCoinFlipPlugin.Log.LogWarning((object)$"Couldn't complete the Void Fields. {arg}"); return false; } } private static void SpawnCompletionPortals(Type arenaType, object arena) { if (!(AccessTools.Field(arenaType, "completionPortalSpawners")?.GetValue(arena) is PortalSpawner[] array) || array.Length == 0) { VoidCoinFlipPlugin.Log.LogWarning((object)"Void Fields: no completion portal spawners found."); return; } MethodInfo methodInfo = AccessTools.Method(typeof(PortalSpawner), "AttemptSpawnPortalServer", (Type[])null, (Type[])null); MethodInfo methodInfo2 = AccessTools.PropertySetter(typeof(PortalSpawner), "NetworkwillSpawn"); if (methodInfo == null) { VoidCoinFlipPlugin.Log.LogWarning((object)"Void Fields: couldn't find how to spawn the completion portal."); return; } PortalSpawner[] array2 = array; foreach (PortalSpawner val in array2) { if (!Object.op_Implicit((Object)(object)val)) { continue; } try { object? obj = AccessTools.Field(typeof(PortalSpawner), "requiredExpansion")?.GetValue(val); ExpansionDef val2 = (ExpansionDef)((obj is ExpansionDef) ? obj : null); if (val2 != null && Object.op_Implicit((Object)(object)val2) && Object.op_Implicit((Object)(object)Run.instance) && !Run.instance.IsExpansionEnabled(val2)) { VoidCoinFlipPlugin.Log.LogInfo((object)("Void Fields: skipping " + ((Object)val).name + " (needs " + ((Object)val2).name + ").")); } else { methodInfo2?.Invoke(val, new object[1] { true }); object obj2 = ((methodInfo.GetParameters().Length == 0) ? methodInfo.Invoke(val, null) : null); VoidCoinFlipPlugin.Log.LogInfo((object)string.Format("Void Fields: completion portal from {0} -> {1}.", ((Object)val).name, obj2 ?? "attempted")); } } catch (Exception ex) { VoidCoinFlipPlugin.Log.LogWarning((object)("Void Fields: couldn't spawn the portal from " + ((Object)val).name + ". " + (ex.InnerException?.Message ?? ex.Message))); } } } private static void StopFog() { Type type = AccessTools.TypeByName("RoR2.FogDamageController"); if (type == null) { return; } int num = 0; foreach (Behaviour item in Object.FindObjectsOfType(type).OfType<Behaviour>()) { if (item.enabled) { item.enabled = false; num++; } } if (num > 0) { VoidCoinFlipPlugin.Log.LogInfo((object)$"Turned off {num} void fog source(s)."); } } private static void StopSpawning(Type arenaType, object arena) { if (AccessTools.Field(arenaType, "combatDirectors")?.GetValue(arena) is CombatDirector[] source) { { foreach (CombatDirector item in source.Where((CombatDirector d) => Object.op_Implicit((Object)(object)d))) { ((Behaviour)item).enabled = false; } return; } } CombatDirector[] array = Object.FindObjectsOfType<CombatDirector>(); for (int num = 0; num < array.Length; num++) { ((Behaviour)array[num]).enabled = false; } } private static void ClearMonsters() { //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Invalid comparison between Unknown and I4 //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) foreach (CharacterMaster item in CharacterMaster.readOnlyInstancesList.ToList()) { if (Object.op_Implicit((Object)(object)item) && (int)item.teamIndex == 2) { CharacterBody body = item.GetBody(); if (Object.op_Implicit((Object)(object)body) && Object.op_Implicit((Object)(object)body.healthComponent) && body.healthComponent.alive) { body.healthComponent.Suicide((GameObject)null, (GameObject)null, default(DamageTypeCombo)); } } } } public static void LockVents() { if (!NetworkServer.active) { return; } ArenaMissionController instance = ArenaMissionController.instance; if (!Object.op_Implicit((Object)(object)instance) || instance.nullWards == null) { return; } int num = 0; GameObject[] nullWards = instance.nullWards; foreach (GameObject val in nullWards) { if (!Object.op_Implicit((Object)(object)val)) { continue; } PurchaseInteraction[] componentsInChildren = val.GetComponentsInChildren<PurchaseInteraction>(true); foreach (PurchaseInteraction val2 in componentsInChildren) { if (val2.available) { val2.SetAvailable(false); num++; } } } if (num > 0) { VoidCoinFlipPlugin.Log.LogInfo((object)$"Void Fields: locked {num} cell vent(s)."); } } public static bool IsCellVent(PurchaseInteraction pi) { ArenaMissionController instance = ArenaMissionController.instance; if (!Object.op_Implicit((Object)(object)pi) || !Object.op_Implicit((Object)(object)instance) || instance.nullWards == null) { return false; } return instance.nullWards.Any((GameObject w) => Object.op_Implicit((Object)(object)w) && ((Component)pi).transform.IsChildOf(w.transform)); } private static void CompleteCells(Type arenaType, object arena) { //IL_00de: Unknown result type (might be due to invalid IL or missing references) //IL_00e8: Expected O, but got Unknown Type completeState = AccessTools.TypeByName("EntityStates.Missions.Arena.NullWard.Complete"); if (completeState == null || !(AccessTools.Field(arenaType, "nullWards")?.GetValue(arena) is GameObject[] array)) { return; } int num = 0; GameObject[] array2 = array; foreach (GameObject val in array2) { if (!Object.op_Implicit((Object)(object)val)) { continue; } try { EntityStateMachine[] components = val.GetComponents<EntityStateMachine>(); EntityStateMachine val2 = ((IEnumerable<EntityStateMachine>)components).FirstOrDefault((Func<EntityStateMachine, bool>)((EntityStateMachine m) => m.state != null && ((object)m.state).GetType().Namespace == completeState.Namespace)) ?? components.FirstOrDefault(); if (Object.op_Implicit((Object)(object)val2) && (val2.state == null || !(((object)val2.state).GetType() == completeState))) { val2.SetState((EntityState)Activator.CreateInstance(completeState)); num++; } } catch (Exception ex) { VoidCoinFlipPlugin.Log.LogWarning((object)("Couldn't finish cell " + ((Object)val).name + ". " + ex.Message)); } } VoidCoinFlipPlugin.Log.LogInfo((object)$"Void Fields: {num} cell(s) set to finished."); } } internal static class WinChime { private const string Candidates = "Play_UI_obj_nullWard_complete,Play_UI_teleporter_event_complete,Play_UI_achievementUnlock"; public const string WinMarker = "The void trials are passed"; private static string working; private static string lastSeen; public static void Play() { GameObject val = SoundSource(); if (!Object.op_Implicit((Object)(object)val)) { return; } string[] array = ((working == null) ? (from s in "Play_UI_obj_nullWard_complete,Play_UI_teleporter_event_complete,Play_UI_achievementUnlock".Split(',') select s.Trim() into s where s.Length > 0 select s).ToArray() : new string[1] { working }); foreach (string text in array) { uint num2 = 0u; try { num2 = Util.PlaySound(text, val); } catch (Exception ex) { VoidCoinFlipPlugin.Log.LogWarning((object)("Win chime '" + text + "' failed: " + ex.Message)); } if (num2 != 0) { if (working == null) { VoidCoinFlipPlugin.Log.LogInfo((object)("Win chime: using '" + text + "'.")); } working = text; return; } VoidCoinFlipPlugin.Log.LogInfo((object)("Win chime: the game has no sound named '" + text + "', trying the next one.")); } VoidCoinFlipPlugin.Log.LogWarning((object)"Win chime: none of the game sounds were found."); } private static GameObject SoundSource() { LocalUser firstLocalUser = LocalUserManager.GetFirstLocalUser(); CharacterBody val = ((firstLocalUser != null) ? firstLocalUser.cachedBody : null); if (Object.op_Implicit((Object)(object)val)) { return ((Component)val).gameObject; } if (Object.op_Implicit((Object)(object)Camera.main)) { return ((Component)Camera.main).gameObject; } if (!Object.op_Implicit((Object)(object)RoR2Application.instance)) { return null; } return ((Component)RoR2Application.instance).gameObject; } public static void OnChatChanged() { if (NetworkServer.active) { return; } ReadOnlyCollection<string> readOnlyLog = Chat.readOnlyLog; if (readOnlyLog != null && readOnlyLog.Count != 0) { string text = readOnlyLog[readOnlyLog.Count - 1]; if (text != null && text.Contains("The void trials are passed") && text != lastSeen) { lastSeen = text; Play(); } } } } }