using 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.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using System.Threading; using System.Threading.Tasks; using Archipelago.MultiClient.Net; using Archipelago.MultiClient.Net.BounceFeatures.DeathLink; using Archipelago.MultiClient.Net.Enums; using Archipelago.MultiClient.Net.Helpers; using Archipelago.MultiClient.Net.MessageLog.Messages; using Archipelago.MultiClient.Net.Models; using BaboonAPI.Hooks; using BaboonAPI.Hooks.Initializer; using BaboonAPI.Hooks.Tracks; using BaboonAPI.Hooks.Tracks.Collections; using BaboonAPI.Utility; using BepInEx; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using Microsoft.FSharp.Core; using Newtonsoft.Json.Linq; using UnityEngine; using UnityEngine.Networking; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: AssemblyCompany("APTromboneChampMod")] [assembly: AssemblyConfiguration("Debug")] [assembly: AssemblyFileVersion("0.0.1.0")] [assembly: AssemblyInformationalVersion("0.0.1+1d5ba63e0afd5e6c76e3af95f0507287ea344881")] [assembly: AssemblyProduct("AP Trombone")] [assembly: AssemblyTitle("APTromboneChampMod")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.0.1.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 APTromboneChampMod { public static class APHandler { [Serializable] [CompilerGenerated] private sealed class <>c { public static readonly <>c <>9 = new <>c(); public static Func <>9__18_0; public static Func <>9__25_1; public static Func <>9__26_0; public static Func <>9__27_0; public static ItemReceivedHandler <>9__30_0; public static CheckedLocationsUpdatedHandler <>9__30_1; public static Func <>9__30_9; public static Action <>9__30_2; public static SocketClosedHandler <>9__30_3; public static MessageReceivedHandler <>9__30_4; public static Func <>9__30_12; public static Func <>9__30_13; public static DataStorageUpdatedHandler <>9__30_5; public static Func <>9__30_14; public static Action> <>9__30_6; public static DeathLinkReceivedHandler <>9__30_7; public static Func <>9__37_1; public static Action> <>9__37_0; internal bool b__18_0(long id) { return !BeatenTracks.Contains(id); } internal bool b__25_1(Hint hint) { return hint.ReceivingPlayer == APSlot && hint.ItemId == 1011; } internal bool b__26_0(Hint hint) { return hint.ReceivingPlayer == APSlot && hint.ItemId == 1001; } internal bool b__27_0(Hint hint) { return hint.ReceivingPlayer == APSlot && hint.ItemId == 1004; } internal void b__30_0(ReceivedItemsHelper helper) { List list = new List(); while (helper.Any()) { ItemInfo val = helper.PeekItem(); if (val.ItemId == 1003) { if (DateTimeOffset.Now.ToUnixTimeMilliseconds() - LastFunFact > 1000) { LastFunFact = DateTimeOffset.Now.ToUnixTimeMilliseconds(); if (UnseenFacts.Count == 0) { UnseenFacts.AddRange(FunFacts); ListExtensions.Shuffle((IList)UnseenFacts); } APSession.Say("FUN FACT: " + UnseenFacts[0]); UnseenFacts.RemoveAt(0); } } else if (val.ItemId != 1002) { long itemId = val.ItemId; if (((ulong)(itemId - 1005) <= 4uL) ? true : false) { if (DateTimeOffset.Now.ToUnixTimeMilliseconds() - ConnectTime > 10000) { long itemId2 = val.ItemId; long num = itemId2; long num2 = num - 1005; if ((ulong)num2 <= 4uL) { switch (num2) { case 0L: APTrapController.AddTrap(APTrapController.TrapType.FlipControls); break; case 1L: APTrapController.AddTrap(APTrapController.TrapType.SilenceTrack); break; case 2L: APTrapController.AddTrap(APTrapController.TrapType.SilenceTrombone); break; case 3L: APTrapController.AddTrap(APTrapController.TrapType.HideNotes); break; case 4L: APTrapController.AddTrap(APTrapController.TrapType.NoBreath); break; } } } } else { APTrapController.TrapType trap = APTrapController.TrapType.GetTrap(val.ItemId); if (trap != null) { if (DateTimeOffset.Now.ToUnixTimeMilliseconds() - ConnectTime > 10000) { APTrapController.AddTrap(trap); } } else { list.Add(val.ItemId); } } } helper.DequeueItem(); } if (list.Count > 0) { ItemHandler.OnReceivedItems(list); } } internal void b__30_1(ReadOnlyCollection locs) { lock (APSentLocations) { using IEnumerator enumerator = locs.GetEnumerator(); while (enumerator.MoveNext()) { <>c__DisplayClass30_0 CS$<>8__locals4 = new <>c__DisplayClass30_0 { loc = enumerator.Current }; if (APSentLocations.Contains(CS$<>8__locals4.loc)) { continue; } APSentLocations.Add(CS$<>8__locals4.loc); Hint[] aPReceivedHints = APReceivedHints; foreach (Hint val in aPReceivedHints) { if (val.FindingPlayer == APSlot && val.LocationId == CS$<>8__locals4.loc) { APReceivedHints = APReceivedHints.Where((Hint it) => it.FindingPlayer != APSlot || it.LocationId != CS$<>8__locals4.loc).ToArray(); break; } } } } OnTrackAvailabilityChanged(); } internal void b__30_2(Hint[] hints) { APReceivedHints = hints.Where((Hint hint) => !hint.Found).ToArray(); OnHintsChanged(); } internal bool b__30_9(Hint hint) { return !hint.Found; } internal void b__30_3(string reason) { ArchipelagoPlugin.Logger.LogInfo((object)("Socket closed: " + reason)); APSlot = -1; APSession = null; OnWorldSettingsChanged(); } internal void b__30_4(LogMessage message) { //IL_018f: Unknown result type (might be due to invalid IL or missing references) //IL_0194: Unknown result type (might be due to invalid IL or missing references) //IL_01a0: Unknown result type (might be due to invalid IL or missing references) //IL_01ae: Unknown result type (might be due to invalid IL or missing references) //IL_01b6: Unknown result type (might be due to invalid IL or missing references) //IL_01bd: Unknown result type (might be due to invalid IL or missing references) //IL_01c8: Unknown result type (might be due to invalid IL or missing references) //IL_01d1: Unknown result type (might be due to invalid IL or missing references) //IL_01df: Unknown result type (might be due to invalid IL or missing references) //IL_01ed: Unknown result type (might be due to invalid IL or missing references) //IL_01f4: Unknown result type (might be due to invalid IL or missing references) //IL_01fa: Unknown result type (might be due to invalid IL or missing references) //IL_0203: Unknown result type (might be due to invalid IL or missing references) //IL_021b: Expected O, but got Unknown HintItemSendLogMessage val = (HintItemSendLogMessage)(object)((message is HintItemSendLogMessage) ? message : null); if (val != null) { if (!((ItemSendLogMessage)val).IsRelatedToActivePlayer) { return; } <>c__DisplayClass30_1 CS$<>8__locals14 = new <>c__DisplayClass30_1 { sender = ((ItemSendLogMessage)val).Sender.Slot, receiver = ((ItemSendLogMessage)val).Receiver.Slot }; bool isFound = val.IsFound; long itemId = ((ItemSendLogMessage)val).Item.ItemId; CS$<>8__locals14.location = ((ItemSendLogMessage)val).Item.LocationId; bool flag = false; Hint[] aPReceivedHints = APReceivedHints; foreach (Hint val2 in aPReceivedHints) { if (val2.FindingPlayer != CS$<>8__locals14.sender || val2.ReceivingPlayer != CS$<>8__locals14.receiver || val2.LocationId != CS$<>8__locals14.location) { continue; } flag = true; if (isFound) { APReceivedHints = APReceivedHints.Where((Hint it) => it.FindingPlayer != CS$<>8__locals14.sender || it.ReceivingPlayer != CS$<>8__locals14.receiver || it.LocationId != CS$<>8__locals14.location).ToArray(); } OnHintsChanged(); break; } if (!isFound && !flag) { Hint[] aPReceivedHints2 = APReceivedHints; int num = 0; Hint[] array = (Hint[])(object)new Hint[1 + aPReceivedHints2.Length]; ReadOnlySpan readOnlySpan = new ReadOnlySpan(aPReceivedHints2); readOnlySpan.CopyTo(new Span(array).Slice(num, readOnlySpan.Length)); num += readOnlySpan.Length; array[num] = new Hint { Entrance = "", FindingPlayer = CS$<>8__locals14.sender, Found = false, ItemFlags = ((ItemSendLogMessage)val).Item.Flags, ItemId = itemId, LocationId = CS$<>8__locals14.location, ReceivingPlayer = CS$<>8__locals14.receiver, Status = (HintStatus)(((((ItemSendLogMessage)val).Item.Flags & 4) != 0) ? 20 : (((int)((ItemSendLogMessage)val).Item.Flags == 0) ? 10 : 30)) }; APReceivedHints = array; OnHintsChanged(); } if (!isFound && ArchipelagoPlugin.SendChatToLog) { ArchipelagoPlugin.Logger.LogInfo((object)((object)message).ToString()); } return; } ItemSendLogMessage val3 = (ItemSendLogMessage)(object)((message is ItemSendLogMessage) ? message : null); if (val3 != null) { if (!val3.IsRelatedToActivePlayer) { return; } <>c__DisplayClass30_2 CS$<>8__locals17 = new <>c__DisplayClass30_2 { sender = val3.Sender.Slot, receiver = val3.Receiver.Slot, location = val3.Item.LocationId }; Hint[] aPReceivedHints3 = APReceivedHints; foreach (Hint val4 in aPReceivedHints3) { if (val4.FindingPlayer == CS$<>8__locals17.sender && val4.ReceivingPlayer == CS$<>8__locals17.receiver && val4.LocationId == CS$<>8__locals17.location) { APReceivedHints = APReceivedHints.Where((Hint it) => it.FindingPlayer != CS$<>8__locals17.sender || it.ReceivingPlayer != CS$<>8__locals17.receiver || it.LocationId != CS$<>8__locals17.location).ToArray(); OnHintsChanged(); break; } } if (ArchipelagoPlugin.SendChatToLog) { ArchipelagoPlugin.Logger.LogInfo((object)((object)message).ToString()); } } else if (ArchipelagoPlugin.SendChatToLog) { ArchipelagoPlugin.Logger.LogInfo((object)((object)message).ToString()); } } internal void b__30_5(JToken oldData, JToken newData, Dictionary args) { long[] beatenTracks = BeatenTracks; BeatenTracks = ((IEnumerable)newData).Select((JToken v) => v.ToObject()).ToArray(); if (HasGoaled()) { APSession.SetGoalAchieved(); } if (beatenTracks.Length != BeatenTracks.Length || beatenTracks.Any((long v) => !BeatenTracks.Contains(v))) { OnTrackAvailabilityChanged(); } } internal long b__30_12(JToken v) { return v.ToObject(); } internal bool b__30_13(long v) { return !BeatenTracks.Contains(v); } internal void b__30_6(Task task) { if (task.IsCompletedSuccessfully) { APReceivedHints = task.Result.Where((Hint hint) => !hint.Found).ToArray(); OnHintsChanged(); } } internal bool b__30_14(Hint hint) { return !hint.Found; } internal void b__30_7(DeathLink deathLinkObj) { ArchipelagoPlugin.Logger.LogInfo((object)("Received death from " + deathLinkObj.Source + ": " + deathLinkObj.Cause)); if (ArchipelagoPlugin.DeathLinkInboundMode != 0) { DeathLinkCounter++; ArchipelagoPlugin.Logger.LogInfo((object)$"DeathLink counter incremented to {DeathLinkCounter}."); } else { ArchipelagoPlugin.Logger.LogInfo((object)"Ignoring death, DeathLink is disabled."); } } internal bool b__37_1(TrackCollection coll) { return coll._unique_id == "all"; } internal void b__37_0(FSharpResult _) { } } [CompilerGenerated] private sealed class <>c__DisplayClass30_0 { public long loc; public Func <>9__8; internal bool b__8(Hint it) { return it.FindingPlayer != APSlot || it.LocationId != loc; } } [CompilerGenerated] private sealed class <>c__DisplayClass30_1 { public int sender; public int receiver; public long location; public Func <>9__10; internal bool b__10(Hint it) { return it.FindingPlayer != sender || it.ReceivingPlayer != receiver || it.LocationId != location; } } [CompilerGenerated] private sealed class <>c__DisplayClass30_2 { public int sender; public int receiver; public long location; public Func <>9__11; internal bool b__11(Hint it) { return it.FindingPlayer != sender || it.ReceivingPlayer != receiver || it.LocationId != location; } } public static APSettings WorldSettings = new APSettings(); public static Track[] FilteredTracks = Array.Empty(); public static Track[] AvailableTracks = Array.Empty(); public static long[] BeatenTracks = Array.Empty(); public static Track? GoalTrack = null; public static ArchipelagoSession APSession = null; public static DeathLinkService DeathLink = null; public static int DeathLinkCounter = 0; public static int APTeam = -1; public static int APSlot = -1; public static readonly Version APVersion = new Version(0, 6, 7); public static readonly List APSentLocations = new List(); public static Hint[] APReceivedHints = Array.Empty(); private static readonly string[] RatingToString = new string[4] { "C", "B", "A", "S" }; public static long ConnectTime; private static long LastFunFact; private static readonly string[] FunFacts = new string[26] { "It takes one-thousand workers a full year to produce a single trombone.", "The trombone is related to the trumpet (they are cousins).", "The trombone is not related to the French Horn (they are just friends).", "Some claim that Mozart's last words before dying were \"At least I got to use a trombone.\"", "A student's trombone generally costs between $100 and $300, but a professional trombone can cost over two billion dollars.", "To this day, scientists don't really know how a trombone makes sound.", "A professional trombone player is known as a \"tromboner\".", "Thirty-four countries have outlawed the use of the trombone. In six countries, playing trombone is punishable by death.", "Trombones contain \"spit valves\" that allow you to blow gobs of your nasty spit all over the floor.", "Without trombones, there could never have been \"ska\" music. Draw your own conclusions from this factoid.", "The average baboon can live to be over 300 years old.", "There are more baboons on Earth than humans.", "Prehistoric trombones were forty feet long and could weigh over six hundred pounds.", "Trombones do not float in water, so do not accidentally drop your trombone into the river last week.", "Cows love the sound of a trombone (because they are smart).", "Playing trombone in your apartment is a great way to make friends with your neighbors.", "Despite its name, the trombone does not have any bones.", "There are between 2 and 4 spiders living inside the average trombone.", "The first trombone was invented in 20,000,000 B.C.", "If you placed all of the trombones on Earth end-to-end, they would wrap around the solar system 4 times.", "There are more trombones on Earth than there are humans.", "The highest note playable on trombones is so high-pitched that only certain species of bats can hear it.", "The world record for \"Most Trombones Owned\" is held by Mike Brass of Omaha, Nebraska. He owns two trombones.", "It takes over three thousand tons of brass to produce a single trombone.", "In real life, there are over nine songs that feature a trombone.", "In England, \"trombone\" is spelled \"troumboune\"." }; private static List UnseenFacts = new List(); private static object TrackUpdateLock = new object(); public static Track? FindTrack(string name) { Track value = FilteredTracks.FirstOrDefault((Track track) => track.Name.ToLower() == name.ToLower()); if (value.Name.ToLower() != name.ToLower()) { return null; } return value; } public static bool IsTrackAvailable(Track track) { if (APSession == null || APSlot == -1) { return false; } if (!FilteredTracks.Contains(track)) { return false; } if (WorldSettings.TrackGating && !ItemHandler.HasTrack(track.ID)) { return false; } if (track.Difficulty > WorldSettings.MinDiff) { if (WorldSettings.DifficultyGating == APSettings.DiffGateType.ON && !ItemHandler.HasDifficulty(track.Difficulty)) { return false; } if (WorldSettings.DifficultyGating == APSettings.DiffGateType.PROG) { int num = track.Difficulty - WorldSettings.MinDiff; if (num > ItemHandler.ProgressiveDifficulties) { return false; } } } if (track.Name == WorldSettings.GoalTrack) { int hotDogs = ItemHandler.HotDogs; if (hotDogs < WorldSettings.HotDogs) { return false; } } return true; } public static string GetRatingString(int rating) { if (rating < 0) { rating = 0; } if (rating >= RatingToString.Length) { rating = RatingToString.Length - 1; } return RatingToString[rating]; } public static int GetRequiredRating() { int initialRating = WorldSettings.InitialRating; return initialRating - ItemHandler.RankReductions; } public static long[] SendTrack(Track track, bool beaten) { //IL_015e: Unknown result type (might be due to invalid IL or missing references) //IL_0168: Expected O, but got Unknown if (APSession == null || APSlot == -1) { return Array.Empty(); } if (!IsTrackAvailable(track)) { return Array.Empty(); } if (DeathLinkCounter > 0) { if (ArchipelagoPlugin.DeathLinkInboundMode == 0) { DeathLinkCounter = 0; ArchipelagoPlugin.Logger.LogInfo((object)"DeathLink is disabled, resetting death counter."); } else { if (ArchipelagoPlugin.DeathLinkInboundMode == 1) { DeathLinkCounter = 0; ArchipelagoPlugin.Logger.LogInfo((object)"DeathLink blocked score entry, counter reset."); return Array.Empty(); } if (ArchipelagoPlugin.DeathLinkInboundMode == 2) { DeathLinkCounter--; ArchipelagoPlugin.Logger.LogInfo((object)$"DeathLink blocked score entry, counter is now {DeathLinkCounter}."); return Array.Empty(); } DeathLinkCounter = 0; ArchipelagoPlugin.Logger.LogInfo((object)"DeathLink mode is immediate, resetting death counter."); } } if (!beaten && ArchipelagoPlugin.DeathLinkOutbound) { ArchipelagoPlugin.Logger.LogInfo((object)"Failed to beat track, sending death."); DeathLink.SendDeathLink(new DeathLink(APSession.Players.ActivePlayer.Alias, APSession.Players.ActivePlayer.Alias + " didn't doot hard enough.")); } long[] array = ((!beaten) ? new long[1] { track.ID } : new long[2] { track.ID, track.ID + 1000 }).Where((long id) => !BeatenTracks.Contains(id)).ToArray(); if (array.Length == 0) { return Array.Empty(); } APSession.Locations.CompleteLocationChecksAsync(array); IDataStorageHelper dataStorage = APSession.DataStorage; string text = $"_{APTeam}_{APSlot}_beaten"; dataStorage[text] += (IEnumerable)new long[1] { track.ID }; long[] beatenTracks = BeatenTracks; int num = 0; long[] array2 = new long[1 + beatenTracks.Length]; ReadOnlySpan readOnlySpan = new ReadOnlySpan(beatenTracks); readOnlySpan.CopyTo(new Span(array2).Slice(num, readOnlySpan.Length)); num += readOnlySpan.Length; array2[num] = track.ID; BeatenTracks = array2; if (HasGoaled()) { APSession.SetGoalAchieved(); if (APSession.Players.ActivePlayer.Alias != "DONE") { APSession.Say("!alias DONE"); } } OnTrackAvailabilityChanged(); return array; } public static bool CanHint() { if (APSession == null || APSlot == -1) { return false; } return APSession.RoomState.HintPoints >= APSession.RoomState.HintCost; } public static string FormatItemHint(Hint hint) { //IL_0084: Unknown result type (might be due to invalid IL or missing references) if (hint == null) { return "-"; } if (hint.ReceivingPlayer == APSlot) { return APSession.Items.GetItemName(hint.ItemId, (string)null); } PlayerInfo playerInfo = APSession.Players.GetPlayerInfo(hint.ReceivingPlayer); string game = playerInfo.Game; string itemName = APSession.Items.GetItemName(hint.ItemId, game); return $"{playerInfo.Alias}'s {itemName} ({hint.Status})"; } public static string FormatLocationString(Hint hint) { if (hint == null) { return "-"; } if (hint.FindingPlayer == APSlot) { return APSession.Locations.GetLocationNameFromId(hint.LocationId, (string)null); } PlayerInfo playerInfo = APSession.Players.GetPlayerInfo(hint.FindingPlayer); string game = playerInfo.Game; string locationNameFromId = APSession.Locations.GetLocationNameFromId(hint.LocationId, game); if (hint.Entrance != "") { return playerInfo.Alias + "'s " + locationNameFromId + " (" + hint.Entrance + ")"; } return playerInfo.Alias + "'s " + locationNameFromId; } public static string FormatFullHint(Hint hint) { //IL_0138: Unknown result type (might be due to invalid IL or missing references) if (hint == null) { return "-"; } PlayerInfo playerInfo = APSession.Players.GetPlayerInfo(hint.FindingPlayer); PlayerInfo playerInfo2 = APSession.Players.GetPlayerInfo(hint.ReceivingPlayer); string locationNameFromId = APSession.Locations.GetLocationNameFromId(hint.LocationId, playerInfo.Game); string itemName = APSession.Items.GetItemName(hint.ItemId, playerInfo2.Game); bool flag = hint.ReceivingPlayer == hint.FindingPlayer; string text = ""; if (hint.Entrance != "") { text = " (" + hint.Entrance + ")"; } if (flag) { return itemName + " is at " + locationNameFromId; } string text2 = playerInfo2.Alias + "'s "; if (playerInfo2.Slot == APSlot) { text2 = ""; } string text3 = playerInfo.Alias + "'s "; if (playerInfo.Slot == APSlot) { text3 = ""; } string text4 = $" ({hint.Status})"; if (playerInfo2.Slot == APSlot) { text4 = ""; } return text2 + itemName + " is at " + text3 + locationNameFromId + text + text4; } public static TrackHints GetTrackHints(Track track) { TrackHints result = new TrackHints(); if (WorldSettings.TrackGating && !ItemHandler.HasTrack(track.ID)) { Hint trackUnlock = null; Hint[] aPReceivedHints = APReceivedHints; foreach (Hint val in aPReceivedHints) { if (val.ReceivingPlayer == APSlot && val.ItemId == track.ID) { trackUnlock = val; break; } } result.TrackUnlock = trackUnlock; } if (track.Difficulty > WorldSettings.MinDiff) { if (WorldSettings.DifficultyGating == APSettings.DiffGateType.ON && !ItemHandler.HasDifficulty(track.Difficulty)) { Hint val2 = null; Hint[] aPReceivedHints2 = APReceivedHints; foreach (Hint val3 in aPReceivedHints2) { if (val3.ReceivingPlayer == APSlot && val3.ItemId == 1010L + (long)track.Difficulty) { val2 = val3; break; } } result.DifficultyUnlocks = (Hint[])(object)new Hint[1] { val2 }; } if (WorldSettings.DifficultyGating == APSettings.DiffGateType.PROG) { int num = track.Difficulty - WorldSettings.MinDiff; int progressiveDifficulties = ItemHandler.ProgressiveDifficulties; if (progressiveDifficulties < num) { int num2 = WorldSettings.MaxDiff - WorldSettings.MinDiff; num2 -= progressiveDifficulties; Hint[] array = (Hint[])(object)new Hint[num2]; int num3 = 0; Hint[] aPReceivedHints3 = APReceivedHints; foreach (Hint val4 in aPReceivedHints3) { if (val4.ReceivingPlayer == APSlot && val4.ItemId == 1011) { array[num3++] = val4; } } result.DifficultyUnlocks = array; } } } if (!APSentLocations.Contains(track.ID)) { Hint playReward = null; Hint[] aPReceivedHints4 = APReceivedHints; foreach (Hint val5 in aPReceivedHints4) { if (val5.FindingPlayer == APSlot && val5.LocationId == track.ID) { playReward = val5; break; } } result.PlayReward = playReward; } if (!APSentLocations.Contains(track.ID + 1000)) { Hint beatReward = null; Hint[] aPReceivedHints5 = APReceivedHints; foreach (Hint val6 in aPReceivedHints5) { if (val6.FindingPlayer == APSlot && val6.LocationId == track.ID + 1000) { beatReward = val6; break; } } result.BeatReward = beatReward; } return result; } public static void TryHintTrack(Track track) { if (WorldSettings.TrackGating && CanHint() && !APReceivedHints.Any((Hint hint) => hint.ReceivingPlayer == APSlot && hint.ItemId == track.ID)) { string itemName = APSession.Items.GetItemName(track.ID, (string)null); if (itemName != null) { APSession.Say("!hint " + itemName); } } } public static void TryHintDifficulty(int diff) { if (WorldSettings.DifficultyGating == APSettings.DiffGateType.OFF || !CanHint() || (WorldSettings.DifficultyGating == APSettings.DiffGateType.ON && APReceivedHints.Any((Hint hint) => hint.ReceivingPlayer == APSlot && hint.ItemId == 1010L + (long)diff))) { return; } if (WorldSettings.DifficultyGating == APSettings.DiffGateType.PROG) { diff = 1; int num = WorldSettings.MaxDiff - WorldSettings.MinDiff - ItemHandler.ProgressiveDifficulties; if (num == 0) { return; } int num2 = APReceivedHints.Count((Hint hint) => hint.ReceivingPlayer == APSlot && hint.ItemId == 1011); if (num2 >= num) { return; } } string itemName = APSession.Items.GetItemName(1010L + (long)diff, (string)null); if (itemName != null) { APSession.Say("!hint " + itemName); } } public static void TryHintRankReduction() { if (WorldSettings.GoalRating == WorldSettings.InitialRating || !CanHint()) { return; } int num = WorldSettings.InitialRating - WorldSettings.GoalRating - ItemHandler.RankReductions; if (num == 0) { return; } int num2 = APReceivedHints.Count((Hint hint) => hint.ReceivingPlayer == APSlot && hint.ItemId == 1001); if (num2 < num) { string itemName = APSession.Items.GetItemName(1001L, (string)null); if (itemName != null) { APSession.Say("!hint " + itemName); } } } public static void TryHintHotDog() { if (WorldSettings.HotDogs == 0 || !CanHint()) { return; } int num = WorldSettings.HotDogs + WorldSettings.ExtraHotDogs; int hotDogs = ItemHandler.HotDogs; if (hotDogs >= WorldSettings.HotDogs) { return; } num -= hotDogs; hotDogs = APReceivedHints.Count((Hint hint) => hint.ReceivingPlayer == APSlot && hint.ItemId == 1004); if (hotDogs < num) { string itemName = APSession.Items.GetItemName(1004L, (string)null); if (itemName != null) { APSession.Say("!hint " + itemName); } } } public static bool HasGoaled() { if (WorldSettings.GoalTracks == 0) { if (GoalTrack.HasValue) { if (BeatenTracks.Contains(GoalTrack.Value.ID)) { return true; } } else { ArchipelagoPlugin.Logger.LogWarning((object)"Goal tracks is 0 and no goal track is set!"); } return false; } return BeatenTracks.Length >= WorldSettings.GoalTracks; } public static void ConnectToAP(string host, int port, string slot, string pass) { //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Expected O, but got Unknown //IL_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Expected O, but got Unknown //IL_012b: Unknown result type (might be due to invalid IL or missing references) //IL_0130: Unknown result type (might be due to invalid IL or missing references) //IL_0136: Expected O, but got Unknown //IL_015a: Unknown result type (might be due to invalid IL or missing references) //IL_015f: Unknown result type (might be due to invalid IL or missing references) //IL_0165: Expected O, but got Unknown //IL_026c: Unknown result type (might be due to invalid IL or missing references) //IL_0272: Expected O, but got Unknown //IL_01e4: Unknown result type (might be due to invalid IL or missing references) //IL_01eb: Expected O, but got Unknown //IL_0344: Unknown result type (might be due to invalid IL or missing references) //IL_0349: Unknown result type (might be due to invalid IL or missing references) //IL_034f: Expected O, but got Unknown //IL_07b4: Unknown result type (might be due to invalid IL or missing references) //IL_023a: Unknown result type (might be due to invalid IL or missing references) //IL_0246: Unknown result type (might be due to invalid IL or missing references) //IL_0876: Unknown result type (might be due to invalid IL or missing references) //IL_087b: Unknown result type (might be due to invalid IL or missing references) //IL_0881: Expected O, but got Unknown ArchipelagoPlugin.Logger.LogInfo((object)$"Connecting to {host}:{port}"); ArchipelagoSession aPSession = APSession; if (aPSession != null) { aPSession.Socket.DisconnectAsync(); } APSession = null; APSlot = -1; APReceivedHints = Array.Empty(); ItemHandler.ResetItems(); APSentLocations.Clear(); OnWorldSettingsChanged(); try { APSession = ArchipelagoSessionFactory.CreateSession(host, port); IReceivedItemsHelper items = APSession.Items; object obj = <>c.<>9__30_0; if (obj == null) { ItemReceivedHandler val = delegate(ReceivedItemsHelper helper) { List list = new List(); while (helper.Any()) { ItemInfo val11 = helper.PeekItem(); if (val11.ItemId == 1003) { if (DateTimeOffset.Now.ToUnixTimeMilliseconds() - LastFunFact > 1000) { LastFunFact = DateTimeOffset.Now.ToUnixTimeMilliseconds(); if (UnseenFacts.Count == 0) { UnseenFacts.AddRange(FunFacts); ListExtensions.Shuffle((IList)UnseenFacts); } APSession.Say("FUN FACT: " + UnseenFacts[0]); UnseenFacts.RemoveAt(0); } } else if (val11.ItemId != 1002) { long itemId = val11.ItemId; if (((ulong)(itemId - 1005) <= 4uL) ? true : false) { if (DateTimeOffset.Now.ToUnixTimeMilliseconds() - ConnectTime > 10000) { long itemId2 = val11.ItemId; long num3 = itemId2; long num4 = num3 - 1005; if ((ulong)num4 <= 4uL) { switch (num4) { case 0L: APTrapController.AddTrap(APTrapController.TrapType.FlipControls); break; case 1L: APTrapController.AddTrap(APTrapController.TrapType.SilenceTrack); break; case 2L: APTrapController.AddTrap(APTrapController.TrapType.SilenceTrombone); break; case 3L: APTrapController.AddTrap(APTrapController.TrapType.HideNotes); break; case 4L: APTrapController.AddTrap(APTrapController.TrapType.NoBreath); break; } } } } else { APTrapController.TrapType trap = APTrapController.TrapType.GetTrap(val11.ItemId); if (trap != null) { if (DateTimeOffset.Now.ToUnixTimeMilliseconds() - ConnectTime > 10000) { APTrapController.AddTrap(trap); } } else { list.Add(val11.ItemId); } } } helper.DequeueItem(); } if (list.Count > 0) { ItemHandler.OnReceivedItems(list); } }; <>c.<>9__30_0 = val; obj = (object)val; } items.ItemReceived += (ItemReceivedHandler)obj; ILocationCheckHelper locations = APSession.Locations; object obj2 = <>c.<>9__30_1; if (obj2 == null) { CheckedLocationsUpdatedHandler val2 = delegate(ReadOnlyCollection locs) { lock (APSentLocations) { foreach (long loc in locs) { if (!APSentLocations.Contains(loc)) { APSentLocations.Add(loc); Hint[] aPReceivedHints = APReceivedHints; foreach (Hint val11 in aPReceivedHints) { if (val11.FindingPlayer == APSlot && val11.LocationId == loc) { APReceivedHints = APReceivedHints.Where((Hint it) => it.FindingPlayer != APSlot || it.LocationId != loc).ToArray(); break; } } } } } OnTrackAvailabilityChanged(); }; <>c.<>9__30_1 = val2; obj2 = (object)val2; } locations.CheckedLocationsUpdated += (CheckedLocationsUpdatedHandler)obj2; APSession.Hints.TrackHints((Action)delegate(Hint[] hints) { APReceivedHints = hints.Where((Hint hint) => !hint.Found).ToArray(); OnHintsChanged(); }, true, (int?)null, (int?)null); IArchipelagoSocketHelper socket = APSession.Socket; object obj3 = <>c.<>9__30_3; if (obj3 == null) { SocketClosedHandler val3 = delegate(string reason) { ArchipelagoPlugin.Logger.LogInfo((object)("Socket closed: " + reason)); APSlot = -1; APSession = null; OnWorldSettingsChanged(); }; <>c.<>9__30_3 = val3; obj3 = (object)val3; } socket.SocketClosed += (SocketClosedHandler)obj3; IMessageLogHelper messageLog = APSession.MessageLog; object obj4 = <>c.<>9__30_4; if (obj4 == null) { MessageReceivedHandler val4 = delegate(LogMessage message) { //IL_018f: Unknown result type (might be due to invalid IL or missing references) //IL_0194: Unknown result type (might be due to invalid IL or missing references) //IL_01a0: Unknown result type (might be due to invalid IL or missing references) //IL_01ae: Unknown result type (might be due to invalid IL or missing references) //IL_01b6: Unknown result type (might be due to invalid IL or missing references) //IL_01bd: Unknown result type (might be due to invalid IL or missing references) //IL_01c8: Unknown result type (might be due to invalid IL or missing references) //IL_01d1: Unknown result type (might be due to invalid IL or missing references) //IL_01df: Unknown result type (might be due to invalid IL or missing references) //IL_01ed: Unknown result type (might be due to invalid IL or missing references) //IL_01f4: Unknown result type (might be due to invalid IL or missing references) //IL_01fa: Unknown result type (might be due to invalid IL or missing references) //IL_0203: Unknown result type (might be due to invalid IL or missing references) //IL_021b: Expected O, but got Unknown HintItemSendLogMessage val11 = (HintItemSendLogMessage)(object)((message is HintItemSendLogMessage) ? message : null); if (val11 != null) { if (((ItemSendLogMessage)val11).IsRelatedToActivePlayer) { int sender = ((ItemSendLogMessage)val11).Sender.Slot; int receiver = ((ItemSendLogMessage)val11).Receiver.Slot; bool isFound = val11.IsFound; long itemId = ((ItemSendLogMessage)val11).Item.ItemId; long location = ((ItemSendLogMessage)val11).Item.LocationId; bool flag = false; Hint[] aPReceivedHints = APReceivedHints; foreach (Hint val12 in aPReceivedHints) { if (val12.FindingPlayer == sender && val12.ReceivingPlayer == receiver && val12.LocationId == location) { flag = true; if (isFound) { APReceivedHints = APReceivedHints.Where((Hint it) => it.FindingPlayer != sender || it.ReceivingPlayer != receiver || it.LocationId != location).ToArray(); } OnHintsChanged(); break; } } if (!isFound && !flag) { Hint[] aPReceivedHints2 = APReceivedHints; int num3 = 0; Hint[] array = (Hint[])(object)new Hint[1 + aPReceivedHints2.Length]; ReadOnlySpan readOnlySpan = new ReadOnlySpan(aPReceivedHints2); readOnlySpan.CopyTo(new Span(array).Slice(num3, readOnlySpan.Length)); num3 += readOnlySpan.Length; array[num3] = new Hint { Entrance = "", FindingPlayer = sender, Found = false, ItemFlags = ((ItemSendLogMessage)val11).Item.Flags, ItemId = itemId, LocationId = location, ReceivingPlayer = receiver, Status = (HintStatus)(((((ItemSendLogMessage)val11).Item.Flags & 4) != 0) ? 20 : (((int)((ItemSendLogMessage)val11).Item.Flags == 0) ? 10 : 30)) }; APReceivedHints = array; OnHintsChanged(); } if (!isFound && ArchipelagoPlugin.SendChatToLog) { ArchipelagoPlugin.Logger.LogInfo((object)((object)message).ToString()); } } } else { ItemSendLogMessage val13 = (ItemSendLogMessage)(object)((message is ItemSendLogMessage) ? message : null); if (val13 != null) { if (val13.IsRelatedToActivePlayer) { int sender2 = val13.Sender.Slot; int receiver2 = val13.Receiver.Slot; long location2 = val13.Item.LocationId; Hint[] aPReceivedHints3 = APReceivedHints; foreach (Hint val14 in aPReceivedHints3) { if (val14.FindingPlayer == sender2 && val14.ReceivingPlayer == receiver2 && val14.LocationId == location2) { APReceivedHints = APReceivedHints.Where((Hint it) => it.FindingPlayer != sender2 || it.ReceivingPlayer != receiver2 || it.LocationId != location2).ToArray(); OnHintsChanged(); break; } } if (ArchipelagoPlugin.SendChatToLog) { ArchipelagoPlugin.Logger.LogInfo((object)((object)message).ToString()); } } } else if (ArchipelagoPlugin.SendChatToLog) { ArchipelagoPlugin.Logger.LogInfo((object)((object)message).ToString()); } } }; <>c.<>9__30_4 = val4; obj4 = (object)val4; } messageLog.OnMessageReceived += (MessageReceivedHandler)obj4; ConnectTime = DateTimeOffset.Now.ToUnixTimeMilliseconds(); LoginResult val5 = APSession.TryConnectAndLogin("Trombone Champ", slot, (ItemsHandlingFlags)7, APVersion, Array.Empty(), (string)null, pass, true); ConnectTime = (LastFunFact = DateTimeOffset.Now.ToUnixTimeMilliseconds()); if (!val5.Successful) { ArchipelagoPlugin.Logger.LogWarning((object)$"Failed to connect to {host}:{port}"); LoginFailure val6 = (LoginFailure)val5; string[] errors = val6.Errors; foreach (string text in errors) { ArchipelagoPlugin.Logger.LogWarning((object)(" " + text)); } ConnectionRefusedError[] errorCodes = val6.ErrorCodes; foreach (ConnectionRefusedError val7 in errorCodes) { ArchipelagoPlugin.Logger.LogWarning((object)$" {val7}"); } return; } LoginSuccessful val8 = (LoginSuccessful)val5; APTeam = val8.Team; APSlot = val8.Slot; ArchipelagoPlugin.Logger.LogInfo((object)$"Successfully connected to {host}:{port} - Team: {APTeam}, Slot: {APSlot}"); APSession.DataStorage[$"_{APTeam}_{APSlot}_beaten"].Initialize((IEnumerable)new long[0]); DataStorageElement obj5 = APSession.DataStorage[$"_{APTeam}_{APSlot}_beaten"]; object obj6 = <>c.<>9__30_5; if (obj6 == null) { DataStorageUpdatedHandler val9 = delegate(JToken oldData, JToken newData, Dictionary args) { long[] beatenTracks = BeatenTracks; BeatenTracks = ((IEnumerable)newData).Select((JToken v) => v.ToObject()).ToArray(); if (HasGoaled()) { APSession.SetGoalAchieved(); } if (beatenTracks.Length != BeatenTracks.Length || beatenTracks.Any((long v) => !BeatenTracks.Contains(v))) { OnTrackAvailabilityChanged(); } }; <>c.<>9__30_5 = val9; obj6 = (object)val9; } obj5.OnValueChanged += (DataStorageUpdatedHandler)obj6; BeatenTracks = APSession.DataStorage[$"_{APTeam}_{APSlot}_beaten"].To(); WorldSettings.GoalTracks = int.Parse(val8.SlotData["goal"].ToString()); WorldSettings.GoalTrack = val8.SlotData["goal_track"].ToString(); if (WorldSettings.GoalTracks == 0) { ArchipelagoPlugin.Logger.LogInfo((object)("Goal track: " + WorldSettings.GoalTrack)); } else { ArchipelagoPlugin.Logger.LogInfo((object)$"Goal track count: {WorldSettings.GoalTracks}"); } WorldSettings.GoalRating = int.Parse(val8.SlotData["rating"].ToString()); WorldSettings.InitialRating = int.Parse(val8.SlotData["rating_start"].ToString()); ArchipelagoPlugin.Logger.LogInfo((object)$"Goal rating: {WorldSettings.GoalRating} | Initial Rating: {WorldSettings.InitialRating}"); WorldSettings.EasyTrackGap = int.Parse(val8.SlotData["easy_track"].ToString()); ArchipelagoPlugin.Logger.LogInfo((object)$"Easy Track Gap: {WorldSettings.EasyTrackGap}"); WorldSettings.HotDogs = int.Parse(val8.SlotData["hot_dogs"].ToString()); WorldSettings.ExtraHotDogs = int.Parse(val8.SlotData["extra_hot_dogs"].ToString()); ArchipelagoPlugin.Logger.LogInfo((object)$"Hot Dogs: {WorldSettings.HotDogs} + {WorldSettings.ExtraHotDogs}"); WorldSettings.TrackGating = int.Parse(val8.SlotData["track_gating"].ToString()) > 0; ArchipelagoPlugin.Logger.LogInfo((object)$"Track gating: {WorldSettings.TrackGating}"); WorldSettings.DifficultyGating = (APSettings.DiffGateType)int.Parse(val8.SlotData["difficulty_gating"].ToString()); ArchipelagoPlugin.Logger.LogInfo((object)$"Difficulty gating: {WorldSettings.DifficultyGating}"); WorldSettings.MinDiff = int.Parse(val8.SlotData["min_diff"].ToString()); WorldSettings.MaxDiff = int.Parse(val8.SlotData["max_diff"].ToString()); ArchipelagoPlugin.Logger.LogInfo((object)$"Difficulty range: {WorldSettings.MinDiff} - {WorldSettings.MaxDiff}"); WorldSettings.Unsafe = int.Parse(val8.SlotData["unsafe"].ToString()) != 0; ArchipelagoPlugin.Logger.LogInfo((object)$"Unsafe: {WorldSettings.Unsafe}"); WorldSettings.Celeste = int.Parse(val8.SlotData["celeste"].ToString()) != 0; ArchipelagoPlugin.Logger.LogInfo((object)$"Celeste DLC: {WorldSettings.Celeste}"); WorldSettings.PizzaTower = int.Parse(val8.SlotData["pizza_tower"].ToString()) != 0; ArchipelagoPlugin.Logger.LogInfo((object)$"Pizza Tower DLC: {WorldSettings.PizzaTower}"); WorldSettings.UndertaleDeltarune = int.Parse(val8.SlotData["undertale_deltarune"].ToString()) != 0; ArchipelagoPlugin.Logger.LogInfo((object)$"Undertale/Deltarune DLC: {WorldSettings.UndertaleDeltarune}"); WorldSettings.RemovedTracks = ((JToken)(JArray)val8.SlotData["removed_tracks"]).ToObject(); ArchipelagoPlugin.Logger.LogInfo((object)("Removed tracks: " + string.Join(", ", WorldSettings.RemovedTracks))); OnWorldSettingsChanged(); APSession.Hints.GetHintsAsync((int?)null, (int?)null).ContinueWith(delegate(Task task) { if (task.IsCompletedSuccessfully) { APReceivedHints = task.Result.Where((Hint hint) => !hint.Found).ToArray(); OnHintsChanged(); } }); DeathLink = DeathLinkProvider.CreateDeathLinkService(APSession); if (ArchipelagoPlugin.ShouldEnableDeathlink) { DeathLink.EnableDeathLink(); } DeathLinkService deathLink = DeathLink; object obj7 = <>c.<>9__30_7; if (obj7 == null) { DeathLinkReceivedHandler val10 = delegate(DeathLink deathLinkObj) { ArchipelagoPlugin.Logger.LogInfo((object)("Received death from " + deathLinkObj.Source + ": " + deathLinkObj.Cause)); if (ArchipelagoPlugin.DeathLinkInboundMode != 0) { DeathLinkCounter++; ArchipelagoPlugin.Logger.LogInfo((object)$"DeathLink counter incremented to {DeathLinkCounter}."); } else { ArchipelagoPlugin.Logger.LogInfo((object)"Ignoring death, DeathLink is disabled."); } }; <>c.<>9__30_7 = val10; obj7 = (object)val10; } deathLink.OnDeathLinkReceived += (DeathLinkReceivedHandler)obj7; } catch (Exception ex) { ArchipelagoPlugin.Logger.LogError((object)("Unusual error: " + ex.Message)); ArchipelagoPlugin.Logger.LogError((object)ex.StackTrace); } } public static void OnHintsChanged() { LevelSelectController val = Object.FindObjectOfType(); if (Object.op_Implicit((Object)(object)val)) { val.populateSongNames(false); } } public static void OnWorldSettingsChanged() { if (APSession == null || APSlot == -1) { WorldSettings.MinDiff = 2; WorldSettings.MaxDiff = 1; } FilteredTracks = APTracks.GetTrackList(WorldSettings).ToArray(); GoalTrack = APTracks.GetGoalTrack(WorldSettings, FilteredTracks); OnTrackAvailabilityChanged(); if (ArchipelagoPlugin.Instance.curGUI == 0 && APSlot != -1) { ArchipelagoPlugin.Instance.curGUI = 1; } if (ArchipelagoPlugin.Instance.curGUI == 1 && APSlot == -1) { ArchipelagoPlugin.Instance.curGUI = 0; } } public static void OnTrackAvailabilityChanged() { lock (TrackUpdateLock) { lock (APSentLocations) { AvailableTracks = FilteredTracks.Where(IsTrackAvailable).ToArray(); if (GlobalVariables.chosen_collection_index < 0 || GlobalVariables.chosen_collection_index >= GlobalVariables.all_track_collections.Count) { return; } TrackCollection val = GlobalVariables.all_track_collections[GlobalVariables.chosen_collection_index]; if (TrackCollectionListener.COLLECTIONS.TryGetValue(val._unique_id, out var value)) { List list = value.BuildTrackList().ToList(); TrackCollection allCollection = GlobalVariables.all_track_collections.First((TrackCollection coll) => coll._unique_id == "all"); val.all_tracks = list.Select((TromboneTrack track) => allCollection.all_tracks.First((SingleTrackData data) => data.trackname_short == track.trackname_short)).ToList(); val._trackcount = list.Count; LevelSelectController val2 = Object.FindObjectOfType(); if (Object.op_Implicit((Object)(object)val2)) { string trackname_short = val2.alltrackslist[val2.songindex].trackname_short; val2.selectNewCollection(true); val2.sortTracks(GlobalVariables.sortmode, false); int num = -1; for (int num2 = 0; num2 < val2.alltrackslist.Count; num2++) { if (val2.alltrackslist[num2].trackname_short == trackname_short) { num = num2; break; } } if (num != -1) { val2.songindex = num; GlobalVariables.levelselect_index = num; val2.populateSongNames(false); } else { val2.populateSongNames(true); } } } IEnumerator enumerator = TrackReloader.ReloadAll((Action)null).ForEach((Action>)delegate { }); while (enumerator.MoveNext()) { } } } } } public struct APSettings { public enum DiffGateType { OFF, ON, PROG } public int GoalTracks; public string GoalTrack; public int GoalRating; public int InitialRating; public int EasyTrackGap; public int HotDogs; public int ExtraHotDogs; public bool TrackGating; public DiffGateType DifficultyGating; public int MinDiff; public int MaxDiff; public bool Unsafe; public bool Celeste; public bool PizzaTower; public bool UndertaleDeltarune; public string[] RemovedTracks; public APSettings() { GoalTracks = 1; GoalTrack = null; GoalRating = 3; InitialRating = 3; EasyTrackGap = 0; HotDogs = 0; ExtraHotDogs = 0; TrackGating = false; DifficultyGating = DiffGateType.OFF; MinDiff = 1; MaxDiff = 10; Unsafe = true; Celeste = true; PizzaTower = true; UndertaleDeltarune = true; RemovedTracks = Array.Empty(); } } public readonly struct Track : IEquatable { public readonly long ID; public readonly string Name; public readonly int Difficulty; public readonly bool Unsafe; public readonly string DLC; public Track(long id, string name, int difficulty, bool allowUnsafe = false, string dlc = "Base") { ID = id; Name = name; Difficulty = difficulty; Unsafe = allowUnsafe; DLC = dlc; } public bool Equals(Track other) { return ID == other.ID; } public override bool Equals(object obj) { return obj is Track other && Equals(other); } public override int GetHashCode() { return (int)ID; } } public class APTracks { public static readonly Track[] TRACKS = new Track[119] { new Track(1L, "Are U Ready", 7), new Track(2L, "Arirang", 3), new Track(3L, "Auld Lang Syne", 7), new Track(4L, "Baboons!", 6), new Track(5L, "Bald Mountain", 7), new Track(6L, "Ball Game", 3), new Track(7L, "Barber of Seville", 7), new Track(8L, "Beethoven's Fifth", 7), new Track(9L, "Blue Danube", 5), new Track(10L, "Bumblebee", 9), new Track(11L, "Carol of the Bells", 7), new Track(12L, "Chop Waltz", 6), new Track(13L, "Commander Tokyo", 9), new Track(14L, "Danny Boy", 3), new Track(15L, "Danse Macabre", 8), new Track(16L, "Eine (CHAMP MIX)", 10), new Track(17L, "Eine Kleine", 5), new Track(18L, "Entertainer", 7), new Track(19L, "Four Seasons (Summer)", 9), new Track(20L, "Funiculi Funicula", 6), new Track(21L, "Gladiators", 8), new Track(22L, "God Save the King", 2), new Track(23L, "Gymnopédie", 5), new Track(24L, "Habanera", 5), new Track(25L, "Happy Birthday", 5), new Track(26L, "Hava Nagila", 5), new Track(27L, "Hello! Ma Baby", 6), new Track(28L, "Hino Do Brasil", 7), new Track(29L, "Hungarian Dance", 7, allowUnsafe: true), new Track(30L, "Hungarian Rhapsody", 9), new Track(31L, "Jarabe Tapatío", 9), new Track(32L, "Jasmine Flower", 3), new Track(33L, "Jingle Bells", 5), new Track(34L, "Korobeiniki", 7), new Track(35L, "Long-Tail Limbo", 5), new Track(36L, "Mars", 4), new Track(37L, "Marseillaise", 7), new Track(38L, "Martian Killbots", 3), new Track(39L, "Merry Gentlemen", 7), new Track(40L, "Mountain King", 8), new Track(41L, "O Canada", 3), new Track(42L, "O Christmas Tree", 4), new Track(43L, "Ode to Joy", 2), new Track(44L, "Oh Chanukah!", 8), new Track(45L, "Old Gray Mare", 5), new Track(46L, "Old MacDonald", 7), new Track(47L, "Rhapsody in Blue", 8), new Track(48L, "Rising Sun Blues", 4), new Track(49L, "Rosamunde", 6), new Track(50L, "Round the Mountain", 7), new Track(51L, "Sailor's Hornpipe", 10), new Track(52L, "Sakura", 2), new Track(53L, "Silent Night", 4), new Track(54L, "SkaBIRD", 6), new Track(55L, "Skeleton Rag", 6), new Track(56L, "Skip To My Lou", 5), new Track(57L, "St James Trombonery", 4), new Track(58L, "Stars & Stripes", 8, allowUnsafe: true), new Track(59L, "Star-Spangled", 5), new Track(60L, "Sugar Plum Fairy", 5), new Track(61L, "T. Champ Medley", 7), new Track(62L, "Taps", 3), new Track(63L, "The Can-Can", 8), new Track(64L, "The Ritz", 7), new Track(65L, "The Riverside", 5), new Track(66L, "The Saints", 5), new Track(67L, "Toccata & Fugue", 8), new Track(68L, "Trombone Fuerte", 9), new Track(69L, "Trombone Skyze", 4), new Track(70L, "Trombone Skyze (Nasty)", 8), new Track(71L, "W. Post March", 7, allowUnsafe: true), new Track(72L, "Warm-Up", 1), new Track(73L, "William Tell", 8), new Track(74L, "Zarathustra", 1), new Track(201L, "Confronting Myself", 7, allowUnsafe: true, "Celeste"), new Track(202L, "First Steps", 7, allowUnsafe: true, "Celeste"), new Track(203L, "Heart of the Mountain", 7, allowUnsafe: true, "Celeste"), new Track(204L, "Madeline and Theo", 6, allowUnsafe: true, "Celeste"), new Track(205L, "Reach for the Summit", 6, allowUnsafe: true, "Celeste"), new Track(206L, "Reflection", 6, allowUnsafe: true, "Celeste"), new Track(207L, "Resurrections", 6, allowUnsafe: true, "Celeste"), new Track(208L, "Scattered and Lost", 8, allowUnsafe: true, "Celeste"), new Track(209L, "Spirit of Hospitality", 6, allowUnsafe: true, "Celeste"), new Track(210L, "Starjump", 8, allowUnsafe: true, "Celeste"), new Track(251L, "Bye Bye There!", 7, allowUnsafe: true, "Pizza Tower"), new Track(252L, "Cold Spaghetti", 8, allowUnsafe: true, "Pizza Tower"), new Track(253L, "Death I Deservioli", 8, allowUnsafe: true, "Pizza Tower"), new Track(254L, "ET Wahwahs", 8, allowUnsafe: true, "Pizza Tower"), new Track(255L, "Funiculi Holiday", 7, allowUnsafe: true, "Pizza Tower"), new Track(256L, "Good Eatin'", 8, allowUnsafe: true, "Pizza Tower"), new Track(257L, "It's Pizza Time!", 8, allowUnsafe: true, "Pizza Tower"), new Track(258L, "Kid's Menu", 9, allowUnsafe: true, "Pizza Tower"), new Track(259L, "Oregano Mirage", 9, allowUnsafe: true, "Pizza Tower"), new Track(260L, "Pizza Deluxe", 7, allowUnsafe: true, "Pizza Tower"), new Track(261L, "Pumpin' Hot Stuff", 7, allowUnsafe: true, "Pizza Tower"), new Track(262L, "Put On A Show!", 7, allowUnsafe: true, "Pizza Tower"), new Track(263L, "Unexpectancy", 9, allowUnsafe: true, "Pizza Tower"), new Track(264L, "Yeehaw", 8, allowUnsafe: true, "Pizza Tower"), new Track(301L, "ASGORE", 8, allowUnsafe: true, "UTDR"), new Track(302L, "BIG SHOT", 7, allowUnsafe: true, "UTDR"), new Track(303L, "Black Knife", 7, allowUnsafe: true, "UTDR"), new Track(304L, "Bonetrousle", 8, allowUnsafe: true, "UTDR"), new Track(305L, "CYBER'S WORLD?", 7, allowUnsafe: true, "UTDR"), new Track(306L, "Dark Sanctuary", 7, allowUnsafe: true, "UTDR"), new Track(307L, "Dummy!", 9, allowUnsafe: true, "UTDR"), new Track(308L, "GUARDIAN", 8, allowUnsafe: true, "UTDR"), new Track(309L, "Hopes and Dreams", 8, allowUnsafe: true, "UTDR"), new Track(310L, "It's TV Time!", 8, allowUnsafe: true, "UTDR"), new Track(311L, "Killer Queen", 8, allowUnsafe: true, "UTDR"), new Track(312L, "Megalovania", 9, allowUnsafe: true, "UTDR"), new Track(313L, "Metal Crusher", 9, allowUnsafe: true, "UTDR"), new Track(314L, "Pandora Palace", 7, allowUnsafe: true, "UTDR"), new Track(315L, "Rude Buster", 9, allowUnsafe: true, "UTDR"), new Track(316L, "Scarlet Forest", 6, allowUnsafe: true, "UTDR"), new Track(317L, "SWORD", 7, allowUnsafe: true, "UTDR"), new Track(318L, "Third Sanctuary", 9, allowUnsafe: true, "UTDR"), new Track(319L, "True Hero", 8, allowUnsafe: true, "UTDR"), new Track(320L, "TV World", 7, allowUnsafe: true, "UTDR"), new Track(321L, "World Revolving", 8, allowUnsafe: true, "UTDR") }; public static IEnumerable GetTrackList(APSettings settings) { Track[] tRACKS = TRACKS; for (int i = 0; i < tRACKS.Length; i++) { Track track = tRACKS[i]; if (track.Difficulty >= settings.MinDiff && track.Difficulty <= settings.MaxDiff && (settings.Unsafe || !track.Unsafe) && (track.DLC == "Base" || (track.DLC == "Celeste" && settings.Celeste) || (track.DLC == "Pizza Tower" && settings.PizzaTower) || (track.DLC == "UTDR" && settings.UndertaleDeltarune)) && !settings.RemovedTracks.Contains(track.Name)) { yield return track; } } } public static Track? GetGoalTrack(APSettings settings, Track[] tracks) { if (settings.GoalTracks > 0) { return null; } Track value = tracks.FirstOrDefault((Track track) => track.Name == settings.GoalTrack); if (value.Name != settings.GoalTrack) { ArchipelagoPlugin.Logger.LogWarning((object)"Goal track count is 0 and goal track failed to resolve to a track!"); return null; } return value; } } public class APTrapController { public class TrapType(long ID) { public class TrapFlipControls : TrapType { public TrapFlipControls() : base(1201L) { } public override void StartTrap(GameController controller) { int num = GlobalVariables.mousecontrolmode; switch (num) { case 0: num = 1; break; case 1: num = 0; break; case 2: num = 3; break; case 3: num = 2; break; } controller.gameplay_settings.mouse_controldirection = num; } public override void EndTrap(GameController controller) { controller.gameplay_settings.mouse_controldirection = GlobalVariables.mousecontrolmode; } public override float TrapDuration() { return 8f; } } public class TrapSilenceTrack : TrapType { private float OriginalVolume; public TrapSilenceTrack() : base(1202L) { } public override void StartTrap(GameController controller) { OriginalVolume = controller.musictrack.volume; } public override void ContinueTrap(GameController controller) { float num = (float)controller.musictrack.timeSamples / (float)controller.musictrack.clip.frequency; float num2 = (num - TrapStartTime) / (TrapEndTime - TrapStartTime); float num3 = num2 * 2f; if (num3 > 1f) { num3 = 2f - num3; } float volume = 0f; if (num3 < 0.25f) { volume = 1f - num3 / 0.25f; } controller.musictrack.volume = volume; } public override void EndTrap(GameController controller) { controller.musictrack.volume = OriginalVolume; } } public class TrapSilenceTrombone : TrapType { public TrapSilenceTrombone() : base(1203L) { } public override void ContinueTrap(GameController controller) { controller.currentnotesound.volume = 0f; } public override void EndTrap(GameController controller) { if (controller.noteactive) { controller.currentnotesound.volume = 1f; } } } public class TrapHideNotes : TrapType { public TrapHideNotes() : base(1204L) { } public override void ContinueTrap(GameController controller) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) controller.noteholderr.anchoredPosition3D = new Vector3(0f, 100f, 0f); } } public class TrapNoBreath : TrapType { public TrapNoBreath() : base(1205L) { } public override void StartTrap(GameController controller) { //IL_0040: Unknown result type (might be due to invalid IL or missing references) controller.breathcounter = 1f; if (!controller.outofbreath) { controller.sfxrefs.outofbreath.Play(); controller.breathglow.anchoredPosition3D = new Vector3(-380f, 0f, 0f); controller.outofbreath = true; controller.noteplaying = false; controller.setPuppetShake(false); controller.setPuppetBreath(true); controller.stopNote(); } } public override void EndTrap(GameController controller) { controller.breathcounter = 0.001f; } public override float TrapDuration() { return 2f; } } public class TrapWarbleTrombone : TrapType { private const float NUM_CYCLES = 5f; public TrapWarbleTrombone() : base(1206L) { } public override void ContinueTrap(GameController controller) { float num = (float)controller.musictrack.timeSamples / (float)controller.musictrack.clip.frequency; float num2 = (num - TrapStartTime) / (TrapEndTime - TrapStartTime); SetTrombonePitchModifier(controller, Mathf.Sin(num2 * 5f * (float)Math.PI * 2f) * 0.2f + 0.9f); } } public class TrapWarpSpeed : TrapType { private static readonly AnimationCurve SpeedCurve = new AnimationCurve((Keyframe[])(object)new Keyframe[8] { new Keyframe(0f, 1f), new Keyframe(0.1f, 1f), new Keyframe(0.3f, 0.9f), new Keyframe(0.35f, 0.9f), new Keyframe(0.65f, 1.25f), new Keyframe(0.7f, 1.25f), new Keyframe(0.9f, 1f), new Keyframe(1f, 1f) }); public TrapWarpSpeed() : base(1207L) { } public override void ContinueTrap(GameController controller) { float num = (float)controller.musictrack.timeSamples / (float)controller.musictrack.clip.frequency; float num2 = (num - TrapStartTime) / (TrapEndTime - TrapStartTime); float num3 = SpeedCurve.Evaluate(num2); if (GlobalVariables.turbomode) { num3 *= 2f; } controller.musictrack.pitch = num3; controller.smooth_scrolling_move_mult = num3; SetTrombonePitchModifier(controller, num3); } public override void EndTrap(GameController controller) { float num = ((!GlobalVariables.turbomode) ? 1 : 2); controller.musictrack.pitch = num; controller.smooth_scrolling_move_mult = num; } public override float TrapDuration() { return 10f; } } public static readonly TrapType FlipControls = new TrapFlipControls(); public static readonly TrapType SilenceTrack = new TrapSilenceTrack(); public static readonly TrapType SilenceTrombone = new TrapSilenceTrombone(); public static readonly TrapType HideNotes = new TrapHideNotes(); public static readonly TrapType NoBreath = new TrapNoBreath(); public static readonly TrapType[] Traps = new TrapType[7] { FlipControls, SilenceTrack, SilenceTrombone, HideNotes, NoBreath, new TrapWarbleTrombone(), new TrapWarpSpeed() }; public readonly long ID = ID; public virtual float TrapDuration() { return 5f; } public virtual void StartTrap(GameController controller) { } public virtual void ContinueTrap(GameController controller) { } public virtual void EndTrap(GameController controller) { } public static TrapType GetTrap(long ID) { return Traps.FirstOrDefault((TrapType trap) => trap.ID == ID); } } private static bool WasPlayingNote; public static List TrapQueue = new List(); private static float TrapStartTime; private static float TrapEndTime; public static TrapType CurTrap { get; private set; } private static void SetTrombonePitchModifier(GameController controller, float modifier) { if (WasPlayingNote) { AudioSource currentnotesound = controller.currentnotesound; currentnotesound.pitch *= modifier; } WasPlayingNote = controller.noteplaying; } public static void AddTrap(TrapType t) { TrapQueue.Add(t); } public static void ResetState() { TrapEndTime = 0f; if (CurTrap != null) { ArchipelagoPlugin.Logger.LogWarning((object)"Trap controller was reset with active traps!"); TrapQueue.Insert(0, CurTrap); } CurTrap = null; } public static void ControllerUpdate(GameController controller) { if (!Object.op_Implicit((Object)(object)controller.musictrack) || !Object.op_Implicit((Object)(object)controller.musictrack.clip)) { return; } float num = (float)controller.musictrack.timeSamples / (float)controller.musictrack.clip.frequency; if (CurTrap != null && num >= TrapEndTime) { CurTrap.EndTrap(controller); CurTrap = null; return; } if (CurTrap == null) { if (TrapQueue.Count == 0) { return; } float num2 = TrapEndTime + 3f; if (num < num2) { return; } float num3 = num + TrapQueue[0].TrapDuration(); if (num3 > controller.levelendtime - 3f) { return; } CurTrap = TrapQueue[0]; CurTrap.StartTrap(controller); TrapQueue.RemoveAt(0); TrapStartTime = num; TrapEndTime = num3; } CurTrap?.ContinueTrap(controller); } } [BepInPlugin("APTromboneChampMod", "AP Trombone", "0.0.1")] [BepInDependency(/*Could not decode attribute arguments.*/)] public class ArchipelagoPlugin : BaseUnityPlugin { [HarmonyPatch(typeof(PointSceneController), "Awake")] private class ScoreScreenChecker { private static void Postfix() { if (APHandler.APSlot == -1) { Logger.LogInfo((object)"AP not connected, not sending."); return; } float gameplay_scoreperc = GlobalVariables.gameplay_scoreperc; int num = (int)(gameplay_scoreperc / 0.2f) - 2; if (num > 3) { num = (GlobalVariables.gameplay_perfect ? 5 : ((!((double)gameplay_scoreperc >= 1.35)) ? 3 : 4)); } bool flag = num >= APHandler.GetRequiredRating(); Track track = APHandler.AvailableTracks.FirstOrDefault((Track track2) => track2.Name.ToLower() == GlobalVariables.chosen_track_data.trackname_short.ToLower()); if (track.Name.ToLower() == GlobalVariables.chosen_track_data.trackname_short.ToLower()) { Logger.LogInfo((object)("Track end screen: " + GlobalVariables.chosen_track_data.trackname_short)); Logger.LogInfo((object)$" Score: {gameplay_scoreperc:P2}"); Logger.LogInfo((object)("Rating: " + (new string[8] { "F", "D", "C", "B", "A", "S", "Wall (S)", "Perfect (S)" })[num + 2])); Logger.LogInfo((object)$"Beaten: {flag}"); if (!APHandler.IsTrackAvailable(track)) { Logger.LogInfo((object)"Submission blocked, track is not available."); return; } long[] sentIDs = APHandler.SendTrack(track, flag); if (HintLocsOnMissed && APHandler.APSlot != -1) { long[] array = new long[2] { track.ID, track.ID + 1000 }.Where((long id) => !sentIDs.Contains(id)).ToArray(); if (array.Length != 0) { APHandler.APSession.Locations.ScoutLocationsAsync((HintCreationPolicy)2, array); } } } else { Logger.LogInfo((object)"Track was not in the list of AP tracks."); } } } [HarmonyPatch(typeof(LevelSelectController), "clickPlay")] private class PreventPlayingTrack { private static bool Prefix(LevelSelectController __instance) { if (APHandler.APSlot == -1) { return true; } if (APHandler.HasGoaled()) { return true; } Track? track = APHandler.FindTrack(__instance.alltrackslist[__instance.songindex].trackname_short); if (!track.HasValue) { return false; } if (!APHandler.IsTrackAvailable(track.Value)) { return false; } return true; } } [HarmonyPatch(typeof(LevelSelectController), "populateSongNames")] private class ChangeSongDescriptionAndDisablePlay { private static object LockObj = new object(); private static void Prefix() { Monitor.Enter(LockObj); } private static void Finalizer(LevelSelectController __instance) { try { TrackCollection val = GlobalVariables.all_track_collections[GlobalVariables.chosen_collection_index]; if (APHandler.APSlot != -1 && APHandler.HasGoaled()) { __instance.songdesctext.text = "Goaled!\nMaybe play for fun?"; ((Behaviour)__instance.playbtn).enabled = true; ((Component)__instance.playbtn).gameObject.SetActive(true); Monitor.Exit(LockObj); return; } if (TrackCollectionListener.COLLECTIONS.TryGetValue(val._unique_id, out var value)) { APCollection aPCollection = (APCollection)value; if (aPCollection.HasNoTracks()) { __instance.songdesctext.text = ((APHandler.APSlot == -1) ? "Not connected to AP!\nPress F1 to open connection manager." : aPCollection.GetNoTrackString()); ((Behaviour)__instance.playbtn).enabled = false; ((Component)__instance.playbtn).gameObject.SetActive(false); Monitor.Exit(LockObj); return; } } bool flag = false; if (APHandler.APSlot == -1) { flag = true; } else { Track? track = APHandler.FindTrack(__instance.alltrackslist[__instance.songindex].trackname_short); if (track.HasValue) { TrackHints trackHints = APHandler.GetTrackHints(track.Value); bool flag2 = APHandler.APSentLocations.Contains(track.Value.ID); bool flag3 = APHandler.APSentLocations.Contains(track.Value.ID + 1000); bool flag4 = APHandler.BeatenTracks.Contains(track.Value.ID); StringBuilder stringBuilder = new StringBuilder(); if (APHandler.GoalTrack.HasValue && APHandler.GoalTrack.Value.ID == track.Value.ID) { stringBuilder.Append("This is the goal track, beat it to win!\n"); } if (APHandler.IsTrackAvailable(track.Value)) { if (flag2 && flag3 && flag4) { stringBuilder.Append("Track already beaten."); } else { flag = true; stringBuilder.Append("Can play this track!"); stringBuilder.Append("\nRequired rating: " + APHandler.GetRatingString(APHandler.GetRequiredRating())); if (!flag2) { stringBuilder.Append("\nPlay reward: " + APHandler.FormatItemHint(trackHints.PlayReward)); } if (!flag3) { stringBuilder.Append("\nBeat reward: " + APHandler.FormatItemHint(trackHints.BeatReward)); } } } else { stringBuilder.Append("Track locked."); if (APHandler.GoalTrack.HasValue && APHandler.GoalTrack.Value.ID == track.Value.ID) { int hotDogs = APHandler.WorldSettings.HotDogs; if (hotDogs > 0) { int hotDogs2 = ItemHandler.HotDogs; if (hotDogs2 < hotDogs) { stringBuilder.Append($"\nHot dogs: {hotDogs2}/{hotDogs}"); } } } if (APHandler.WorldSettings.TrackGating && !ItemHandler.HasTrack(track.Value.ID)) { stringBuilder.Append("\nTrack unlock: " + APHandler.FormatLocationString(trackHints.TrackUnlock)); } if (APHandler.WorldSettings.DifficultyGating == APSettings.DiffGateType.ON && !ItemHandler.HasDifficulty(track.Value.Difficulty)) { stringBuilder.Append($"\nDifficulty {track.Value.Difficulty}: {APHandler.FormatLocationString(trackHints.DifficultyUnlocks[0])}"); } if (APHandler.WorldSettings.DifficultyGating == APSettings.DiffGateType.PROG) { int num = track.Value.Difficulty - APHandler.WorldSettings.MinDiff; if (num > 0) { int progressiveDifficulties = ItemHandler.ProgressiveDifficulties; if (progressiveDifficulties < num) { stringBuilder.Append($"\nDifficulty unlocks: {progressiveDifficulties}/{num}"); Hint[] difficultyUnlocks = trackHints.DifficultyUnlocks; foreach (Hint hint in difficultyUnlocks) { stringBuilder.Append("\nProgressive Difficulty: " + APHandler.FormatLocationString(hint)); } } } } } __instance.songdesctext.text = stringBuilder.ToString(); } else { __instance.songdesctext.text = "Not an AP track."; } } ((Behaviour)__instance.playbtn).enabled = flag; ((Component)__instance.playbtn).gameObject.SetActive(flag); } catch (Exception ex) { Logger.LogWarning((object)("Caught exception: " + ex.Message)); Logger.LogWarning((object)ex.StackTrace); } Monitor.Exit(LockObj); } } [HarmonyPatch(typeof(GameController), "Awake")] private class TrapReset { private static void Postfix() { APTrapController.ResetState(); } } [HarmonyPatch(typeof(GameController), "Update")] private class TrapPatch { private static void Postfix(GameController __instance) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Invalid comparison between Unknown and I4 if (DeathLinkInboundMode == 3 && APHandler.DeathLinkCounter > 0 && (int)__instance.musictrack_status != 2) { APHandler.DeathLinkCounter = 0; float num = (float)__instance.musictrack.timeSamples / (float)__instance.musictrack.clip.frequency; if (!__instance.retrying && num > 5f) { Logger.LogInfo((object)"DeathLink triggered, restarting track."); __instance.sfxrefs.recordscratch.Play(); __instance.musictrack.Pause(); __instance.curtainc.closeCurtain(true); __instance.paused = true; __instance.retrying = true; __instance.quitting = true; } else { Logger.LogInfo((object)"DeathLink triggered, ignoring as too early or already restarting."); } } APTrapController.ControllerUpdate(__instance); } } private static Harmony _harmony = new Harmony("archipelago"); public static ArchipelagoPlugin Instance; internal static ManualLogSource Logger; private string uri = "archipelago.gg"; private string port = "38281"; private string slotname = ""; private string password = ""; public int curGUI = -1; private Rect windowRect = new Rect(20f, 20f, 700f, 300f); private static GUIStyle textStyle = new GUIStyle { fontSize = 17 }; public static bool SendChatToLog = true; public static bool HintLocsOnMissed = false; public static int DeathLinkInboundMode = 0; private static string[] DeathLinkButtonText = new string[4] { "Disabled", "Enabled", "Cumulative", "Immediate" }; public static bool DeathLinkOutbound = false; private Vector2 hintScroll1 = Vector2.zero; private Vector2 hintScroll2 = Vector2.zero; private const int hintEntryWidth = 240; private const int hintEntryInfoWidth = 70; public static bool ShouldEnableDeathlink => DeathLinkInboundMode != 0 || DeathLinkOutbound; private void Awake() { Instance = this; Logger = ((BaseUnityPlugin)this).Logger; GameInitializationEvent.Register(((BaseUnityPlugin)this).Info, (Action)TryInitialize); } private void TryInitialize() { ImageHandler.LoadTextures(); TrackCollectionRegistrationEvent.EVENT.Register((Listener)(object)new TrackCollectionListener()); _harmony.PatchAll(); } private void Update() { if (Input.GetKeyDown((KeyCode)282)) { int num = curGUI; if ((num > 1 || num == -1) ? true : false) { if (APHandler.APSlot == -1) { curGUI = 0; } else { curGUI = 1; } } else { curGUI = -1; } } if (!Input.GetKeyDown((KeyCode)283)) { return; } if (curGUI != 2) { if (APHandler.APSlot == -1) { curGUI = 0; } else { curGUI = 2; } } else { curGUI = -1; } } private void OnGUI() { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Expected O, but got Unknown //IL_002f: 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_0064: Unknown result type (might be due to invalid IL or missing references) //IL_0140: Unknown result type (might be due to invalid IL or missing references) //IL_01b6: Unknown result type (might be due to invalid IL or missing references) //IL_01ff: Unknown result type (might be due to invalid IL or missing references) //IL_0211: Unknown result type (might be due to invalid IL or missing references) //IL_021b: Expected O, but got Unknown //IL_0216: Unknown result type (might be due to invalid IL or missing references) //IL_021b: Unknown result type (might be due to invalid IL or missing references) //IL_0223: Unknown result type (might be due to invalid IL or missing references) //IL_0236: Unknown result type (might be due to invalid IL or missing references) //IL_024e: Unknown result type (might be due to invalid IL or missing references) //IL_0260: Unknown result type (might be due to invalid IL or missing references) //IL_049b: Unknown result type (might be due to invalid IL or missing references) //IL_04ab: Unknown result type (might be due to invalid IL or missing references) //IL_04c9: Unknown result type (might be due to invalid IL or missing references) //IL_04d3: Expected O, but got Unknown //IL_04ce: Unknown result type (might be due to invalid IL or missing references) //IL_04d3: Unknown result type (might be due to invalid IL or missing references) //IL_04db: Unknown result type (might be due to invalid IL or missing references) //IL_04ee: Unknown result type (might be due to invalid IL or missing references) //IL_0506: Unknown result type (might be due to invalid IL or missing references) //IL_0518: Unknown result type (might be due to invalid IL or missing references) //IL_03a1: Unknown result type (might be due to invalid IL or missing references) //IL_03c3: Unknown result type (might be due to invalid IL or missing references) //IL_03de: Unknown result type (might be due to invalid IL or missing references) //IL_03e8: Expected O, but got Unknown //IL_03e3: Unknown result type (might be due to invalid IL or missing references) //IL_03e8: Unknown result type (might be due to invalid IL or missing references) //IL_03f0: Unknown result type (might be due to invalid IL or missing references) //IL_0403: Unknown result type (might be due to invalid IL or missing references) //IL_041b: Unknown result type (might be due to invalid IL or missing references) //IL_042d: Unknown result type (might be due to invalid IL or missing references) //IL_0660: Unknown result type (might be due to invalid IL or missing references) if (curGUI != -1) { windowRect = GUI.Window(curGUI, windowRect, new WindowFunction(WindowHandler), "Archipelago Menu"); } if (!ImageHandler.TexturesLoaded) { return; } int height = Screen.height; GUI.DrawTexture(new Rect(10f, (float)(height - 50), 40f, 40f), (Texture)(object)((APHandler.APSlot == -1) ? ImageHandler.ArchipelagoGrey : ImageHandler.Archipelago)); if (APHandler.APSlot == -1) { return; } int num = 60; if (APHandler.HasGoaled()) { return; } if (APHandler.GoalTrack.HasValue && APHandler.IsTrackAvailable(APHandler.GoalTrack.Value)) { int rankReductions = ItemHandler.RankReductions; int num2 = APHandler.WorldSettings.InitialRating - APHandler.WorldSettings.GoalRating; if (rankReductions >= num2) { return; } } if (APHandler.WorldSettings.HotDogs > 0) { bool flag = ItemHandler.HotDogs >= APHandler.WorldSettings.HotDogs; GUI.DrawTexture(new Rect((float)num, (float)(height - 50), 40f, 40f), (Texture)(object)(flag ? ImageHandler.HotDog : ImageHandler.HotDogGrey)); num += 50; } if (APHandler.WorldSettings.InitialRating > APHandler.WorldSettings.GoalRating) { bool flag2 = ItemHandler.RankReductions >= APHandler.WorldSettings.InitialRating - APHandler.WorldSettings.GoalRating; GUI.DrawTexture(new Rect((float)num, (float)(height - 50), 40f, 40f), (Texture)(object)(flag2 ? ImageHandler.RankIndicator : ImageHandler.RankIndicatorGrey)); string text = (new string[4] { "C", "B", "A", "S" })[APHandler.GetRequiredRating()]; GUI.color = Color.black; Vector2 val = textStyle.CalcSize(new GUIContent(text)); GUI.Label(new Rect((float)(num + 20) - val.x / 2f, (float)(height - 30) - val.y / 2f, 40f, 40f), text, textStyle); GUI.color = Color.white; num += 50; } if (APHandler.WorldSettings.DifficultyGating != APSettings.DiffGateType.OFF) { List list = new List(); List list2 = new List(); if (APHandler.WorldSettings.DifficultyGating == APSettings.DiffGateType.PROG) { int num3 = APHandler.WorldSettings.MinDiff + ItemHandler.ProgressiveDifficulties; for (int i = APHandler.WorldSettings.MinDiff + 1; i <= APHandler.WorldSettings.MaxDiff; i++) { list.Add(i); if (num3 < i) { list2.Add(i); } } } if (APHandler.WorldSettings.DifficultyGating == APSettings.DiffGateType.ON) { for (int j = APHandler.WorldSettings.MinDiff + 1; j <= APHandler.WorldSettings.MaxDiff; j++) { list.Add(j); if (!ItemHandler.HasDifficulty(j)) { list2.Add(j); } } } foreach (int item in list) { GUI.DrawTexture(new Rect((float)num, (float)(height - 50), 40f, 40f), (Texture)(object)(list2.Contains(item) ? ImageHandler.DifficultyIndicatorGrey : ImageHandler.DifficultyIndicator)); GUI.color = Color.black; string text2 = item.ToString(); Vector2 val2 = textStyle.CalcSize(new GUIContent(text2)); GUI.Label(new Rect((float)(num + 20) - val2.x / 2f, (float)(height - 28) - val2.y / 2f, 40f, 40f), text2, textStyle); GUI.color = Color.white; num += 50; } } if (DeathLinkInboundMode != 0 && DeathLinkInboundMode != 3 && APHandler.DeathLinkCounter > 0) { num += 20; GUI.DrawTexture(new Rect((float)num, (float)(height - 50), 40f, 40f), (Texture)(object)ImageHandler.DeathLinkIndicator); GUI.color = Color.black; string text3 = APHandler.DeathLinkCounter.ToString(); Vector2 val3 = textStyle.CalcSize(new GUIContent(text3)); GUI.Label(new Rect((float)(num + 20) - val3.x / 2f, (float)(height - 30) - val3.y / 2f, 40f, 40f), text3, textStyle); GUI.color = Color.white; num += 50; } APTrapController.TrapType curTrap = APTrapController.CurTrap; List trapQueue = APTrapController.TrapQueue; int num4 = 0; APTrapController.TrapType[] array = new APTrapController.TrapType[1 + trapQueue.Count]; array[num4] = curTrap; num4++; foreach (APTrapController.TrapType item2 in trapQueue) { array[num4] = item2; num4++; } APTrapController.TrapType[] array2 = array; num += 20; APTrapController.TrapType[] array3 = array2; foreach (APTrapController.TrapType trapType in array3) { if (trapType == null) { continue; } APTrapController.TrapType trapType2 = trapType; APTrapController.TrapType trapType3 = trapType2; Texture2D val4; if (!(trapType3 is APTrapController.TrapType.TrapFlipControls)) { if (!(trapType3 is APTrapController.TrapType.TrapHideNotes)) { if (!(trapType3 is APTrapController.TrapType.TrapNoBreath)) { if (!(trapType3 is APTrapController.TrapType.TrapSilenceTrack)) { if (!(trapType3 is APTrapController.TrapType.TrapSilenceTrombone)) { if (!(trapType3 is APTrapController.TrapType.TrapWarbleTrombone)) { if (!(trapType3 is APTrapController.TrapType.TrapWarpSpeed)) { continue; } val4 = ImageHandler.TrapWarpSpeedIndicator; } else { val4 = ImageHandler.TrapWarbleTromboneIndicator; } } else { val4 = ImageHandler.TrapSilenceTromboneIndicator; } } else { val4 = ImageHandler.TrapSilenceTrackIndicator; } } else { val4 = ImageHandler.TrapNoBreathIndicator; } } else { val4 = ImageHandler.TrapHideNotesIndicator; } } else { val4 = ImageHandler.TrapFlipControlsIndicator; } GUI.DrawTexture(new Rect((float)num, (float)(height - 50), 40f, 40f), (Texture)(object)val4); num += 50; } } private void WindowHandler(int ID) { switch (ID) { case 0: ShowLoginWindow(); break; case 1: ShowTrackerWindow(); break; case 2: ShowHintWindow(); break; default: Logger.LogWarning((object)$"Unknown GUI ID: {ID}"); curGUI = -1; break; } } private void ShowLoginWindow() { GUILayout.Label("Server URI: ", Array.Empty()); uri = GUILayout.TextField(uri, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(200f) }); GUILayout.Label("Server Port: ", Array.Empty()); port = GUILayout.TextField(port, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(200f) }); GUILayout.Label("Server Slotname: ", Array.Empty()); slotname = GUILayout.TextField(slotname, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(200f) }); GUILayout.Label("Server Password (Optional): ", Array.Empty()); password = GUILayout.PasswordField(password, '*', (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(200f) }); if (GUILayout.Button("Connect Archipelago", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(30f) }) && int.TryParse(port.Trim(), out var result)) { APHandler.ConnectToAP(uri, result, slotname, password); } if (GUILayout.Button("Close", Array.Empty())) { curGUI = -1; } } private void ShowTrackerWindow() { GUILayout.Label("Connected to AP server.", Array.Empty()); SendChatToLog = GUILayout.Toggle(SendChatToLog, "Send Chat to Log", Array.Empty()); GUILayout.Space(10f); HintLocsOnMissed = GUILayout.Toggle(HintLocsOnMissed, "Hint missed locations on track completion", Array.Empty()); GUILayout.Space(10f); GUILayout.Label("Receive DeathLink from other players", Array.Empty()); if (GUILayout.Button(DeathLinkButtonText[DeathLinkInboundMode], Array.Empty())) { DeathLinkInboundMode = (DeathLinkInboundMode + 1) % 4; if (ShouldEnableDeathlink) { APHandler.DeathLink.EnableDeathLink(); } else { APHandler.DeathLink.DisableDeathLink(); } } bool deathLinkOutbound = DeathLinkOutbound; DeathLinkOutbound = GUILayout.Toggle(DeathLinkOutbound, "Send DeathLink on failing to beat tracks", Array.Empty()); if (deathLinkOutbound != DeathLinkOutbound) { if (ShouldEnableDeathlink) { APHandler.DeathLink.EnableDeathLink(); } else { APHandler.DeathLink.DisableDeathLink(); } } GUILayout.Space(10f); Track[] array = APTracks.GetTrackList(APHandler.WorldSettings).ToArray(); string text; if (APHandler.HasGoaled()) { text = "Goaled!"; } else if (APHandler.WorldSettings.GoalTracks == 0) { text = "Goal track: " + APHandler.WorldSettings.GoalTrack; } else { int num = array.Count((Track track) => APHandler.BeatenTracks.Contains(track.ID)); text = $"Beat tracks: {num}/{APHandler.WorldSettings.GoalTracks}"; } GUILayout.Label(text, Array.Empty()); if (APHandler.WorldSettings.HotDogs > 0) { int hotDogs = ItemHandler.HotDogs; if (APHandler.WorldSettings.ExtraHotDogs > 0) { int num2 = APHandler.WorldSettings.HotDogs + APHandler.WorldSettings.ExtraHotDogs; GUILayout.Label($"Hot Dogs: {hotDogs}/{APHandler.WorldSettings.HotDogs} ({num2})", Array.Empty()); } else { GUILayout.Label($"Hot Dogs: {hotDogs}/{APHandler.WorldSettings.HotDogs}", Array.Empty()); } } string[] array2 = new string[4] { "C", "B", "A", "S" }; GUILayout.Label("Required rating: " + array2[APHandler.GetRequiredRating()], Array.Empty()); if (APHandler.WorldSettings.InitialRating != APHandler.WorldSettings.GoalRating) { int num3 = APHandler.WorldSettings.InitialRating - APHandler.WorldSettings.GoalRating; int rankReductions = ItemHandler.RankReductions; GUILayout.Label($"Rating Reduction items: {rankReductions}/{num3}", Array.Empty()); } GUILayout.Space(10f); if (APHandler.WorldSettings.TrackGating || APHandler.WorldSettings.DifficultyGating != APSettings.DiffGateType.OFF) { if (APHandler.WorldSettings.TrackGating) { int num4 = array.Count((Track track) => ItemHandler.HasTrack(track.ID)); GUILayout.Label($"Tracks unlocked: {num4}/{array.Length}", Array.Empty()); } if (APHandler.WorldSettings.DifficultyGating == APSettings.DiffGateType.ON) { List list = new List(1) { APHandler.WorldSettings.MinDiff }; for (int num5 = APHandler.WorldSettings.MinDiff + 1; num5 <= APHandler.WorldSettings.MaxDiff; num5++) { if (ItemHandler.HasDifficulty(num5)) { list.Add(num5); } } GUILayout.Label("Difficulties unlocked: " + string.Join(", ", list), Array.Empty()); } if (APHandler.WorldSettings.DifficultyGating == APSettings.DiffGateType.PROG) { int num6 = APHandler.WorldSettings.MinDiff + ItemHandler.ProgressiveDifficulties; GUILayout.Label($"Max difficulty: {num6}/{APHandler.WorldSettings.MaxDiff}", Array.Empty()); } GUILayout.Space(10f); } if (GUILayout.Button("Disconnect", Array.Empty())) { APHandler.APSession.Socket.DisconnectAsync(); APHandler.APSlot = -1; curGUI = 0; } if (GUILayout.Button("Close", Array.Empty())) { curGUI = -1; } } private void ShowHintWindow() { //IL_0075: 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_0094: Unknown result type (might be due to invalid IL or missing references) //IL_095d: Unknown result type (might be due to invalid IL or missing references) //IL_0977: Unknown result type (might be due to invalid IL or missing references) //IL_097c: Unknown result type (might be due to invalid IL or missing references) if (APHandler.APSlot == -1) { curGUI = 0; return; } bool flag = APHandler.CanHint(); GUILayout.Label($"Hint points: {APHandler.APSession.RoomState.HintPoints}/{APHandler.APSession.RoomState.HintCost}", Array.Empty()); GUILayout.BeginHorizontal(Array.Empty()); GUILayout.BeginVertical(Array.Empty()); hintScroll1 = GUILayout.BeginScrollView(hintScroll1, false, true, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(340f) }); bool flag2 = false; if (APHandler.WorldSettings.DifficultyGating == APSettings.DiffGateType.ON) { List list = new List(); for (int i = APHandler.WorldSettings.MinDiff + 1; i <= APHandler.WorldSettings.MaxDiff; i++) { if (!ItemHandler.HasDifficulty(i)) { list.Add(i); } } if (list.Count > 0) { flag2 = true; GUILayout.Label($"Missing difficulties: {list.Count}", Array.Empty()); foreach (int diff in list) { GUILayout.BeginHorizontal(Array.Empty()); GUILayout.Label($"Difficulty {diff}", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(240f) }); Hint val = ((IEnumerable)APHandler.APReceivedHints).FirstOrDefault((Func)((Hint val3) => val3.ReceivingPlayer == APHandler.APSlot && val3.ItemId == (long)diff + 1010L)); if (val != null && val.ReceivingPlayer == APHandler.APSlot && val.ItemId == (long)diff + 1010L) { GUI.enabled = false; GUILayout.Button("HINTED", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(70f) }); GUI.enabled = true; } else if (flag) { if (GUILayout.Button("Hint", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(70f) })) { APHandler.TryHintDifficulty(diff); } } else { GUI.enabled = false; GUILayout.Button("MISSING", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(70f) }); GUI.enabled = true; } GUILayout.EndHorizontal(); } } } if (APHandler.WorldSettings.DifficultyGating == APSettings.DiffGateType.PROG) { int num = APHandler.WorldSettings.MaxDiff - APHandler.WorldSettings.MinDiff; int progressiveDifficulties = ItemHandler.ProgressiveDifficulties; if (progressiveDifficulties < num) { flag2 = true; Hint[] array = APHandler.APReceivedHints.Where((Hint val3) => val3.ReceivingPlayer == APHandler.APSlot && val3.ItemId == 1011).ToArray(); GUILayout.BeginHorizontal(Array.Empty()); GUILayout.Label($"Progressive Difficulty ({progressiveDifficulties}/{num})", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(240f) }); int num2 = num - progressiveDifficulties; if (flag) { if (GUILayout.Button($"Hint {array.Length}/{num2}", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(70f) })) { APHandler.TryHintDifficulty(1); } } else if (array.Length != 0) { GUI.enabled = false; GUILayout.Button($"HINTED {array.Length}/{num2}", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(70f) }); GUI.enabled = true; } else { GUI.enabled = false; GUILayout.Button("MISSING", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(70f) }); GUI.enabled = true; } GUILayout.EndHorizontal(); } } if (APHandler.WorldSettings.InitialRating != APHandler.WorldSettings.GoalRating) { int num3 = APHandler.WorldSettings.InitialRating - APHandler.WorldSettings.GoalRating; int rankReductions = ItemHandler.RankReductions; if (rankReductions < num3) { flag2 = true; Hint[] array2 = APHandler.APReceivedHints.Where((Hint val3) => val3.ReceivingPlayer == APHandler.APSlot && val3.ItemId == 1001).ToArray(); GUILayout.BeginHorizontal(Array.Empty()); GUILayout.Label($"Rank Reduction ({rankReductions}/{num3})", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(240f) }); int num4 = num3 - rankReductions; if (flag) { if (GUILayout.Button($"Hint {array2.Length}/{num4}", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(70f) })) { APHandler.TryHintRankReduction(); } } else if (array2.Length != 0) { GUI.enabled = false; GUILayout.Button($"HINTED {array2.Length}/{num4}", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(70f) }); GUI.enabled = true; } else { GUI.enabled = false; GUILayout.Button("MISSING", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(70f) }); GUI.enabled = true; } GUILayout.EndHorizontal(); } } if (APHandler.WorldSettings.HotDogs > 0) { int num5 = APHandler.WorldSettings.HotDogs + APHandler.WorldSettings.ExtraHotDogs; int hotDogs = ItemHandler.HotDogs; if (hotDogs < APHandler.WorldSettings.HotDogs) { flag2 = true; Hint[] array3 = APHandler.APReceivedHints.Where((Hint val3) => val3.ReceivingPlayer == APHandler.APSlot && val3.ItemId == 1004).ToArray(); GUILayout.BeginHorizontal(Array.Empty()); GUILayout.Label($"Hot Dog ({hotDogs}/{APHandler.WorldSettings.HotDogs} ({num5}))", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(240f) }); int num6 = num5 - hotDogs; if (flag) { if (GUILayout.Button($"Hint {array3.Length}/{num6}", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(70f) })) { APHandler.TryHintHotDog(); } } else if (array3.Length != 0) { GUI.enabled = false; GUILayout.Button($"HINTED {array3.Length}/{num6}", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(70f) }); GUI.enabled = true; } else { GUI.enabled = false; GUILayout.Button("MISSING", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(70f) }); GUI.enabled = true; } GUILayout.EndHorizontal(); } } if (APHandler.WorldSettings.TrackGating) { Track[] array4 = APHandler.FilteredTracks.Where((Track track2) => !ItemHandler.HasTrack(track2.ID)).ToArray(); if (array4.Length != 0) { flag2 = true; GUILayout.Label($"Track unlocks remaining: {array4.Length}", Array.Empty()); Track[] array5 = array4; for (int num7 = 0; num7 < array5.Length; num7++) { Track track = array5[num7]; GUILayout.BeginHorizontal(Array.Empty()); GUILayout.Label(track.Name, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(240f) }); Hint val2 = ((IEnumerable)APHandler.APReceivedHints).FirstOrDefault((Func)((Hint val3) => val3.ReceivingPlayer == APHandler.APSlot && val3.ItemId == track.ID)); if (val2 != null && val2.ReceivingPlayer == APHandler.APSlot && val2.ItemId == track.ID) { GUI.enabled = false; GUILayout.Button("HINTED", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(70f) }); GUI.enabled = true; } else if (flag) { if (GUILayout.Button("Hint", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(70f) })) { APHandler.TryHintTrack(track); } } else { GUI.enabled = false; GUILayout.Button("MISSING", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(70f) }); GUI.enabled = true; } GUILayout.EndHorizontal(); } } } if (!flag2) { GUILayout.Label("No more items!", Array.Empty()); } GUILayout.EndScrollView(); GUILayout.EndVertical(); GUILayout.BeginVertical(Array.Empty()); hintScroll2 = GUILayout.BeginScrollView(hintScroll2, false, true, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(340f) }); Hint[] array6 = APHandler.APReceivedHints.Where((Hint val3) => val3.ReceivingPlayer != APHandler.APSlot || (val3.ItemId != 1002 && val3.ItemId != 1003)).ToArray(); if (array6.Length == 0) { GUILayout.Label("No hints!", Array.Empty()); } else { Hint[] array7 = array6.Where((Hint val3) => val3.FindingPlayer == APHandler.APSlot && val3.ReceivingPlayer == APHandler.APSlot).ToArray(); Hint[] array8 = array6.Where((Hint val3) => val3.FindingPlayer != APHandler.APSlot && val3.ReceivingPlayer == APHandler.APSlot).ToArray(); Hint[] array9 = array6.Where((Hint val3) => val3.ReceivingPlayer != APHandler.APSlot).ToArray(); Hint[] array10 = array7; foreach (Hint hint in array10) { GUILayout.Label(APHandler.FormatFullHint(hint), Array.Empty()); } Hint[] array11 = array8; foreach (Hint hint2 in array11) { GUILayout.Label(APHandler.FormatFullHint(hint2), Array.Empty()); } Hint[] array12 = array9; foreach (Hint hint3 in array12) { GUILayout.Label(APHandler.FormatFullHint(hint3), Array.Empty()); } } GUILayout.EndScrollView(); GUILayout.EndVertical(); GUILayout.EndHorizontal(); if (GUILayout.Button("Disconnect", Array.Empty())) { APHandler.APSession.Socket.DisconnectAsync(); APHandler.APSlot = -1; curGUI = 0; } if (GUILayout.Button("Close", Array.Empty())) { curGUI = -1; } } } public static class ImageHandler { public static Sprite ArchipelagoCollection; public static Sprite ArchipelagoCollectionFiltered; public static Sprite ArchipelagoCollectionLocked; public static Texture2D Archipelago; public static Texture2D ArchipelagoGrey; public static Texture2D HotDog; public static Texture2D HotDogGrey; public static Texture2D RankIndicator; public static Texture2D RankIndicatorGrey; public static Texture2D DifficultyIndicator; public static Texture2D DifficultyIndicatorGrey; public static Texture2D TrapFlipControlsIndicator; public static Texture2D TrapSilenceTrackIndicator; public static Texture2D TrapSilenceTromboneIndicator; public static Texture2D TrapHideNotesIndicator; public static Texture2D TrapNoBreathIndicator; public static Texture2D TrapWarbleTromboneIndicator; public static Texture2D TrapWarpSpeedIndicator; public static Texture2D DeathLinkIndicator; public static bool TexturesLoaded; public static void LoadTextures() { FromFile("ap"); FromFile("ap_grey"); FromFile("difficulty"); FromFile("difficulty_grey"); FromFile("hotdog"); FromFile("hotdog_grey"); FromFile("rank"); FromFile("rank_grey"); FromFile("trap_flip"); FromFile("trap_silencetrack"); FromFile("trap_silencetrombone"); FromFile("trap_hide"); FromFile("trap_breath"); FromFile("trap_warble"); FromFile("trap_warp"); FromFile("deathlink"); FromFileSprite("coll_ap"); FromFileSprite("coll_ap_filter"); FromFileSprite("coll_ap_locked"); } private static void FromFile(string name) { string text = Path.Combine(Path.GetDirectoryName(((BaseUnityPlugin)ArchipelagoPlugin.Instance).Info.Location), name + ".png"); ArchipelagoPlugin.Logger.LogInfo((object)("Loading texture from " + text)); UnityWebRequest req = UnityWebRequestTexture.GetTexture(text); UnityWebRequestAsyncOperation val = req.SendWebRequest(); bool done = false; ((AsyncOperation)val).completed += delegate { done = true; SetTexture(req.downloadHandler.data, name); }; if (((AsyncOperation)val).isDone && !done) { SetTexture(req.downloadHandler.data, name); } } private static void SetTexture(byte[] data, string name) { //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Expected O, but got Unknown Texture2D val = new Texture2D(1, 1); ImageConversion.LoadImage(val, data); switch (name) { case "ap": Archipelago = val; break; case "ap_grey": ArchipelagoGrey = val; break; case "difficulty": DifficultyIndicator = val; break; case "difficulty_grey": DifficultyIndicatorGrey = val; break; case "hotdog": HotDog = val; break; case "hotdog_grey": HotDogGrey = val; break; case "rank": RankIndicator = val; break; case "rank_grey": RankIndicatorGrey = val; break; case "trap_flip": TrapFlipControlsIndicator = val; break; case "trap_silencetrack": TrapSilenceTrackIndicator = val; break; case "trap_silencetrombone": TrapSilenceTromboneIndicator = val; break; case "trap_hide": TrapHideNotesIndicator = val; break; case "trap_breath": TrapNoBreathIndicator = val; break; case "trap_warble": TrapWarbleTromboneIndicator = val; break; case "trap_warp": TrapWarpSpeedIndicator = val; break; case "deathlink": DeathLinkIndicator = val; break; default: ArchipelagoPlugin.Logger.LogWarning((object)("Texture loaded but unknown name: " + name)); break; } if (Object.op_Implicit((Object)(object)Archipelago) && Object.op_Implicit((Object)(object)ArchipelagoGrey) && Object.op_Implicit((Object)(object)DifficultyIndicator) && Object.op_Implicit((Object)(object)DifficultyIndicatorGrey) && Object.op_Implicit((Object)(object)HotDog) && Object.op_Implicit((Object)(object)HotDogGrey) && Object.op_Implicit((Object)(object)RankIndicator) && Object.op_Implicit((Object)(object)RankIndicatorGrey) && Object.op_Implicit((Object)(object)ArchipelagoCollection) && Object.op_Implicit((Object)(object)ArchipelagoCollectionFiltered) && Object.op_Implicit((Object)(object)ArchipelagoCollectionLocked) && Object.op_Implicit((Object)(object)TrapFlipControlsIndicator) && Object.op_Implicit((Object)(object)TrapSilenceTrackIndicator) && Object.op_Implicit((Object)(object)TrapSilenceTromboneIndicator) && Object.op_Implicit((Object)(object)TrapHideNotesIndicator) && Object.op_Implicit((Object)(object)TrapNoBreathIndicator) && Object.op_Implicit((Object)(object)TrapWarbleTromboneIndicator) && Object.op_Implicit((Object)(object)TrapWarpSpeedIndicator) && Object.op_Implicit((Object)(object)DeathLinkIndicator)) { TexturesLoaded = true; } } private static void FromFileSprite(string name) { string text = Path.Combine(Path.GetDirectoryName(((BaseUnityPlugin)ArchipelagoPlugin.Instance).Info.Location), name + ".png"); ArchipelagoPlugin.Logger.LogInfo((object)("Loading texture from " + text)); UnityWebRequest req = UnityWebRequestTexture.GetTexture(text); UnityWebRequestAsyncOperation val = req.SendWebRequest(); bool done = false; ((AsyncOperation)val).completed += delegate { done = true; SetSprite(req.downloadHandler.data, name); }; if (((AsyncOperation)val).isDone && !done) { SetSprite(req.downloadHandler.data, name); } } private static void SetSprite(byte[] data, string name) { //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Expected O, but got Unknown //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) Texture2D val = new Texture2D(1, 1); ImageConversion.LoadImage(val, data); Sprite val2 = Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f)); switch (name) { case "coll_ap": ArchipelagoCollection = val2; break; case "coll_ap_filter": ArchipelagoCollectionFiltered = val2; break; case "coll_ap_locked": ArchipelagoCollectionLocked = val2; break; default: ArchipelagoPlugin.Logger.LogWarning((object)("Sprite loaded but unknown name: " + name)); break; } if (Object.op_Implicit((Object)(object)Archipelago) && Object.op_Implicit((Object)(object)ArchipelagoGrey) && Object.op_Implicit((Object)(object)DifficultyIndicator) && Object.op_Implicit((Object)(object)DifficultyIndicatorGrey) && Object.op_Implicit((Object)(object)HotDog) && Object.op_Implicit((Object)(object)HotDogGrey) && Object.op_Implicit((Object)(object)RankIndicator) && Object.op_Implicit((Object)(object)RankIndicatorGrey) && Object.op_Implicit((Object)(object)ArchipelagoCollection) && Object.op_Implicit((Object)(object)ArchipelagoCollectionFiltered) && Object.op_Implicit((Object)(object)ArchipelagoCollectionLocked)) { TexturesLoaded = true; } } } public static class ItemHandler { private static Timer timer; private static List ItemQueue; private static readonly List ReceivedTracks; private static bool HasDifficulty2; private static bool HasDifficulty3; private static bool HasDifficulty4; private static bool HasDifficulty5; private static bool HasDifficulty6; private static bool HasDifficulty7; private static bool HasDifficulty8; private static bool HasDifficulty9; private static bool HasDifficulty10; public static int RankReductions { get; private set; } public static int HotDogs { get; private set; } public static int ProgressiveDifficulties { get; private set; } static ItemHandler() { ItemQueue = new List(); ReceivedTracks = new List(); timer = new Timer(Run, null, 0, 100); } public static bool HasTrack(long ID) { try { for (int i = 0; i < ReceivedTracks.Count; i++) { if (ReceivedTracks[i] == ID) { return true; } } return false; } catch (IndexOutOfRangeException) { return false; } } public static bool HasDifficulty(int diff) { switch (diff) { case 2: return HasDifficulty2; case 3: return HasDifficulty3; case 4: return HasDifficulty4; case 5: return HasDifficulty5; case 6: return HasDifficulty6; case 7: return HasDifficulty7; case 8: return HasDifficulty8; case 9: return HasDifficulty9; case 10: return HasDifficulty10; default: ArchipelagoPlugin.Logger.LogWarning((object)$"HasDifficulty called with difficulty {diff}"); return false; } } public static void OnReceivedItems(List items) { lock (ItemQueue) { ItemQueue.AddRange(items); } } public static void ResetItems() { lock (timer) { ReceivedTracks.Clear(); RankReductions = 0; HotDogs = 0; ProgressiveDifficulties = 0; HasDifficulty2 = false; HasDifficulty3 = false; HasDifficulty4 = false; HasDifficulty5 = false; HasDifficulty6 = false; HasDifficulty7 = false; HasDifficulty8 = false; HasDifficulty9 = false; HasDifficulty10 = false; } } private static void Run(object state) { if (!Monitor.TryEnter(timer)) { return; } try { bool flag = false; bool flag2 = false; long[] array; lock (ItemQueue) { array = ItemQueue.ToArray(); ItemQueue.Clear(); } long[] array2 = array; foreach (long num in array2) { if (num < 1000) { ReceivedTracks.Add(num); } else { switch (num) { case 1001L: RankReductions++; break; case 1004L: HotDogs++; break; case 1011L: ProgressiveDifficulties++; break; case 1012L: HasDifficulty2 = true; break; case 1013L: HasDifficulty3 = true; break; case 1014L: HasDifficulty4 = true; break; case 1015L: HasDifficulty5 = true; break; case 1016L: HasDifficulty6 = true; break; case 1017L: HasDifficulty7 = true; break; case 1018L: HasDifficulty8 = true; break; case 1019L: HasDifficulty9 = true; break; case 1020L: HasDifficulty10 = true; break; } } bool flag3 = num > 0 && num < 1000; bool flag4 = flag3; bool flag5; if (!flag4) { flag5 = ((num == 1001 || num == 1004) ? true : false); flag4 = flag5; } if (flag4 || num > 1010) { flag = true; } flag5 = ((num == 1001 || num == 1004 || num == 1011) ? true : false); if (flag5 || num > 1011) { flag2 = true; } } if (flag) { APHandler.OnTrackAvailabilityChanged(); } else if (flag2) { APHandler.OnHintsChanged(); } } catch (Exception ex) { ArchipelagoPlugin.Logger.LogError((object)ex); } finally { Monitor.Exit(timer); } } } public interface APCollection { bool HasNoTracks(); string GetNoTrackString(); } public class TrackCollectionAllAP : BaseTromboneCollection, APCollection { public TrackCollectionAllAP() : base("AP", "Archipelago", "All tracks required for Archipelago") { } public override IEnumerable BuildTrackList() { int yielded = 0; ArrayList unseen = new ArrayList(APHandler.FilteredTracks); List unknownTracks = new List(); foreach (TromboneTrack track in (IEnumerable)TrackLookup.allTracks()) { Track? match = null; foreach (Track trackDef in unseen) { if (trackDef.Name.ToLower() == track.trackname_short.ToLower()) { match = trackDef; break; } } if (match.HasValue) { unseen.Remove(match); yielded++; yield return track; } else { unknownTracks.Add(track.trackname_short); } } if (unseen.Count > 0) { foreach (Track missed in unseen) { ArchipelagoPlugin.Logger.LogInfo((object)("Missed track: " + missed.Name)); } foreach (string unknown in unknownTracks) { ArchipelagoPlugin.Logger.LogInfo((object)("Unknown track: " + unknown)); } } if (yielded == 0) { yield return ((IEnumerable)TrackLookup.allTracks()).First((TromboneTrack val) => val.trackname_short == "Warm-Up"); } } public override YieldTask> LoadSprite() { return Coroutines.sync>(FuncConvert.FromFunc>((Func>)(() => FSharpResult.NewOk(ImageHandler.ArchipelagoCollection)))); } public bool HasNoTracks() { foreach (TromboneTrack item in (IEnumerable)TrackLookup.allTracks()) { Track[] filteredTracks = APHandler.FilteredTracks; for (int i = 0; i < filteredTracks.Length; i++) { Track track = filteredTracks[i]; if (track.Name.ToLower() == item.trackname_short.ToLower()) { return false; } } } return true; } public string GetNoTrackString() { return "AP song list is empty!\nReport this with your config included."; } } public class TrackCollectionAvailWithChecksOnly : BaseTromboneCollection, APCollection { public TrackCollectionAvailWithChecksOnly() : base("AP_checks", "Archipelago Checks", "Tracks that are unlocked and have checks remaining") { } public override IEnumerable BuildTrackList() { int yielded = 0; ArrayList unseen = new ArrayList(APHandler.FilteredTracks); List unknownTracks = new List(); foreach (TromboneTrack track in (IEnumerable)TrackLookup.allTracks()) { Track? match = null; foreach (Track trackDef in unseen) { if (trackDef.Name.ToLower() == track.trackname_short.ToLower()) { match = trackDef; break; } } if (match.HasValue) { unseen.Remove(match.Value); if (APHandler.IsTrackAvailable(match.Value) && (!APHandler.BeatenTracks.Contains(match.Value.ID) || !APHandler.APSentLocations.Contains(match.Value.ID) || !APHandler.APSentLocations.Contains(match.Value.ID + 1000))) { yielded++; yield return track; } } else { unknownTracks.Add(track.trackname_short); } } if (unseen.Count > 0) { foreach (Track missed in unseen) { ArchipelagoPlugin.Logger.LogInfo((object)("Missed track: " + missed.Name)); } foreach (string unknown in unknownTracks) { ArchipelagoPlugin.Logger.LogInfo((object)("Unknown track: " + unknown)); } } if (yielded == 0) { yield return ((IEnumerable)TrackLookup.allTracks()).First((TromboneTrack val) => val.trackname_short == "Warm-Up"); } } public override YieldTask> LoadSprite() { return Coroutines.sync>(FuncConvert.FromFunc>((Func>)(() => FSharpResult.NewOk(ImageHandler.ArchipelagoCollectionFiltered)))); } public bool HasNoTracks() { foreach (TromboneTrack item in (IEnumerable)TrackLookup.allTracks()) { Track[] filteredTracks = APHandler.FilteredTracks; for (int i = 0; i < filteredTracks.Length; i++) { Track track = filteredTracks[i]; if (track.Name.ToLower() == item.trackname_short.ToLower() && APHandler.IsTrackAvailable(track) && (!APHandler.BeatenTracks.Contains(track.ID) || !APHandler.APSentLocations.Contains(track.ID) || !APHandler.APSentLocations.Contains(track.ID + 1000))) { return false; } } } return true; } public string GetNoTrackString() { return "No songs left to play.\nMaybe press F2 to hint something?"; } } public class TrackCollectionLockedOnly : BaseTromboneCollection, APCollection { public TrackCollectionLockedOnly() : base("AP_locked", "Archipelago Locked", "Tracks that aren't yet available") { } public override IEnumerable BuildTrackList() { int yielded = 0; ArrayList unseen = new ArrayList(APHandler.FilteredTracks); List unknownTracks = new List(); foreach (TromboneTrack track in (IEnumerable)TrackLookup.allTracks()) { Track? match = null; foreach (Track trackDef in unseen) { if (trackDef.Name.ToLower() == track.trackname_short.ToLower()) { match = trackDef; break; } } if (match.HasValue) { unseen.Remove(match.Value); if (!APHandler.IsTrackAvailable(match.Value)) { yielded++; yield return track; } } else { unknownTracks.Add(track.trackname_short); } } if (unseen.Count > 0) { foreach (Track missed in unseen) { ArchipelagoPlugin.Logger.LogInfo((object)("Missed track: " + missed.Name)); } foreach (string unknown in unknownTracks) { ArchipelagoPlugin.Logger.LogInfo((object)("Unknown track: " + unknown)); } } if (yielded == 0) { yield return ((IEnumerable)TrackLookup.allTracks()).First((TromboneTrack val) => val.trackname_short == "Warm-Up"); } } public override YieldTask> LoadSprite() { return Coroutines.sync>(FuncConvert.FromFunc>((Func>)(() => FSharpResult.NewOk(ImageHandler.ArchipelagoCollectionLocked)))); } public bool HasNoTracks() { foreach (TromboneTrack item in (IEnumerable)TrackLookup.allTracks()) { Track[] filteredTracks = APHandler.FilteredTracks; for (int i = 0; i < filteredTracks.Length; i++) { Track track = filteredTracks[i]; if (track.Name.ToLower() == item.trackname_short.ToLower() && !APHandler.IsTrackAvailable(track)) { return false; } } } return true; } public string GetNoTrackString() { return "All songs unlocked.\nGo play them!"; } } public class TrackCollectionListener : Listener { public static readonly Dictionary COLLECTIONS = new Dictionary { { "AP", (BaseTromboneCollection)(object)new TrackCollectionAllAP() }, { "AP_checks", (BaseTromboneCollection)(object)new TrackCollectionAvailWithChecksOnly() }, { "AP_locked", (BaseTromboneCollection)(object)new TrackCollectionLockedOnly() } }; public IEnumerable OnRegisterCollections() { foreach (BaseTromboneCollection value in COLLECTIONS.Values) { yield return (TromboneCollection)(object)value; } } } public struct TrackHints { public Hint TrackUnlock; public Hint[] DifficultyUnlocks; public Hint PlayReward; public Hint BeatReward; public TrackHints() { TrackUnlock = null; DifficultyUnlocks = Array.Empty(); PlayReward = null; BeatReward = null; } } public static class MyPluginInfo { public const string PLUGIN_GUID = "APTromboneChampMod"; public const string PLUGIN_NAME = "AP Trombone"; public const string PLUGIN_VERSION = "0.0.1"; } }