using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.IO; using System.Net.Http; using System.Net.WebSockets; 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 BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using HutongGames.PlayMaker; using HutongGames.PlayMaker.Actions; using Microsoft.CodeAnalysis; using Silksong.DataManager; using UnityEngine; using UnityEngine.EventSystems; using UnityEngine.Events; using UnityEngine.SceneManagement; using UnityEngine.UI; using VogsBingoMod.Automarking; using VogsBingoMod.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("VogsBingoMod")] [assembly: AssemblyConfiguration("Debug")] [assembly: AssemblyFileVersion("1.1.2.0")] [assembly: AssemblyInformationalVersion("1.1.2+a778e6d701569f84725f36ba18592f2c34dae3b8")] [assembly: AssemblyProduct("VogsBingoMod")] [assembly: AssemblyTitle("VogsBingoMod")] [assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/AtlasOfSouls/VogsBingoMod")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.1.2.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [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 BepInEx { [AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)] [Conditional("CodeGeneration")] internal sealed class BepInAutoPluginAttribute : Attribute { public BepInAutoPluginAttribute(string? id = null, string? name = null, string? version = null) { } } } namespace BepInEx.Preloader.Core.Patching { [AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)] [Conditional("CodeGeneration")] internal sealed class PatcherAutoPluginAttribute : Attribute { public PatcherAutoPluginAttribute(string? id = null, string? name = null, string? version = null) { } } } namespace VogsBingoMod { internal enum ConnectionState { NotConnected, Connecting, Connected, Disconnecting } internal class Coroutiner : MonoBehaviour { private static GameObject? coroutineObj; private static Coroutiner? coroutineComponent; internal static void CreateCoroutine(IEnumerator enumerator) { if ((Object)(object)coroutineComponent != (Object)null) { ((MonoBehaviour)coroutineComponent).StartCoroutine(enumerator); } else { VogsBingoModPlugin.LogError("Failed to start coroutine."); } } internal static void Initialize() { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Expected O, but got Unknown coroutineObj = new GameObject("BingoModCoroutineObject"); Object.DontDestroyOnLoad((Object)(object)coroutineObj); coroutineComponent = coroutineObj.AddComponent(); } } internal static class JsonHelper { internal static string[] GetNamesFromBoard(string boardJson) { string[] array = boardJson.Split("}, {"); string[] array2 = new string[array.Length]; for (int i = 0; i < array.Length; i++) { int num = int.Parse(GetStringValueOfKey("slot", array[i]).Substring(4)) - 1; array2[num] = GetStringValueOfKey("name", array[i]); } return array2; } internal static int[][] GetColorsFromBoard(string boardJson) { string[] array = boardJson.Split("}, {"); int[][] array2 = new int[array.Length][]; for (int i = 0; i < array.Length; i++) { string[] array3 = GetStringValueOfKey("colors", array[i]).Split(" "); if (array3.Length == 1 && array3[0].Equals("blank")) { array2[i] = new int[0]; } else { array2[i] = new int[array3.Length]; } for (int j = 0; j < array2[i].Length; j++) { array2[i][j] = GoalColors.NameToID(array3[j]); } } return array2; } internal static string GetStringValueOfKey(string key, string jsonObj) { int num = jsonObj.IndexOf(key); int num2 = num + key.Length + 4; int num3 = jsonObj.IndexOf("\"", num2); int length = num3 - num2; return jsonObj.Substring(num2, length); } internal static bool GetBoolValueOfKey(string key, string jsonObj) { int num = jsonObj.IndexOf(key); int startIndex = num + key.Length + 3; if (jsonObj.Substring(startIndex, 4).Equals("true")) { return true; } if (jsonObj.Substring(startIndex, 5).Equals("false")) { return false; } throw new Exception("The value of the key you requested (" + key + ") was not a boolean."); } internal static string GetObjectValueOfKey(string key, string jsonObj) { int num = jsonObj.IndexOf(key); int num2 = num + key.Length + 4; int num3 = 0; int num4 = 1; for (int i = num2; i < jsonObj.Length; i++) { if (jsonObj[i] == '{') { num4++; } else if (jsonObj[i] == '}') { num4--; if (num4 <= 0) { num3 = i; break; } } } int length = num3 - num2; return jsonObj.Substring(num2, length); } internal static double GetDoubleValueFromKey(string key, string jsonObj) { int num = jsonObj.IndexOf(key); int num2 = num + key.Length + 3; int num3 = num2; for (int i = num2; i < jsonObj.Length; i++) { if ((jsonObj[i] < '0' || jsonObj[i] > '9') && jsonObj[i] != '.') { num3 = i; break; } } int length = num3 - num2; return double.Parse(jsonObj.Substring(num2, length)); } internal static string CreateGoalMarkJson(int slotIndex, string roomCode, string color, bool remove, RoomType roomType) { if (roomType == RoomType.Bingosync) { return $"{{\"slot\": {slotIndex}, \"color\": \"{color}\", \"remove_color\": {remove.ToString().ToLower()}, \"room\": \"{roomCode}\"}}"; } return $"{{\"slot\": {slotIndex}, \"color\": \"{color}\", \"remove_color\": {remove.ToString().ToLower()}, \"room\": \"{roomCode}\"}}"; } internal static string CreateColorSwitchJson(int colorID, string roomCode, RoomType roomType) { return "{\"room\": \"" + roomCode + "\", \"color\": \"" + GoalColors.IDToName(colorID) + "\"}"; } internal static string CreateRevealCardJson(string roomCode) { return "{\"room\": \"" + roomCode + "\"}"; } internal static string[] GetGoalNamesFromList(string json) { string[] array = json.Split("},"); for (int i = 0; i < array.Length; i++) { array[i] = GetStringValueOfKey("name", array[i]).ToLower(); } return array; } internal static Dictionary GetSupportedGoals(string json) { Dictionary dictionary = new Dictionary(); string[] array = json.Split("},"); for (int i = 0; i < array.Length; i++) { string key = GetStringValueOfKey("name", array[i]).ToLower(); dictionary.Add(key, GetBoolValueOfKey("automarking_support", array[i])); } return dictionary; } } internal static class NetworkHandler { private class HttpTaskList : Dictionary, CancellationTokenSource> { private bool isExitingRoom = false; internal new void Add(Task task, CancellationTokenSource tokenSource) { base.Add(task, tokenSource); Coroutiner.CreateCoroutine(UIHelper.SetConnectionPendingActive_Main(setActive: true)); } internal new bool Remove(Task task) { if (ContainsKey(task)) { base[task].Cancel(); base[task].Dispose(); task.Dispose(); bool result = base.Remove(task); Coroutiner.CreateCoroutine(UIHelper.SetConnectionPendingActive_Main(base.Count > 0 || isExitingRoom)); return result; } return false; } internal new void Clear() { using (Dictionary, CancellationTokenSource>.Enumerator enumerator = GetEnumerator()) { while (enumerator.MoveNext()) { KeyValuePair, CancellationTokenSource> current = enumerator.Current; current.Value.Cancel(); current.Value.Dispose(); current.Key.Dispose(); } } base.Clear(); Coroutiner.CreateCoroutine(UIHelper.SetConnectionPendingActive_Main(isExitingRoom)); } internal void SetIsExitingRoom(bool isExitingRoom) { this.isExitingRoom = isExitingRoom; if (isExitingRoom) { Coroutiner.CreateCoroutine(UIHelper.SetConnectionPendingActive_Main(setActive: true)); } else { Coroutiner.CreateCoroutine(UIHelper.SetConnectionPendingActive_Main(base.Count > 0)); } } internal void CheckForTimeout() { bool flag = false; foreach (CancellationTokenSource value in base.Values) { if (value.IsCancellationRequested) { flag = true; } } if (flag || (webSocketClient != null && connectState == ConnectionState.Connected && webSocketClient.State != WebSocketState.Open)) { VogsBingoModPlugin.LogInfo("CANCEL REQUESTED"); ForceExitRoomWithDisconnectError(1); } } } private const string startOfBingosyncRoomLink = "https://bingosync.com/room/"; private const string startOfCaravanRoomLink = "https://caravan.kobold60.com/room/"; private const float WSCheckInterval = 5f; private const int defaultTimeout = 15000; private static HttpClient httpClient = new HttpClient { Timeout = TimeSpan.FromSeconds(15.0) }; private static ClientWebSocket? webSocketClient; private static string socketKeyJson = string.Empty; private static string roomCode = string.Empty; private static byte[] receivedWebSocketMessage = new byte[1024]; private static UTF8Encoding utf8 = new UTF8Encoding(encoderShouldEmitUTF8Identifier: false, throwOnInvalidBytes: true); private static string domainName = ""; private static string socketDomainName = ""; private static HttpTaskList CurrentHttpTasks = new HttpTaskList(); private static CancellationTokenSource cancellationTokenSource = new CancellationTokenSource(); private static float timer = 0f; internal static ConnectionState connectState { get; private set; } = ConnectionState.NotConnected; internal static bool CanConnectToRoom => connectState == ConnectionState.NotConnected; internal static bool CanDisconnectFromRoom => connectState == ConnectionState.Connected; internal static RoomType roomType { get; private set; } = RoomType.Bingosync; internal static void Update() { if (timer <= 0f) { timer = 5f; CurrentHttpTasks.CheckForTimeout(); } else { timer -= Time.unscaledDeltaTime; } } internal static void SendRevealCardMessage() { if (connectState == ConnectionState.Connected) { string content = JsonHelper.CreateRevealCardJson(roomCode); StringContent content2 = new StringContent(content, Encoding.UTF8, "application/json"); SendPostRequest("https://" + domainName + ".com/api/revealed", content2, requiresWS: true)?.ContinueWith(VerifyReveal); } } private static void VerifyReveal(Task revealCardTask) { HttpResponseMessage result = revealCardTask.Result; CurrentHttpTasks.Remove(revealCardTask); try { result.EnsureSuccessStatusCode(); } catch (Exception ex) { VogsBingoModPlugin.LogError(ex.Message ?? ""); Coroutiner.CreateCoroutine(UIHelper.TriggerErrorText_Main()); } Task task = result.Content.ReadAsStringAsync(); task.ContinueWith(LogComplete); } internal static void SetMyColor(int newColorID) { if (connectState == ConnectionState.Connected) { string content = JsonHelper.CreateColorSwitchJson(newColorID, roomCode, roomType); StringContent content2 = new StringContent(content, Encoding.UTF8, "application/json"); SendPostRequest("https://" + domainName + ".com/api/color", content2, requiresWS: true)?.ContinueWith(PostColorSwitch); } } private static void PostColorSwitch(Task switchColorTask) { HttpResponseMessage result = switchColorTask.Result; CurrentHttpTasks.Remove(switchColorTask); try { result.EnsureSuccessStatusCode(); } catch (Exception ex) { VogsBingoModPlugin.LogError(ex.Message ?? ""); Coroutiner.CreateCoroutine(UIHelper.TriggerErrorText_Main()); } Task task = result.Content.ReadAsStringAsync(); task.ContinueWith(LogComplete); } internal static void MarkGoal(int slotIndex, bool remove, string color) { if (connectState == ConnectionState.Connected) { string content = JsonHelper.CreateGoalMarkJson(slotIndex + 1, roomCode, color, remove, roomType); StringContent content2 = new StringContent(content, Encoding.UTF8, "application/json"); try { SendPostRequest("https://" + domainName + ".com/api/select", content2, requiresWS: true)?.ContinueWith(PostMark); } catch (Exception e) { VogsBingoModPlugin.LogError(e); } } } private static void PostMark(Task markTask) { HttpResponseMessage result = markTask.Result; CurrentHttpTasks.Remove(markTask); bool flag = false; try { result.EnsureSuccessStatusCode(); } catch (Exception) { flag = true; } Task task = result.Content.ReadAsStringAsync(); task.ContinueWith(CheckForLockoutBlock, flag); } private static void CheckForLockoutBlock(Task task, object data) { bool flag = (bool)data; string result = task.Result; task.Dispose(); if (flag && !result.Equals("Blocked by Lockout")) { Coroutiner.CreateCoroutine(UIHelper.TriggerErrorText_Main()); } else if (flag) { VogsBingoModPlugin.LogInfo("Mark was blocked by lockout."); } } private static void LogComplete(Task task) { task.Dispose(); } internal static void JoinRoom(string roomUrl, string nicknameInput, string passwordInput) { if (connectState != ConnectionState.NotConnected) { return; } if (roomUrl.Length > "https://bingosync.com/room/".Length && roomUrl.Substring(0, "https://bingosync.com/room/".Length).Equals("https://bingosync.com/room/")) { VogsBingoModPlugin.LogInfo("Attempting to connect to bingosync room..."); roomCode = roomUrl.Substring("https://bingosync.com/room/".Length); domainName = "www.bingosync"; socketDomainName = "bingosync"; roomType = RoomType.Bingosync; } else { if (roomUrl.Length <= "https://caravan.kobold60.com/room/".Length || !roomUrl.Substring(0, "https://caravan.kobold60.com/room/".Length).Equals("https://caravan.kobold60.com/room/")) { VogsBingoModPlugin.LogInfo("The room link that was entered could not be recognized."); return; } VogsBingoModPlugin.LogInfo("Attempting to connect to caravan room..."); roomCode = roomUrl.Substring("https://caravan.kobold60.com/room/".Length); domainName = "caravan.kobold60"; socketDomainName = "kobold60"; roomType = RoomType.Caravan; } connectState = ConnectionState.Connecting; Coroutiner.CreateCoroutine(UIHelper.NotifyOfConnectingToRoom_Main()); string content = "{\"room\": \"" + roomCode + "\",\n\"nickname\": \"" + nicknameInput + "\",\n\"password\": \"" + passwordInput + "\"}"; StringContent content2 = new StringContent(content, Encoding.UTF8, "application/json"); try { SendPostRequest("https://" + domainName + ".com/api/join-room", content2, requiresWS: false)?.ContinueWith(ReadSocketKey); } catch (Exception e) { VogsBingoModPlugin.LogError(e); } } private static void ReadSocketKey(Task httpPostReqTask) { HttpResponseMessage result = httpPostReqTask.Result; CurrentHttpTasks.Remove(httpPostReqTask); try { result.EnsureSuccessStatusCode(); } catch (Exception) { connectState = ConnectionState.NotConnected; Coroutiner.CreateCoroutine(UIHelper.NotifyOfConnectingToRoomCancel_Main()); return; } try { Task task = result.Content.ReadAsStringAsync(); task.ContinueWith(StartWebSocket); } catch (Exception e) { VogsBingoModPlugin.LogError(e); } } private static void StartWebSocket(Task readSocketKeyTask) { VogsBingoModPlugin.LogInfo("Starting WS..."); socketKeyJson = readSocketKeyTask.Result; readSocketKeyTask.Dispose(); webSocketClient = new ClientWebSocket(); Uri uri = new Uri("wss://sockets." + socketDomainName + ".com/broadcast"); try { Task task = webSocketClient.ConnectAsync(uri, cancellationTokenSource.Token); task.ContinueWith(SendJoinViaWebSocket); } catch (Exception e) { VogsBingoModPlugin.LogError(e); Coroutiner.CreateCoroutine(UIHelper.NotifyOfConnectingToRoomCancel_Main(1)); } } private static void SendJoinViaWebSocket(Task wsTask) { byte[] bytes = utf8.GetBytes(socketKeyJson); if (webSocketClient != null) { try { wsTask = webSocketClient.SendAsync(bytes, WebSocketMessageType.Text, endOfMessage: true, cancellationTokenSource.Token); } catch (Exception e) { VogsBingoModPlugin.LogError(e); } socketKeyJson = string.Empty; } wsTask.ContinueWith(PostJoin); } private static void PostJoin(Task wsTask) { wsTask.Dispose(); StartListeningForMessages(); connectState = ConnectionState.Connected; Coroutiner.CreateCoroutine(UIHelper.NotifyOfRoomEnter_Main(roomType)); RequestBoardViaHttp(); } internal static void ExitRoom() { if (connectState == ConnectionState.Connected && webSocketClient != null) { roomCode = string.Empty; domainName = string.Empty; socketDomainName = string.Empty; VogsBingoModPlugin.LogInfo("Starting the process of leaving the room..."); connectState = ConnectionState.Disconnecting; try { Task task = webSocketClient.CloseAsync(WebSocketCloseStatus.NormalClosure, "Exit Room button", CancellationToken.None); CurrentHttpTasks.SetIsExitingRoom(isExitingRoom: true); task.ContinueWith(PostExit); } catch (Exception e) { VogsBingoModPlugin.LogError(e); ForceExitRoomWithDisconnectError(2); } } } private static void PostExit(Task wsTask) { CurrentHttpTasks.SetIsExitingRoom(isExitingRoom: false); wsTask.Dispose(); CancelHttpTasks(); if (webSocketClient != null) { webSocketClient.Dispose(); } webSocketClient = null; connectState = ConnectionState.NotConnected; Coroutiner.CreateCoroutine(UIHelper.NotifyOfRoomExit_Main()); VogsBingoModPlugin.LogInfo("The room has been exited."); } internal static void RequestBoardViaHttp() { try { SendGetRequest("https://" + domainName + ".com/room/" + roomCode + "/board", requiresWS: true)?.ContinueWith(ReadBoard); } catch (Exception e) { VogsBingoModPlugin.LogError(e); } } private static void ReadBoard(Task httpGetReqTask) { HttpResponseMessage result = httpGetReqTask.Result; CurrentHttpTasks.Remove(httpGetReqTask); try { result.EnsureSuccessStatusCode(); } catch (Exception ex) { VogsBingoModPlugin.LogError("Error requesting the board: " + ex.Message); } Task task = result.Content.ReadAsStringAsync(); task.ContinueWith(SendBoardToUI); } private static void SendBoardToUI(Task readBoardTask) { string result = readBoardTask.Result; readBoardTask.Dispose(); Coroutiner.CreateCoroutine(UIHelper.SetBoard_Main(result, roomType)); } private static void StartListeningForMessages() { if (webSocketClient != null) { try { Task task = webSocketClient.ReceiveAsync(receivedWebSocketMessage, cancellationTokenSource.Token); task.ContinueWith(ReceiveWSMessage); } catch (Exception e) { VogsBingoModPlugin.LogError(e); } } } private static void ReceiveWSMessage(Task wsTask) { WebSocketReceiveResult result = wsTask.Result; if (result.MessageType == WebSocketMessageType.Text) { string text = Encoding.UTF8.GetString(receivedWebSocketMessage); string stringValueOfKey = JsonHelper.GetStringValueOfKey("type", text); string text2 = stringValueOfKey; if (!(text2 == "goal")) { if (text2 == "new-card") { HandleNewCardMessage(); } } else { HandleGoalMessage(text); } } Array.Clear(receivedWebSocketMessage, 0, receivedWebSocketMessage.Length); if (webSocketClient != null) { try { wsTask = webSocketClient.ReceiveAsync(receivedWebSocketMessage, cancellationTokenSource.Token); wsTask.ContinueWith(ReceiveWSMessage); return; } catch (Exception e) { VogsBingoModPlugin.LogError(e); return; } } wsTask.Dispose(); } private static void HandleGoalMessage(string jsonStr) { int colorID = GoalColors.NameToID(JsonHelper.GetStringValueOfKey("color", jsonStr)); bool boolValueOfKey = JsonHelper.GetBoolValueOfKey("remove", jsonStr); int slotIndex = int.Parse(JsonHelper.GetStringValueOfKey("slot", JsonHelper.GetObjectValueOfKey("square", jsonStr)).Substring(4)) - 1; try { Coroutiner.CreateCoroutine(UIHelper.UpdateGoal_Main(colorID, boolValueOfKey, slotIndex)); } catch (Exception e) { VogsBingoModPlugin.LogError(e); } } private static void HandleNewCardMessage() { Coroutiner.CreateCoroutine(UIHelper.UnrevealCard_Main()); Coroutiner.CreateCoroutine(RequestNewBoardAfterWaiting()); } private static IEnumerator RequestNewBoardAfterWaiting() { yield return (object)new WaitForSecondsRealtime(1f); RequestBoardViaHttp(); } internal static void Dispose() { httpClient.Dispose(); cancellationTokenSource.Dispose(); if (webSocketClient != null) { webSocketClient.Dispose(); } } private static Task? SendPostRequest(string uri, HttpContent content, bool requiresWS) { if (!requiresWS || (webSocketClient != null && webSocketClient.State == WebSocketState.Open)) { try { CancellationTokenSource cancellationTokenSource = new CancellationTokenSource(); if (!requiresWS) { cancellationTokenSource.CancelAfter(15000); } Task task = httpClient.PostAsync(uri, content, cancellationTokenSource.Token); CurrentHttpTasks.Add(task, cancellationTokenSource); return task; } catch (Exception e) { VogsBingoModPlugin.LogError(e); } } ForceExitRoomWithDisconnectError(3); return null; } private static void ForceExitRoomWithDisconnectError(int errorCode) { cancellationTokenSource.Dispose(); cancellationTokenSource = new CancellationTokenSource(); VogsBingoModPlugin.LogInfo("Forcing disconnect"); if (webSocketClient != null) { webSocketClient.Dispose(); webSocketClient = null; } CancelHttpTasks(); connectState = ConnectionState.NotConnected; CurrentHttpTasks.SetIsExitingRoom(isExitingRoom: false); Coroutiner.CreateCoroutine(UIHelper.NotifyOfRoomExit_Main(errorCode)); } private static void CancelHttpTasks() { httpClient.CancelPendingRequests(); CurrentHttpTasks.Clear(); } private static Task? SendGetRequest(string uri, bool requiresWS) { if (!requiresWS || (webSocketClient != null && webSocketClient.State == WebSocketState.Open)) { try { CancellationTokenSource cancellationTokenSource = new CancellationTokenSource(); if (!requiresWS) { cancellationTokenSource.CancelAfter(15000); } Task async = httpClient.GetAsync(uri, cancellationTokenSource.Token); CurrentHttpTasks.Add(async, cancellationTokenSource); return async; } catch (Exception e) { VogsBingoModPlugin.LogError(e); } } ForceExitRoomWithDisconnectError(4); return null; } } internal enum RoomType { Bingosync, Caravan } [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInPlugin("io.github.atlasofsouls.VogsBingoMod", "VogsBingoMod", "1.1.2")] public class VogsBingoModPlugin : BaseUnityPlugin, ISaveDataMod, IRawSaveDataMod { internal enum UIScaleOptions { Default, Small, Tiny } internal const string PersistentName = "VogsBingoMod"; internal static VogsBingoModPlugin instance; private ManualLogSource logger; private ConfigEntry toggleUIVisibility; private ConfigEntry toggleUIOpacity; private ConfigEntry revealBoardKeybind; internal ConfigEntry uiScaleConfig; private SaveData _saveData = new SaveData(); public const string Id = "io.github.atlasofsouls.VogsBingoMod"; public SaveData SaveData { get { return _saveData; } [param: AllowNull] set { _saveData = ((value == null) ? new SaveData() : value); } } public static string Name => "VogsBingoMod"; public static string Version => "1.1.2"; internal static void LogInfo(string str) { instance.logger.LogInfo((object)str); } internal static void LogError(string str) { instance.logger.LogError((object)str); } internal static void LogError(Exception e) { instance.logger.LogError((object)(e.Message + ", " + e.StackTrace)); } private void Update() { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) Automarker.RunFrameChecks(); if (!UIHelper.IsTyping()) { if (Input.GetKeyDown(toggleUIVisibility.Value)) { UIHelper.CycleVisibility(); } if (Input.GetKeyDown(toggleUIOpacity.Value)) { UIHelper.CycleOpacity(); } if (Input.GetKeyDown(revealBoardKeybind.Value)) { UIHelper.RevealCardPressed(); } } NetworkHandler.Update(); } private void Awake() { //IL_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Expected O, but got Unknown instance = this; logger = ((BaseUnityPlugin)this).Logger; toggleUIVisibility = ((BaseUnityPlugin)this).Config.Bind("Keybinds", "Toggle UI", (KeyCode)98, "Cycles the currently active UI elements, allowing the user to show or hide the board as necessary."); toggleUIOpacity = ((BaseUnityPlugin)this).Config.Bind("Keybinds", "Toggle Opacity", (KeyCode)111, "Changes how transparent the UI is over the game."); revealBoardKeybind = ((BaseUnityPlugin)this).Config.Bind("Keybinds", "Reveal Card", (KeyCode)0, "Reveals the current bingo card."); uiScaleConfig = ((BaseUnityPlugin)this).Config.Bind("UI Settings", "UI Scale", UIScaleOptions.Default, "Change the size of the UI, such as the Bingo board."); uiScaleConfig.SettingChanged += UIScaleChanged; Harmony val = new Harmony("io.github.atlasofsouls.VogsBingoMod"); val.PatchAll(); UIHelper.uiCanvas.FirstAwake(); Coroutiner.Initialize(); AutomarkRosaryStringHandler.Initialize(); } private void OnDisable() { NetworkHandler.Dispose(); } private void UIScaleChanged(object? sender, EventArgs args) { UIHelper.UpdateUIScale(); } } } namespace VogsBingoMod.UI { internal static class FontHandler { private static Dictionary fonts = new Dictionary(); internal static Font GetFont(string fontName) { if (!fonts.ContainsKey(fontName)) { Font[] array = Resources.FindObjectsOfTypeAll(); for (int i = 0; i < array.Length; i++) { if (((Object)array[i]).name.Equals(fontName)) { fonts.Add(fontName, array[i]); break; } } } return fonts[fontName]; } } internal enum GoalColorID { none, pink, red, orange, brown, yellow, green, teal, blue, navy, purple, beastling, hornet, vespa, scrounge, sherma, huntress, gilly, magnetite, plasmium, architect } internal static class GoalColors { internal const int BingosyncColorsFirstID = 1; internal const int CaravanColorsFirstID = 11; internal static int myColorID = 2; internal static Color[] colorsList = (Color[])(object)new Color[21] { new Color(0f, 0f, 0f, 0f), new Color(1f, 0.7f, 1f, 0.7f), new Color(1f, 0f, 0f, 0.7f), new Color(1f, 0.4f, 0f, 0.7f), new Color(0.5f, 0.3f, 0f, 0.7f), new Color(1f, 1f, 0f, 0.7f), new Color(0f, 1f, 0f, 0.7f), new Color(0.2f, 0.5f, 0.5f, 0.7f), new Color(0f, 0.8f, 1f, 0.7f), new Color(0f, 0f, 1f, 0.7f), new Color(0.7f, 0.3f, 1f, 0.7f), new Color(1f, 0.5f, 0.6f, 0.7f), new Color(0.7f, 0.1f, 0.2f, 0.7f), new Color(0.7f, 0.3f, 0f, 0.7f), new Color(0.9f, 0.7f, 0.4f, 0.7f), new Color(0.9f, 0.8f, 0.1f, 0.7f), new Color(0.5f, 0.8f, 0.5f, 0.7f), new Color(0.1f, 0.5f, 0.2f, 0.7f), new Color(0.5f, 0.7f, 0.9f, 0.7f), new Color(0f, 0.3f, 0.7f, 0.7f), new Color(0.3f, 0.1f, 0.4f, 0.7f) }; internal static string MyColorName => IDToName(myColorID); internal static string[] ColorOptions => new string[21] { "none", "pink", "red", "orange", "brown", "yellow", "green", "teal", "blue", "navy", "purple", "beastling", "hornet", "vespa", "scrounge", "sherma", "huntress", "gilly", "magnetite", "plasmium", "architect" }; internal static int NameToID(string colorName) { string text = colorName.ToLower(); if (1 == 0) { } int result = text switch { "pink" => 1, "red" => 2, "orange" => 3, "brown" => 4, "yellow" => 5, "green" => 6, "teal" => 7, "blue" => 8, "navy" => 9, "purple" => 10, "beastling" => 11, "hornet" => 12, "vespa" => 13, "scrounge" => 14, "sherma" => 15, "huntress" => 16, "gilly" => 17, "magnetite" => 18, "plasmium" => 19, "architect" => 20, _ => 0, }; if (1 == 0) { } return result; } internal static string IDToName(int colorID) { return ColorOptions[colorID]; } internal static void SetMyColorToDefault(RoomType roomType) { if (roomType == RoomType.Bingosync) { myColorID = 2; } else { myColorID = 12; } } } internal static class TextureHandler { private const int goalPngWidth = 100; private const int goalPngHeight = 100; internal const string standardBackgroundName = "StandardBackground"; internal const string standardBackgroundHighlightName = "StandardBackgroundHighlight"; private static Dictionary textures = new Dictionary(); private static Dictionary sprites = new Dictionary(); internal static Texture2D GetTexture(string imgName) { imgName = "VogsBingoMod.Assets." + imgName + ".png"; if (textures.Count <= 0) { LoadTextures(); } if (!textures.ContainsKey(imgName)) { VogsBingoModPlugin.LogError("could not find sprite \"" + imgName + "\""); } return textures[imgName]; } internal static void SetSprite(string spriteName, Image imgComponent) { imgComponent.sprite = GetSprite(spriteName); } internal static Sprite CreateGoalColorsSprite() { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Expected O, but got Unknown //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) Texture2D val = new Texture2D(95, 95); ClearTexture(val); return Sprite.Create(val, new Rect(0f, 0f, 95f, 95f), Vector2.one * 0.5f); } internal static void ClearTexture(Texture2D texture) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) for (int i = 0; i < ((Texture)texture).width; i++) { for (int j = 0; j < ((Texture)texture).height; j++) { texture.SetPixel(i, j, GoalColors.colorsList[0]); } } texture.Apply(); } internal static bool ShouldSliceSprite(string imgName) { return imgName.Equals("StandardBackground") || imgName.Equals("StandardBackgroundHighlight"); } private static byte[] LoadEmbeddedImage(string imgName) { Assembly executingAssembly = Assembly.GetExecutingAssembly(); Stream manifestResourceStream = executingAssembly.GetManifestResourceStream(imgName ?? ""); if (manifestResourceStream == null) { VogsBingoModPlugin.LogError("Could not find resource: " + imgName); return new byte[0]; } MemoryStream memoryStream = new MemoryStream(); manifestResourceStream.CopyTo(memoryStream); byte[] result = memoryStream.ToArray(); manifestResourceStream.Dispose(); memoryStream.Dispose(); return result; } internal static void LoadTextures() { //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Expected O, but got Unknown string[] manifestResourceNames = Assembly.GetExecutingAssembly().GetManifestResourceNames(); foreach (string text in manifestResourceNames) { if (text.StartsWith("VogsBingoMod.Assets.")) { Texture2D val = new Texture2D(1, 1); byte[] array = LoadEmbeddedImage(text); ImageConversion.LoadImage(val, array); textures.Add(text, val); } } } private static Sprite GetSprite(string spriteName) { //IL_0034: 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) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) if (!sprites.ContainsKey(spriteName)) { Texture2D texture = GetTexture(spriteName); Sprite value = Sprite.Create(texture, new Rect(0f, 0f, (float)((Texture)texture).width, (float)((Texture)texture).height), Vector2.one * 0.5f, 100f, 0u, (SpriteMeshType)0, Vector4.one * 5f); sprites.Add(spriteName, value); } return sprites[spriteName]; } } internal enum UIAnchor { MiddleCenter, TopRight } internal class UIButton : MonoBehaviour, IPointerClickHandler, IEventSystemHandler { internal Action? leftClickCallback { get; private set; } internal Action? rightClickCallback { get; private set; } public void OnPointerClick(PointerEventData eventData) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Invalid comparison between Unknown and I4 //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Invalid comparison between Unknown and I4 if ((int)eventData.button == 0) { LeftClick(); } else if ((int)eventData.button == 1) { RightClick(); } } internal void SetupCallbacks(Action? leftClickAction, Action? rightClickAction) { leftClickCallback = leftClickAction; rightClickCallback = rightClickAction; } internal void LeftClick() { if (leftClickCallback != null) { leftClickCallback(); } } internal void RightClick() { if (rightClickCallback != null) { rightClickCallback(); } } } internal class UICanvas : MonoBehaviour { private const int goalSpacing = 110; private const int goalsXOffset = 90; private const int goalsYOffset = -10; private const int sortOrder = 10000; private const int defaultBoardSize = 5; private const int defaultcolorOptions = 10; private const float defaultUIScale = 1f; private const float smallUIScale = 0.8f; private const float tinyUIScale = 0.6f; internal GameObject boardObj; internal UIButton? revealCardButton; internal UIButton? revealHandModeButton; internal UIButton? joinRoomButton; internal UIButton? exitRoomButton; internal UITextInput? roomUrlInputField; internal UITextInput? nicknameInputField; internal UITextInput? passwordInputField; internal UIDropdown? teamColorsDropdown; internal UIText? loadingCardText; internal UIText? errorText; internal UIText? connectingErrorText; internal GameObject? connectionPendingIcon; internal List bingosyncColorOptions; internal List caravanColorOptions; private static UICanvas? instance; private float[] opacityOptions = new float[4] { 1f, 0.8f, 0.5f, 0.3f }; private int currentOpacityIndex = 0; private UIGoal[] uiGoals; internal float currentScale { get; private set; } internal static UICanvas GetInstance() { //IL_0016: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)instance == (Object)null) { instance = new GameObject("BingoCanvas").AddComponent(); } return instance; } internal void FirstAwake() { Object.DontDestroyOnLoad((Object)(object)((Component)this).gameObject); boardObj = UIHelper.CreateUIObject(((Component)this).transform, "BoardContainer", 0f, 0f, 100f, 100f, UIAnchor.TopRight); SceneManager.activeSceneChanged += OnSceneChange; ((Component)this).gameObject.SetActive(false); } internal void Initialize() { //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_0197: Unknown result type (might be due to invalid IL or missing references) //IL_027a: Unknown result type (might be due to invalid IL or missing references) //IL_03b6: Unknown result type (might be due to invalid IL or missing references) //IL_03c0: Expected O, but got Unknown //IL_03dc: Unknown result type (might be due to invalid IL or missing references) //IL_03e6: Expected O, but got Unknown Canvas val = ((Component)this).gameObject.AddComponent(); CanvasScaler val2 = ((Component)this).gameObject.AddComponent(); val2.uiScaleMode = (ScaleMode)1; val2.referenceResolution = Vector2.right * 1920f + Vector2.up * 1080f; val2.matchWidthOrHeight = 1f; GraphicRaycaster val3 = ((Component)this).gameObject.AddComponent(); val.sortingOrder = 10000; val.renderMode = (RenderMode)0; val3.blockingMask = LayerMask.op_Implicit(0); revealCardButton = UIHelper.CreateUIButton(boardObj.transform, "RevealCardButton", RevealCard, null, "Reveal Card", -230f, -200f); ((Component)revealCardButton).gameObject.SetActive(false); revealHandModeButton = UIHelper.CreateUIButton(((Component)revealCardButton).transform, "RevealCardInHandModeButton", RevealCardInHandMode, null, "Automark With Card Hidden", 0f, -110f); loadingCardText = UIHelper.CreateUIText(boardObj.transform, "LoadingCardText", "Loading Card...", 30, -230f, -200f, 300f, 100f, supportRichText: true, (TextAnchor)4); ((Component)loadingCardText).gameObject.SetActive(false); errorText = UIHelper.CreateUIText(((Component)this).transform, "ErrorText", "An error occurred while communicating with the room.", 30, -20f, -760f, 420f, 100f, supportRichText: true, (TextAnchor)4, Color.red, UIAnchor.TopRight); ((Component)errorText).gameObject.SetActive(false); connectionPendingIcon = UIHelper.CreateUIImage(boardObj.transform, "ConnectionPendingIcon", "ConnectionPendingIcon"); connectionPendingIcon.SetActive(false); SetupGoals(5); HideGoals(); joinRoomButton = UIHelper.CreateUIButton(((Component)this).transform, "JoinRoomButton", JoinRoomButtonClicked, null, "Join Room", -20f, -655f, UIAnchor.TopRight); connectingErrorText = UIHelper.CreateUIText(((Component)joinRoomButton).transform, "ConnectionErrorText", "An error occurred while connecting to the room. Check that the room link and password are correct.", 30, 0f, 160f, 420f, 200f, supportRichText: true, (TextAnchor)4, Color.red); ((Component)connectingErrorText).gameObject.SetActive(false); exitRoomButton = UIHelper.CreateUIButton(((Component)this).transform, "ExitRoomButton", ExitRoomButtonClicked, null, "Exit Room", -20f, -675f, UIAnchor.TopRight); ((Component)exitRoomButton).gameObject.SetActive(false); roomUrlInputField = UIHelper.CreateUITextInput(((Component)joinRoomButton).gameObject.transform, "RoomLinkInput", "Enter the room link...", 0f, -100f); nicknameInputField = UIHelper.CreateUITextInput(((Component)joinRoomButton).gameObject.transform, "NicknameInput", "Enter your nickname...", 0f, -180f); passwordInputField = UIHelper.CreateUITextInput(((Component)joinRoomButton).gameObject.transform, "PasswordInput", "Enter the room password...", 0f, -260f, isPassword: true); bingosyncColorOptions = new List(); caravanColorOptions = new List(); for (int i = 0; i < 10; i++) { bingosyncColorOptions.Add(new OptionData(" " + GoalColors.ColorOptions[i + 1])); caravanColorOptions.Add(new OptionData(" " + GoalColors.ColorOptions[i + 11])); } teamColorsDropdown = UIHelper.CreateUIDropdown(((Component)exitRoomButton).transform, "TeamSelector", TeamChanged, bingosyncColorOptions, -325f, 30f); UpdateUIScale(); } internal void FixedUpdate() { //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)connectionPendingIcon != (Object)null && connectionPendingIcon.activeInHierarchy) { connectionPendingIcon.transform.Rotate(Vector3.forward * 3f, (Space)1); } } internal void ShowGoals() { UIButton? uIButton = revealCardButton; if (uIButton != null) { ((Component)uIButton).gameObject.SetActive(false); } for (int i = 0; i < uiGoals.Length; i++) { ((Component)uiGoals[i]).gameObject.SetActive(true); } } internal void HideGoals() { for (int i = 0; i < uiGoals.Length; i++) { ((Component)uiGoals[i]).gameObject.SetActive(false); } } internal void OnSceneChange(Scene oldScene, Scene newScene) { if (((Scene)(ref newScene)).name.Equals("Menu_Title")) { Initialize(); ((Component)this).gameObject.SetActive(true); SceneManager.activeSceneChanged -= OnSceneChange; } } internal void JoinRoomButtonClicked() { VogsBingoModPlugin.LogInfo("The room link that was entered was: " + roomUrlInputField?.GetText()); if (NetworkHandler.CanConnectToRoom && (Object)(object)roomUrlInputField != (Object)null && (Object)(object)nicknameInputField != (Object)null && (Object)(object)passwordInputField != (Object)null) { NetworkHandler.JoinRoom(roomUrlInputField.GetText(), nicknameInputField.GetText(), passwordInputField.GetText()); } } internal void ExitRoomButtonClicked() { if (NetworkHandler.CanDisconnectFromRoom) { UIButton? uIButton = exitRoomButton; if (uIButton != null) { ((Component)uIButton).gameObject.SetActive(false); } UIButton? uIButton2 = revealCardButton; if (uIButton2 != null) { ((Component)uIButton2).gameObject.SetActive(false); } HideGoals(); NetworkHandler.ExitRoom(); } } internal void SetGoalNames(string[] goalNames, int boardSize) { SetupGoals(boardSize); for (int i = 0; i < goalNames.Length; i++) { uiGoals[i].SetGoalName(goalNames[i]); } } internal void SetBoardColors(int[][] colorIDs) { for (int i = 0; i < colorIDs.Length; i++) { uiGoals[i].SetColors(colorIDs[i]); uiGoals[i].isHighlighted = false; } } internal void MarkGoal(int colorID, int slotIndex) { uiGoals[slotIndex].MarkGoal(colorID); } internal void UnmarkGoal(int colorID, int slotIndex) { uiGoals[slotIndex].UnmarkGoal(colorID); } internal void ResetBoard() { for (int i = 0; i < uiGoals.Length; i++) { uiGoals[i].ResetColors(); } } internal void TeamChanged(int newColorID) { newColorID = ((NetworkHandler.roomType != RoomType.Bingosync) ? (newColorID + 11) : (newColorID + 1)); GoalColors.myColorID = newColorID; VogsBingoModPlugin.LogInfo($"Switched color to {newColorID}, AKA {GoalColors.IDToName(newColorID)}"); NetworkHandler.SetMyColor(newColorID); } internal void RevealCard() { NetworkHandler.SendRevealCardMessage(); HideRevealCardButton(); ShowGoals(); } internal void RevealCardInHandMode() { NetworkHandler.SendRevealCardMessage(); HideRevealCardButton(); ShowGoals(); UIHelper.CycleVisibility(UIHelper.VisibilityState.Nothing); } internal void UnrevealCard() { ShowRevealCardButton(); HideGoals(); } internal void ShowRevealCardButton() { UIButton? uIButton = revealCardButton; if (uIButton != null) { ((Component)uIButton).gameObject.SetActive(true); } } internal void HideRevealCardButton() { UIButton? uIButton = revealCardButton; if (uIButton != null) { ((Component)uIButton).gameObject.SetActive(false); } } internal void ShowCardLoadingText() { UIText? uIText = loadingCardText; if (uIText != null) { ((Component)uIText).gameObject.SetActive(true); } HideRevealCardButton(); } internal void HideCardLoadingText() { UIText? uIText = loadingCardText; if (uIText != null) { ((Component)uIText).gameObject.SetActive(false); } } internal void CycleOpacity() { //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) currentOpacityIndex++; if (currentOpacityIndex >= opacityOptions.Length) { currentOpacityIndex = 0; } Image[] componentsInChildren = ((Component)this).gameObject.GetComponentsInChildren(true); Image[] array = componentsInChildren; foreach (Image val in array) { if (((Object)((Component)val).gameObject).name != "Blocker") { ((Graphic)val).color = new Color(((Graphic)val).color.r, ((Graphic)val).color.g, ((Graphic)val).color.b, opacityOptions[currentOpacityIndex]); } } } internal bool HasColor(int slotIndex, int colorID) { return uiGoals[slotIndex].HasColor(colorID); } internal void SetDropdownOptions(RoomType roomType) { if (roomType == RoomType.Bingosync) { teamColorsDropdown?.SetOptions(bingosyncColorOptions); } else { teamColorsDropdown?.SetOptions(caravanColorOptions); } } internal void UpdateUIScale() { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) float uIScaleFromConfig = GetUIScaleFromConfig(); boardObj.transform.localScale = Vector3.one * uIScaleFromConfig; UIButton? uIButton = joinRoomButton; if (uIButton != null) { ((Component)uIButton).gameObject.transform.localScale = Vector3.one * uIScaleFromConfig; } UIButton? uIButton2 = exitRoomButton; if (uIButton2 != null) { ((Component)uIButton2).gameObject.transform.localScale = Vector3.one * uIScaleFromConfig; } currentScale = uIScaleFromConfig; } private float GetUIScaleFromConfig() { VogsBingoModPlugin.UIScaleOptions uIScaleOptions = (VogsBingoModPlugin.UIScaleOptions)((ConfigEntryBase)VogsBingoModPlugin.instance.uiScaleConfig).BoxedValue; if (1 == 0) { } float result = uIScaleOptions switch { VogsBingoModPlugin.UIScaleOptions.Default => 1f, VogsBingoModPlugin.UIScaleOptions.Small => 0.8f, VogsBingoModPlugin.UIScaleOptions.Tiny => 0.6f, _ => 1f, }; if (1 == 0) { } return result; } private void SetupGoals(int boardSize) { //IL_00ff: Unknown result type (might be due to invalid IL or missing references) //IL_0109: Unknown result type (might be due to invalid IL or missing references) //IL_010e: Unknown result type (might be due to invalid IL or missing references) //IL_0118: Unknown result type (might be due to invalid IL or missing references) //IL_011d: Unknown result type (might be due to invalid IL or missing references) UIGoal[] array = new UIGoal[boardSize * boardSize]; int i = 0; if (uiGoals != null) { for (; i < array.Length && i < uiGoals.Length; i++) { int xPos = i % boardSize * 110 + 90 - 110 * boardSize; int yPos = i / boardSize * -110 + -10; array[i] = uiGoals[i]; array[i].SetPosition(xPos, yPos); } } for (; i < array.Length; i++) { int num = i % boardSize * 110 + 90 - 110 * boardSize; int num2 = i / boardSize * -110 + -10; array[i] = UIHelper.CreateUIGoal(boardObj.transform, $"Goal{i}", num, num2, i); array[i].SetOpacity(opacityOptions[currentOpacityIndex]); } uiGoals = array; GameObject? obj = connectionPendingIcon; if (obj != null) { obj.GetComponent().anchoredPosition = Vector2.right * (float)(-110 * boardSize) + Vector2.up * 25f; } HideGoals(); } } internal class UIDropdown : Dropdown { private const int defaultValue = 1; internal void SetOptions(List options) { ((Dropdown)this).ClearOptions(); ((Dropdown)this).AddOptions(options); ((Dropdown)this).SetValueWithoutNotify(1); } internal int IsOpen() { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Expected I4, but got Unknown return (int)((Selectable)this).currentSelectionState; } } internal class UIGoal : MonoBehaviour { internal UIGoalColors goalColors; internal int slotIndex = -1; private UIText? goalText; private bool _isHighlighted = false; internal bool isHighlighted { get { return _isHighlighted; } set { if (value != _isHighlighted) { _isHighlighted = value; UpdateHighlightStatus(); } } } private Image imageComponent => ((Component)this).gameObject.GetComponent(); internal void SetGoalName(string goalName) { if ((Object)(object)goalText == (Object)null) { goalText = ((Component)this).gameObject.GetComponentInChildren(true); } goalText.SetText(goalName); } internal void MarkGoal(int colorID) { goalColors.AddColor(colorID); } internal void UnmarkGoal(int colorID) { goalColors.RemoveColor(colorID); } internal void SetColors(int[] colorIDs) { goalColors.SetColors(colorIDs); } internal void ResetColors() { goalColors.ResetColors(); } internal bool HasColor(int colorID) { return goalColors.HasColor(colorID); } internal void OnLeftClick() { UIHelper.MarkGoal(slotIndex, HasColor(GoalColors.myColorID)); } internal void OnRightClick() { isHighlighted = !isHighlighted; } private void UpdateHighlightStatus() { if (isHighlighted) { TextureHandler.SetSprite("StandardBackgroundHighlight", imageComponent); } else { TextureHandler.SetSprite("StandardBackground", imageComponent); } } internal void SetPosition(int xPos, int yPos) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) ((Component)this).gameObject.GetComponent().anchoredPosition = Vector2.right * (float)xPos + Vector2.up * (float)yPos; } internal void SetOpacity(float opacity) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_001a: 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_0030: Unknown result type (might be due to invalid IL or missing references) Image component = ((Component)this).gameObject.GetComponent(); ((Graphic)component).color = new Color(((Graphic)component).color.r, ((Graphic)component).color.g, ((Graphic)component).color.b, opacity); goalColors.SetOpacity(opacity); } } internal class UIGoalColors : MonoBehaviour { private Texture2D? texture; private List currentColorIDs = new List(); private Texture2D Texture => ((Object)(object)texture != (Object)null) ? texture : (texture = ((Component)this).gameObject.GetComponent().sprite.texture); internal void AddColor(int colorID) { if (currentColorIDs.BinarySearch(colorID) < 0) { currentColorIDs.Add(colorID); currentColorIDs.Sort(); RefreshColors(); } } internal void RemoveColor(int colorID) { currentColorIDs.Remove(colorID); RefreshColors(); } internal void SetColors(int[] colorIDs) { currentColorIDs.Clear(); foreach (int item in colorIDs) { currentColorIDs.Add(item); currentColorIDs.Sort(); } RefreshColors(); } internal bool HasColor(int colorID) { return currentColorIDs.Contains(colorID); } internal void ResetColors() { currentColorIDs.Clear(); TextureHandler.ClearTexture(Texture); } internal void SetOpacity(float opacity) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_001a: 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_0030: Unknown result type (might be due to invalid IL or missing references) Image component = ((Component)this).gameObject.GetComponent(); ((Graphic)component).color = new Color(((Graphic)component).color.r, ((Graphic)component).color.g, ((Graphic)component).color.b, opacity); } private void RefreshColors() { //IL_00ac: Unknown result type (might be due to invalid IL or missing references) if (currentColorIDs.Count <= 0) { ResetColors(); return; } int num = (((Texture)Texture).width + ((Texture)Texture).height) / currentColorIDs.Count; for (int i = 0; i < ((Texture)Texture).width; i++) { for (int j = 0; j < ((Texture)Texture).height; j++) { int num2 = (i + ((Texture)Texture).height - 1 - j) / num; if (num2 >= currentColorIDs.Count) { num2 = currentColorIDs.Count - 1; } Texture.SetPixel(i, j, GoalColors.colorsList[currentColorIDs[num2]]); } } Texture.Apply(); } } internal static class UIHelper { internal enum VisibilityState { Everything, JustBoard, Nothing } private const int defaultDropdownOptionWidth = 200; private const int defaultDropdownOptionHeight = 35; private const int defaultDropdownFontSize = 25; private const int defaultButtonFontSize = 30; private const int defaultTextInputFontSize = 30; private const int defaultMaxTextResize = 25; private const int defaultMinTextResize = 14; private const int defaultButtonHeight = 100; private const int defaultButtonWidth = 418; private const int defaultTextInputHeight = 66; private const int defaultTextInputWidth = 418; private const int defaultGoalWidth = 100; private const int defaultGoalHeight = 100; internal static UICanvas uiCanvas = UICanvas.GetInstance(); private static VisibilityState visibilityState = VisibilityState.Everything; internal static IEnumerator NotifyOfRoomEnter_Main(RoomType roomType) { yield return null; UIButton? exitRoomButton = uiCanvas.exitRoomButton; if (exitRoomButton != null) { ((Component)exitRoomButton).gameObject.SetActive(true); } uiCanvas.SetDropdownOptions(roomType); GoalColors.SetMyColorToDefault(roomType); } internal static IEnumerator SetBoard_Main(string boardJson, RoomType roomType) { yield return null; string[] goalNames = JsonHelper.GetNamesFromBoard(boardJson); try { Automarker.SetGoalNames(goalNames); uiCanvas.SetGoalNames(Automarker.AddSupportNotations(goalNames), (roomType == RoomType.Bingosync) ? 5 : 6); new Texture2D(1, 1); } catch (Exception ex) { Exception e = ex; VogsBingoModPlugin.LogError(e); } uiCanvas.SetBoardColors(JsonHelper.GetColorsFromBoard(boardJson)); uiCanvas.HideGoals(); uiCanvas.HideCardLoadingText(); uiCanvas.ShowRevealCardButton(); } internal static IEnumerator NotifyOfConnectingToRoom_Main() { yield return null; UIButton? joinRoomButton = uiCanvas.joinRoomButton; if (joinRoomButton != null) { ((Component)joinRoomButton).gameObject.SetActive(false); } } internal static IEnumerator NotifyOfConnectingToRoomCancel_Main(int errorCode = 0) { yield return null; UIButton? joinRoomButton = uiCanvas.joinRoomButton; if (joinRoomButton != null) { ((Component)joinRoomButton).gameObject.SetActive(true); } string errorText = "An error occurred while connecting to the room "; TriggerErrorText(textToDisplay: (errorCode != 0 && errorCode == 1) ? (errorText + "(1). Check that your internet connection is working.") : (errorText + "(0). Check that the room link and password are correct."), errorText: uiCanvas.connectingErrorText); } internal static IEnumerator NotifyOfRoomExit_Main(int errorCode = 0) { yield return null; UIButton? joinRoomButton = uiCanvas.joinRoomButton; if (joinRoomButton != null) { ((Component)joinRoomButton).gameObject.SetActive(true); } uiCanvas.HideGoals(); UIButton? exitRoomButton = uiCanvas.exitRoomButton; if (exitRoomButton != null) { ((Component)exitRoomButton).gameObject.SetActive(false); } uiCanvas.HideRevealCardButton(); if (errorCode > 0) { TriggerErrorText(uiCanvas.connectingErrorText, $"An error occurred while trying to communicate with the room. ({errorCode})"); } } internal static IEnumerator UpdateGoal_Main(int colorID, bool shouldRemoveColor, int slotIndex) { yield return null; if (shouldRemoveColor) { uiCanvas.UnmarkGoal(colorID, slotIndex); } else { uiCanvas.MarkGoal(colorID, slotIndex); } } internal static IEnumerator UnrevealCard_Main() { yield return null; uiCanvas.HideGoals(); uiCanvas.ShowCardLoadingText(); } internal static IEnumerator TriggerErrorText_Main() { yield return null; UIText? errorText = uiCanvas.errorText; if (errorText != null) { ((Component)errorText).gameObject.SetActive(true); } UIText? errorText2 = uiCanvas.errorText; Coroutiner.CreateCoroutine(DisableErrorText((errorText2 != null) ? ((Component)errorText2).gameObject : null)); } internal static IEnumerator SetConnectionPendingActive_Main(bool setActive) { yield return null; GameObject? connectionPendingIcon = uiCanvas.connectionPendingIcon; if (connectionPendingIcon != null) { connectionPendingIcon.SetActive(setActive); } } internal static IEnumerator DisableErrorText(GameObject? errorObject) { yield return (object)new WaitForSecondsRealtime(3f); if (errorObject != null) { errorObject.SetActive(false); } } internal static void CycleVisibility() { switch (visibilityState) { case VisibilityState.Everything: if (NetworkHandler.connectState == ConnectionState.Connected) { UIButton? exitRoomButton2 = uiCanvas.exitRoomButton; if (exitRoomButton2 != null) { ((Component)exitRoomButton2).gameObject.SetActive(false); } visibilityState = VisibilityState.JustBoard; } else if (NetworkHandler.connectState == ConnectionState.NotConnected) { UIButton? joinRoomButton2 = uiCanvas.joinRoomButton; if (joinRoomButton2 != null) { ((Component)joinRoomButton2).gameObject.SetActive(false); } visibilityState = VisibilityState.Nothing; } break; case VisibilityState.JustBoard: uiCanvas.boardObj.SetActive(false); visibilityState = VisibilityState.Nothing; break; case VisibilityState.Nothing: if (NetworkHandler.connectState == ConnectionState.Connected) { uiCanvas.boardObj.SetActive(true); UIButton? exitRoomButton = uiCanvas.exitRoomButton; if (exitRoomButton != null) { ((Component)exitRoomButton).gameObject.SetActive(true); } visibilityState = VisibilityState.Everything; } else { uiCanvas.boardObj.SetActive(true); UIButton? joinRoomButton = uiCanvas.joinRoomButton; if (joinRoomButton != null) { ((Component)joinRoomButton).gameObject.SetActive(true); } visibilityState = VisibilityState.Everything; } break; } } internal static void CycleVisibility(VisibilityState stateToCycleTo) { VisibilityState visibilityState = UIHelper.visibilityState; while (UIHelper.visibilityState != stateToCycleTo) { CycleVisibility(); if (UIHelper.visibilityState == visibilityState) { break; } } } internal static UIGoal CreateUIGoal(Transform parent, string objName, float xOffset, float yOffset, int slotIndex, float width = 100f, float height = 100f) { GameObject val = CreateUIObject(parent, objName, xOffset, yOffset, 100f, 100f, UIAnchor.TopRight); val.AddComponent(); Image val2 = SetupImageComponent(val, "StandardBackground", width, height); UIGoal uIGoal = val.AddComponent(); uIGoal.slotIndex = slotIndex; uIGoal.goalColors = CreateUIGoalColorsObject(val.transform, objName + "Colors"); try { Text textComponent = CreateUIText(val.transform, objName + "Text", "Talk to Forge Daughter and Twelfth Architect", 14, 0f, 0f, width - 10f, height - 10f, supportRichText: true, (TextAnchor)4).textComponent; textComponent.resizeTextForBestFit = true; textComponent.resizeTextMaxSize = 25; textComponent.resizeTextMinSize = 14; } catch (Exception e) { VogsBingoModPlugin.LogError(e); } val.AddComponent().SetupCallbacks(uIGoal.OnLeftClick, uIGoal.OnRightClick); return uIGoal; } internal static UIText CreateUIText(Transform parent, string objName, string text = "", int fontSize = 14, float xOffset = 0f, float yOffset = 0f, float width = 100f, float height = 100f, bool supportRichText = true, TextAnchor anchor = (TextAnchor)4, Color? color = null, UIAnchor canvasAnchor = UIAnchor.MiddleCenter) { //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) GameObject val = CreateUIObject(parent, objName, xOffset, yOffset, width, height, canvasAnchor); val.AddComponent(); Text val2 = val.AddComponent(); val2.text = text; val2.font = FontHandler.GetFont("LegacyRuntime"); val2.alignment = anchor; val2.fontSize = fontSize; val2.supportRichText = supportRichText; if (!color.HasValue) { color = Color.white; } ((Graphic)val2).color = color.Value; UIText uIText = val.AddComponent(); uIText.textComponent = val2; return uIText; } internal static GameObject CreateUIObject(Transform parent, string objName, float xOffset = 0f, float yOffset = 0f, float width = 100f, float height = 100f, UIAnchor anchor = UIAnchor.MiddleCenter) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Expected O, but got Unknown //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject(objName); RectTransform val2 = val.AddComponent(); val.transform.SetParent(parent); ((Transform)val2).localScale = Vector3.one; if (anchor == UIAnchor.TopRight) { val2.anchorMin = Vector2.one; val2.anchorMax = Vector2.one; val2.pivot = Vector2.one; } val2.SetSizeWithCurrentAnchors((Axis)0, width); val2.SetSizeWithCurrentAnchors((Axis)1, height); val2.anchoredPosition = Vector2.right * xOffset + Vector2.up * yOffset; return val; } internal static UIButton CreateUIButton(Transform parent, string objName, Action? leftClickCallback, Action? rightClickCallback, string displayText, float xOffset = 0f, float yOffset = 0f, UIAnchor anchor = UIAnchor.MiddleCenter, float width = 418f, float height = 100f) { //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) GameObject val = CreateUIObject(parent, objName, xOffset, yOffset, 100f, 100f, anchor); val.AddComponent(); SetupImageComponent(val, "StandardBackground", width, height); UIButton uIButton = val.AddComponent(); uIButton.SetupCallbacks(leftClickCallback, rightClickCallback); Transform transform = val.transform; string objName2 = objName + "Text"; Rect rect = val.GetComponent().rect; CreateUIText(transform, objName2, displayText, 30, 0f, 0f, ((Rect)(ref rect)).width, 100f, supportRichText: true, (TextAnchor)4); return uIButton; } internal static UITextInput CreateUITextInput(Transform parent, string objName, string textWhenEmpty, float xOffset = 0f, float yOffset = 0f, bool isPassword = false) { //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_00eb: Unknown result type (might be due to invalid IL or missing references) GameObject val = CreateUIObject(parent, objName, xOffset, yOffset); SetupImageComponent(val, "StandardBackground", 418f, 66f); Transform transform = val.transform; string objName2 = objName + "Text"; string empty = string.Empty; Rect rect = val.GetComponent().rect; CreateUIText(transform, objName2, empty, 30, 0f, 0f, ((Rect)(ref rect)).width, 100f, supportRichText: true, (TextAnchor)4); UITextInput uITextInput = val.AddComponent(); InputField val2 = val.AddComponent(); if (isPassword) { val2.contentType = (ContentType)7; } val2.textComponent = val.GetComponentInChildren(true); ((UnityEvent)(object)val2.onValueChanged).AddListener((UnityAction)uITextInput.UpdatePlaceholder); uITextInput.placeholderObj = ((Component)CreateUIText(val.transform, objName + "Placeholder", textWhenEmpty, 30, 0f, 0f, 418f, 66f, supportRichText: true, (TextAnchor)4, Color.grey)).gameObject; return uITextInput; } internal static UIDropdown CreateUIDropdown(Transform parent, string objName, UnityAction callbackOnValueChanged, List optionData, float xOffset = 0f, float yOffset = 0f) { //IL_00f4: Unknown result type (might be due to invalid IL or missing references) //IL_00fb: Expected O, but got Unknown //IL_011a: Unknown result type (might be due to invalid IL or missing references) int count = optionData.Count; float width = 200f; float num = 35f; GameObject val = CreateUIObject(parent, objName, xOffset, yOffset); val.AddComponent(); Image val2 = SetupImageComponent(val, "StandardBackground", 200f, 35f); UIDropdown uIDropdown = val.AddComponent(); UIText uIText = CreateUIText(val.transform, "Label", " red", 25, 0f, 0f, width, num, supportRichText: true, (TextAnchor)3); ((Dropdown)uIDropdown).captionText = uIText.textComponent; GameObject val3 = CreateUIObject(val.transform, "Template", 0f, (float)(-(count + 1)) * num / 2f, width, num); val3.SetActive(false); val3.AddComponent(); Image imgComponent = val3.AddComponent(); TextureHandler.SetSprite("DropdownFullPanel", imgComponent); ((Dropdown)uIDropdown).template = val3.GetComponent(); GameObject val4 = new GameObject("Toggle"); RectTransform val5 = val4.AddComponent(); val4.transform.SetParent(val3.transform); val5.anchoredPosition = Vector2.zero; val5.SetSizeWithCurrentAnchors((Axis)1, num); val4.AddComponent(); UIText uIText2 = CreateUIText(val4.transform, "Item Text", "Placeholder Option", 25, 0f, 0f, width, num, supportRichText: true, (TextAnchor)3); ((Dropdown)uIDropdown).itemText = uIText2.textComponent; uIDropdown.SetOptions(optionData); ((UnityEvent)(object)((Dropdown)uIDropdown).onValueChanged).AddListener(callbackOnValueChanged); return uIDropdown; } internal static GameObject CreateUIImage(Transform parent, string objName, string imgName, float xOffset = 0f, float yOffset = 0f, float width = -1f, float height = -1f, UIAnchor anchor = UIAnchor.MiddleCenter) { GameObject val = CreateUIObject(parent, objName, xOffset, yOffset, 100f, 100f, anchor); SetupImageComponent(val, imgName, width, height); return val; } internal static void RevealCardPressed() { if ((Object)(object)uiCanvas.revealCardButton != (Object)null && ((Component)uiCanvas.revealCardButton).gameObject.activeInHierarchy) { uiCanvas.revealCardButton.LeftClick(); } } internal static void CycleOpacity() { if (!IsTyping()) { uiCanvas.CycleOpacity(); } } internal static void MarkGoal(int slotIndex, bool remove) { NetworkHandler.MarkGoal(slotIndex, remove, GoalColors.MyColorName); } internal static void MarkIfUnmarkedGoal(int slotIndex) { if ((Object)(object)uiCanvas.revealCardButton == (Object)null) { VogsBingoModPlugin.LogInfo("the reveal card button was null"); return; } VogsBingoModPlugin.LogInfo($"Can mark: {!((Component)uiCanvas.revealCardButton).gameObject.activeSelf} and {!uiCanvas.HasColor(slotIndex, GoalColors.myColorID)}"); if (!((Component)uiCanvas.revealCardButton).gameObject.activeSelf && !uiCanvas.HasColor(slotIndex, GoalColors.myColorID)) { MarkGoal(slotIndex, remove: false); } } internal static void UpdateUIScale() { uiCanvas.UpdateUIScale(); } private static Image SetupImageComponent(GameObject objToAttachTo, string imageName = "", float width = -1f, float height = -1f) { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) RectTransform component = objToAttachTo.GetComponent(); Image val = objToAttachTo.AddComponent(); TextureHandler.SetSprite(imageName, val); Rect rect = val.sprite.rect; float num = ((Rect)(ref rect)).width; rect = val.sprite.rect; float num2 = ((Rect)(ref rect)).height; if (width >= 0f) { num = width; } if (height >= 0f) { num2 = height; } component.SetSizeWithCurrentAnchors((Axis)0, num); component.SetSizeWithCurrentAnchors((Axis)1, num2); if (TextureHandler.ShouldSliceSprite(imageName)) { val.type = (Type)1; val.fillCenter = true; } return val; } private static UIGoalColors CreateUIGoalColorsObject(Transform parent, string objName) { //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) GameObject val = CreateUIObject(parent, objName); val.AddComponent(); Image val2 = val.AddComponent(); Sprite val3 = (val2.sprite = TextureHandler.CreateGoalColorsSprite()); RectTransform component = val.GetComponent(); Rect rect = val3.rect; component.SetSizeWithCurrentAnchors((Axis)0, ((Rect)(ref rect)).width); rect = val3.rect; component.SetSizeWithCurrentAnchors((Axis)1, ((Rect)(ref rect)).height); return val.AddComponent(); } internal static bool IsTyping() { if ((Object)(object)uiCanvas.roomUrlInputField != (Object)null && (Object)(object)uiCanvas.nicknameInputField != (Object)null && (Object)(object)uiCanvas.passwordInputField != (Object)null) { return uiCanvas.roomUrlInputField.IsFocused() || uiCanvas.nicknameInputField.IsFocused() || uiCanvas.passwordInputField.IsFocused(); } return true; } internal static void TriggerErrorText(UIText? errorText, string textToDisplay) { errorText?.SetText(textToDisplay); if (errorText != null) { ((Component)errorText).gameObject.SetActive(true); } Coroutiner.CreateCoroutine(DisableErrorText((errorText != null) ? ((Component)errorText).gameObject : null)); } } internal class UIText : MonoBehaviour { internal Text textComponent; internal void SetText(string text) { if ((Object)(object)textComponent == (Object)null) { textComponent = ((Component)this).gameObject.GetComponentInChildren(true); } textComponent.text = text; } } internal class UITextInput : MonoBehaviour { internal GameObject placeholderObj; private InputField? inputComponent; private InputField InputComponent => ((Object)(object)inputComponent != (Object)null) ? inputComponent : (inputComponent = ((Component)this).gameObject.GetComponent()); internal string GetText() { return InputComponent.text; } internal void UpdatePlaceholder(string currentText) { if (currentText.Equals("")) { placeholderObj.SetActive(true); } else { placeholderObj.SetActive(false); } } internal bool IsFocused() { return InputComponent.isFocused; } } } namespace VogsBingoMod.Automarking { internal class Automarker : MonoBehaviour { private static float currentTimer = 1f; private static Dictionary supportedGoals = GetSupportedGoals(); private static Dictionary currentGoals = new Dictionary(); internal static void SetGoalNames(string[] goalNames) { currentGoals.Clear(); for (int i = 0; i < goalNames.Length; i++) { int key = GoalHelper.NameToID(goalNames[i].ToLower()); if (currentGoals.ContainsKey(key)) { key = -i; } currentGoals.Add(key, i); } } internal static string[] AddSupportNotations(string[] goalNames) { for (int i = 0; i < goalNames.Length; i++) { string key = goalNames[i].ToLower(); if (supportedGoals.TryGetValue(key, out var value)) { if (!value) { goalNames[i] += " (U)"; } } else { goalNames[i] += " (M)"; } } return goalNames; } internal static bool BoardHasGoal(int goalID) { return currentGoals.ContainsKey(goalID); } internal static bool BoardHasGoal(GoalID goalID) { return BoardHasGoal((int)goalID); } internal static void MarkIfAvailable(int goalID) { VogsBingoModPlugin.LogInfo($"Checking if goal {(GoalID)goalID} is on the board"); if (BoardHasGoal(goalID)) { VogsBingoModPlugin.LogInfo("the goal is on the board, checking if it is unmarked so far"); UIHelper.MarkIfUnmarkedGoal(currentGoals[goalID]); } } internal static void MarkIfAvailable(GoalID goalID) { MarkIfAvailable((int)goalID); } internal static string GetGoalsJson() { Assembly executingAssembly = Assembly.GetExecutingAssembly(); Stream manifestResourceStream = executingAssembly.GetManifestResourceStream("VogsBingoMod.Automarking.Goals.json"); if (manifestResourceStream == null) { VogsBingoModPlugin.LogError("Could not find the goals resource."); return ""; } MemoryStream memoryStream = new MemoryStream(); manifestResourceStream.CopyTo(memoryStream); manifestResourceStream.Dispose(); byte[] bytes = memoryStream.ToArray(); memoryStream.Dispose(); return Encoding.UTF8.GetString(bytes); } private static Dictionary GetSupportedGoals() { string goalsJson = GetGoalsJson(); return JsonHelper.GetSupportedGoals(goalsJson); } internal static void UpdateTools(IEnumerable tools) { //IL_0034: 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) //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Expected I4, but got Unknown VogsBingoModPlugin.LogInfo("updating tools"); int num = 0; int num2 = 0; int num3 = 0; foreach (ToolItem tool in tools) { UpdateTool(tool.name); ToolItemType type = tool.type; ToolItemType val = type; switch ((int)val) { case 0: num++; break; case 1: num2++; break; case 2: num3++; break; } } int num4 = num; int num5 = num4; if (num5 < 5) { if (num5 >= 3) { MarkIfAvailable(GoalID.ThreeRedTools); } } else { MarkIfAvailable(GoalID.FiveRedTools); } if (num2 >= 3) { MarkIfAvailable(GoalID.ThreeBlueTools); } int num6 = num3; int num7 = num6; if (num7 < 5) { if (num7 >= 3) { MarkIfAvailable(GoalID.ThreeYellowTools); } } else { MarkIfAvailable(GoalID.FiveYellowTools); } if (num >= 2 && num2 >= 2 && num3 >= 2) { MarkIfAvailable(GoalID.Twoofeachtooltype); } } private static void UpdateTool(string toolName) { switch (toolName) { case "Straight Pin": VogsBingoModPlugin.instance.SaveData.StraightPin.Value = true; break; case "Tri Pin": VogsBingoModPlugin.instance.SaveData.ThreefoldPin.Value = true; break; case "Sting Shard": VogsBingoModPlugin.instance.SaveData.StingShard.Value = true; break; case "Tack": MarkIfAvailable(GoalID.Tacks); break; case "Harpoon": VogsBingoModPlugin.instance.SaveData.Longpin.Value = true; break; case "Curve Claws": VogsBingoModPlugin.instance.SaveData.Curveclaw.Value = true; break; case "Pimpilo": VogsBingoModPlugin.instance.SaveData.Pimpillo.Value = true; break; case "Conch Drill": MarkIfAvailable(GoalID.Conchcutter); break; case "WebShot Forge": MarkIfAvailable(GoalID.RepairSilkshot); break; case "WebShot Architect": MarkIfAvailable(GoalID.RepairSilkshot); break; case "WebShot Weaver": MarkIfAvailable(GoalID.RepairSilkshot); break; case "Screw Attack": MarkIfAvailable(GoalID.DelversDrill); break; case "Cogwork Flier": MarkIfAvailable(GoalID.Cogfly); break; case "Rosary Cannon": MarkIfAvailable(GoalID.RosaryCannon); break; case "Lightning Rod": VogsBingoModPlugin.instance.SaveData.Voltvessels.Value = true; break; case "Flintstone": MarkIfAvailable(GoalID.Flintslate); break; case "Silk Snare": MarkIfAvailable(GoalID.SnareSetter); break; case "Lifeblood Syringe": MarkIfAvailable(GoalID.PlasmiumPhial); break; case "Mosscreep Tool 2": MarkIfAvailable(GoalID.UpgradeDruidsEye); break; case "Lava Charm": VogsBingoModPlugin.instance.SaveData.MagmaBell.Value = true; break; case "Bell Bind": VogsBingoModPlugin.instance.SaveData.WardingBell.Value = true; break; case "Poison Pouch": VogsBingoModPlugin.instance.SaveData.PollipPouch.Value = true; MarkIfAvailable(GoalID.PollipPouch); break; case "Fractured Mask": VogsBingoModPlugin.instance.SaveData.FracturedMask.Value = true; break; case "Multibind": MarkIfAvailable(GoalID.Multibinder); break; case "White Ring": VogsBingoModPlugin.instance.SaveData.Weavelight.Value = true; break; case "Brolly Spike": VogsBingoModPlugin.instance.SaveData.SawtoothCirclet.Value = true; break; case "Quickbind": VogsBingoModPlugin.instance.SaveData.InjectorBand.Value = true; break; case "Dazzle Bind": VogsBingoModPlugin.instance.SaveData.ClawMirror.Value = true; break; case "Revenge Crystal": MarkIfAvailable(GoalID.MemoryCrystal); break; case "Quick Sling": MarkIfAvailable(GoalID.QuickSling); break; case "Maggot Charm": MarkIfAvailable(GoalID.WreathofPurity); break; case "Pinstress Tool": MarkIfAvailable(GoalID.PinBadge); break; case "Compass": VogsBingoModPlugin.instance.SaveData.Compass.Value = true; break; case "Bone Necklace": VogsBingoModPlugin.instance.SaveData.ShardPendant.Value = true; break; case "Rosary Magnet": VogsBingoModPlugin.instance.SaveData.MagnetiteBrooch.Value = true; break; case "Weighted Anklet": VogsBingoModPlugin.instance.SaveData.WeightedBelt.Value = true; break; case "Barbed Wire": VogsBingoModPlugin.instance.SaveData.BarbedBracelet.Value = true; break; case "Dead Mans Purse": VogsBingoModPlugin.instance.SaveData.DeadBugsPurse.Value = true; break; case "Magnetite Dice": VogsBingoModPlugin.instance.SaveData.MagnetiteDice.Value = true; break; case "Scuttlebrace": VogsBingoModPlugin.instance.SaveData.Scuttlebrace.Value = true; break; case "Wallcling": VogsBingoModPlugin.instance.SaveData.AscendantsGrip.Value = true; break; case "Sprintmaster": VogsBingoModPlugin.instance.SaveData.SilkspeedAnklets.Value = true; break; } } internal static void UpdateSilkSkills() { int num = 0; if (PlayerData.instance.hasNeedleThrow) { num++; } if (PlayerData.instance.hasThreadSphere) { num++; MarkIfAvailable(GoalID.ThreadStorm); } if (PlayerData.instance.hasSilkCharge) { num++; MarkIfAvailable(GoalID.Sharpdart); } if (PlayerData.instance.hasParry) { num++; } if (PlayerData.instance.hasSilkBomb) { num++; } if (PlayerData.instance.hasSilkBossNeedle) { num++; MarkIfAvailable(GoalID.PaleNails); } VogsBingoModPlugin.instance.SaveData.SilkSkills.Value = num; } internal static void CheckIfGoalCompleted(GoalID goalID) { bool flag = false; switch (goalID) { case GoalID.CompassPendantBrooch: flag = (bool)VogsBingoModPlugin.instance.SaveData.ShardPendant && (bool)VogsBingoModPlugin.instance.SaveData.Compass && (bool)VogsBingoModPlugin.instance.SaveData.MagnetiteBrooch; break; case GoalID.StraightThreefoldandLongPin: flag = (bool)VogsBingoModPlugin.instance.SaveData.StraightPin && (bool)VogsBingoModPlugin.instance.SaveData.ThreefoldPin && (bool)VogsBingoModPlugin.instance.SaveData.Longpin; break; case GoalID.DeadBugsPurseaSilkeater: flag = (bool)VogsBingoModPlugin.instance.SaveData.DeadBugsPurse && (int)VogsBingoModPlugin.instance.SaveData.Silkeaters >= 1; break; case GoalID.BarbedBraceletFracturedMask: flag = (bool)VogsBingoModPlugin.instance.SaveData.BarbedBracelet && (bool)VogsBingoModPlugin.instance.SaveData.FracturedMask; break; case GoalID.MagnetiteDiceMagnetiteBrooch: flag = (bool)VogsBingoModPlugin.instance.SaveData.MagnetiteDice && (bool)VogsBingoModPlugin.instance.SaveData.MagnetiteBrooch; break; case GoalID.WardingBellClawMirror: flag = (bool)VogsBingoModPlugin.instance.SaveData.WardingBell && (bool)VogsBingoModPlugin.instance.SaveData.ClawMirror; break; case GoalID.WardingBellSawtoothCirclet: flag = (bool)VogsBingoModPlugin.instance.SaveData.WardingBell && (bool)VogsBingoModPlugin.instance.SaveData.SawtoothCirclet; break; case GoalID.MagmaBellCurveclaw: flag = (bool)VogsBingoModPlugin.instance.SaveData.MagmaBell && (bool)VogsBingoModPlugin.instance.SaveData.Curveclaw; break; case GoalID.WeightedBeltAscendantsGrip: flag = (bool)VogsBingoModPlugin.instance.SaveData.WeightedBelt && (bool)VogsBingoModPlugin.instance.SaveData.AscendantsGrip; break; case GoalID.ScuttlebraceSilkspeed: flag = (bool)VogsBingoModPlugin.instance.SaveData.Scuttlebrace && (bool)VogsBingoModPlugin.instance.SaveData.SilkspeedAnklets; break; case GoalID.PimpilloVoltvessels: flag = (bool)VogsBingoModPlugin.instance.SaveData.Pimpillo && (bool)VogsBingoModPlugin.instance.SaveData.Voltvessels; break; case GoalID.PollipPouchStingShard: flag = (bool)VogsBingoModPlugin.instance.SaveData.PollipPouch && (bool)VogsBingoModPlugin.instance.SaveData.StingShard; break; case GoalID.WeavelightInjectorBand: flag = (bool)VogsBingoModPlugin.instance.SaveData.Weavelight && (bool)VogsBingoModPlugin.instance.SaveData.InjectorBand; break; case GoalID.BlastedStepsSilkeaterCraftmetal: flag = (bool)VogsBingoModPlugin.instance.SaveData.BlastedSilkeater && (bool)VogsBingoModPlugin.instance.SaveData.BlastedCraftmetal; break; case GoalID.BothFreeSimpleKeys: flag = (bool)VogsBingoModPlugin.instance.SaveData.SinnersKey && (bool)VogsBingoModPlugin.instance.SaveData.KarakKey; break; case GoalID.ShellwoodVaultsMaskShards: flag = (bool)VogsBingoModPlugin.instance.SaveData.ShellwoodMaskShard && (bool)VogsBingoModPlugin.instance.SaveData.VaultsMaskShard; break; case GoalID.CogworkClapperJournalEntry: flag = (bool)VogsBingoModPlugin.instance.SaveData.HasJournal && (bool)VogsBingoModPlugin.instance.SaveData.CogworkClapperKilled; break; case GoalID.ImobaJournalEntry: flag = (bool)VogsBingoModPlugin.instance.SaveData.HasJournal && (bool)VogsBingoModPlugin.instance.SaveData.ImobaKilled; break; case GoalID.SquirrmJournalEntry: flag = (bool)VogsBingoModPlugin.instance.SaveData.HasJournal && (bool)VogsBingoModPlugin.instance.SaveData.SquirrmKilled; break; case GoalID.GromlingJournalEntry: flag = (bool)VogsBingoModPlugin.instance.SaveData.HasJournal && (bool)VogsBingoModPlugin.instance.SaveData.GromlingKilled; break; case GoalID.CraggliteJournalEntry: flag = (bool)VogsBingoModPlugin.instance.SaveData.HasJournal && (bool)VogsBingoModPlugin.instance.SaveData.CraggliteKilled; break; case GoalID.DeepDiverJournalEntry: flag = (bool)VogsBingoModPlugin.instance.SaveData.HasJournal && (bool)VogsBingoModPlugin.instance.SaveData.DeepDiverKilled; break; case GoalID.SkullwingJournalEntry: flag = (bool)VogsBingoModPlugin.instance.SaveData.HasJournal && (bool)VogsBingoModPlugin.instance.SaveData.SkullwingKilled; break; case GoalID.MiteMotherJournalEntry: flag = (bool)VogsBingoModPlugin.instance.SaveData.HasJournal && (bool)VogsBingoModPlugin.instance.SaveData.MiteMotherKilled; break; case GoalID.UnravelledJournalEntry: flag = (bool)VogsBingoModPlugin.instance.SaveData.HasJournal && (bool)VogsBingoModPlugin.instance.SaveData.UnravelledKilled; break; case GoalID.ShadowChargerJournalEntry: flag = (bool)VogsBingoModPlugin.instance.SaveData.HasJournal && (bool)VogsBingoModPlugin.instance.SaveData.ShadowChargerKilled; break; case GoalID.MassiveMossgrubJournalEntry: flag = (bool)VogsBingoModPlugin.instance.SaveData.HasJournal && (bool)VogsBingoModPlugin.instance.SaveData.MassiveMossgrubKilled; break; case GoalID.TalktoStyxHuntress: flag = (bool)VogsBingoModPlugin.instance.SaveData.HuntressSpokenTo && (bool)VogsBingoModPlugin.instance.SaveData.StyxSpokenTo; break; case GoalID.TalktoForgeDaughterandTwelfthArchitect: flag = (bool)VogsBingoModPlugin.instance.SaveData.TwelfthArchitectSpokenTo && (bool)VogsBingoModPlugin.instance.SaveData.ForgeDaughterSpokenTo; break; case GoalID.BreakBothofStyxsOneways: flag = (bool)VogsBingoModPlugin.instance.SaveData.SinnersStyxWallBroken && (bool)VogsBingoModPlugin.instance.SaveData.GreymoorStyxWallBroken; break; case GoalID.BothVendorSimpleKeys: flag = (bool)VogsBingoModPlugin.instance.SaveData.JubilanaKeyBought && (bool)VogsBingoModPlugin.instance.SaveData.PebbKeyBought; break; case GoalID.GreymoorFleasTwoKratt: flag = (bool)VogsBingoModPlugin.instance.SaveData.FleaCrawLake && (bool)VogsBingoModPlugin.instance.SaveData.FleaGreymoorTower && (bool)VogsBingoModPlugin.instance.SaveData.FleaKratt; break; case GoalID.FarFieldsFleasTwo: flag = (bool)VogsBingoModPlugin.instance.SaveData.FleaFarFieldsCage && (bool)VogsBingoModPlugin.instance.SaveData.FleaPilgrimsRest; break; case GoalID.ShellwoodBellhartFleasTwo: flag = (bool)VogsBingoModPlugin.instance.SaveData.FleaShellwood && (bool)VogsBingoModPlugin.instance.SaveData.FleaBellvein; break; case GoalID.DeepDocksFleasThree: flag = (bool)VogsBingoModPlugin.instance.SaveData.FleaSwiftStep && (bool)VogsBingoModPlugin.instance.SaveData.FleaDeeperDocks && (bool)VogsBingoModPlugin.instance.SaveData.FleaDeepDocksBellway; break; case GoalID.WormwaysBlastedStepsFleasTwo: flag = (bool)VogsBingoModPlugin.instance.SaveData.FleaWormways && (bool)VogsBingoModPlugin.instance.SaveData.FleaBlastedSteps; break; case GoalID.UnderworksFleasTwo: flag = (bool)VogsBingoModPlugin.instance.SaveData.FleaUnderworksCauldron && (bool)VogsBingoModPlugin.instance.SaveData.FleaUnderworksWispThicket; break; case GoalID.LowerBilewaterHuntersMarchFleasTwo: flag = (bool)VogsBingoModPlugin.instance.SaveData.FleaBilewaterThieves && (bool)VogsBingoModPlugin.instance.SaveData.FleaHuntersMarch; break; case GoalID.SinnersRoadVaultsFleasTwo: flag = (bool)VogsBingoModPlugin.instance.SaveData.FleaSinnersRoad && (bool)VogsBingoModPlugin.instance.SaveData.FleaVaults; break; case GoalID.DeepDocksSpoolFragmentsTwo: flag = (bool)VogsBingoModPlugin.instance.SaveData.DeepDocksSpoolFragNearSpa && (bool)VogsBingoModPlugin.instance.SaveData.DeeperDocksSpoolFrag; break; case GoalID.HaveSixRosaryStringsnopurchasing: flag = AutomarkRosaryStringHandler.GetNonPurchasedStringsCurrentlyHeld() + AutomarkRosaryStringHandler.GetFrayedStringsCurrentlyHeld() >= 6; break; case GoalID.BreakEightRosaryStringsnopurchasing: flag = AutomarkRosaryStringHandler.GetNonPurchasedStringsBroken() + AutomarkRosaryStringHandler.GetFrayedStringsBroken() >= 8; break; default: VogsBingoModPlugin.LogError($"There isn't a check for goalID {goalID}"); break; } if (flag) { MarkIfAvailable(goalID); } } internal static void CheckIfGoalsCompleted(GoalID[] goalIDs) { foreach (GoalID goalID in goalIDs) { CheckIfGoalCompleted(goalID); } } internal static void CheckIfGoalsCompleted(AutomarkIntValue[] values, int currentValue) { foreach (AutomarkIntValue markValue in values) { CheckIfGoalCompleted(markValue, currentValue); } } internal static void CheckIfGoalCompleted(AutomarkIntValue markValue, int currentValue) { VogsBingoModPlugin.LogInfo($"Checking if goal {markValue.goalToMark} is finished"); if (currentValue >= markValue.markValue) { VogsBingoModPlugin.LogInfo($"Goal {markValue.goalToMark} is finished, checking if the goal is on the board..."); MarkIfAvailable(markValue.goalToMark); } } internal static void RunFrameChecks() { //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Invalid comparison between Unknown and I4 //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Invalid comparison between Unknown and I4 currentTimer -= Time.unscaledDeltaTime; if (!(currentTimer < 0f)) { return; } currentTimer = 1f; if (PlayerData.instance != null) { if ((int)PlayerData.instance.CaravanTroupeLocation == 2) { MarkIfAvailable(GoalID.MeetCaravanattheGrandGateTwelve); } else if ((int)PlayerData.instance.CaravanTroupeLocation == 1) { MarkIfAvailable(GoalID.MeettheCaravaninGreymoor); } if (PlayerData.instance.HasMelodyArchitect) { MarkIfAvailable(GoalID.ArchitectsMelody); } if (PlayerData.instance.HasMelodyConductor) { MarkIfAvailable(GoalID.ConductorsMelody); } if (PlayerData.instance.HasMelodyLibrarian) { MarkIfAvailable(GoalID.VaultkeepersMelody); } if (PlayerData.instance.act3_wokeUp) { MarkIfAvailable(GoalID.EnterActThree); } if (PlayerData.instance.mapBoolList != null && VogsBingoModPlugin.instance.SaveData.MapCount.Value != PlayerData.instance.mapBoolList.HasCount) { VogsBingoModPlugin.instance.SaveData.MapCount.Value = PlayerData.instance.mapBoolList.HasCount; } } } internal static void UpdateFleas() { if (PlayerData.instance != null) { int num = PlayerData.instance.SavedFleasCount; VogsBingoModPlugin.instance.SaveData.CitadelFleas.Value = 0; if (PlayerData.instance.SavedFlea_Song_11) { VogsBingoModPlugin.instance.SaveData.CitadelFleas.Value++; } if (PlayerData.instance.SavedFlea_Song_14) { VogsBingoModPlugin.instance.SaveData.CitadelFleas.Value++; } if (PlayerData.instance.SavedFlea_Library_09) { VogsBingoModPlugin.instance.SaveData.CitadelFleas.Value++; } if (PlayerData.instance.tamedGiantFlea) { VogsBingoModPlugin.instance.SaveData.CitadelFleas.Value++; MarkIfAvailable(GoalID.BeatBigFlea); num++; } if (PlayerData.instance.SavedFlea_Library_01) { VogsBingoModPlugin.instance.SaveData.CitadelFleas.Value++; VogsBingoModPlugin.instance.SaveData.FleaVaults.Value = true; } VogsBingoModPlugin.instance.SaveData.FleaBellvein.Value = PlayerData.instance.SavedFlea_Belltown_04; VogsBingoModPlugin.instance.SaveData.FleaBilewaterThieves.Value = PlayerData.instance.SavedFlea_Shadow_28; VogsBingoModPlugin.instance.SaveData.FleaBlastedSteps.Value = PlayerData.instance.SavedFlea_Coral_35; VogsBingoModPlugin.instance.SaveData.FleaCrawLake.Value = PlayerData.instance.SavedFlea_Greymoor_15b; VogsBingoModPlugin.instance.SaveData.FleaDeepDocksBellway.Value = PlayerData.instance.SavedFlea_Dock_16; VogsBingoModPlugin.instance.SaveData.FleaDeeperDocks.Value = PlayerData.instance.SavedFlea_Dock_03d; VogsBingoModPlugin.instance.SaveData.FleaFarFieldsCage.Value = PlayerData.instance.SavedFlea_Bone_East_17b; VogsBingoModPlugin.instance.SaveData.FleaGreymoorTower.Value = PlayerData.instance.SavedFlea_Greymoor_06; VogsBingoModPlugin.instance.SaveData.FleaHuntersMarch.Value = PlayerData.instance.SavedFlea_Ant_03; VogsBingoModPlugin.instance.SaveData.FleaPilgrimsRest.Value = PlayerData.instance.SavedFlea_Bone_East_10_Church; VogsBingoModPlugin.instance.SaveData.FleaShellwood.Value = PlayerData.instance.SavedFlea_Shellwood_03; VogsBingoModPlugin.instance.SaveData.FleaSinnersRoad.Value = PlayerData.instance.SavedFlea_Dust_12; VogsBingoModPlugin.instance.SaveData.FleaSwiftStep.Value = PlayerData.instance.SavedFlea_Bone_06; VogsBingoModPlugin.instance.SaveData.FleaUnderworksCauldron.Value = PlayerData.instance.SavedFlea_Under_21; VogsBingoModPlugin.instance.SaveData.FleaUnderworksWispThicket.Value = PlayerData.instance.SavedFlea_Under_23; VogsBingoModPlugin.instance.SaveData.FleaWormways.Value = PlayerData.instance.SavedFlea_Crawl_06; if (PlayerData.instance.SavedFlea_Dust_09) { MarkIfAvailable(GoalID.ExhaustOrganFleaOne); } if (PlayerData.instance.SavedFlea_Peak_05c) { MarkIfAvailable(GoalID.MtFayFleaOne); } if (PlayerData.instance.SavedFlea_Coral_24) { MarkIfAvailable(GoalID.SandsofKarakFleaOne); } if (PlayerData.instance.CaravanLechSaved) { VogsBingoModPlugin.instance.SaveData.FleaKratt.Value = true; num++; } if (PlayerData.instance.MetTroupeHunterWild) { MarkIfAvailable(GoalID.TalktoVog); num++; } VogsBingoModPlugin.instance.SaveData.FleasSaved.Value = num; } } } public class SaveData { internal SaveDataBool StraightPin = new SaveDataBool(new GoalID[1] { GoalID.StraightThreefoldandLongPin }, "StraightPin"); internal SaveDataBool Longpin = new SaveDataBool(new GoalID[1] { GoalID.StraightThreefoldandLongPin }, "Longpin"); internal SaveDataBool ThreefoldPin = new SaveDataBool(new GoalID[1] { GoalID.StraightThreefoldandLongPin }, "ThreefoldPin"); internal SaveDataBool DeadBugsPurse = new SaveDataBool(new GoalID[1] { GoalID.DeadBugsPurseaSilkeater }, "DeadBugsPurse"); internal SaveDataBool BarbedBracelet = new SaveDataBool(new GoalID[1] { GoalID.BarbedBraceletFracturedMask }, "BarbedBracelet"); internal SaveDataBool FracturedMask = new SaveDataBool(new GoalID[1] { GoalID.BarbedBraceletFracturedMask }, "FracturedMask"); internal SaveDataBool MagnetiteDice = new SaveDataBool(new GoalID[1] { GoalID.MagnetiteDiceMagnetiteBrooch }, "MagnetiteDice"); internal SaveDataBool MagnetiteBrooch = new SaveDataBool(new GoalID[2] { GoalID.CompassPendantBrooch, GoalID.MagnetiteDiceMagnetiteBrooch }, "MagnetiteBrooch"); internal SaveDataBool Compass = new SaveDataBool(new GoalID[1] { GoalID.CompassPendantBrooch }, "Compass"); internal SaveDataBool ShardPendant = new SaveDataBool(new GoalID[1] { GoalID.CompassPendantBrooch }, "ShardPendant"); internal SaveDataBool WardingBell = new SaveDataBool(new GoalID[2] { GoalID.WardingBellClawMirror, GoalID.WardingBellSawtoothCirclet }, "WardingBell"); internal SaveDataBool ClawMirror = new SaveDataBool(new GoalID[1] { GoalID.WardingBellClawMirror }, "ClawMirror"); internal SaveDataBool SawtoothCirclet = new SaveDataBool(new GoalID[1] { GoalID.WardingBellSawtoothCirclet }, "SawtoothCirclet"); internal SaveDataBool MagmaBell = new SaveDataBool(new GoalID[1] { GoalID.MagmaBellCurveclaw }, "MagmaBell"); internal SaveDataBool Curveclaw = new SaveDataBool(new GoalID[1] { GoalID.MagmaBellCurveclaw }, "Curveclaw"); internal SaveDataBool WeightedBelt = new SaveDataBool(new GoalID[1] { GoalID.WeightedBeltAscendantsGrip }, "WeightedBelt"); internal SaveDataBool AscendantsGrip = new SaveDataBool(new GoalID[1] { GoalID.WeightedBeltAscendantsGrip }, "AscendantsGrip"); internal SaveDataBool Scuttlebrace = new SaveDataBool(new GoalID[1] { GoalID.ScuttlebraceSilkspeed }, "Scuttlebrace"); internal SaveDataBool SilkspeedAnklets = new SaveDataBool(new GoalID[1] { GoalID.ScuttlebraceSilkspeed }, "SilkspeedAnklets"); internal SaveDataBool Pimpillo = new SaveDataBool(new GoalID[1] { GoalID.PimpilloVoltvessels }, "Pimpillo"); internal SaveDataBool Voltvessels = new SaveDataBool(new GoalID[1] { GoalID.PimpilloVoltvessels }, "Voltvessels"); internal SaveDataBool PollipPouch = new SaveDataBool(new GoalID[1] { GoalID.PollipPouchStingShard }, "PollipPouch"); internal SaveDataBool StingShard = new SaveDataBool(new GoalID[1] { GoalID.PollipPouchStingShard }, "StingShard"); internal SaveDataBool Weavelight = new SaveDataBool(new GoalID[1] { GoalID.WeavelightInjectorBand }, "Weavelight"); internal SaveDataBool InjectorBand = new SaveDataBool(new GoalID[1] { GoalID.WeavelightInjectorBand }, "InjectorBand"); internal SaveDataBool BlastedSilkeater = new SaveDataBool(new GoalID[1] { GoalID.BlastedStepsSilkeaterCraftmetal }, "BlastedSilkeater"); internal SaveDataBool BlastedCraftmetal = new SaveDataBool(new GoalID[1] { GoalID.BlastedStepsSilkeaterCraftmetal }, "BlastedCraftmetal"); internal SaveDataBool SinnersKey = new SaveDataBool(new GoalID[1] { GoalID.BothFreeSimpleKeys }, "SinnersKey"); internal SaveDataBool KarakKey = new SaveDataBool(new GoalID[1] { GoalID.BothFreeSimpleKeys }, "KarakKey"); internal SaveDataBool SilkeaterBool = new SaveDataBool(new GoalID[1] { GoalID.DeadBugsPurseaSilkeater }, "SilkeaterBool"); internal SaveDataBool ShellwoodMaskShard = new SaveDataBool(new GoalID[1] { GoalID.ShellwoodVaultsMaskShards }, "ShellwoodMaskShard"); internal SaveDataBool VaultsMaskShard = new SaveDataBool(new GoalID[1] { GoalID.ShellwoodVaultsMaskShards }, "VaultsMaskShard"); internal SaveDataBool HasJournal = new SaveDataBool(new GoalID[11] { GoalID.ImobaJournalEntry, GoalID.SquirrmJournalEntry, GoalID.GromlingJournalEntry, GoalID.CraggliteJournalEntry, GoalID.DeepDiverJournalEntry, GoalID.SkullwingJournalEntry, GoalID.MiteMotherJournalEntry, GoalID.UnravelledJournalEntry, GoalID.ShadowChargerJournalEntry, GoalID.CogworkClapperJournalEntry, GoalID.MassiveMossgrubJournalEntry }, "HasJournal"); internal SaveDataBool CogworkClapperKilled = new SaveDataBool(new GoalID[1] { GoalID.CogworkClapperJournalEntry }, "CogworkClapperKilled"); internal SaveDataBool SquirrmKilled = new SaveDataBool(new GoalID[1] { GoalID.SquirrmJournalEntry }, "SquirrmKilled"); internal SaveDataBool SkullwingKilled = new SaveDataBool(new GoalID[1] { GoalID.SkullwingJournalEntry }, "SkullwingKilled"); internal SaveDataBool CraggliteKilled = new SaveDataBool(new GoalID[1] { GoalID.CraggliteJournalEntry }, "CraggliteKilled"); internal SaveDataBool GromlingKilled = new SaveDataBool(new GoalID[1] { GoalID.GromlingJournalEntry }, "GromlingKilled"); internal SaveDataBool MiteMotherKilled = new SaveDataBool(new GoalID[1] { GoalID.MiteMotherJournalEntry }, "MiteMotherKilled"); internal SaveDataBool MassiveMossgrubKilled = new SaveDataBool(new GoalID[1] { GoalID.MassiveMossgrubJournalEntry }, "MassiveMossgrubKilled"); internal SaveDataBool DeepDiverKilled = new SaveDataBool(new GoalID[1] { GoalID.DeepDiverJournalEntry }, "DeepDiverKilled"); internal SaveDataBool UnravelledKilled = new SaveDataBool(new GoalID[1] { GoalID.UnravelledJournalEntry }, "UnravelledKilled"); internal SaveDataBool ShadowChargerKilled = new SaveDataBool(new GoalID[1] { GoalID.ShadowChargerJournalEntry }, "ShadowChargerKilled"); internal SaveDataBool ImobaKilled = new SaveDataBool(new GoalID[1] { GoalID.ImobaJournalEntry }, "ImobaKilled"); internal SaveDataBool HuntressSpokenTo = new SaveDataBool(new GoalID[1] { GoalID.TalktoStyxHuntress }, "HuntressSpokenTo"); internal SaveDataBool StyxSpokenTo = new SaveDataBool(new GoalID[1] { GoalID.TalktoStyxHuntress }, "StyxSpokenTo"); internal SaveDataBool ForgeDaughterSpokenTo = new SaveDataBool(new GoalID[1] { GoalID.TalktoForgeDaughterandTwelfthArchitect }, "ForgeDaughterSpokenTo"); internal SaveDataBool TwelfthArchitectSpokenTo = new SaveDataBool(new GoalID[1] { GoalID.TalktoForgeDaughterandTwelfthArchitect }, "TwelfthArchitectSpokenTo"); internal SaveDataBool GreymoorStyxWallBroken = new SaveDataBool(new GoalID[1] { GoalID.BreakBothofStyxsOneways }, "GreymoorStyxWallBroken"); internal SaveDataBool SinnersStyxWallBroken = new SaveDataBool(new GoalID[1] { GoalID.BreakBothofStyxsOneways }, "SinnersStyxWallBroken"); internal SaveDataBool JubilanaKeyBought = new SaveDataBool(new GoalID[1] { GoalID.BothVendorSimpleKeys }, "JubilanaKeyBought"); internal SaveDataBool PebbKeyBought = new SaveDataBool(new GoalID[1] { GoalID.BothVendorSimpleKeys }, "PebbKeyBought"); internal SaveDataBool FleaCrawLake = new SaveDataBool(new GoalID[1] { GoalID.GreymoorFleasTwoKratt }, "FleaCrawLake"); internal SaveDataBool FleaKratt = new SaveDataBool(new GoalID[1] { GoalID.GreymoorFleasTwoKratt }, "FleaKratt"); internal SaveDataBool FleaGreymoorTower = new SaveDataBool(new GoalID[1] { GoalID.GreymoorFleasTwoKratt }, "FleaGreymoorTower"); internal SaveDataBool FleaFarFieldsCage = new SaveDataBool(new GoalID[1] { GoalID.FarFieldsFleasTwo }, "FleaFarFieldsCage"); internal SaveDataBool FleaPilgrimsRest = new SaveDataBool(new GoalID[1] { GoalID.FarFieldsFleasTwo }, "FleaPilgrimsRest"); internal SaveDataBool FleaShellwood = new SaveDataBool(new GoalID[1] { GoalID.ShellwoodBellhartFleasTwo }, "FleaShellwood"); internal SaveDataBool FleaBellvein = new SaveDataBool(new GoalID[1] { GoalID.ShellwoodBellhartFleasTwo }, "FleaBellvein"); internal SaveDataBool FleaSwiftStep = new SaveDataBool(new GoalID[1] { GoalID.DeepDocksFleasThree }, "FleaSwiftStep"); internal SaveDataBool FleaDeepDocksBellway = new SaveDataBool(new GoalID[1] { GoalID.DeepDocksFleasThree }, "FleaDeepDocksBellway"); internal SaveDataBool FleaDeeperDocks = new SaveDataBool(new GoalID[1] { GoalID.DeepDocksFleasThree }, "FleaDeeperDocks"); internal SaveDataBool FleaWormways = new SaveDataBool(new GoalID[1] { GoalID.WormwaysBlastedStepsFleasTwo }, "FleaWormways"); internal SaveDataBool FleaBlastedSteps = new SaveDataBool(new GoalID[1] { GoalID.WormwaysBlastedStepsFleasTwo }, "FleaBlastedSteps"); internal SaveDataBool FleaUnderworksCauldron = new SaveDataBool(new GoalID[1] { GoalID.UnderworksFleasTwo }, "FleaUnderworksCauldron"); internal SaveDataBool FleaUnderworksWispThicket = new SaveDataBool(new GoalID[1] { GoalID.UnderworksFleasTwo }, "FleaUnderworksWispThicket"); internal SaveDataBool FleaBilewaterThieves = new SaveDataBool(new GoalID[1] { GoalID.LowerBilewaterHuntersMarchFleasTwo }, "FleaBilewaterThieves"); internal SaveDataBool FleaHuntersMarch = new SaveDataBool(new GoalID[1] { GoalID.LowerBilewaterHuntersMarchFleasTwo }, "FleaHuntersMarch"); internal SaveDataBool FleaSinnersRoad = new SaveDataBool(new GoalID[1] { GoalID.SinnersRoadVaultsFleasTwo }, "FleaSinnersRoad"); internal SaveDataBool FleaVaults = new SaveDataBool(new GoalID[1] { GoalID.SinnersRoadVaultsFleasTwo }, "FleaVaults"); internal SaveDataBool DeepDocksSpoolFragNearSpa = new SaveDataBool(new GoalID[1] { GoalID.DeepDocksSpoolFragmentsTwo }, "DeepDocksSpoolFragNearSpa"); internal SaveDataBool DeeperDocksSpoolFrag = new SaveDataBool(new GoalID[1] { GoalID.DeepDocksSpoolFragmentsTwo }, "DeeperDocksSpoolFrag"); internal SaveDataInt SilkSkills = new SaveDataInt(new AutomarkIntValue[2] { new AutomarkIntValue { markValue = 3, goalToMark = GoalID.ThreeSilkSkills }, new AutomarkIntValue { markValue = 4, goalToMark = GoalID.FourSilkSkills } }, "SilkSkills"); internal SaveDataInt Crests = new SaveDataInt(new AutomarkIntValue[1] { new AutomarkIntValue { markValue = 3, goalToMark = GoalID.ThreeNonHunterCrests } }, "Crests"); internal SaveDataInt ExtraMasks = new SaveDataInt(new AutomarkIntValue[2] { new AutomarkIntValue { markValue = 1, goalToMark = GoalID.OneExtraMask }, new AutomarkIntValue { markValue = 2, goalToMark = GoalID.TwoExtraMasks } }, "ExtraMasks"); internal SaveDataInt SpoolFragments = new SaveDataInt(new AutomarkIntValue[3] { new AutomarkIntValue { markValue = 2, goalToMark = GoalID.OneSpoolUpgrade }, new AutomarkIntValue { markValue = 4, goalToMark = GoalID.TwoSpoolUpgrades }, new AutomarkIntValue { markValue = 6, goalToMark = GoalID.ThreeSpoolUpgrades } }, "SpoolFragments"); internal SaveDataInt SilkHearts = new SaveDataInt(new AutomarkIntValue[1] { new AutomarkIntValue { markValue = 2, goalToMark = GoalID.TwoSilkHearts } }, "SilkHearts"); internal SaveDataInt WishesCompleted = new SaveDataInt(new AutomarkIntValue[2] { new AutomarkIntValue { markValue = 5, goalToMark = GoalID.CompleteFiveWishes }, new AutomarkIntValue { markValue = 7, goalToMark = GoalID.CompleteSevenWishes } }, "WishesCompleted"); internal SaveDataInt HuntWishes = new SaveDataInt(new AutomarkIntValue[2] { new AutomarkIntValue { markValue = 2, goalToMark = GoalID.TwoHuntWishes }, new AutomarkIntValue { markValue = 4, goalToMark = GoalID.FourHuntWishes } }, "HuntWishes"); internal SaveDataInt GatherWishes = new SaveDataInt(new AutomarkIntValue[2] { new AutomarkIntValue { markValue = 2, goalToMark = GoalID.TwoGatherWishes }, new AutomarkIntValue { markValue = 3, goalToMark = GoalID.ThreeGatherWishes } }, "GatherWishes"); internal SaveDataInt WayfarerWishes = new SaveDataInt(new AutomarkIntValue[2] { new AutomarkIntValue { markValue = 2, goalToMark = GoalID.TwoWayfarerWishes }, new AutomarkIntValue { markValue = 4, goalToMark = GoalID.FourWayfarerWishes } }, "WayfarerWishes"); internal SaveDataInt DonationWishes = new SaveDataInt(new AutomarkIntValue[2] { new AutomarkIntValue { markValue = 2, goalToMark = GoalID.TwoDonationWishes }, new AutomarkIntValue { markValue = 3, goalToMark = GoalID.ThreeDonationWishes } }, "DonationWishes"); internal SaveDataInt Silkeaters = new SaveDataInt(new AutomarkIntValue[2] { new AutomarkIntValue { markValue = 3, goalToMark = GoalID.ObtainThreeSilkeaters }, new AutomarkIntValue { markValue = 5, goalToMark = GoalID.ObtainFiveSilkeaters } }, "Silkeaters"); internal SaveDataInt Craftmetal = new SaveDataInt(new AutomarkIntValue[2] { new AutomarkIntValue { markValue = 3, goalToMark = GoalID.ObtainThreeCraftmetal }, new AutomarkIntValue { markValue = 5, goalToMark = GoalID.ObtainFiveCraftmetal } }, "Craftmetal"); internal SaveDataInt RuneHarps = new SaveDataInt(new AutomarkIntValue[1] { new AutomarkIntValue { markValue = 2, goalToMark = GoalID.ObtainTwoRuneHarps } }, "RuneHarps"); internal SaveDataInt BoneScrolls = new SaveDataInt(new AutomarkIntValue[2] { new AutomarkIntValue { markValue = 3, goalToMark = GoalID.ObtainThreeBoneScrolls }, new AutomarkIntValue { markValue = 4, goalToMark = GoalID.ObtainFourBoneScrolls } }, "BoneScrolls"); internal SaveDataInt BeastShards = new SaveDataInt(new AutomarkIntValue[4] { new AutomarkIntValue { markValue = 2, goalToMark = GoalID.ObtainTwoBeastShards }, new AutomarkIntValue { markValue = 3, goalToMark = GoalID.ObtainThreeBeastShards }, new AutomarkIntValue { markValue = 4, goalToMark = GoalID.ObtainFourBeastShards }, new AutomarkIntValue { markValue = 5, goalToMark = GoalID.ObtainFiveBeastShards } }, "BeastShards"); internal SaveDataInt CogheartPieces = new SaveDataInt(new AutomarkIntValue[2] { new AutomarkIntValue { markValue = 1, goalToMark = GoalID.OneCogheartPiece }, new AutomarkIntValue { markValue = 2, goalToMark = GoalID.TwoCogheartPieces } }, "CogheartPieces"); internal SaveDataInt MapCount = new SaveDataInt(new AutomarkIntValue[2] { new AutomarkIntValue { markValue = 5, goalToMark = GoalID.ObtainFiveMaps }, new AutomarkIntValue { markValue = 8, goalToMark = GoalID.ObtainEightMaps } }, "MapCount"); internal SaveDataInt CraftKitToolPouchCount = new SaveDataInt(new AutomarkIntValue[1] { new AutomarkIntValue { markValue = 3, goalToMark = GoalID.ThreeToolPouchUpgradesCraftingKits } }, "CraftKitToolPouchCount"); internal SaveDataInt FleasSaved = new SaveDataInt(new AutomarkIntValue[4] { new AutomarkIntValue { markValue = 8, goalToMark = GoalID.FreeEightFleas }, new AutomarkIntValue { markValue = 10, goalToMark = GoalID.FreeTenFleas }, new AutomarkIntValue { markValue = 12, goalToMark = GoalID.FreeTwelveFleas }, new AutomarkIntValue { markValue = 14, goalToMark = GoalID.FreeFourteenFleas } }, "FleasSaved"); internal SaveDataInt CitadelFleas = new SaveDataInt(new AutomarkIntValue[1] { new AutomarkIntValue { markValue = 3, goalToMark = GoalID.ThreeCitadelFleas } }, "CitadelFleas"); internal SaveDataInt MemoryLockets = new SaveDataInt(new AutomarkIntValue[1] { new AutomarkIntValue { markValue = 5, goalToMark = GoalID.ObtainFiveMemoryLockets } }, "MemoryLockets"); internal SaveDataInt NonPurchasedShardBundles = new SaveDataInt(Array.Empty(), "NonPurchasedShardBundles"); internal SaveDataInt NonPurchasedBrokenShardBundles = new SaveDataInt(new AutomarkIntValue[2] { new AutomarkIntValue { markValue = 4, goalToMark = GoalID.BreakFourShardBundlesnopurchasing }, new AutomarkIntValue { markValue = 6, goalToMark = GoalID.BreakSixShardBundlesnopurchasing } }, "NonPurchasedBrokenShardBundles"); internal SaveDataInt CurrentPurchasedRosaryNecklaces = new SaveDataInt(Array.Empty(), "CurrentPurchasedRosaryNecklaces"); internal SaveDataInt NonPurchasedRosaryNecklaces = new SaveDataInt(new AutomarkIntValue[1] { new AutomarkIntValue { markValue = 3, goalToMark = GoalID.HaveThreeRosaryNecklacesnopurchasing } }, "NonPurchasedRosaryNecklaces"); internal SaveDataInt VoidMassesKilled = new SaveDataInt(new AutomarkIntValue[2] { new AutomarkIntValue { markValue = 3, goalToMark = GoalID.ThreeVoidMasses }, new AutomarkIntValue { markValue = 6, goalToMark = GoalID.SixVoidMasses } }, "VoidMassesKilled"); internal SaveDataInt DuoMossMothers = new SaveDataInt(new AutomarkIntValue[1] { new AutomarkIntValue { markValue = 2, goalToMark = GoalID.MossMotherDuo } }, "DuoMossMothers"); internal SaveDataInt VerdaniaFountainOrbs = new SaveDataInt(new AutomarkIntValue[1] { new AutomarkIntValue { markValue = 5, goalToMark = GoalID.VerdaniaFountainOrbs } }, "VerdaniaFountainOrbs"); internal SaveDataInt MementosObtained = new SaveDataInt(new AutomarkIntValue[1] { new AutomarkIntValue { markValue = 2, goalToMark = GoalID.TwoMementos } }, "MementosObtained"); internal SaveDataBitmask ShakraLocations = new SaveDataBitmask(new AutomarkIntValue[1] { new AutomarkIntValue { markValue = 5, goalToMark = GoalID.TalktoShakraatFiveLocations } }, "ShakraLocations"); internal SaveDataBitmask RelicTypesObtained = new SaveDataBitmask(new AutomarkIntValue[1] { new AutomarkIntValue { markValue = 4, goalToMark = GoalID.ObtainFourDifferentTypesofRelic } }, "RelicTypesObtained"); internal SaveDataBitmask RelicTypesCurrentlyHeld = new SaveDataBitmask(new AutomarkIntValue[1] { new AutomarkIntValue { markValue = 3, goalToMark = GoalID.HaveThreeDifferentTypesofRelic } }, "RelicTypesCurrentlyHeld"); } [Flags] internal enum ShakraLocationFlags { BoneBottom = 1, Marrow = 2, DeepDocks = 4, HuntersMarch = 8, FarFields = 0x10, GreymoorBell = 0x20, GreymoorDuel = 0x40, GreymoorAct3 = 0x80, Bellhart = 0x100, ShellwoodNormal = 0x200, ShellwoodAct3 = 0x400, Wormways = 0x800, BlastedSteps = 0x1000, SinnersRoad = 0x2000, Bilewater = 0x4000, SandsOfKarak = 0x8000, MountFay = 0x10000, TrailsEnd = 0x20000, HighHallsArena = 0x40000 } [Flags] internal enum RelicTypeFlags { ChoralCommandment = 1, WeaverEffigy = 2, RuneHarp = 4, BoneScroll = 8, ArcaneEgg = 0x10 } internal struct AutomarkIntValue { internal int markValue; internal GoalID goalToMark; } internal class SaveDataBitmask { internal string Name; internal uint bitmask = 0u; internal AutomarkIntValue[] AutomarkValues { get; private set; } internal void AddFlag(uint flag) { bitmask |= flag; CheckForAutomarks(); } internal SaveDataBitmask(AutomarkIntValue[] automarkValues, string name) { Name = name; AutomarkValues = automarkValues; } internal void ResetFlags() { bitmask = 0u; } private void CheckForAutomarks() { int num = 32; int num2 = 0; for (int i = 0; i < num; i++) { if ((int)(bitmask & (1 << i)) != 0) { num2++; } } Automarker.CheckIfGoalsCompleted(AutomarkValues, num2); } } internal class SaveDataBool { internal const bool defaultValue = false; internal bool _value = false; internal GoalID[] GoalIDs; internal bool Value { get { return _value; } set { _value = value; VogsBingoModPlugin.LogInfo($"Updated value {Name} to {_value}."); Automarker.CheckIfGoalsCompleted(GoalIDs); } } internal string Name { get; private set; } public static implicit operator bool(SaveDataBool data) { return data.Value; } internal SaveDataBool(GoalID[] goalIDs, string name, bool value = false) { _value = value; GoalIDs = goalIDs; Name = name; } internal void ResetToDefault() { Value = false; } } internal class SaveDataInt { internal string Name; internal int _value; internal AutomarkIntValue[] AutomarkValues; internal int Value { get { return _value; } set { _value = value; VogsBingoModPlugin.LogInfo($"Updated value {Name} to {_value}."); AutomarkIntValue[] automarkValues = AutomarkValues; for (int i = 0; i < automarkValues.Length; i++) { AutomarkIntValue automarkIntValue = automarkValues[i]; VogsBingoModPlugin.LogInfo($"Goal {Name} marks at {automarkIntValue.markValue} for goal {automarkIntValue.goalToMark}"); } Automarker.CheckIfGoalsCompleted(AutomarkValues, _value); } } public static implicit operator int(SaveDataInt data) { return data.Value; } internal SaveDataInt(AutomarkIntValue[] automarkValues, string name, int startValue = 0) { _value = startValue; AutomarkValues = automarkValues; Name = name; } internal void ResetToDefault() { Value = 0; } } [HarmonyPatch] internal class AutomarkPatches { [HarmonyPrefix] [HarmonyPatch(typeof(ToolItemManager), "SetEquippedCrest")] private static void CrestUnlockPatch(string crestId) { switch (crestId) { case "Wanderer": Automarker.MarkIfAvailable(GoalID.WanderersCrest); break; case "Warrior": Automarker.MarkIfAvailable(GoalID.BeastsCrest); break; case "Hunter_v2": Automarker.MarkIfAvailable(GoalID.EvolvedHuntersCrest); break; case "Reaper": Automarker.MarkIfAvailable(GoalID.ReapersCrest); break; case "Witch": Automarker.MarkIfAvailable(GoalID.WitchCrest); break; case "Spell": Automarker.MarkIfAvailable(GoalID.ShamanCrest); break; } } [HarmonyPostfix] [HarmonyPatch(typeof(FullQuestBase), "TryEndQuest")] private static void QuestCompletionPatch(bool __result, FullQuestBase __instance) { if (__result && __instance.IsCompleted) { switch (((Object)__instance).name) { case "Crow Feathers": Automarker.MarkIfAvailable(GoalID.CrawbugClearing); break; case "Rock Rollers": Automarker.MarkIfAvailable(GoalID.VolatileFlintbeetles); break; case "Save City Merchant": Automarker.MarkIfAvailable(GoalID.SaveJubilana); break; case "A Pinsmiths Tools": Automarker.MarkIfAvailable(GoalID.UpgradeNeedleTwice); break; case "Wood Witch Curse": Automarker.MarkIfAvailable(GoalID.GetCursed); break; } switch (((Object)((BasicQuestBase)__instance).QuestType).name.ToLower()) { case "hunt": case "grand hunt": VogsBingoModPlugin.instance.SaveData.HuntWishes.Value++; VogsBingoModPlugin.instance.SaveData.WishesCompleted.Value++; break; case "gather": VogsBingoModPlugin.instance.SaveData.GatherWishes.Value++; VogsBingoModPlugin.instance.SaveData.WishesCompleted.Value++; break; case "wayfarer": VogsBingoModPlugin.instance.SaveData.WayfarerWishes.Value++; VogsBingoModPlugin.instance.SaveData.WishesCompleted.Value++; break; case "donate": VogsBingoModPlugin.instance.SaveData.DonationWishes.Value++; VogsBingoModPlugin.instance.SaveData.WishesCompleted.Value++; break; case "delivery": case "learn": case "sprint": case "witness": case "steel": VogsBingoModPlugin.instance.SaveData.WishesCompleted.Value++; break; } } } [HarmonyPrefix] [HarmonyPatch(typeof(CollectableUIMsg), "Spawn", new Type[] { typeof(ICollectableUIMsgItem), typeof(Color), typeof(CollectableUIMsg), typeof(bool) })] private static void UIMsgPatch(ICollectableUIMsgItem item) { switch (((Object)item.GetUIMsgSprite()).name) { case "belltown_house_key": Automarker.MarkIfAvailable(GoalID.BellhomeKey); break; case "Silk_Grub_idle0000": VogsBingoModPlugin.instance.SaveData.Silkeaters.Value++; VogsBingoModPlugin.instance.SaveData.SilkeaterBool.Value = true; if (IsScene("Coral_37")) { VogsBingoModPlugin.instance.SaveData.BlastedSilkeater.Value = true; } break; case "Hornet_Tool_Metal": { VogsBingoModPlugin.instance.SaveData.Craftmetal.Value++; string sceneName2 = GetSceneName(); string text2 = sceneName2; if (!(text2 == "Coral_32")) { if (text2 == "Aqueduct_05") { Automarker.MarkIfAvailable(GoalID.PaleLakeCraftmetal); } } else { VogsBingoModPlugin.instance.SaveData.BlastedCraftmetal.Value = true; } break; } case "I_slab_key_brass": Automarker.MarkIfAvailable(GoalID.ApostateKey); break; case "I_quill_red": Automarker.MarkIfAvailable(GoalID.RedQuill); break; case "_0007_quest_coral_nut": Automarker.MarkIfAvailable(GoalID.Crustnut); break; case "Mossberry_Stew": Automarker.MarkIfAvailable(GoalID.MossberrySoup); break; case "vintage_nectar_item": Automarker.MarkIfAvailable(GoalID.VintageNectar); break; case "mandrake_icon0000": Automarker.MarkIfAvailable(GoalID.TwistedBud); break; case "I_token_of_faith": { string sceneName = GetSceneName(); string text = sceneName; if (!(text == "Dust_06")) { if (text == "Bellshrine_Coral") { VogsBingoModPlugin.instance.SaveData.KarakKey.Value = true; } } else { VogsBingoModPlugin.instance.SaveData.SinnersKey.Value = true; } break; } case "Hornet_icon_0002_R_weaver_record": VogsBingoModPlugin.instance.SaveData.RuneHarps.Value++; VogsBingoModPlugin.instance.SaveData.RelicTypesObtained.AddFlag(4u); VogsBingoModPlugin.instance.SaveData.RelicTypesCurrentlyHeld.AddFlag(4u); break; case "Hornet_icon_0002_R_bone_record": VogsBingoModPlugin.instance.SaveData.BoneScrolls.Value++; VogsBingoModPlugin.instance.SaveData.RelicTypesObtained.AddFlag(8u); VogsBingoModPlugin.instance.SaveData.RelicTypesCurrentlyHeld.AddFlag(8u); break; case "Hornet_icon_0005_R_saint_locket": VogsBingoModPlugin.instance.SaveData.RelicTypesObtained.AddFlag(2u); VogsBingoModPlugin.instance.SaveData.RelicTypesCurrentlyHeld.AddFlag(2u); break; case "Hornet_icon_0000_R_seal_chit": VogsBingoModPlugin.instance.SaveData.RelicTypesObtained.AddFlag(1u); VogsBingoModPlugin.instance.SaveData.RelicTypesCurrentlyHeld.AddFlag(1u); break; case "Icon_Beast_Shard": VogsBingoModPlugin.instance.SaveData.BeastShards.Value++; break; case "cog_heart__0001_left": case "cog_heart__0002_right": case "cog_heart__0003_back": VogsBingoModPlugin.instance.SaveData.CogheartPieces.Value++; break; case "Shop_map_icon__0012_cradle": Automarker.MarkIfAvailable(GoalID.CradleMap); break; case "Shop_map_icon__weavehome": if (IsScene("Abyss_12")) { Automarker.MarkIfAvailable(GoalID.AbyssMap); } break; case "Shop_map_icon__0003_clover": Automarker.MarkIfAvailable(GoalID.VerdaniaMap); break; case "Hornet_icon_0004_R_ancient_egg": Automarker.MarkIfAvailable(GoalID.OneArcaneEgg); VogsBingoModPlugin.instance.SaveData.RelicTypesObtained.AddFlag(16u); VogsBingoModPlugin.instance.SaveData.RelicTypesCurrentlyHeld.AddFlag(16u); break; case "surface_memento": Automarker.MarkIfAvailable(GoalID.SurfaceMemento); VogsBingoModPlugin.instance.SaveData.MementosObtained.Value++; break; case "grey_warrior_memento": Automarker.MarkIfAvailable(GoalID.GreyMemento); VogsBingoModPlugin.instance.SaveData.MementosObtained.Value++; break; case "Inv_tool_pouch_upgrade_02": if (PlayerData.instance.pinGalleriesCompleted >= 1) { Automarker.MarkIfAvailable(GoalID.WinaLoddieMinigame); } VogsBingoModPlugin.instance.SaveData.CraftKitToolPouchCount.Value++; Automarker.MarkIfAvailable(GoalID.OneToolPouchUpgrade); break; case "icon_tool_kit_upgrade": VogsBingoModPlugin.instance.SaveData.CraftKitToolPouchCount.Value++; Automarker.MarkIfAvailable(GoalID.OneCraftingKit); break; case "Charm_Notch": VogsBingoModPlugin.instance.SaveData.MemoryLockets.Value++; break; case "Hornet_Tool_Metal_Pouch": VogsBingoModPlugin.instance.SaveData.NonPurchasedShardBundles.Value++; break; case "I_rosary_necklace_0000_3": case "I_rosary_necklace_0000_3_old": case "I_rosary_necklace_0001_2": VogsBingoModPlugin.instance.SaveData.NonPurchasedRosaryNecklaces.Value++; break; case "I_rosary_necklace_0002_1": if (IsScene("Greymoor_01") || IsScene("Shellwood_08c") || IsScene("Hang_06_bank")) { AutomarkRosaryStringHandler.AddPurchasedString(); } else { AutomarkRosaryStringHandler.AddNonPurchasedString(); } break; case "I_rosary_necklace_0002_1_frayed": AutomarkRosaryStringHandler.AddFrayedString(); break; case "garmond_memento": VogsBingoModPlugin.instance.SaveData.MementosObtained.Value++; break; case "craw_court_memento": VogsBingoModPlugin.instance.SaveData.MementosObtained.Value++; break; case "hunter_nuu_memento_seal": VogsBingoModPlugin.instance.SaveData.MementosObtained.Value++; break; case "sprintmaster_memento": VogsBingoModPlugin.instance.SaveData.MementosObtained.Value++; break; case "seth_memento": VogsBingoModPlugin.instance.SaveData.MementosObtained.Value++; break; } } [HarmonyPrefix] [HarmonyPatch(typeof(InventoryItemCollectable), "PlayConsumeFinalShake")] private static void ConsumeCollectablePatch(InventoryItemCollectable __instance) { switch (((Object)__instance).name) { case "Rosary_Set_Medium": if ((int)VogsBingoModPlugin.instance.SaveData.CurrentPurchasedRosaryNecklaces > 0) { VogsBingoModPlugin.instance.SaveData.CurrentPurchasedRosaryNecklaces.Value--; } else { VogsBingoModPlugin.instance.SaveData.NonPurchasedRosaryNecklaces.Value--; } break; case "Rosary_Set_Large": case "Rosary_Set_Huge_White": VogsBingoModPlugin.instance.SaveData.NonPurchasedRosaryNecklaces.Value--; break; case "Shard Pouch": if ((int)VogsBingoModPlugin.instance.SaveData.NonPurchasedShardBundles > (int)VogsBingoModPlugin.instance.SaveData.NonPurchasedBrokenShardBundles) { VogsBingoModPlugin.instance.SaveData.NonPurchasedBrokenShardBundles.Value++; } break; case "Rosary_Set_Small": AutomarkRosaryStringHandler.BreakString(); break; case "Rosary_Set_Frayed": AutomarkRosaryStringHandler.BreakFrayedString(); break; } } [HarmonyPostfix] [HarmonyPatch(typeof(PlayerDataIntAdd), "OnEnter")] private static void MossberryPatch(PlayerDataIntAdd __instance) { if (PlayerData.instance.druidMossBerriesSold > 0 && IsScene("Mosstown_02c")) { Automarker.MarkIfAvailable(GoalID.SellaMossberry); } } [HarmonyPrefix] [HarmonyPatch(typeof(CreateUIMsgGetItem), "OnEnter")] private static void UIItemMsgPatch(CreateUIMsgGetItem __instance) { switch (GetSceneName()) { case "Room_Pinstress": Automarker.MarkIfAvailable(GoalID.NeedleStrike); break; case "Peak_08b": Automarker.MarkIfAvailable(GoalID.FaydownCloak); break; case "Halfway_01": VogsBingoModPlugin.instance.SaveData.HasJournal.Value = true; break; case "Bellway_Centipede_Arena": Automarker.MarkIfAvailable(GoalID.BeastlingCall); break; } } [HarmonyPrefix] [HarmonyPatch(typeof(ItemReceptacle), "AcceptedPrompt")] private static void AcceptPromptPatch() { string sceneName = GetSceneName(); string text = sceneName; if (!(text == "Room_Forge")) { if (text == "Dust_02") { Automarker.MarkIfAvailable(GoalID.FreeGreenPrince); } } else { Automarker.MarkIfAvailable(GoalID.UseaSimpleKeyinDeepDocks); } } [HarmonyPrefix] [HarmonyPatch(typeof(EnemyJournalManager), "RecordKill", new Type[] { typeof(EnemyJournalRecord), typeof(bool), typeof(bool) })] private static void KillRecordPatch(EnemyJournalRecord journalRecord) { switch (((Object)journalRecord).name) { case "Song Automaton Ball": VogsBingoModPlugin.instance.SaveData.CogworkClapperKilled.Value = true; break; case "Bone Goomba Bounce Fly": VogsBingoModPlugin.instance.SaveData.SkullwingKilled.Value = true; break; case "Small Crab": VogsBingoModPlugin.instance.SaveData.CraggliteKilled.Value = true; break; case "Crypt Worm": VogsBingoModPlugin.instance.SaveData.GromlingKilled.Value = true; break; case "Gnat Giant": VogsBingoModPlugin.instance.SaveData.MiteMotherKilled.Value = true; break; case "MossBone Crawler Fat": VogsBingoModPlugin.instance.SaveData.MassiveMossgrubKilled.Value = true; break; case "Dock Charger": VogsBingoModPlugin.instance.SaveData.DeepDiverKilled.Value = true; break; case "Conductor Boss": VogsBingoModPlugin.instance.SaveData.UnravelledKilled.Value = true; break; case "Abyss Crawler Large": VogsBingoModPlugin.instance.SaveData.ShadowChargerKilled.Value = true; break; case "Spike Lazy Flyer": VogsBingoModPlugin.instance.SaveData.ImobaKilled.Value = true; break; case "Coral Judge Child": VogsBingoModPlugin.instance.SaveData.SquirrmKilled.Value = true; break; case "Coral Conch Driller Giant": { string sceneName = GetSceneName(); string text = sceneName; if (!(text == "Coral_27")) { if (text == "Coral_11") { Automarker.MarkIfAvailable(GoalID.GreatConchfliesBlastedSteps); } } else { Automarker.MarkIfAvailable(GoalID.RagingConchflySandsofKarak); } break; } case "Mossbone Mother": if (IsScene("Weave_03")) { VogsBingoModPlugin.instance.SaveData.DuoMossMothers.Value++; } if (PlayerData.instance.act3_wokeUp) { Automarker.MarkIfAvailable(GoalID.DefeataBlackthreadedBoss); } break; case "Song Golem": Automarker.MarkIfAvailable(GoalID.FourthChorus); break; case "Roof Crab": Automarker.MarkIfAvailable(GoalID.Craggler); break; case "Vampire Gnat": Automarker.MarkIfAvailable(GoalID.Moorwing); if (PlayerData.instance.act3_wokeUp) { Automarker.MarkIfAvailable(GoalID.DefeataBlackthreadedBoss); } break; case "Bone Flyer Giant": Automarker.MarkIfAvailable(GoalID.SavageBeastfly); if (PlayerData.instance.act3_wokeUp) { Automarker.MarkIfAvailable(GoalID.DefeataBlackthreadedBoss); } break; case "Rhino": Automarker.MarkIfAvailable(GoalID.DefeataRhinogrund); break; case "Clockwork Dancer": Automarker.MarkIfAvailable(GoalID.CogworkDancers); break; case "Last Judge": Automarker.MarkIfAvailable(GoalID.LastJudge); break; case "Phantom": Automarker.MarkIfAvailable(GoalID.Phantom); break; case "Trobbio": Automarker.MarkIfAvailable(GoalID.Trobbio); break; case "Roachkeeper Chef": Automarker.MarkIfAvailable(GoalID.DisgracedChefLugoli); if (PlayerData.instance.act3_wokeUp) { Automarker.MarkIfAvailable(GoalID.DefeataBlackthreadedBoss); } break; case "Wisp Pyre Effigy": Automarker.MarkIfAvailable(GoalID.FatherOfTheFlame); break; case "Dock Guard Thrower": Automarker.MarkIfAvailable(GoalID.ForebrothersSignisGron); break; case "Rosary Pilgrim": Automarker.MarkIfAvailable(GoalID.DefeataCovetousPilgrim); break; case "Splinter Queen": Automarker.MarkIfAvailable(GoalID.SisterSplinter); break; case "Zap Core Enemy": Automarker.MarkIfAvailable(GoalID.Voltvyrm); break; case "Skull King": Automarker.MarkIfAvailable(GoalID.SkullTyrant); if (PlayerData.instance.act3_wokeUp) { Automarker.MarkIfAvailable(GoalID.DefeataBlackthreadedBoss); } break; case "Giant Flea": Automarker.MarkIfAvailable(GoalID.BeatBigFlea); Automarker.UpdateFleas(); break; case "Seth": Automarker.MarkIfAvailable(GoalID.FightSeth); break; case "Cloverstag White": Automarker.MarkIfAvailable(GoalID.PaleStag); break; case "Tormented Trobbio": Automarker.MarkIfAvailable(GoalID.TormentedTrobbio); break; case "Black Thread Core": VogsBingoModPlugin.instance.SaveData.VoidMassesKilled.Value++; break; case "Garmond": if (PlayerData.instance.act3_wokeUp) { Automarker.MarkIfAvailable(GoalID.DefeataBlackthreadedBoss); } break; case "Abyss Mass": Automarker.MarkIfAvailable(GoalID.DefeataBlackthreadedBoss); break; case "Lost Lace": Automarker.MarkIfAvailable(GoalID.DefeataBlackthreadedBoss); break; } } [HarmonyPrefix] [HarmonyPatch(typeof(CompleteJournalRecordV2), "OnEnter")] private static void JournalFullCompletePatch() { if (IsScene("Hang_14")) { Automarker.MarkIfAvailable(GoalID.DisabletheClawmaidens); } } [HarmonyPrefix] [HarmonyPatch(typeof(PlayMakerNPC), "OnStartingDialogue")] private static void NPCDialogueStartPatch(PlayMakerNPC __instance) { switch (((Object)__instance).name) { case "Mapper NPC": case "Mapper Sit NPC": case "Mapper NPC (1)": case "Mapper Rest NPC": switch (GetSceneName()) { case "Bonetown": VogsBingoModPlugin.instance.SaveData.ShakraLocations.AddFlag(1u); break; case "Bone_04": VogsBingoModPlugin.instance.SaveData.ShakraLocations.AddFlag(2u); break; case "Bone_East_01": VogsBingoModPlugin.instance.SaveData.ShakraLocations.AddFlag(4u); break; case "Ant_04_mid": case "Ant_20": VogsBingoModPlugin.instance.SaveData.ShakraLocations.AddFlag(8u); break; case "Bone_East_21": VogsBingoModPlugin.instance.SaveData.ShakraLocations.AddFlag(16u); break; case "Greymoor_02": VogsBingoModPlugin.instance.SaveData.ShakraLocations.AddFlag(32u); break; case "Greymoor_08": if (PlayerData.instance.mapperLocationAct3 == 3) { VogsBingoModPlugin.instance.SaveData.ShakraLocations.AddFlag(128u); } break; case "Belltown": VogsBingoModPlugin.instance.SaveData.ShakraLocations.AddFlag(256u); break; case "Shellwood_16": VogsBingoModPlugin.instance.SaveData.ShakraLocations.AddFlag(512u); break; case "Shellwood_01": if (PlayerData.instance.mapperLocationAct3 == 1) { VogsBingoModPlugin.instance.SaveData.ShakraLocations.AddFlag(1024u); } break; case "Crawl_01": VogsBingoModPlugin.instance.SaveData.ShakraLocations.AddFlag(2048u); break; case "Coral_12": VogsBingoModPlugin.instance.SaveData.ShakraLocations.AddFlag(4096u); break; case "Dust_10": VogsBingoModPlugin.instance.SaveData.ShakraLocations.AddFlag(8192u); break; case "Peak_02": VogsBingoModPlugin.instance.SaveData.ShakraLocations.AddFlag(65536u); break; case "Coral_40": Automarker.MarkIfAvailable(GoalID.TalktoShakrainSandsofKarak); VogsBingoModPlugin.instance.SaveData.ShakraLocations.AddFlag(32768u); break; case "Shadow_23": Automarker.MarkIfAvailable(GoalID.TalktoShakrainBilewater); VogsBingoModPlugin.instance.SaveData.ShakraLocations.AddFlag(16384u); break; } break; case "Mapper Spar NPC": VogsBingoModPlugin.instance.SaveData.ShakraLocations.AddFlag(64u); break; case "Mapper Master NPC": VogsBingoModPlugin.instance.SaveData.ShakraLocations.AddFlag(131072u); break; case "Shakra Aid NPC": case "Victory NPC": VogsBingoModPlugin.instance.SaveData.ShakraLocations.AddFlag(262144u); break; case "Huntress": VogsBingoModPlugin.instance.SaveData.HuntressSpokenTo.Value = true; Automarker.MarkIfAvailable(GoalID.TalktoHuntress); break; case "Grub Farmer NPC": VogsBingoModPlugin.instance.SaveData.StyxSpokenTo.Value = true; break; case "Shop Prompt": if (IsScene("Room_Forge")) { VogsBingoModPlugin.instance.SaveData.ForgeDaughterSpokenTo.Value = true; } break; case "Architect NPC": VogsBingoModPlugin.instance.SaveData.TwelfthArchitectSpokenTo.Value = true; break; case "Understore Large Worker": Automarker.MarkIfAvailable(GoalID.TalktoLoam); break; case "Peak Mask Maker": Automarker.MarkIfAvailable(GoalID.TalktoMaskMaker); break; case "Fixer Sitting Bone_10": Automarker.MarkIfAvailable(GoalID.TalktoFlickatSurvivorsCamp); break; case "Mr Mushroom NPC": Automarker.MarkIfAvailable(GoalID.TalktoMrMushroom); break; case "Sherma Citadel Spa NPC": Automarker.MarkIfAvailable(GoalID.MeetShermaintheSpa); break; case "Plinney Outside": Automarker.MarkIfAvailable(GoalID.SavePinmasterPlinney); break; } } [HarmonyPrefix] [HarmonyPatch(typeof(SetCollider), "OnEnter")] private static void SetColliderPatch(SetCollider __instance) { if (!IsScene("Dust_11")) { return; } string name = ((Object)((FsmStateAction)__instance).Fsm.GetOwnerDefaultTarget(__instance.gameObject)).name; string text = name; if (!(text == "One Way Wall (1)")) { if (text == "One Way Wall (2)") { VogsBingoModPlugin.instance.SaveData.SinnersStyxWallBroken.Value = true; } } else { VogsBingoModPlugin.instance.SaveData.GreymoorStyxWallBroken.Value = true; } } [HarmonyPrefix] [HarmonyPatch(typeof(ShopItem), "SetPurchased")] private static void ShopItemPurchasePatch(ShopItem __instance) { if (IsScene("Coral_42") && !((Object)__instance.Item).name.Equals("Rosary_Set_Small")) { Automarker.MarkIfAvailable(GoalID.BuyFromGrindleNoString); } switch (((Object)__instance).name) { case "Bonebottom Faith Token": VogsBingoModPlugin.instance.SaveData.PebbKeyBought.Value = true; break; case "City Merchant Simple Key": VogsBingoModPlugin.instance.SaveData.JubilanaKeyBought.Value = true; break; case "Belltown Spool Segment": Automarker.MarkIfAvailable(GoalID.FreysSpoolFragment); break; } if ((Object)(object)__instance.Item != (Object)null) { switch (((Object)__instance.Item).name) { case "Seal Chit City Merchant": VogsBingoModPlugin.instance.SaveData.RelicTypesObtained.AddFlag(1u); VogsBingoModPlugin.instance.SaveData.RelicTypesCurrentlyHeld.AddFlag(1u); break; case "Rosary_Set_Medium": VogsBingoModPlugin.instance.SaveData.CurrentPurchasedRosaryNecklaces.Value++; break; case "Rosary_Set_Small": AutomarkRosaryStringHandler.AddPurchasedString(); break; case "Crest Socket Unlocker": VogsBingoModPlugin.instance.SaveData.MemoryLockets.Value++; break; case "Tool Metal": VogsBingoModPlugin.instance.SaveData.Craftmetal.Value++; break; case "Silk Spool": VogsBingoModPlugin.instance.SaveData.SpoolFragments.Value++; break; } } } [HarmonyPrefix] [HarmonyPatch(typeof(YesNoAction), "SendEvent")] private static void YesNoActionPatch(YesNoAction __instance, bool isYes) { if (!isYes) { return; } switch (GetSceneName()) { case "Under_08": if (((FsmStateAction)__instance).fsm.GameObjectName.Equals("NPC Control")) { Automarker.MarkIfAvailable(GoalID.PayToConfess); } break; case "Song_01b": if (((FsmStateAction)__instance).fsm.GameObjectName.Equals("tube_toll_machine")) { Automarker.MarkIfAvailable(GoalID.ChoralChambersVentrica); } break; case "Hang_06b": if (((FsmStateAction)__instance).fsm.GameObjectName.Equals("tube_toll_machine")) { Automarker.MarkIfAvailable(GoalID.HighHallsVentrica); } break; case "Arborium_Tube": Automarker.MarkIfAvailable(GoalID.MemoriumVentrica); break; case "Bellway_Shadow": if (((FsmStateAction)__instance).fsm.GameObjectName.Equals("Bellway Toll Machine")) { Automarker.MarkIfAvailable(GoalID.BilewaterBellway); } break; case "Cog_10": Automarker.MarkIfAvailable(GoalID.ActivateSecondSentinel); break; case "Belltown_Room_Relic": VogsBingoModPlugin.instance.SaveData.RelicTypesCurrentlyHeld.ResetFlags(); break; } if (((FsmStateAction)__instance).fsm.GameObjectName.Equals("Caravan Lech")) { Automarker.MarkIfAvailable(GoalID.PayforaFleaSpa); } } [HarmonyPrefix] [HarmonyPatch(typeof(InventoryToolCrestSlot), "PlayFinalShake")] private static void CrestSlotUnlock(InventoryToolCrestSlot __instance) { if (((InventoryItemSelectable)__instance).DisplayName.Equals("Hunter")) { return; } foreach (InventoryToolCrestSlot activeSlot in __instance.Crest.activeSlots) { if (activeSlot.IsLocked) { return; } } Automarker.MarkIfAvailable(GoalID.FullyUnlockaNonHuntersCrest); } [HarmonyPrefix] [HarmonyPatch(typeof(Breakable), "Break")] private static void BreakablePatch(Breakable __instance) { if (IsScene("Dust_10") && ((Object)((Component)__instance).gameObject).name.Equals("main root")) { Automarker.MarkIfAvailable(GoalID.FixtheSinnersRoadBench); } } [HarmonyPrefix] [HarmonyPatch(typeof(SetBoolValue), "OnEnter")] private static void BoolValuePatch(SetBoolValue __instance) { switch (((Object)((FsmStateAction)__instance).owner).name) { case "Heart Piece": case "Heart Piece (1)": switch (GetSceneName()) { case "Dock_08": Automarker.MarkIfAvailable(GoalID.DeepDocksMaskShard); break; case "Bone_East_LavaChallenge": Automarker.MarkIfAvailable(GoalID.FarfieldsEscapeMaskShard); break; case "Slab_17": Automarker.MarkIfAvailable(GoalID.SlabMaskShard); break; case "Shadow_13": Automarker.MarkIfAvailable(GoalID.BilewaterMaskShard); break; case "Shellwood_14": VogsBingoModPlugin.instance.SaveData.ShellwoodMaskShard.Value = true; break; case "Library_05": VogsBingoModPlugin.instance.SaveData.VaultsMaskShard.Value = true; break; case "Coral_19b": Automarker.MarkIfAvailable(GoalID.BlastedStepsMaskShard); break; case "Song_09": Automarker.MarkIfAvailable(GoalID.CogworkCoreMaskShard); break; case "Wisp_07": Automarker.MarkIfAvailable(GoalID.WispThicketMaskShard); break; case "Peak_04c": Automarker.MarkIfAvailable(GoalID.MtFayMaskShard); break; case "Peak_06": Automarker.MarkIfAvailable(GoalID.BrightveinMaskShard); break; } break; case "Silk Spool": VogsBingoModPlugin.instance.SaveData.SpoolFragments.Value++; switch (GetSceneName()) { case "Bone_East_13": VogsBingoModPlugin.instance.SaveData.DeepDocksSpoolFragNearSpa.Value = true; break; case "Dock_03c": VogsBingoModPlugin.instance.SaveData.DeeperDocksSpoolFrag.Value = true; break; case "Greymoor_02": Automarker.MarkIfAvailable(GoalID.GreymoorSpoolFragment); break; case "Song_19_entrance": Automarker.MarkIfAvailable(GoalID.GrandGateSpoolFragment); break; case "Hang_03_top": Automarker.MarkIfAvailable(GoalID.HighHallsSpoolFragment); break; } break; } } [HarmonyPrefix] [HarmonyPatch(typeof(EventRegister), "SendEvent", new Type[] { typeof(string), typeof(GameObject) })] private static void SendEventPatch(string eventName) { if (eventName == "MEMORY ORB COLLECT") { VogsBingoModPlugin.instance.SaveData.SilkHearts.Value++; } } [HarmonyPrefix] [HarmonyPatch(typeof(DeliveryQuestItem), "BreakEffect")] private static void CourierBreakPatch() { Automarker.MarkIfAvailable(GoalID.BreakaCourierItem); } [HarmonyPostfix] [HarmonyPatch(typeof(SavedItemGetV2), "OnEnter")] private static void ItemGetPatch(SavedItemGetV2 __instance) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) if (((Object)(SavedItem)__instance.Item.Value).name.Equals("FleasCollected Target")) { Automarker.UpdateFleas(); } } [HarmonyPostfix] [HarmonyPatch(typeof(PlayerData), "AddToMaxHealth")] private static void AddToMaxHealthPatch() { VogsBingoModPlugin.instance.SaveData.ExtraMasks.Value = PlayerData.instance.CurrentMaxHealth - 5; } [HarmonyPrefix] [HarmonyPatch(typeof(CollectableItemPickup), "EndInteraction")] private static void ItemPickupPatch(CollectableItemPickup __instance, bool didPickup) { if (!didPickup) { return; } string name = ((Object)__instance.Item).name; string text = name; switch (text) { default: if (text.Length == 0 && PlayerData.instance.CollectedHeartClover && PlayerData.instance.CollectedHeartCoral && PlayerData.instance.CollectedHeartFlower) { VogsBingoModPlugin.instance.SaveData.MementosObtained.Value++; } break; case null: break; case "Flower Heart": Automarker.MarkIfAvailable(GoalID.PollenHeart); if (PlayerData.instance.CollectedHeartClover && PlayerData.instance.CollectedHeartCoral && PlayerData.instance.CollectedHeartHunter) { VogsBingoModPlugin.instance.SaveData.MementosObtained.Value++; } break; case "Clover Heart": Automarker.MarkIfAvailable(GoalID.ConjoinedHeart); if (PlayerData.instance.CollectedHeartHunter && PlayerData.instance.CollectedHeartCoral && PlayerData.instance.CollectedHeartFlower) { VogsBingoModPlugin.instance.SaveData.MementosObtained.Value++; } break; case "Hunter Heart": Automarker.MarkIfAvailable(GoalID.HuntersHeart); if (PlayerData.instance.CollectedHeartClover && PlayerData.instance.CollectedHeartCoral && PlayerData.instance.CollectedHeartFlower) { VogsBingoModPlugin.instance.SaveData.MementosObtained.Value++; } break; } } [HarmonyPrefix] [HarmonyPatch(typeof(BasicNPC), "OnStartDialogue")] private static void BasicNPCPatch(BasicNPC __instance) { foreach (SavedItem giveOnFirstTalkItem in __instance.giveOnFirstTalkItems) { if (((Object)giveOnFirstTalkItem).name.Equals("Magnetite")) { Automarker.MarkIfAvailable(GoalID.InspectMagnetiteinBrightvein); } } } [HarmonyPostfix] [HarmonyPatch(typeof(MemoryOrbGroup), "CollectedOrb")] private static void MemoryOrbGroupPatch(MemoryOrbGroup __instance) { if (__instance.IsAllCollected && IsScene("Clover_18")) { VogsBingoModPlugin.instance.SaveData.VerdaniaFountainOrbs.Value++; } } [HarmonyPostfix] [HarmonyPatch(typeof(BattleScene), "DoEndBattle")] private static void ArenaCompletePatch(BattleScene __instance) { if (__instance.completed && IsScene("Memory_Coral_Tower")) { Automarker.MarkIfAvailable(GoalID.ClearFirstCoralTowerArena); } } [HarmonyPrefix] [HarmonyPatch(typeof(SprintRaceController), "CheckCompletion")] private static void RaceCompletePatch(SprintRaceController __instance, bool isHero) { if (isHero && __instance.heroLapsCompleted >= __instance.lapCount && !__instance.isCompleted) { Automarker.MarkIfAvailable(GoalID.WinARace); } } [HarmonyPrefix] [HarmonyPatch(typeof(Remasker), "Entered")] private static void AreaEnterPatch(Remasker __instance) { if (IsScene("Dust_11") && ((Object)__instance).name.Equals("Remasker New (2)")) { Automarker.MarkIfAvailable(GoalID.VisitStyxsMaskRoom); } } [HarmonyPrefix] [HarmonyPatch(typeof(ToolCrest), "Unlock")] private static void ToolCrestUnlockPatch(ToolCrest __instance) { if (!__instance.IsUnlocked) { VogsBingoModPlugin.instance.SaveData.Crests.Value++; } } [HarmonyPostfix] [HarmonyPatch(typeof(ToolItemManager), "ReportToolUnlocked", new Type[] { typeof(ToolItemType), typeof(bool) })] private static void ToolUnlockPatch(ToolItemType type) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0003: Invalid comparison between Unknown and I4 if ((int)type == 3) { Automarker.UpdateSilkSkills(); } else { Automarker.UpdateTools(ToolItemManager.GetUnlockedTools()); } } private static bool IsScene(string sceneName) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) Scene activeScene = SceneManager.GetActiveScene(); return ((Scene)(ref activeScene)).name.Equals(sceneName); } private static string GetSceneName() { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) Scene activeScene = SceneManager.GetActiveScene(); return ((Scene)(ref activeScene)).name; } } internal static class AutomarkRosaryStringHandler { private static SaveDataInt FrayedStringsCurrentlyHeld = new SaveDataInt(Array.Empty(), "FrayedStringsCurrentlyHeld"); private static SaveDataInt FrayedStringsBroken = new SaveDataInt(Array.Empty(), "FrayedStringsBroken"); private static SaveDataInt PurchasedStringsCurrentlyHeld = new SaveDataInt(Array.Empty(), "PurchasedStringsCurrentlyHeld"); private static SaveDataInt NonPurchasedStringsCurrentlyHeld = new SaveDataInt(Array.Empty(), "NonPurchasedStringsCurrentlyHeld"); private static SaveDataInt NonPurchasedStringsBroken = new SaveDataInt(Array.Empty(), "NonPurchasedStringsBroken"); internal static void Initialize() { } internal static int GetFrayedStringsCurrentlyHeld() { return FrayedStringsCurrentlyHeld.Value; } internal static int GetFrayedStringsBroken() { return FrayedStringsBroken.Value; } internal static int GetPurchasedStringsCurrentlyHeld() { return PurchasedStringsCurrentlyHeld.Value; } internal static int GetNonPurchasedStringsCurrentlyHeld() { return NonPurchasedStringsCurrentlyHeld.Value; } internal static int GetNonPurchasedStringsBroken() { return NonPurchasedStringsBroken.Value; } internal static void AddFrayedString() { FrayedStringsCurrentlyHeld.Value++; Automarker.CheckIfGoalCompleted(GoalID.HaveSixRosaryStringsnopurchasing); } internal static void BreakFrayedString() { FrayedStringsBroken.Value++; FrayedStringsCurrentlyHeld.Value--; Automarker.CheckIfGoalCompleted(GoalID.BreakEightRosaryStringsnopurchasing); } internal static void AddPurchasedString() { PurchasedStringsCurrentlyHeld.Value++; } internal static void AddNonPurchasedString() { NonPurchasedStringsCurrentlyHeld.Value++; Automarker.CheckIfGoalCompleted(GoalID.HaveSixRosaryStringsnopurchasing); } internal static void BreakString() { if ((int)PurchasedStringsCurrentlyHeld <= 0 || ((int)NonPurchasedStringsCurrentlyHeld > 0 && Automarker.BoardHasGoal(GoalID.BreakEightRosaryStringsnopurchasing) && !Automarker.BoardHasGoal(GoalID.HaveSixRosaryStringsnopurchasing))) { NonPurchasedStringsBroken.Value++; NonPurchasedStringsCurrentlyHeld.Value--; Automarker.CheckIfGoalCompleted(GoalID.BreakEightRosaryStringsnopurchasing); } else { PurchasedStringsCurrentlyHeld.Value--; } } } internal class GoalHelper { internal const string SpriteNameCouriersSwag = "courier_items_destroyed_0003_Layer-1"; internal const string SpriteNameCouriersRasher = "courier_items_destroyed_0000_Layer-4"; internal const string SpriteNameQueensEgg = "courier_items_destroyed_0001_Layer-3"; internal const string SpriteNameLiquidLacquer = "courier_items_destroyed_0002_Layer-2"; internal const string SpriteNameBellhomeKey = "belltown_house_key"; internal const string SpriteNameSilkeater = "Silk_Grub_idle0000"; internal const string SpriteNameCraftmetal = "Hornet_Tool_Metal"; internal const string SpriteNameApostateKey = "I_slab_key_brass"; internal const string SpriteNameRedQuill = "I_quill_red"; internal const string SpriteNameCrustnut = "_0007_quest_coral_nut"; internal const string SpriteNameMossberryStew = "Mossberry_Stew"; internal const string SpriteNameVintageNectar = "vintage_nectar_item"; internal const string SpriteNameTwistedBud = "mandrake_icon0000"; internal const string SpriteNameSimpleKey = "I_token_of_faith"; internal const string SpriteNameRuneHarp = "Hornet_icon_0002_R_weaver_record"; internal const string SpriteNameBoneScroll = "Hornet_icon_0002_R_bone_record"; internal const string SpriteNameChoralCommandment = "Hornet_icon_0000_R_seal_chit"; internal const string SpriteNameWeaverEffigy = "Hornet_icon_0005_R_saint_locket"; internal const string SpriteNameBeastShard = "Icon_Beast_Shard"; internal const string SpriteNameCogheartPiece0 = "cog_heart__0001_left"; internal const string SpriteNameCogheartPiece1 = "cog_heart__0002_right"; internal const string SpriteNameCogheartPiece2 = "cog_heart__0003_back"; internal const string SpriteNameCradleMap = "Shop_map_icon__0012_cradle"; internal const string SpriteNameWeavenestMap = "Shop_map_icon__weavehome"; internal const string SpriteNameVerdaniaMap = "Shop_map_icon__0003_clover"; internal const string SpriteNameArcaneEgg = "Hornet_icon_0004_R_ancient_egg"; internal const string SpriteNameSurfaceMemento = "surface_memento"; internal const string SpriteNameGreyMemento = "grey_warrior_memento"; internal const string SpriteNameRosaryNecklace = "I_rosary_necklace_0000_3"; internal const string SpriteNameHeavyRosaryNecklace = "I_rosary_necklace_0000_3_old"; internal const string SpriteNamePaleRosaryNecklace = "I_rosary_necklace_0001_2"; internal const string SpriteNameRosaryString = "I_rosary_necklace_0002_1"; internal const string SpriteNameFrayedString = "I_rosary_necklace_0002_1_frayed"; internal const string SpriteNameToolPouch = "Inv_tool_pouch_upgrade_02"; internal const string SpriteNameCraftingKit = "icon_tool_kit_upgrade"; internal const string SpriteNameMemoryLocket = "Charm_Notch"; internal const string SpriteNameShardBundle = "Hornet_Tool_Metal_Pouch"; internal const string SpriteNameHerosMemento = "garmond_memento"; internal const string SpriteNameHuntersMemento = "hunter_nuu_memento_seal"; internal const string SpriteNameCrawMemento = "craw_court_memento"; internal const string SpriteNameSprintmasterMemento = "sprintmaster_memento"; internal const string SpriteNameSethMemento = "seth_memento"; internal const string EnemyNameCogworkClapper = "Song Automaton Ball"; internal const string EnemyNameSquirrm = "Coral Judge Child"; internal const string EnemyNameSkullwing = "Bone Goomba Bounce Fly"; internal const string EnemyNameCragglite = "Small Crab"; internal const string EnemyNameGromling = "Crypt Worm"; internal const string EnemyNameMiteMother = "Gnat Giant"; internal const string EnemyNameMassiveMossgrub = "MossBone Crawler Fat"; internal const string EnemyNameDeepDiver = "Dock Charger"; internal const string EnemyNameUnravelled = "Conductor Boss"; internal const string EnemyNameShadowCharger = "Abyss Crawler Large"; internal const string EnemyNameImoba = "Spike Lazy Flyer"; internal const string EnemyNameCraggler = "Roof Crab"; internal const string EnemyNameMoorwing = "Vampire Gnat"; internal const string EnemyNameSavageBeastfly = "Bone Flyer Giant"; internal const string EnemyNameGreatConchfly = "Coral Conch Driller Giant"; internal const string EnemyNameMossMother = "Mossbone Mother"; internal const string EnemyNameRhinogrund = "Rhino"; internal const string EnemyNameFourthChorus = "Song Golem"; internal const string EnemyNameCogworkDancers = "Clockwork Dancer"; internal const string EnemyNameLastJudge = "Last Judge"; internal const string EnemyNamePhantom = "Phantom"; internal const string EnemyNameTrobbio = "Trobbio"; internal const string EnemyNameChefLugoli = "Roachkeeper Chef"; internal const string EnemyNameFatherOfTheFlame = "Wisp Pyre Effigy"; internal const string EnemyNameForebrothers = "Dock Guard Thrower"; internal const string EnemyNameCovetousPilgrim = "Rosary Pilgrim"; internal const string EnemyNameSisterSplinter = "Splinter Queen"; internal const string EnemyNameVoltvyrm = "Zap Core Enemy"; internal const string EnemyNameSkullTyrant = "Skull King"; internal const string EnemyNameBigFlea = "Giant Flea"; internal const string EnemyNameSeth = "Seth"; internal const string EnemyNamePaleStag = "Cloverstag White"; internal const string EnemyNameTormentedTrobbio = "Tormented Trobbio"; internal const string EnemyNameVoidMass = "Black Thread Core"; internal const string NPCNameShakra = "Mapper NPC"; internal const string NPCNameShakraSitting = "Mapper Sit NPC"; internal const string NPCNameShakraDupe = "Mapper NPC (1)"; internal const string NPCNameShakraRest = "Mapper Rest NPC"; internal const string NPCNameShakraTrailsEnd = "Mapper Master NPC"; internal const string NPCNameShakraDuel = "Mapper Spar NPC"; internal const string NPCNameShakraAid = "Shakra Aid NPC"; internal const string NPCNameShakraHHAWin = "Victory NPC"; internal const string NPCNameHuntress = "Huntress"; internal const string NPCNameStyx = "Grub Farmer NPC"; internal const string NPCNameForgeDaughter = "Shop Prompt"; internal const string NPCNameTwelfthArchitect = "Architect NPC"; internal const string NPCNameLoam = "Understore Large Worker"; internal const string NPCNameMaskMaker = "Peak Mask Maker"; internal const string NPCNameFlickSurvivorsCamp = "Fixer Sitting Bone_10"; internal const string NPCNameMrMushroom = "Mr Mushroom NPC"; internal const string NPCNameShermaSpa = "Sherma Citadel Spa NPC"; internal const string NPCNamePlinneySave = "Plinney Outside"; internal const string ObjectNameVentrica = "tube_toll_machine"; internal const string ObjectNameMaskShard = "Heart Piece"; internal const string ObjectNameMaskShardDupe = "Heart Piece (1)"; internal const string ObjectNameSilkSpool = "Silk Spool"; internal const string ObjectNameSilkHeart = "Silk Heart"; internal const string ObjectNameFrayedString = "Rosary_Set_Frayed"; internal const string ObjectNameRosaryString = "Rosary_Set_Small"; internal const string ObjectNameRosaryNecklace = "Rosary_Set_Medium"; internal const string ObjectNameHeavyNecklace = "Rosary_Set_Large"; internal const string ObjectNamePaleNecklace = "Rosary_Set_Huge_White"; internal const string ObjectNameShardBundle = "Shard Pouch"; internal const string ShopItemNameGrindleSpoolFrag = "Grindle Spool Piece"; internal const string ItemNamePollenHeart = "Flower Heart"; internal const string ItemNameConjoinedHeart = "Clover Heart"; internal const string ItemNameHuntersHeart = "Hunter Heart"; internal const string ItemNameEncrustedHeart = ""; private static string[] idToName = GetEmbeddedGoals(); private static Dictionary nameToID = GenerateNameToIDs(); internal static int NameToID(string goalName) { try { return nameToID[goalName]; } catch (Exception) { VogsBingoModPlugin.LogError("Could not find a goal ID for goal: \"" + goalName + "\""); return 0; } } private static Dictionary GenerateNameToIDs() { Dictionary dictionary = new Dictionary(); for (int i = 0; i < idToName.Length; i++) { dictionary.Add(idToName[i].ToLower(), i); } return dictionary; } private static string[] GetEmbeddedGoals() { string json; try { json = Automarker.GetGoalsJson(); } catch (Exception e) { VogsBingoModPlugin.LogError(e); json = ""; } return JsonHelper.GetGoalNamesFromList(json); } } internal enum GoalID { TwoDonationWishes, ThreeDonationWishes, BellhomeKey, TwoHuntWishes, FourHuntWishes, TwoWayfarerWishes, FourWayfarerWishes, TwoGatherWishes, ThreeGatherWishes, CompleteFiveWishes, CompleteSevenWishes, BreakaCourierItem, CrawbugClearing, VolatileFlintbeetles, ThreeRedTools, FiveRedTools, ThreeBlueTools, ThreeYellowTools, FiveYellowTools, Twoofeachtooltype, StraightThreefoldandLongPin, DeadBugsPurseaSilkeater, BarbedBraceletFracturedMask, MagnetiteDiceMagnetiteBrooch, CompassPendantBrooch, WardingBellClawMirror, WardingBellSawtoothCirclet, MagmaBellCurveclaw, WeightedBeltAscendantsGrip, ScuttlebraceSilkspeed, PimpilloVoltvessels, DelversDrill, PollipPouch, PollipPouchStingShard, Tacks, QuickSling, WeavelightInjectorBand, PlasmiumPhial, MemoryCrystal, Flintslate, RepairSilkshot, Multibinder, RosaryCannon, Cogfly, SnareSetter, Conchcutter, PaleLakeCraftmetal, UpgradeDruidsEye, SellaMossberry, WanderersCrest, ReapersCrest, BeastsCrest, NeedleStrike, UpgradeNeedleTwice, ThreadStorm, Sharpdart, EvolvedHuntersCrest, FaydownCloak, ApostateKey, UseaSimpleKeyinDeepDocks, ThreeSilkSkills, FourSilkSkills, FarfieldsEscapeMaskShard, SlabMaskShard, BilewaterMaskShard, DeepDocksMaskShard, ShellwoodVaultsMaskShards, BlastedStepsMaskShard, CogworkCoreMaskShard, WispThicketMaskShard, MtFayMaskShard, Craggler, Moorwing, SavageBeastfly, GreatConchfliesBlastedSteps, RagingConchflySandsofKarak, MossMotherDuo, DefeataRhinogrund, DisabletheClawmaidens, FourthChorus, CogworkDancers, LastJudge, Phantom, Trobbio, RedQuill, DisgracedChefLugoli, FatherOfTheFlame, ForebrothersSignisGron, DefeataCovetousPilgrim, CogworkClapperJournalEntry, SisterSplinter, Voltvyrm, SkullTyrant, FreeGreenPrince, WinaLoddieMinigame, TalktoStyxHuntress, WreathofPurity, BreakBothofStyxsOneways, TalktoLoam, TalktoMaskMaker, BuyFromGrindleNoString, BlastedStepsSilkeaterCraftmetal, PayToConfess, ChoralChambersVentrica, HighHallsVentrica, MemoriumVentrica, ObtainThreeCraftmetal, ObtainFiveCraftmetal, Crustnut, MossberrySoup, VintageNectar, TwistedBud, BothFreeSimpleKeys, BothVendorSimpleKeys, OneExtraMask, TwoExtraMasks, PayforaFleaSpa, GreymoorFleasTwoKratt, FarFieldsFleasTwo, ShellwoodBellhartFleasTwo, DeepDocksFleasThree, WormwaysBlastedStepsFleasTwo, UnderworksFleasTwo, LowerBilewaterHuntersMarchFleasTwo, FreeEightFleas, FreeTenFleas, FreeTwelveFleas, FreeFourteenFleas, MeetCaravanattheGrandGateTwelve, SinnersRoadVaultsFleasTwo, SandsofKarakFleaOne, ExhaustOrganFleaOne, ThreeCitadelFleas, MtFayFleaOne, BeatBigFlea, TalktoVog, DeepDocksSpoolFragmentsTwo, GreymoorSpoolFragment, FreysSpoolFragment, GrandGateSpoolFragment, HighHallsSpoolFragment, OneSpoolUpgrade, TwoSpoolUpgrades, ThreeSpoolUpgrades, HaveThreeRosaryNecklacesnopurchasing, HaveSixRosaryStringsnopurchasing, BreakEightRosaryStringsnopurchasing, BreakFourShardBundlesnopurchasing, BreakSixShardBundlesnopurchasing, ObtainThreeSilkeaters, ObtainFiveSilkeaters, OneToolPouchUpgrade, OneCraftingKit, ThreeToolPouchUpgradesCraftingKits, ObtainFiveMemoryLockets, FullyUnlockaNonHuntersCrest, HaveThreeDifferentTypesofRelic, ObtainFourDifferentTypesofRelic, ObtainTwoRuneHarps, ObtainThreeBoneScrolls, ObtainFourBoneScrolls, TalktoShakraatFiveLocations, FixtheSinnersRoadBench, ObtainFiveMaps, ObtainEightMaps, TalktoShakrainBilewater, TalktoShakrainSandsofKarak, TalktoHuntress, SaveJubilana, SquirrmJournalEntry, SkullwingJournalEntry, CraggliteJournalEntry, GromlingJournalEntry, MiteMotherJournalEntry, MassiveMossgrubJournalEntry, DeepDiverJournalEntry, ObtainTwoBeastShards, ObtainThreeBeastShards, ObtainFourBeastShards, ObtainFiveBeastShards, BilewaterBellway, TalktoForgeDaughterandTwelfthArchitect, OneCogheartPiece, TwoCogheartPieces, ActivateSecondSentinel, MeetShermaintheSpa, TwoSilkHearts, UnravelledJournalEntry, ArchitectsMelody, ConductorsMelody, VaultkeepersMelody, GetCursed, WitchCrest, CradleMap, EnterActThree, BeastlingCall, ThreeVoidMasses, SixVoidMasses, SavePinmasterPlinney, TalktoFlickatSurvivorsCamp, ThreeNonHunterCrests, DefeataBlackthreadedBoss, PinBadge, AbyssMap, VerdaniaMap, OneArcaneEgg, ShadowChargerJournalEntry, FightSeth, PollenHeart, HuntersHeart, PaleStag, InspectMagnetiteinBrightvein, VerdaniaFountainOrbs, ConjoinedHeart, PaleNails, ClearFirstCoralTowerArena, TormentedTrobbio, VisitStyxsMaskRoom, TalktoMrMushroom, SurfaceMemento, ImobaJournalEntry, GreyMemento, TwoMementos, BrightveinMaskShard, WinARace, ShamanCrest, MeettheCaravaninGreymoor } }