diff --git a/APRandomizerMain.cs b/APRandomizerMain.cs index 9eb97fd..bf16a09 100644 --- a/APRandomizerMain.cs +++ b/APRandomizerMain.cs @@ -21,959 +21,958 @@ using static Mod.Courier.UI.TextEntryButtonInfo; using Object = UnityEngine.Object; -namespace MessengerRando +namespace MessengerRando; + +/// +/// Where it all begins! This class defines and injects all the necessary for the mod. +/// +// ReSharper disable once ClassNeverInstantiated.Global +public class APRandomizerMain : CourierModule { - /// - /// Where it all begins! This class defines and injects all the necessary for the mod. - /// - // ReSharper disable once ClassNeverInstantiated.Global - public class APRandomizerMain : CourierModule - { - private float updateTimer; - public static float UpdateTime = 3.0f; - - private RandomizerStateManager randoStateManager; - private SkylandsGeneratorManager skylandsGeneratorManager; - private TrackerManager trackerManager; - - private TextMeshProUGUI apTextDisplay8; - private TextMeshProUGUI apTextDisplay16; - private TextMeshProUGUI apMessagesDisplay8; - private TextMeshProUGUI apMessagesDisplay16; - public static string ModPath = Courier.ModsFolder.Replace("/Mods", "/"); - - private TextEntryPopup closeLater; - private float closeLaterTimer; - //Set up save data - public override Type ModuleSaveType => typeof(RandoSave); - // ReSharper disable once MemberCanBePrivate.Global - public RandoSave Save => (RandoSave)ModuleSave; - - public override void Load() - { - Console.WriteLine("Randomizer loading and ready to try things!"); - - //Initialize the randomizer state manager - skylandsGeneratorManager = new SkylandsGeneratorManager(); - RandomizerStateManager.skylandsGeneratorManager = skylandsGeneratorManager; - - randoStateManager = new RandomizerStateManager(); - - trackerManager = new TrackerManager(); - ItemsAndLocationsHandler.TrackerManager = trackerManager; - RandoPortalManager.TrackerManager = trackerManager; - RandoLevelManager.TrackerManager = trackerManager; - - //Plug in my code :3 - On.InventoryManager.AddItem += InventoryManager_AddItem; - On.ProgressionManager.SetChallengeRoomAsCompleted += ProgressionManager_SetChallengeRoomAsCompleted; - On.HasItem.IsTrue += HasItem_IsTrue; - On.AwardNoteCutscene.ShouldPlay += AwardNoteCutscene_ShouldPlay; - On.CutsceneHasPlayed.IsTrue += CutsceneHasPlayed_IsTrue; - On.SaveGameSelectionScreen.OnLoadGame += SaveGameSelectionScreen_OnLoadGame; - On.SaveGameSelectionScreen.OnNewGame += SaveGameSelectionScreen_OnNewGame; - On.SaveGameSelectionScreen.ConfirmSaveDelete += SaveGameSelectionScreen_ConfirmSaveDelete; - On.SaveGameSelectionScreen.OnDeleteChoiceDone += SaveGameSelectionScreen_OnDelete; - On.SaveGameSelectionScreen.Update += SaveSelectionScreen_OnUpdate; - On.NameSavePopup.Update += OnNameSaveUpdate; - On.BackToTitleScreen.GoBackToTitleScreen += PauseScreen_OnQuitToTitle; - On.NecrophobicWorkerCutscene.Play += NecrophobicWorkerCutscene_Play; - IL.RuxxtinNoteAndAwardAmuletCutscene.Play += RuxxtinNoteAndAwardAmuletCutscene_Play; - On.DialogCutscene.Play += DialogCutscene_Play; - On.CatacombLevelInitializer.OnBeforeInitDone += CatacombLevelInitializer_OnBeforeInitDone; - On.DialogManager.LoadDialogs_ELanguage += DialogChanger.LoadDialogs_Elanguage; - On.OptionScreen.OnEnable += OnOptionScreenEnable; - On.LostWoods.SetAsSolved += LostWoodsManager.OnSetAsSolved; - // shop management - On.UpgradeButtonData.GetPrice += RandoShopManager.GetPrice; - On.LocalizationManager.GetText += RandoShopManager.GetText; - // On.UpgradeButton.Refresh += RandoShopManager.UpgradeButton_Refresh; - On.BuyMoneyWrenchCutscene.OnBuyWrenchChoice += RandoShopManager.BuyMoneyWrench; - On.BuyMoneyWrenchCutscene.EndCutsceneOnDialogDone += RandoShopManager.EndMoneyWrenchCutscene; - On.MoneySinkUnclogCutscene.OnDialogOutDone += RandoShopManager.UnclogSink; - On.GoToSousSolCutscene.EndCutScene += RandoShopManager.GoToSousSol; - On.IronHoodShopScreen.GetFigurineData += RandoShopManager.GetFigurineData; - On.SousSol.UnlockFigurine += RandoShopManager.UnlockFigurine; - On.Shop.Init += RandoShopManager.ShopInit; - On.JukeboxTrack.IsUnlocked += (orig, self) => true; - On.UpgradeButtonData.IsStoryUnlocked += RandoShopManager.IsStoryUnlocked; - On.AudioManager.PlayMusic += RandoMusicManager.OnPlayMusic; - // boss management - On.ProgressionManager.HasDefeatedBoss += - (orig, self, bossName) => RandoBossManager.HasBossDefeated(bossName); - On.ProgressionManager.HasEverDefeatedBoss += - (orig, self, bossName) => RandoBossManager.HasBossDefeated(bossName); - On.ProgressionManager.SetBossAsDefeated += - (orig, self, bossName) => RandoBossManager.SetBossAsDefeated(bossName); - // level teleporting etc management - On.Level.ChangeRoom += RandoRoomManager.Level_ChangeRoom; - On.LevelManager.LoadLevel += RandoLevelManager.LoadLevel; - On.LevelManager.EndLevelLoading += RandoLevelManager.EndLevelLoading; - On.ElementalSkylandsLevelInitializer.OnBeforeInitDone += RandoLevelManager.ElementalSkylandsInit; - // On.PortalOpeningCutscene.OnOpenPortalEvent += RandoPortalManager.OpenPortalEvent; - On.TotHQ.LeaveToLevel += RandoPortalManager.LeaveHQ; - // generator deactivation management - skylandsGeneratorManager.ApplyHooks(); - //These functions let us override and manage power seals ourselves with 'fake' items - On.ProgressionManager.TotalPowerSealCollected += ProgressionManager_TotalPowerSealCollected; - On.ShopChestOpenCutscene.OnChestOpened += (orig, self) => - RandomizerStateManager.Instance.PowerSealManager?.OnShopChestOpen(orig, self); - On.ShopChestChangeShurikenCutscene.Play += (orig, self) => - RandomizerStateManager.Instance.PowerSealManager?.OnShopChestOpen(orig, self); - //update loops for Archipelago - Courier.Events.PlayerController.OnUpdate += PlayerController_OnUpdate; - On.InGameHud.OnGUI += InGameHud_OnGUI; - On.SaveManager.DoActualSaving += SaveManager_DoActualSave; - On.PlayerController.Die += OnPlayerDie; - On.Quarble.OnDeathScreenDone += OnDeathScreenDone; - // On.MegaTimeShard.NextState += RandoTimeShardManager.NextState; - // On.MegaTimeShard.ReceiveHit += RandoTimeShardManager.ReceiveHit; - On.MegaTimeShard.OnBreakDone += MegaTimeShard_OnBreakDone; - On.DialogSequence.GetDialogList += DialogSequence_GetDialogList; - On.Cutscene.Play += Cutscene_Play; - On.PlayerController.Awake += OnPlayerController_Awake; - //temp add + private float updateTimer; + public static float UpdateTime = 3.0f; + + private RandomizerStateManager randoStateManager; + private SkylandsGeneratorManager skylandsGeneratorManager; + private TrackerManager trackerManager; + + private TextMeshProUGUI apTextDisplay8; + private TextMeshProUGUI apTextDisplay16; + private TextMeshProUGUI apMessagesDisplay8; + private TextMeshProUGUI apMessagesDisplay16; + public static string ModPath = Courier.ModsFolder.Replace("/Mods", "/"); + + private TextEntryPopup closeLater; + private float closeLaterTimer; + //Set up save data + public override Type ModuleSaveType => typeof(RandoSave); + // ReSharper disable once MemberCanBePrivate.Global + public RandoSave Save => (RandoSave)ModuleSave; + + public override void Load() + { + Console.WriteLine("Randomizer loading and ready to try things!"); + + //Initialize the randomizer state manager + skylandsGeneratorManager = new SkylandsGeneratorManager(); + RandomizerStateManager.skylandsGeneratorManager = skylandsGeneratorManager; + + randoStateManager = new RandomizerStateManager(); + + trackerManager = new TrackerManager(); + ItemsAndLocationsHandler.TrackerManager = trackerManager; + RandoPortalManager.TrackerManager = trackerManager; + RandoLevelManager.TrackerManager = trackerManager; + + //Plug in my code :3 + On.InventoryManager.AddItem += InventoryManager_AddItem; + On.ProgressionManager.SetChallengeRoomAsCompleted += ProgressionManager_SetChallengeRoomAsCompleted; + On.HasItem.IsTrue += HasItem_IsTrue; + On.AwardNoteCutscene.ShouldPlay += AwardNoteCutscene_ShouldPlay; + On.CutsceneHasPlayed.IsTrue += CutsceneHasPlayed_IsTrue; + On.SaveGameSelectionScreen.OnLoadGame += SaveGameSelectionScreen_OnLoadGame; + On.SaveGameSelectionScreen.OnNewGame += SaveGameSelectionScreen_OnNewGame; + On.SaveGameSelectionScreen.ConfirmSaveDelete += SaveGameSelectionScreen_ConfirmSaveDelete; + On.SaveGameSelectionScreen.OnDeleteChoiceDone += SaveGameSelectionScreen_OnDelete; + On.SaveGameSelectionScreen.Update += SaveSelectionScreen_OnUpdate; + On.NameSavePopup.Update += OnNameSaveUpdate; + On.BackToTitleScreen.GoBackToTitleScreen += PauseScreen_OnQuitToTitle; + On.NecrophobicWorkerCutscene.Play += NecrophobicWorkerCutscene_Play; + IL.RuxxtinNoteAndAwardAmuletCutscene.Play += RuxxtinNoteAndAwardAmuletCutscene_Play; + On.DialogCutscene.Play += DialogCutscene_Play; + On.CatacombLevelInitializer.OnBeforeInitDone += CatacombLevelInitializer_OnBeforeInitDone; + On.DialogManager.LoadDialogs_ELanguage += DialogChanger.LoadDialogs_Elanguage; + On.OptionScreen.OnEnable += OnOptionScreenEnable; + On.LostWoods.SetAsSolved += LostWoodsManager.OnSetAsSolved; + // shop management + On.UpgradeButtonData.GetPrice += RandoShopManager.GetPrice; + On.LocalizationManager.GetText += RandoShopManager.GetText; + // On.UpgradeButton.Refresh += RandoShopManager.UpgradeButton_Refresh; + On.BuyMoneyWrenchCutscene.OnBuyWrenchChoice += RandoShopManager.BuyMoneyWrench; + On.BuyMoneyWrenchCutscene.EndCutsceneOnDialogDone += RandoShopManager.EndMoneyWrenchCutscene; + On.MoneySinkUnclogCutscene.OnDialogOutDone += RandoShopManager.UnclogSink; + On.GoToSousSolCutscene.EndCutScene += RandoShopManager.GoToSousSol; + On.IronHoodShopScreen.GetFigurineData += RandoShopManager.GetFigurineData; + On.SousSol.UnlockFigurine += RandoShopManager.UnlockFigurine; + On.Shop.Init += RandoShopManager.ShopInit; + On.JukeboxTrack.IsUnlocked += (orig, self) => true; + On.UpgradeButtonData.IsStoryUnlocked += RandoShopManager.IsStoryUnlocked; + On.AudioManager.PlayMusic += RandoMusicManager.OnPlayMusic; + // boss management + On.ProgressionManager.HasDefeatedBoss += + (orig, self, bossName) => RandoBossManager.HasBossDefeated(bossName); + On.ProgressionManager.HasEverDefeatedBoss += + (orig, self, bossName) => RandoBossManager.HasBossDefeated(bossName); + On.ProgressionManager.SetBossAsDefeated += + (orig, self, bossName) => RandoBossManager.SetBossAsDefeated(bossName); + // level teleporting etc management + On.Level.ChangeRoom += RandoRoomManager.Level_ChangeRoom; + On.LevelManager.LoadLevel += RandoLevelManager.LoadLevel; + On.LevelManager.EndLevelLoading += RandoLevelManager.EndLevelLoading; + On.ElementalSkylandsLevelInitializer.OnBeforeInitDone += RandoLevelManager.ElementalSkylandsInit; + // On.PortalOpeningCutscene.OnOpenPortalEvent += RandoPortalManager.OpenPortalEvent; + On.TotHQ.LeaveToLevel += RandoPortalManager.LeaveHQ; + // generator deactivation management + skylandsGeneratorManager.ApplyHooks(); + //These functions let us override and manage power seals ourselves with 'fake' items + On.ProgressionManager.TotalPowerSealCollected += ProgressionManager_TotalPowerSealCollected; + On.ShopChestOpenCutscene.OnChestOpened += (orig, self) => + RandomizerStateManager.Instance.PowerSealManager?.OnShopChestOpen(orig, self); + On.ShopChestChangeShurikenCutscene.Play += (orig, self) => + RandomizerStateManager.Instance.PowerSealManager?.OnShopChestOpen(orig, self); + //update loops for Archipelago + Courier.Events.PlayerController.OnUpdate += PlayerController_OnUpdate; + On.InGameHud.OnGUI += InGameHud_OnGUI; + On.SaveManager.DoActualSaving += SaveManager_DoActualSave; + On.PlayerController.Die += OnPlayerDie; + On.Quarble.OnDeathScreenDone += OnDeathScreenDone; + // On.MegaTimeShard.NextState += RandoTimeShardManager.NextState; + // On.MegaTimeShard.ReceiveHit += RandoTimeShardManager.ReceiveHit; + On.MegaTimeShard.OnBreakDone += MegaTimeShard_OnBreakDone; + On.DialogSequence.GetDialogList += DialogSequence_GetDialogList; + On.Cutscene.Play += Cutscene_Play; + On.PlayerController.Awake += OnPlayerController_Awake; + //temp add #if DEBUG - On.PhantomIntroCutscene.OnEnterRoom += PhantomIntro_OnEnterRoom; //this lets us skip the phantom fight - On.UIManager.ShowView += UIManager_ShowView; - On.MusicBox.SetNotesState += MusicBox_SetNotesState; - On.PowerSeal.OnEnterRoom += PowerSeal_OnEnterRoom; + On.PhantomIntroCutscene.OnEnterRoom += PhantomIntro_OnEnterRoom; //this lets us skip the phantom fight + On.UIManager.ShowView += UIManager_ShowView; + On.MusicBox.SetNotesState += MusicBox_SetNotesState; + On.PowerSeal.OnEnterRoom += PowerSeal_OnEnterRoom; #endif - ItemsAndLocationsHandler.SkylandsGeneratorManager = skylandsGeneratorManager; + ItemsAndLocationsHandler.SkylandsGeneratorManager = skylandsGeneratorManager; - Console.WriteLine("Randomizer finished loading!"); - } + Console.WriteLine("Randomizer finished loading!"); + } - private void SaveSelectionScreen_OnUpdate(On.SaveGameSelectionScreen.orig_Update orig, SaveGameSelectionScreen self) + private void SaveSelectionScreen_OnUpdate(On.SaveGameSelectionScreen.orig_Update orig, SaveGameSelectionScreen self) + { + orig(self); + if (closeLater) { - orig(self); - if (closeLater) + closeLaterTimer += Time.deltaTime; + if (closeLaterTimer >= 3) { - closeLaterTimer += Time.deltaTime; - if (closeLaterTimer >= 3) - { - closeLater.gameObject.SetActive(false); - closeLater = null; - } + closeLater.gameObject.SetActive(false); + closeLater = null; } } + } - private void OnNameSaveUpdate(On.NameSavePopup.orig_Update orig, NameSavePopup self) - { - self.OnLetterErased(); - } - - private void OnPlayerController_Awake(On.PlayerController.orig_Awake orig, PlayerController self) - { - // try { - // GameObject darkness = Courier.LoadFromAssetBundles("Assets/PrefabInstance/modded/DarkCave_LightStencil.prefab"); - // Object.Instantiate(darkness, self.transform); - // } catch(Exception e) { - // e.LogDetailed(); - // } + private void OnNameSaveUpdate(On.NameSavePopup.orig_Update orig, NameSavePopup self) + { + self.OnLetterErased(); + } - orig(self); - } + private void OnPlayerController_Awake(On.PlayerController.orig_Awake orig, PlayerController self) + { + // try { + // GameObject darkness = Courier.LoadFromAssetBundles("Assets/PrefabInstance/modded/DarkCave_LightStencil.prefab"); + // Object.Instantiate(darkness, self.transform); + // } catch(Exception e) { + // e.LogDetailed(); + // } + + orig(self); + } - private void OnOptionScreenEnable(On.OptionScreen.orig_OnEnable orig, OptionScreen self) - { - if (RandomizerStateManager.Instance.APSave == null) - RandoSave.TryLoad(Save.APSaveData); - orig(self); - } + private void OnOptionScreenEnable(On.OptionScreen.orig_OnEnable orig, OptionScreen self) + { + if (RandomizerStateManager.Instance.APSave == null) + RandoSave.TryLoad(Save.APSaveData); + orig(self); + } - public override void Initialize() - { + public override void Initialize() + { #if DEBUG - SceneManager.sceneLoaded += OnSceneLoadedRando; + SceneManager.sceneLoaded += OnSceneLoadedRando; #endif - //load config - Debug.Log("Loading config from APConfig.toml"); - try - { - UserConfig.ReadConfig(ModPath); - } - catch (Exception e) { Console.Write(e); } - ArchipelagoMenu.BuildArchipelagoMenu(); - RandoMenu.BuildRandoMenu(); - HintMenu.BuildHintMenu(); - } - - //temp function for seal research - void PowerSeal_OnEnterRoom(On.PowerSeal.orig_OnEnterRoom orig, PowerSeal self, bool teleportedInRoom) + //load config + Debug.Log("Loading config from APConfig.toml"); + try { - //just print out some info for me - Console.WriteLine($"Entered power seal room: {Manager.Instance.GetRoomAtPosition(self.transform.position).roomKey}"); - orig(self, teleportedInRoom); + UserConfig.ReadConfig(ModPath); } + catch (Exception e) { Console.Write(e); } + ArchipelagoMenu.BuildArchipelagoMenu(); + RandoMenu.BuildRandoMenu(); + HintMenu.BuildHintMenu(); + } - List DialogSequence_GetDialogList(On.DialogSequence.orig_GetDialogList orig, DialogSequence self) + //temp function for seal research + void PowerSeal_OnEnterRoom(On.PowerSeal.orig_OnEnterRoom orig, PowerSeal self, bool teleportedInRoom) + { + //just print out some info for me + Console.WriteLine($"Entered power seal room: {Manager.Instance.GetRoomAtPosition(self.transform.position).roomKey}"); + orig(self, teleportedInRoom); + } + + List DialogSequence_GetDialogList(On.DialogSequence.orig_GetDialogList orig, DialogSequence self) + { + //Using this function to add some of my own dialog stuff to the game. + if (ArchipelagoClient.HasConnected && + new[] { "ARCHIPELAGO_ITEM", "DEATH_LINK" }.Contains(self.dialogID)) { - //Using this function to add some of my own dialog stuff to the game. - if (ArchipelagoClient.HasConnected && - new[] { "ARCHIPELAGO_ITEM", "DEATH_LINK" }.Contains(self.dialogID)) + var dialogInfoList = new List(); + var dialog = new DialogInfo(); + switch (self.dialogID) { - var dialogInfoList = new List(); - var dialog = new DialogInfo(); - switch (self.dialogID) - { - case "ARCHIPELAGO_ITEM": - dialog.text = self.name; - break; - case "DEATH_LINK": - dialog.text = $"Deathlink: {self.name}"; - break; - } - - dialogInfoList.Add(dialog); - - return dialogInfoList; + case "ARCHIPELAGO_ITEM": + dialog.text = self.name; + break; + case "DEATH_LINK": + dialog.text = $"Deathlink: {self.name}"; + break; } - return orig(self); + dialogInfoList.Add(dialog); + + return dialogInfoList; } - void InventoryManager_AddItem(On.InventoryManager.orig_AddItem orig, InventoryManager self, EItems itemId, int quantity) + return orig(self); + } + + void InventoryManager_AddItem(On.InventoryManager.orig_AddItem orig, InventoryManager self, EItems itemId, int quantity) + { + if (!itemId.Equals(EItems.TIME_SHARD)) { - if (!itemId.Equals(EItems.TIME_SHARD)) + Debug.Log($"Called InventoryManager_AddItem method. Looking to give x{quantity} amount of item '{itemId}'."); + if (quantity == ItemsAndLocationsHandler.APQuantity) { - Debug.Log($"Called InventoryManager_AddItem method. Looking to give x{quantity} amount of item '{itemId}'."); - if (quantity == ItemsAndLocationsHandler.APQuantity) - { - orig(self, itemId, 1); - return; - } - if (randoStateManager.IsLocationRandomized(itemId, out var randoItemCheck)) + orig(self, itemId, 1); + return; + } + if (randoStateManager.IsLocationRandomized(itemId, out var randoItemCheck)) + { + if (itemId.Equals(EItems.CANDLE) && + randoStateManager.IsLocationRandomized(EItems.TEA_SEED, out var seedCheck) && + !RandomizerStateManager.HasCompletedCheck(seedCheck)) { - if (itemId.Equals(EItems.CANDLE) && - randoStateManager.IsLocationRandomized(EItems.TEA_SEED, out var seedCheck) && - !RandomizerStateManager.HasCompletedCheck(seedCheck)) - { - ItemsAndLocationsHandler.SendLocationCheck(seedCheck); - } - ItemsAndLocationsHandler.SendLocationCheck(randoItemCheck); - return; + ItemsAndLocationsHandler.SendLocationCheck(seedCheck); } + ItemsAndLocationsHandler.SendLocationCheck(randoItemCheck); + return; } - //Call original add with items - orig(self, itemId, quantity); - } + //Call original add with items + orig(self, itemId, quantity); + + } - void ProgressionManager_SetChallengeRoomAsCompleted(On.ProgressionManager.orig_SetChallengeRoomAsCompleted orig, ProgressionManager self, string roomKey) + void ProgressionManager_SetChallengeRoomAsCompleted(On.ProgressionManager.orig_SetChallengeRoomAsCompleted orig, ProgressionManager self, string roomKey) + { + //if this is a rando file, go ahead and give the item we expect to get + if (ArchipelagoClient.HasConnected) { - //if this is a rando file, go ahead and give the item we expect to get - if (ArchipelagoClient.HasConnected) - { - var powerSealLocation = - ItemsAndLocationsHandler.ArchipelagoLocations.Find(loc => loc.Equals(roomKey)); - ItemsAndLocationsHandler.SendLocationCheck(powerSealLocation); - } - //For now calling the orig method once we are done so the game still things we are collecting seals. We can change this later. - orig(self, roomKey); + var powerSealLocation = + ItemsAndLocationsHandler.ArchipelagoLocations.Find(loc => loc.Equals(roomKey)); + ItemsAndLocationsHandler.SendLocationCheck(powerSealLocation); } + //For now calling the orig method once we are done so the game still things we are collecting seals. We can change this later. + orig(self, roomKey); + } - bool HasItem_IsTrue(On.HasItem.orig_IsTrue orig, HasItem self) + bool HasItem_IsTrue(On.HasItem.orig_IsTrue orig, HasItem self) + { + bool hasItem = false; + //Check to make sure this is an item that was randomized and make sure we are not ignoring this specific trigger check + if (ArchipelagoClient.HasConnected && randoStateManager.IsLocationRandomized(self.item, out var check) && !RandomizerConstants.GetSpecialTriggerNames().Contains(self.Owner.name)) { - bool hasItem = false; - //Check to make sure this is an item that was randomized and make sure we are not ignoring this specific trigger check - if (ArchipelagoClient.HasConnected && randoStateManager.IsLocationRandomized(self.item, out var check) && !RandomizerConstants.GetSpecialTriggerNames().Contains(self.Owner.name)) + if (self.transform.parent != null && "InteractionZone".Equals(self.Owner.name) && RandomizerConstants.GetSpecialTriggerNames().Contains(self.transform.parent.name) && EItems.KEY_OF_LOVE != self.item) { - if (self.transform.parent != null && "InteractionZone".Equals(self.Owner.name) && RandomizerConstants.GetSpecialTriggerNames().Contains(self.transform.parent.name) && EItems.KEY_OF_LOVE != self.item) - { - //Special triggers that need to use normal logic, call orig method. This also includes the trigger check for the key of love on the sunken door because yeah. - Console.WriteLine($"While checking if player HasItem in an interaction zone, found parent object '{self.transform.parent.name}' in ignore logic. Calling orig HasItem logic."); - return orig(self); - } - - //OLD WAY - //Don't actually check for the item i have, check to see if I have the item that was at it's location. - //int itemQuantity = Manager.Instance.GetItemQuantity(randoStateManager.CurrentLocationToItemMapping[check].Item); + //Special triggers that need to use normal logic, call orig method. This also includes the trigger check for the key of love on the sunken door because yeah. + Console.WriteLine($"While checking if player HasItem in an interaction zone, found parent object '{self.transform.parent.name}' in ignore logic. Calling orig HasItem logic."); + return orig(self); + } - //NEW WAY - //Don't actually check for the item I have, check to see if I have done this check before. We'll do this by seeing if the item at its location has been collected yet or not - int itemQuantity = RandomizerStateManager.HasCompletedCheck(check) ? 1 : 0; - if (self.item.Equals(EItems.CANDLE) && itemQuantity == 1) - { - var seed = ItemsAndLocationsHandler.LocationFromEItem(EItems.TEA_SEED); - var leaves = ItemsAndLocationsHandler.LocationFromEItem(EItems.TEA_LEAVES); - itemQuantity = RandomizerStateManager.HasCompletedCheck(seed) && - RandomizerStateManager.HasCompletedCheck(leaves) - ? 1 - : 0; - } + //OLD WAY + //Don't actually check for the item i have, check to see if I have the item that was at it's location. + //int itemQuantity = Manager.Instance.GetItemQuantity(randoStateManager.CurrentLocationToItemMapping[check].Item); - switch (self.conditionOperator) - { - case EConditionOperator.LESS_THAN: - hasItem = itemQuantity < self.quantityToHave; - break; - case EConditionOperator.LESS_OR_EQUAL: - hasItem = itemQuantity <= self.quantityToHave; - break; - case EConditionOperator.EQUAL: - hasItem = itemQuantity == self.quantityToHave; - break; - case EConditionOperator.GREATER_OR_EQUAL: - hasItem = itemQuantity >= self.quantityToHave; - break; - case EConditionOperator.GREATER_THAN: - hasItem = itemQuantity > self.quantityToHave; - break; - } - return hasItem; + //NEW WAY + //Don't actually check for the item I have, check to see if I have done this check before. We'll do this by seeing if the item at its location has been collected yet or not + int itemQuantity = RandomizerStateManager.HasCompletedCheck(check) ? 1 : 0; + if (self.item.Equals(EItems.CANDLE) && itemQuantity == 1) + { + var seed = ItemsAndLocationsHandler.LocationFromEItem(EItems.TEA_SEED); + var leaves = ItemsAndLocationsHandler.LocationFromEItem(EItems.TEA_LEAVES); + itemQuantity = RandomizerStateManager.HasCompletedCheck(seed) && + RandomizerStateManager.HasCompletedCheck(leaves) + ? 1 + : 0; } - Console.WriteLine("HasItem check was not randomized. Doing vanilla checks."); - Debug.Log($"Is randomized file : '{ArchipelagoClient.HasConnected}' | Is location '{self.item}' randomized: '{randoStateManager.IsLocationRandomized(self.item, out check)}' | Not in the special triggers list: '{!RandomizerConstants.GetSpecialTriggerNames().Contains(self.Owner.name)}'|"); - return orig(self); + switch (self.conditionOperator) + { + case EConditionOperator.LESS_THAN: + hasItem = itemQuantity < self.quantityToHave; + break; + case EConditionOperator.LESS_OR_EQUAL: + hasItem = itemQuantity <= self.quantityToHave; + break; + case EConditionOperator.EQUAL: + hasItem = itemQuantity == self.quantityToHave; + break; + case EConditionOperator.GREATER_OR_EQUAL: + hasItem = itemQuantity >= self.quantityToHave; + break; + case EConditionOperator.GREATER_THAN: + hasItem = itemQuantity > self.quantityToHave; + break; + } + return hasItem; } + Console.WriteLine("HasItem check was not randomized. Doing vanilla checks."); + Debug.Log($"Is randomized file : '{ArchipelagoClient.HasConnected}' | Is location '{self.item}' randomized: '{randoStateManager.IsLocationRandomized(self.item, out check)}' | Not in the special triggers list: '{!RandomizerConstants.GetSpecialTriggerNames().Contains(self.Owner.name)}'|"); + return orig(self); - bool AwardNoteCutscene_ShouldPlay(On.AwardNoteCutscene.orig_ShouldPlay orig, AwardNoteCutscene self) - { - //Need to handle note cutscene triggers so they will play as long as I dont have the actual item it grants - if (!randoStateManager.IsLocationRandomized(self.noteToAward, out var noteCheck)) - return orig(self); - var shouldPlay = !ArchipelagoClient.ServerData.CheckedLocations.Contains(noteCheck); - if (shouldPlay) - ItemsAndLocationsHandler.SendLocationCheck(noteCheck); - return shouldPlay; - } + } - bool CutsceneHasPlayed_IsTrue(On.CutsceneHasPlayed.orig_IsTrue orig, CutsceneHasPlayed self) - { - if (RandomizerConstants.GetCutsceneMappings().ContainsKey(self.cutsceneId) && - randoStateManager.IsLocationRandomized(RandomizerConstants.GetCutsceneMappings()[self.cutsceneId], - out var cutsceneCheck)) - { - return RandomizerStateManager.HasCompletedCheck(cutsceneCheck); - } + bool AwardNoteCutscene_ShouldPlay(On.AwardNoteCutscene.orig_ShouldPlay orig, AwardNoteCutscene self) + { + //Need to handle note cutscene triggers so they will play as long as I dont have the actual item it grants + if (!randoStateManager.IsLocationRandomized(self.noteToAward, out var noteCheck)) return orig(self); - } + var shouldPlay = !ArchipelagoClient.ServerData.CheckedLocations.Contains(noteCheck); + if (shouldPlay) + ItemsAndLocationsHandler.SendLocationCheck(noteCheck); + return shouldPlay; + } - void SaveGameSelectionScreen_OnLoadGame(On.SaveGameSelectionScreen.orig_OnLoadGame orig, SaveGameSelectionScreen self, int slotIndex) + bool CutsceneHasPlayed_IsTrue(On.CutsceneHasPlayed.orig_IsTrue orig, CutsceneHasPlayed self) + { + if (RandomizerConstants.GetCutsceneMappings().ContainsKey(self.cutsceneId) && + randoStateManager.IsLocationRandomized(RandomizerConstants.GetCutsceneMappings()[self.cutsceneId], + out var cutsceneCheck)) { - //slotIndex is 0-based, going to increment it locally to keep things simple. - randoStateManager.CurrentFileSlot = slotIndex + 1; + return RandomizerStateManager.HasCompletedCheck(cutsceneCheck); + } + return orig(self); + } - //This is probably a bad way to do this - try + void SaveGameSelectionScreen_OnLoadGame(On.SaveGameSelectionScreen.orig_OnLoadGame orig, SaveGameSelectionScreen self, int slotIndex) + { + //slotIndex is 0-based, going to increment it locally to keep things simple. + randoStateManager.CurrentFileSlot = slotIndex + 1; + + //This is probably a bad way to do this + try + { + RandoSave.TryLoad(Save.APSaveData); + if (ArchipelagoData.LoadData(randoStateManager.CurrentFileSlot)) { - RandoSave.TryLoad(Save.APSaveData); - if (ArchipelagoData.LoadData(randoStateManager.CurrentFileSlot)) - { - if (!ArchipelagoClient.Offline) - { - // need to wait for the scout response from the server - while (ArchipelagoClient.Authenticated && (randoStateManager.ScoutedLocations == null || - randoStateManager.ScoutedLocations.Count < 1)) - { - Console.WriteLine("locations not scouted yet. waiting..."); - Thread.Sleep(100); - } - } - Manager.Instance.LoadDialogs(Manager.Instance.CurrentLanguage); - //The player is connected to an Archipelago server and trying to load a save file so check it's valid - Console.WriteLine($"Successfully loaded Archipelago seed {randoStateManager.CurrentFileSlot}"); - Console.WriteLine("Current Inventory:"); - foreach (var item in randoStateManager.APSave[randoStateManager.CurrentFileSlot].ReceivedItems.Keys) - { - Console.WriteLine($"{item}: {randoStateManager.APSave[randoStateManager.CurrentFileSlot].ReceivedItems[item]}"); - } - } - else if (ArchipelagoClient.Authenticated && - string.IsNullOrEmpty(randoStateManager.APSave[randoStateManager.CurrentFileSlot].SlotName)) + if (!ArchipelagoClient.Offline) { - ArchipelagoClient.ServerData.StartNewSeed(); - //We force a reload of all dialog when loading the game - try + // need to wait for the scout response from the server + while (ArchipelagoClient.Authenticated && (randoStateManager.ScoutedLocations == null || + randoStateManager.ScoutedLocations.Count < 1)) { - Manager.Instance.LoadDialogs(Manager.Instance - .CurrentLanguage); - } - catch (Exception e) - { - Console.WriteLine(e); + Console.WriteLine("locations not scouted yet. waiting..."); + Thread.Sleep(100); } } - else if (ArchipelagoClient.Offline) + Manager.Instance.LoadDialogs(Manager.Instance.CurrentLanguage); + //The player is connected to an Archipelago server and trying to load a save file so check it's valid + Console.WriteLine($"Successfully loaded Archipelago seed {randoStateManager.CurrentFileSlot}"); + Console.WriteLine("Current Inventory:"); + foreach (var item in randoStateManager.APSave[randoStateManager.CurrentFileSlot].ReceivedItems.Keys) { - if (ItemsAndLocationsHandler.ItemsLookup == null) - ItemsAndLocationsHandler.Initialize(); - Manager.Instance.LoadDialogs(Manager.Instance.CurrentLanguage); + Console.WriteLine($"{item}: {randoStateManager.APSave[randoStateManager.CurrentFileSlot].ReceivedItems[item]}"); } } - catch (Exception e) - { - Console.WriteLine(e); - } - if (!ArchipelagoClient.HasConnected) - { - Console.WriteLine( - $"This file slot ({randoStateManager.CurrentFileSlot}) has no seed generated or is not " + - "a randomized file. Resetting the mappings and putting game items back to normal."); - ArchipelagoClient.ServerData = new ArchipelagoData(); - } - else - { - RandomizerStateManager.OnMainMenu = false; - } - - orig(self, slotIndex); - Manager.Instance.levelMusicShuffle = RandoMusicManager.ShuffleMusic; - RandoMusicManager.BuildMusicLibrary(); - } - - void SaveGameSelectionScreen_OnNewGame(On.SaveGameSelectionScreen.orig_OnNewGame orig, SaveGameSelectionScreen self, SaveSlotUI slot) - { - Console.WriteLine("trying to load new game"); - if (ArchipelagoClient.Authenticated) - RandomizerStateManager.InitializeNewSecondQuest(self, slot.slotIndex); - else if (ArchipelagoClient.Offline) + else if (ArchipelagoClient.Authenticated && + string.IsNullOrEmpty(randoStateManager.APSave[randoStateManager.CurrentFileSlot].SlotName)) { + ArchipelagoClient.ServerData.StartNewSeed(); + //We force a reload of all dialog when loading the game try { - RandomizerStateManager.InitializeNewSecondQuest(self, slot.slotIndex); + Manager.Instance.LoadDialogs(Manager.Instance + .CurrentLanguage); } catch (Exception e) { Console.WriteLine(e); } } - else if (Environment.GetCommandLineArgs().Length > 1) - { - Console.WriteLine("loading new game save... found command line args"); - foreach (var arg in Environment.GetCommandLineArgs()) - { - Console.WriteLine(arg); - if (!arg.Contains("archipelago")) continue; - var uri = new Uri(arg); - ArchipelagoClient.ServerData = new ArchipelagoData(); - var userInfo = uri.UserInfo.Split(':'); - ArchipelagoClient.ServerData.SlotName = userInfo[0]; - ArchipelagoClient.ServerData.Password = userInfo[1] == "None" ? "" : userInfo[1]; - ArchipelagoClient.ServerData.Uri = uri.Host; - ArchipelagoClient.ServerData.Port = uri.Port; - Console.WriteLine(ArchipelagoClient.ServerData.SlotName); - Console.WriteLine(ArchipelagoClient.ServerData.Password); - Console.WriteLine(ArchipelagoClient.ServerData.Uri); - Console.WriteLine(ArchipelagoClient.ServerData.Port); - var result = ArchipelagoClient.Connect(); - if (ArchipelagoClient.Authenticated) - { - RandomizerStateManager.InitializeNewSecondQuest(self, slot.slotIndex); - return; - } - break; - } - orig(self, slot); - self.nameSavePopup.OnLetterErased(); - closeLater = - InitTextEntryPopup(self, - "Not connected to an Archipelago server. Please connect before continuing.", - _ => true, 0, null, - CharsetFlags.Space); - closeLater.Init(""); - closeLater.gameObject.SetActive(true); - closeLaterTimer = 0f; - } - else + else if (ArchipelagoClient.Offline) { - orig(self, slot); - self.nameSavePopup.OnLetterErased(); - closeLater = - InitTextEntryPopup(self, - "", - _ => true, 0, null, - CharsetFlags.Space); - closeLater.Init("Not connected to an Archipelago server. Please connect before continuing."); - closeLater.gameObject.SetActive(true); - closeLaterTimer = 0f; + if (ItemsAndLocationsHandler.ItemsLookup == null) + ItemsAndLocationsHandler.Initialize(); + Manager.Instance.LoadDialogs(Manager.Instance.CurrentLanguage); } } - - private void SaveGameSelectionScreen_ConfirmSaveDelete(On.SaveGameSelectionScreen.orig_ConfirmSaveDelete orig, SaveGameSelectionScreen self, SaveSlotUI slot) + catch (Exception e) { - orig(self, slot); + Console.WriteLine(e); } - - private void SaveGameSelectionScreen_OnDelete(On.SaveGameSelectionScreen.orig_OnDeleteChoiceDone orig, SaveGameSelectionScreen self, bool delete) + if (!ArchipelagoClient.HasConnected) { - if (delete) - { - RandoSave.TryLoad(Save.APSaveData); - var slotIndex = self.GetPrivateField("focusedSlot").slotIndex + 1; - randoStateManager.APSave[slotIndex] = new ArchipelagoData(); - Save?.ForceUpdate(); - } - orig(self, delete); + Console.WriteLine( + $"This file slot ({randoStateManager.CurrentFileSlot}) has no seed generated or is not " + + "a randomized file. Resetting the mappings and putting game items back to normal."); + ArchipelagoClient.ServerData = new ArchipelagoData(); } - - void PauseScreen_OnQuitToTitle(On.BackToTitleScreen.orig_GoBackToTitleScreen orig) + else { - if (ArchipelagoClient.HasConnected) - { - ArchipelagoClient.Disconnect(); - ArchipelagoClient.HasConnected = false; - ArchipelagoClient.Offline = false; - ArchipelagoClient.OfflineReceivedItems = 0; - RandoBossManager.DefeatedBosses = []; - RandoPortalManager.StartingPortals = null; - RandoPortalManager.PortalMapping = null; - RandoLevelManager.RandoLevelMapping = null; - Manager.Instance.powerSealTotal = 0; - HintMenu.ReBuildHintMenu(); - } - randoStateManager = new RandomizerStateManager(); - ArchipelagoClient.ServerData = new ArchipelagoData(); - RandomizerStateManager.OnMainMenu = true; - orig(); - Console.WriteLine("returned to title"); - Manager.Instance.GetView().UpdateShurikenVisibility(); + RandomizerStateManager.OnMainMenu = false; } - //Fixing necro cutscene check - void CatacombLevelInitializer_OnBeforeInitDone(On.CatacombLevelInitializer.orig_OnBeforeInitDone orig, CatacombLevelInitializer self) + orig(self, slotIndex); + Manager.Instance.levelMusicShuffle = RandoMusicManager.ShuffleMusic; + RandoMusicManager.BuildMusicLibrary(); + } + + void SaveGameSelectionScreen_OnNewGame(On.SaveGameSelectionScreen.orig_OnNewGame orig, SaveGameSelectionScreen self, SaveSlotUI slot) + { + Console.WriteLine("trying to load new game"); + if (ArchipelagoClient.Authenticated) + RandomizerStateManager.InitializeNewSecondQuest(self, slot.slotIndex); + else if (ArchipelagoClient.Offline) { - //check to see if we already have the item at Necro check - if (ArchipelagoClient.HasConnected) + try { - if (!RandomizerStateManager.HasCompletedCheck( - ItemsAndLocationsHandler.LocationsLookup[new LocationRO("Necro")])) - self.necrophobicWorkerCutscene.Play(); - else self.necrophobicWorkerCutscene.phobekin.gameObject.SetActive(false); - //Call our overriden fixing function - RandoCatacombLevelInitializer.FixPlayerStuckInChallengeRoom(); + RandomizerStateManager.InitializeNewSecondQuest(self, slot.slotIndex); } - else + catch (Exception e) { - //we are not rando here, call orig method - orig(self); + Console.WriteLine(e); } - } - - // Breaking into Necro cutscene to fix things - private static void NecrophobicWorkerCutscene_Play(On.NecrophobicWorkerCutscene.orig_Play orig, NecrophobicWorkerCutscene self) + else if (Environment.GetCommandLineArgs().Length > 1) { - //Cutscene moves Ninja around, lets see if i can stop it by making that "location" the current location the player is. - if (ArchipelagoClient.HasConnected) - self.playerStartPosition = Object.FindObjectOfType().transform; - orig(self); + Console.WriteLine("loading new game save... found command line args"); + foreach (var arg in Environment.GetCommandLineArgs()) + { + Console.WriteLine(arg); + if (!arg.Contains("archipelago")) continue; + var uri = new Uri(arg); + ArchipelagoClient.ServerData = new ArchipelagoData(); + var userInfo = uri.UserInfo.Split(':'); + ArchipelagoClient.ServerData.SlotName = userInfo[0]; + ArchipelagoClient.ServerData.Password = userInfo[1] == "None" ? "" : userInfo[1]; + ArchipelagoClient.ServerData.Uri = uri.Host; + ArchipelagoClient.ServerData.Port = uri.Port; + Console.WriteLine(ArchipelagoClient.ServerData.SlotName); + Console.WriteLine(ArchipelagoClient.ServerData.Password); + Console.WriteLine(ArchipelagoClient.ServerData.Uri); + Console.WriteLine(ArchipelagoClient.ServerData.Port); + var result = ArchipelagoClient.Connect(); + if (ArchipelagoClient.Authenticated) + { + RandomizerStateManager.InitializeNewSecondQuest(self, slot.slotIndex); + return; + } + break; + } + orig(self, slot); + self.nameSavePopup.OnLetterErased(); + closeLater = + InitTextEntryPopup(self, + "Not connected to an Archipelago server. Please connect before continuing.", + _ => true, 0, null, + CharsetFlags.Space); + closeLater.Init(""); + closeLater.gameObject.SetActive(true); + closeLaterTimer = 0f; + } + else + { + orig(self, slot); + self.nameSavePopup.OnLetterErased(); + closeLater = + InitTextEntryPopup(self, + "", + _ => true, 0, null, + CharsetFlags.Space); + closeLater.Init("Not connected to an Archipelago server. Please connect before continuing."); + closeLater.gameObject.SetActive(true); + closeLaterTimer = 0f; } + } + + private void SaveGameSelectionScreen_ConfirmSaveDelete(On.SaveGameSelectionScreen.orig_ConfirmSaveDelete orig, SaveGameSelectionScreen self, SaveSlotUI slot) + { + orig(self, slot); + } - void RuxxtinNoteAndAwardAmuletCutscene_Play(ILContext il) + private void SaveGameSelectionScreen_OnDelete(On.SaveGameSelectionScreen.orig_OnDeleteChoiceDone orig, SaveGameSelectionScreen self, bool delete) + { + if (delete) { - ILCursor cursor = new ILCursor(il); + RandoSave.TryLoad(Save.APSaveData); + var slotIndex = self.GetPrivateField("focusedSlot").slotIndex + 1; + randoStateManager.APSave[slotIndex] = new ArchipelagoData(); + Save?.ForceUpdate(); + } + orig(self, delete); + } - while (cursor.TryGotoNext(MoveType.After, instr => instr.MatchLdcI4(55))) - { - cursor.EmitDelegate>(GetRandoItemByItem); - } + void PauseScreen_OnQuitToTitle(On.BackToTitleScreen.orig_GoBackToTitleScreen orig) + { + if (ArchipelagoClient.HasConnected) + { + ArchipelagoClient.Disconnect(); + ArchipelagoClient.HasConnected = false; + ArchipelagoClient.Offline = false; + ArchipelagoClient.OfflineReceivedItems = 0; + RandoBossManager.DefeatedBosses = []; + RandoPortalManager.StartingPortals = null; + RandoPortalManager.PortalMapping = null; + RandoLevelManager.RandoLevelMapping = null; + Manager.Instance.powerSealTotal = 0; + HintMenu.ReBuildHintMenu(); + } + randoStateManager = new RandomizerStateManager(); + ArchipelagoClient.ServerData = new ArchipelagoData(); + RandomizerStateManager.OnMainMenu = true; + orig(); + Console.WriteLine("returned to title"); + Manager.Instance.GetView().UpdateShurikenVisibility(); + } + //Fixing necro cutscene check + void CatacombLevelInitializer_OnBeforeInitDone(On.CatacombLevelInitializer.orig_OnBeforeInitDone orig, CatacombLevelInitializer self) + { + //check to see if we already have the item at Necro check + if (ArchipelagoClient.HasConnected) + { + if (!RandomizerStateManager.HasCompletedCheck( + ItemsAndLocationsHandler.LocationsLookup[new LocationRO("Necro")])) + self.necrophobicWorkerCutscene.Play(); + else self.necrophobicWorkerCutscene.phobekin.gameObject.SetActive(false); + //Call our overriden fixing function + RandoCatacombLevelInitializer.FixPlayerStuckInChallengeRoom(); } - - void MegaTimeShard_OnBreakDone(On.MegaTimeShard.orig_OnBreakDone orig, MegaTimeShard self) + else { - var currentLevel = Manager.Instance.GetCurrentLevelEnum(); - var currentRoom = Manager.Instance.CurrentRoom.roomKey; - RandoTimeShardManager.BreakShard(new RandoTimeShardManager.MegaShard(currentLevel, currentRoom)); + //we are not rando here, call orig method orig(self); } - int ProgressionManager_TotalPowerSealCollected(On.ProgressionManager.orig_TotalPowerSealCollected orig, - ProgressionManager self) + } + + // Breaking into Necro cutscene to fix things + private static void NecrophobicWorkerCutscene_Play(On.NecrophobicWorkerCutscene.orig_Play orig, NecrophobicWorkerCutscene self) + { + //Cutscene moves Ninja around, lets see if i can stop it by making that "location" the current location the player is. + if (ArchipelagoClient.HasConnected) + self.playerStartPosition = Object.FindObjectOfType().transform; + orig(self); + } + + void RuxxtinNoteAndAwardAmuletCutscene_Play(ILContext il) + { + ILCursor cursor = new ILCursor(il); + + while (cursor.TryGotoNext(MoveType.After, instr => instr.MatchLdcI4(55))) { - return randoStateManager.PowerSealManager?.AmountPowerSealsCollected() ?? orig(self); + cursor.EmitDelegate>(GetRandoItemByItem); } - void Cutscene_Play(On.Cutscene.orig_Play orig, Cutscene self) - { - var eventName = self.GetType().ToString(); + } + + void MegaTimeShard_OnBreakDone(On.MegaTimeShard.orig_OnBreakDone orig, MegaTimeShard self) + { + var currentLevel = Manager.Instance.GetCurrentLevelEnum(); + var currentRoom = Manager.Instance.CurrentRoom.roomKey; + RandoTimeShardManager.BreakShard(new RandoTimeShardManager.MegaShard(currentLevel, currentRoom)); + orig(self); + } + + int ProgressionManager_TotalPowerSealCollected(On.ProgressionManager.orig_TotalPowerSealCollected orig, + ProgressionManager self) + { + return randoStateManager.PowerSealManager?.AmountPowerSealsCollected() ?? orig(self); + } + + void Cutscene_Play(On.Cutscene.orig_Play orig, Cutscene self) + { + var eventName = self.GetType().ToString(); #if DEBUG - Console.WriteLine($"Playing cutscene: {eventName}"); + Console.WriteLine($"Playing cutscene: {eventName}"); #endif - if (eventName == "PortalOpeningCutscene") + if (eventName == "PortalOpeningCutscene") + { + if (RandoPortalManager.StartingPortals != null) { - if (RandoPortalManager.StartingPortals != null) + var progManager = Manager.Instance; + foreach (var portal in RandoPortalManager.StartingPortals.Where( + portal => !portal.StartsWith("Autumn") + && !portal.StartsWith("Howling") + && !portal.StartsWith("Glacial"))) { - var progManager = Manager.Instance; - foreach (var portal in RandoPortalManager.StartingPortals.Where( - portal => !portal.StartsWith("Autumn") - && !portal.StartsWith("Howling") - && !portal.StartsWith("Glacial"))) - { - var cutsceneName = $"{portal.Replace(" ", "")}OpeningCutscene"; - progManager.cutscenesPlayed.Add(cutsceneName); - } + var cutsceneName = $"{portal.Replace(" ", "")}OpeningCutscene"; + progManager.cutscenesPlayed.Add(cutsceneName); } } - - if (ArchipelagoClient.EventsICareAbout.Contains(eventName) && ArchipelagoClient.Authenticated) - { - ArchipelagoClient.Session.DataStorage[Scope.Slot, "Events"] += - new List { eventName }; - } - - if (eventName.EndsWith("PortalOpeningCutscene")) - { - self.onDone += OnAnyPortalOpeningCutsceneDone; - } - - orig(self); } - private void OnAnyPortalOpeningCutsceneDone(Cutscene cutscene) + if (ArchipelagoClient.EventsICareAbout.Contains(eventName) && ArchipelagoClient.Authenticated) { - cutscene.onDone -= OnAnyPortalOpeningCutsceneDone; - trackerManager.ReconciliateUnlockedPortals(); + ArchipelagoClient.Session.DataStorage[Scope.Slot, "Events"] += + new List { eventName }; } - void PhantomIntro_OnEnterRoom(On.PhantomIntroCutscene.orig_OnEnterRoom orig, PhantomIntroCutscene self, - bool teleportedInRoom) + if (eventName.EndsWith("PortalOpeningCutscene")) { - if (randoStateManager.SkipPhantom) - { - Manager.Instance.StopMusic(); - Object.FindObjectOfType().Play(); - } - else - { - orig(self, teleportedInRoom); - } + self.onDone += OnAnyPortalOpeningCutsceneDone; } + orig(self); + } - View UIManager_ShowView(On.UIManager.orig_ShowView orig, UIManager self, Type viewType, - EScreenLayers layer, IViewParams screenParams, bool transitionIn, AnimatorUpdateMode animUpdateMode) + private void OnAnyPortalOpeningCutsceneDone(Cutscene cutscene) + { + cutscene.onDone -= OnAnyPortalOpeningCutsceneDone; + trackerManager.ReconciliateUnlockedPortals(); + } + + void PhantomIntro_OnEnterRoom(On.PhantomIntroCutscene.orig_OnEnterRoom orig, PhantomIntroCutscene self, + bool teleportedInRoom) + { + if (randoStateManager.SkipPhantom) + { + Manager.Instance.StopMusic(); + Object.FindObjectOfType().Play(); + } + else { - Console.WriteLine($"viewType {viewType}"); - Console.WriteLine($"layer {layer}"); - Console.WriteLine($"params {screenParams}"); - Console.WriteLine($"transition {transitionIn}"); - Console.WriteLine($"updateMode {animUpdateMode}"); - return orig(self, viewType, layer, screenParams, transitionIn, animUpdateMode); + orig(self, teleportedInRoom); } + } - void DialogCutscene_Play(On.DialogCutscene.orig_Play orig, DialogCutscene self) + + View UIManager_ShowView(On.UIManager.orig_ShowView orig, UIManager self, Type viewType, + EScreenLayers layer, IViewParams screenParams, bool transitionIn, AnimatorUpdateMode animUpdateMode) + { + Console.WriteLine($"viewType {viewType}"); + Console.WriteLine($"layer {layer}"); + Console.WriteLine($"params {screenParams}"); + Console.WriteLine($"transition {transitionIn}"); + Console.WriteLine($"updateMode {animUpdateMode}"); + return orig(self, viewType, layer, screenParams, transitionIn, animUpdateMode); + } + + void DialogCutscene_Play(On.DialogCutscene.orig_Play orig, DialogCutscene self) + { + // Console.WriteLine($"Playing dialog cutscene: {self}"); + //ruxxtin cutscene is being a bitch so just gonna hard code around it here. + if (ArchipelagoClient.HasConnected && self.name.Equals("ReadNote")) { - // Console.WriteLine($"Playing dialog cutscene: {self}"); - //ruxxtin cutscene is being a bitch so just gonna hard code around it here. - if (ArchipelagoClient.HasConnected && self.name.Equals("ReadNote")) + if (randoStateManager.IsLocationRandomized(EItems.RUXXTIN_AMULET, out var locID)) { - if (randoStateManager.IsLocationRandomized(EItems.RUXXTIN_AMULET, out var locID)) + if (!RandomizerStateManager.HasCompletedCheck(locID)) { - if (!RandomizerStateManager.HasCompletedCheck(locID)) - { - ItemsAndLocationsHandler.SendLocationCheck(locID); - } + ItemsAndLocationsHandler.SendLocationCheck(locID); } } - orig(self); } + orig(self); + } - void MusicBox_SetNotesState(On.MusicBox.orig_SetNotesState orig, MusicBox self) - { - // this determines which notes should be shown present in the music box - orig(self); - } + void MusicBox_SetNotesState(On.MusicBox.orig_SetNotesState orig, MusicBox self) + { + // this determines which notes should be shown present in the music box + orig(self); + } - public static void OnToggleWindmillShuriken() - { - Manager.Instance.useWindmillShuriken = !Manager.Instance.useWindmillShuriken; - InGameHud view = Manager.Instance.GetView(); - if (view != null) - view.UpdateShurikenVisibility(); - } + public static void OnToggleWindmillShuriken() + { + Manager.Instance.useWindmillShuriken = !Manager.Instance.useWindmillShuriken; + InGameHud view = Manager.Instance.GetView(); + if (view != null) + view.UpdateShurikenVisibility(); + } - public static void OnSelectTeleportToHq() - { - Console.WriteLine("Teleporting to HQ!"); + public static void OnSelectTeleportToHq() + { + Console.WriteLine("Teleporting to HQ!"); #if DEBUG - var position = Manager.Instance.Player.transform.position; - Console.WriteLine($"{position.x} {position.y} {position.z}"); + var position = Manager.Instance.Player.transform.position; + Console.WriteLine($"{position.x} {position.y} {position.z}"); #endif - // ArchipelagoMenu.archipelagoScreen.Close(false); + // ArchipelagoMenu.archipelagoScreen.Close(false); - RandoLevelManager.CleanupBeforeOptionsTeleport(); - //Load the HQ - Manager.Instance.TeleportInToTHQ(true, ELevelEntranceID.ENTRANCE_A, null); - ArchipelagoClient.Session.DataStorage[Scope.Slot, "CurrentRegion"] = ELevel.Level_13_TowerOfTimeHQ.ToString(); - RandoLevelManager.CleanupAfterTeleport(); - } + RandoLevelManager.CleanupBeforeOptionsTeleport(); + //Load the HQ + Manager.Instance.TeleportInToTHQ(true, ELevelEntranceID.ENTRANCE_A, null); + ArchipelagoClient.Session.DataStorage[Scope.Slot, "CurrentRegion"] = ELevel.Level_13_TowerOfTimeHQ.ToString(); + RandoLevelManager.CleanupAfterTeleport(); + } - public static void OnSelectTeleportToNinjaVillage() - { - Console.WriteLine("Teleporting to Ninja Village."); - // ArchipelagoMenu.archipelagoScreen.Close(false); - EBits dimension = Manager.Instance.currentDimension; + public static void OnSelectTeleportToNinjaVillage() + { + Console.WriteLine("Teleporting to Ninja Village."); + // ArchipelagoMenu.archipelagoScreen.Close(false); + EBits dimension = Manager.Instance.currentDimension; + + RandoLevelManager.CleanupBeforeOptionsTeleport(); + //Load to Ninja Village + RandoLevelManager.TeleportInArea(new LevelConstants.RandoLevel(ELevel.Level_01_NinjaVillage, + new Vector3(-153.3f, -56.5f))); + } - RandoLevelManager.CleanupBeforeOptionsTeleport(); - //Load to Ninja Village - RandoLevelManager.TeleportInArea(new LevelConstants.RandoLevel(ELevel.Level_01_NinjaVillage, - new Vector3(-153.3f, -56.5f))); - } + public static void OnSelectTeleportToSearing() + { + RandoLevelManager.CleanupBeforeOptionsTeleport(); + RandoLevelManager.TeleportInArea(new LevelConstants.RandoLevel(ELevel.Level_08_SearingCrags, + new Vector3(380.5f, 311))); + } - public static void OnSelectTeleportToSearing() - { - RandoLevelManager.CleanupBeforeOptionsTeleport(); - RandoLevelManager.TeleportInArea(new LevelConstants.RandoLevel(ELevel.Level_08_SearingCrags, - new Vector3(380.5f, 311))); - } + public static bool OnSelectArchipelagoHost(string answer) + { + if (answer == null) return true; + if (ArchipelagoClient.ServerData == null) ArchipelagoClient.ServerData = new ArchipelagoData(); + var uri = answer; + ArchipelagoClient.ServerData.Uri = uri; + return true; + } - public static bool OnSelectArchipelagoHost(string answer) - { - if (answer == null) return true; - if (ArchipelagoClient.ServerData == null) ArchipelagoClient.ServerData = new ArchipelagoData(); - var uri = answer; - ArchipelagoClient.ServerData.Uri = uri; - return true; - } + public static bool OnSelectArchipelagoPort(string answer) + { + if (answer == null) return true; + if (ArchipelagoClient.ServerData == null) ArchipelagoClient.ServerData = new ArchipelagoData(); + int.TryParse(answer, out var port); + ArchipelagoClient.ServerData.Port = port; + return true; + } - public static bool OnSelectArchipelagoPort(string answer) + public static bool ArchipelagoPortEnabled() + { + if (Manager.Instance.GetCurrentLevelEnum().Equals(ELevel.NONE)) { - if (answer == null) return true; - if (ArchipelagoClient.ServerData == null) ArchipelagoClient.ServerData = new ArchipelagoData(); - int.TryParse(answer, out var port); - ArchipelagoClient.ServerData.Port = port; - return true; + return !ArchipelagoClient.HasConnected; } - public static bool ArchipelagoPortEnabled() - { - if (Manager.Instance.GetCurrentLevelEnum().Equals(ELevel.NONE)) - { - return !ArchipelagoClient.HasConnected; - } + return ArchipelagoClient.HasConnected && !ArchipelagoClient.Authenticated && !ArchipelagoClient.Offline; + } - return ArchipelagoClient.HasConnected && !ArchipelagoClient.Authenticated && !ArchipelagoClient.Offline; - } + public static bool OnSelectArchipelagoName(string answer) + { + if (answer == null) return true; + if (ArchipelagoClient.ServerData == null) ArchipelagoClient.ServerData = new ArchipelagoData(); + ArchipelagoClient.ServerData.SlotName = answer; + return true; + } - public static bool OnSelectArchipelagoName(string answer) + public static bool OnSelectArchipelagoPass(string answer) + { + if (answer == null) return true; + if (ArchipelagoClient.ServerData == null) ArchipelagoClient.ServerData = new ArchipelagoData(); + ArchipelagoClient.ServerData.Password = answer; + return true; + } + + public static void OnSelectArchipelagoConnect() + { + ArchipelagoClient.ServerData ??= new ArchipelagoData(); + if (!UserConfig.SlotName.IsNullOrEmpty()) { - if (answer == null) return true; - if (ArchipelagoClient.ServerData == null) ArchipelagoClient.ServerData = new ArchipelagoData(); - ArchipelagoClient.ServerData.SlotName = answer; - return true; + ArchipelagoClient.ServerData.Uri = UserConfig.HostName; + ArchipelagoClient.ServerData.Port = UserConfig.Port; + ArchipelagoClient.ServerData.SlotName = UserConfig.SlotName; + ArchipelagoClient.ServerData.Password = UserConfig.Password; } - - public static bool OnSelectArchipelagoPass(string answer) + else if (ArchipelagoClient.ServerData.SlotName.IsNullOrEmpty()) { - if (answer == null) return true; - if (ArchipelagoClient.ServerData == null) ArchipelagoClient.ServerData = new ArchipelagoData(); - ArchipelagoClient.ServerData.Password = answer; - return true; + return; } - public static void OnSelectArchipelagoConnect() - { - ArchipelagoClient.ServerData ??= new ArchipelagoData(); - if (!UserConfig.SlotName.IsNullOrEmpty()) - { - ArchipelagoClient.ServerData.Uri = UserConfig.HostName; - ArchipelagoClient.ServerData.Port = UserConfig.Port; - ArchipelagoClient.ServerData.SlotName = UserConfig.SlotName; - ArchipelagoClient.ServerData.Password = UserConfig.Password; - } - else if (ArchipelagoClient.ServerData.SlotName.IsNullOrEmpty()) - { - return; - } + ArchipelagoClient.ConnectAsync(ArchipelagoMenu.ArchipelagoConnectButton); + } - ArchipelagoClient.ConnectAsync(ArchipelagoMenu.ArchipelagoConnectButton); - } + public static void OnSelectArchipelagoRelease() + { + ArchipelagoClient.SendSayPacket("!release"); + } - public static void OnSelectArchipelagoRelease() - { - ArchipelagoClient.SendSayPacket("!release"); - } + public static void OnSelectArchipelagoCollect() + { + ArchipelagoClient.SendSayPacket("!collect"); + } - public static void OnSelectArchipelagoCollect() - { - ArchipelagoClient.SendSayPacket("!collect"); - } + public static bool OnSelectArchipelagoHint(string answer) + { + ArchipelagoClient.SendSayPacket($"!hint {answer}"); + return true; + } - public static bool OnSelectArchipelagoHint(string answer) - { - ArchipelagoClient.SendSayPacket($"!hint {answer}"); - return true; - } + public static void OnToggleAPStatus() + { + ArchipelagoClient.DisplayStatus = !ArchipelagoClient.DisplayStatus; + } - public static void OnToggleAPStatus() - { - ArchipelagoClient.DisplayStatus = !ArchipelagoClient.DisplayStatus; - } + public static void OnToggleAPMessages() + { + ArchipelagoClient.DisplayAPMessages = !ArchipelagoClient.DisplayAPMessages; + } - public static void OnToggleAPMessages() - { - ArchipelagoClient.DisplayAPMessages = !ArchipelagoClient.DisplayAPMessages; - } + public static void OnToggleDeathLink() + { + ArchipelagoData.DeathLink = !ArchipelagoData.DeathLink; + if (ArchipelagoData.DeathLink) ArchipelagoClient.DeathLinkHandler.DeathLinkService.EnableDeathLink(); + else ArchipelagoClient.DeathLinkHandler.DeathLinkService.DisableDeathLink(); + } - public static void OnToggleDeathLink() - { - ArchipelagoData.DeathLink = !ArchipelagoData.DeathLink; - if (ArchipelagoData.DeathLink) ArchipelagoClient.DeathLinkHandler.DeathLinkService.EnableDeathLink(); - else ArchipelagoClient.DeathLinkHandler.DeathLinkService.DisableDeathLink(); - } + public static bool OnSelectMessageTimer(string answer) + { + if (answer == null) return true; + if (ArchipelagoClient.ServerData == null) ArchipelagoClient.ServerData = new ArchipelagoData(); + int.TryParse(answer, out var newTime); + UpdateTime = newTime; + return true; + } - public static bool OnSelectMessageTimer(string answer) - { - if (answer == null) return true; - if (ArchipelagoClient.ServerData == null) ArchipelagoClient.ServerData = new ArchipelagoData(); - int.TryParse(answer, out var newTime); - UpdateTime = newTime; - return true; - } + /// + /// Delegate function for getting rando item. This can be used by IL hooks that need to make this call later. + /// + /// + /// + private EItems GetRandoItemByItem(EItems item) + { + return !randoStateManager.IsLocationRandomized(item, out var ruxxAmuletLocation) ? item : EItems.POTION; + } - /// - /// Delegate function for getting rando item. This can be used by IL hooks that need to make this call later. - /// - /// - /// - private EItems GetRandoItemByItem(EItems item) - { - return !randoStateManager.IsLocationRandomized(item, out var ruxxAmuletLocation) ? item : EItems.POTION; - } + public static string GetCurrentSeedNum() + { + string seedNum = "Unknown"; - public static string GetCurrentSeedNum() + if (ArchipelagoClient.HasConnected) { - string seedNum = "Unknown"; + seedNum = ArchipelagoClient.ServerData.SeedName; + } - if (ArchipelagoClient.HasConnected) - { - seedNum = ArchipelagoClient.ServerData.SeedName; - } + return seedNum; + } - return seedNum; - } + private void OnSceneLoadedRando(Scene scene, LoadSceneMode mode) + { + Console.WriteLine($"Scene loaded: '{scene.name}'"); + } - private void OnSceneLoadedRando(Scene scene, LoadSceneMode mode) + private void PlayerController_OnUpdate(PlayerController controller) + { + if (!ArchipelagoClient.HasConnected || randoStateManager.CurrentFileSlot == 0) { - Console.WriteLine($"Scene loaded: '{scene.name}'"); + return; } - - private void PlayerController_OnUpdate(PlayerController controller) + if (ArchipelagoClient.Authenticated) { - if (!ArchipelagoClient.HasConnected || randoStateManager.CurrentFileSlot == 0) + if (ArchipelagoClient.DeathLinkHandler.Player == null) { - return; + ArchipelagoClient.DeathLinkHandler.Player = controller; } - if (ArchipelagoClient.Authenticated) - { - if (ArchipelagoClient.DeathLinkHandler.Player == null) - { - ArchipelagoClient.DeathLinkHandler.Player = controller; - } - if (RandomizerStateManager.IsSafeTeleportState() && !Manager.Instance.IsPaused) - { - ArchipelagoClient.DeathLinkHandler.KillPlayer(); - } + if (RandomizerStateManager.IsSafeTeleportState() && !Manager.Instance.IsPaused) + { + ArchipelagoClient.DeathLinkHandler.KillPlayer(); } - //This updates every {updateTime} seconds - updateTimer += Time.deltaTime; - TrapManager.TrapTimer += Time.deltaTime; - if (!(updateTimer >= UpdateTime)) return; - updateTimer = 0; - ArchipelagoClient.UpdateArchipelagoState(); - apMessagesDisplay16.text = apMessagesDisplay8.text = ArchipelagoClient.UpdateMessagesText(); } + //This updates every {updateTime} seconds + updateTimer += Time.deltaTime; + TrapManager.TrapTimer += Time.deltaTime; + if (!(updateTimer >= UpdateTime)) return; + updateTimer = 0; + ArchipelagoClient.UpdateArchipelagoState(); + apMessagesDisplay16.text = apMessagesDisplay8.text = ArchipelagoClient.UpdateMessagesText(); + } - private void InGameHud_OnGUI(On.InGameHud.orig_OnGUI orig, InGameHud self) + private void InGameHud_OnGUI(On.InGameHud.orig_OnGUI orig, InGameHud self) + { + orig(self); + if (apTextDisplay8 == null) { - orig(self); - if (apTextDisplay8 == null) - { - apTextDisplay8 = Object.Instantiate(self.hud_8.coinCount, self.hud_8.gameObject.transform); - apTextDisplay16 = Object.Instantiate(self.hud_16.coinCount, self.hud_16.gameObject.transform); - apTextDisplay8.transform.Translate(0f, -110f, 0f); - apTextDisplay16.transform.Translate(0f, -110f, 0f); - apTextDisplay16.fontSize = apTextDisplay8.fontSize = UserConfig.StatusTextSize; - apTextDisplay16.alignment = apTextDisplay8.alignment = TextAlignmentOptions.TopRight; - apTextDisplay16.enableWordWrapping = apTextDisplay8.enableWordWrapping = true; - apTextDisplay16.color = apTextDisplay8.color = Color.white; - - apMessagesDisplay8 = Object.Instantiate(self.hud_8.coinCount, self.hud_8.gameObject.transform); - apMessagesDisplay16 = Object.Instantiate(self.hud_16.coinCount, self.hud_16.gameObject.transform); - apMessagesDisplay8.transform.Translate(0f, -200f, 0f); - apMessagesDisplay16.transform.Translate(0f, -200f, 0f); - apMessagesDisplay16.fontSize = apMessagesDisplay8.fontSize = UserConfig.MessageTextSize; - apMessagesDisplay16.alignment = apMessagesDisplay8.alignment = TextAlignmentOptions.BottomRight; - apMessagesDisplay16.enableWordWrapping = apMessagesDisplay16.enableWordWrapping = true; - apMessagesDisplay16.color = apMessagesDisplay8.color = Color.green; - apMessagesDisplay16.text = apMessagesDisplay8.text = string.Empty; - } - - if (ArchipelagoClient.Offline) return; - //This updates every frame + apTextDisplay8 = Object.Instantiate(self.hud_8.coinCount, self.hud_8.gameObject.transform); + apTextDisplay16 = Object.Instantiate(self.hud_16.coinCount, self.hud_16.gameObject.transform); + apTextDisplay8.transform.Translate(0f, -110f, 0f); + apTextDisplay16.transform.Translate(0f, -110f, 0f); apTextDisplay16.fontSize = apTextDisplay8.fontSize = UserConfig.StatusTextSize; + apTextDisplay16.alignment = apTextDisplay8.alignment = TextAlignmentOptions.TopRight; + apTextDisplay16.enableWordWrapping = apTextDisplay8.enableWordWrapping = true; + apTextDisplay16.color = apTextDisplay8.color = Color.white; + + apMessagesDisplay8 = Object.Instantiate(self.hud_8.coinCount, self.hud_8.gameObject.transform); + apMessagesDisplay16 = Object.Instantiate(self.hud_16.coinCount, self.hud_16.gameObject.transform); + apMessagesDisplay8.transform.Translate(0f, -200f, 0f); + apMessagesDisplay16.transform.Translate(0f, -200f, 0f); apMessagesDisplay16.fontSize = apMessagesDisplay8.fontSize = UserConfig.MessageTextSize; - apTextDisplay16.text = apTextDisplay8.text = ArchipelagoClient.UpdateStatusText(); + apMessagesDisplay16.alignment = apMessagesDisplay8.alignment = TextAlignmentOptions.BottomRight; + apMessagesDisplay16.enableWordWrapping = apMessagesDisplay16.enableWordWrapping = true; + apMessagesDisplay16.color = apMessagesDisplay8.color = Color.green; + apMessagesDisplay16.text = apMessagesDisplay8.text = string.Empty; } - private void SaveManager_DoActualSave(On.SaveManager.orig_DoActualSaving orig, SaveManager self, bool applySaveDelay = true) - { - // var checkpoint = Manager.Instance.checkpointSaveInfo; - // var pos = checkpoint.loadedLevelPlayerPosition; - // Console.WriteLine($"{checkpoint.loadedLevelCheckpointIndex} \n{checkpoint.playerFacingDirection}\n {pos.x} {pos.y} {pos.z}"); - orig(self, applySaveDelay); - if (!ArchipelagoClient.HasConnected) return; - Save?.Update(); - try - { - if (RandoPortalManager.LeftHQPortal && RandoPortalManager.ForceTeleport) - { - RandoPortalManager.Teleport(); - RandoPortalManager.ForceTeleport = false; - return; - } - } - catch (Exception e) - { - Console.WriteLine(e); - } + if (ArchipelagoClient.Offline) return; + //This updates every frame + apTextDisplay16.fontSize = apTextDisplay8.fontSize = UserConfig.StatusTextSize; + apMessagesDisplay16.fontSize = apMessagesDisplay8.fontSize = UserConfig.MessageTextSize; + apTextDisplay16.text = apTextDisplay8.text = ArchipelagoClient.UpdateStatusText(); + } - if (LostWoodsManager.NeedsUnsolved) - { - LostWoodsManager.UnsolveLostWoods(); - } - else if (LostWoodsManager.NeedsSolved) - { - // just keep trying to solve it until it eventually works lmao - LostWoodsManager.SolveLostWoods(); + private void SaveManager_DoActualSave(On.SaveManager.orig_DoActualSaving orig, SaveManager self, bool applySaveDelay = true) + { + // var checkpoint = Manager.Instance.checkpointSaveInfo; + // var pos = checkpoint.loadedLevelPlayerPosition; + // Console.WriteLine($"{checkpoint.loadedLevelCheckpointIndex} \n{checkpoint.playerFacingDirection}\n {pos.x} {pos.y} {pos.z}"); + orig(self, applySaveDelay); + if (!ArchipelagoClient.HasConnected) return; + Save?.Update(); + try + { + if (RandoPortalManager.LeftHQPortal && RandoPortalManager.ForceTeleport) + { + RandoPortalManager.Teleport(); + RandoPortalManager.ForceTeleport = false; + return; } + } + catch (Exception e) + { + Console.WriteLine(e); + } - // The game calls the save method after the ending cutscene before rolling credits - if (ArchipelagoClient.Authenticated - && Manager.Instance.GetCurrentLevelEnum().Equals(ELevel.Level_Ending)) - { - ArchipelagoClient.UpdateClientStatus(ArchipelagoClientState.ClientGoal); - } + if (LostWoodsManager.NeedsUnsolved) + { + LostWoodsManager.UnsolveLostWoods(); + } + else if (LostWoodsManager.NeedsSolved) + { + // just keep trying to solve it until it eventually works lmao + LostWoodsManager.SolveLostWoods(); } - private void OnPlayerDie(On.PlayerController.orig_Die orig, PlayerController self, EDeathType deathType, - Transform killedBy) + // The game calls the save method after the ending cutscene before rolling credits + if (ArchipelagoClient.Authenticated + && Manager.Instance.GetCurrentLevelEnum().Equals(ELevel.Level_Ending)) { - try - { - TrapManager.ResetPlayerState(); - Manager.Instance.CloseAllScreensOfType(false); - ArchipelagoClient.DeathLinkHandler?.SendDeathLink(deathType, killedBy); - } - catch (Exception e) - { - Console.WriteLine(e); - } - orig(self, deathType, killedBy); + ArchipelagoClient.UpdateClientStatus(ArchipelagoClientState.ClientGoal); } + } - private void OnDeathScreenDone(On.Quarble.orig_OnDeathScreenDone orig, Quarble self) + private void OnPlayerDie(On.PlayerController.orig_Die orig, PlayerController self, EDeathType deathType, + Transform killedBy) + { + try { - orig(self); - // this code doesn't expect music shuffle lmao - Manager.Instance.StopMusic(); + TrapManager.ResetPlayerState(); + Manager.Instance.CloseAllScreensOfType(false); + ArchipelagoClient.DeathLinkHandler?.SendDeathLink(deathType, killedBy); } + catch (Exception e) + { + Console.WriteLine(e); + } + orig(self, deathType, killedBy); + } + + private void OnDeathScreenDone(On.Quarble.orig_OnDeathScreenDone orig, Quarble self) + { + orig(self); + // this code doesn't expect music shuffle lmao + Manager.Instance.StopMusic(); } } diff --git a/Archipelago/ArchipelagoClient.cs b/Archipelago/ArchipelagoClient.cs index 534b507..c16213f 100644 --- a/Archipelago/ArchipelagoClient.cs +++ b/Archipelago/ArchipelagoClient.cs @@ -15,547 +15,546 @@ using UnityEngine; using static Mod.Courier.UI.TextEntryButtonInfo; -namespace MessengerRando.Archipelago +namespace MessengerRando.Archipelago; + +public static class ArchipelagoClient { - public static class ArchipelagoClient - { - private const string ApVersion = "0.5.0"; - public static ArchipelagoData ServerData = new(); - - private delegate void OnConnectAttempt(string result); - - public static bool Authenticated; - public static bool HasConnected; - private static bool attemptingConnection; - public static bool Offline; - - public static bool DisplayAPMessages = true; - public static bool FilterAPMessages = true; - public static bool DisplayStatus = true; - public static bool HintPopUps = true; - - public static ArchipelagoSession Session; - public static DeathLinkInterface DeathLinkHandler; - - public static Queue ItemQueue = new(); - public static Queue DialogQueue = new(); - private static Queue messageQueue = new(); - public static int OfflineReceivedItems; - private static string statusText = string.Empty; - private static bool roomUpdate; - - public static List EventsICareAbout = - [ - "DecurseQueenCutscene", - "QueenDefrostLanternsCutscene", - "ElderAwardSeedCutscene", - "PlantTeaSeedCutscene", - ]; - - public static void ConnectAsync() - { - if (attemptingConnection || Authenticated) return; - attemptingConnection = true; - Debug.Log($"Connecting to {ServerData.Uri}:{ServerData.Port} as {ServerData.SlotName}"); - ThreadPool.QueueUserWorkItem(_ => Connect(OnConnected)); - } + private const string ApVersion = "0.5.0"; + public static ArchipelagoData ServerData = new(); + + private delegate void OnConnectAttempt(string result); + + public static bool Authenticated; + public static bool HasConnected; + private static bool attemptingConnection; + public static bool Offline; + + public static bool DisplayAPMessages = true; + public static bool FilterAPMessages = true; + public static bool DisplayStatus = true; + public static bool HintPopUps = true; + + public static ArchipelagoSession Session; + public static DeathLinkInterface DeathLinkHandler; + + public static Queue ItemQueue = new(); + public static Queue DialogQueue = new(); + private static Queue messageQueue = new(); + public static int OfflineReceivedItems; + private static string statusText = string.Empty; + private static bool roomUpdate; + + public static List EventsICareAbout = + [ + "DecurseQueenCutscene", + "QueenDefrostLanternsCutscene", + "ElderAwardSeedCutscene", + "PlantTeaSeedCutscene", + ]; + + public static void ConnectAsync() + { + if (attemptingConnection || Authenticated) return; + attemptingConnection = true; + Debug.Log($"Connecting to {ServerData.Uri}:{ServerData.Port} as {ServerData.SlotName}"); + ThreadPool.QueueUserWorkItem(_ => Connect(OnConnected)); + } + + public static void ConnectAsync(SubMenuButtonInfo connectButton) + { + if (attemptingConnection || Authenticated) return; + attemptingConnection = true; + if (ServerData == null) + ServerData = new ArchipelagoData(); + Debug.Log($"Connecting to {ServerData.Uri}:{ServerData.Port} as {ServerData.SlotName}"); + Connect(result => OnConnected(result, connectButton)); + } - public static void ConnectAsync(SubMenuButtonInfo connectButton) + private static void OnConnected(string connectStats) + { + if (ServerData.CheckedLocations != null) { - if (attemptingConnection || Authenticated) return; - attemptingConnection = true; - if (ServerData == null) - ServerData = new ArchipelagoData(); - Debug.Log($"Connecting to {ServerData.Uri}:{ServerData.Port} as {ServerData.SlotName}"); - Connect(result => OnConnected(result, connectButton)); + Session.Locations.CompleteLocationChecksAsync( + _ => ServerData.CheckedLocations = Session.Locations.AllLocationsChecked.ToList(), + ServerData.CheckedLocations.ToArray()); } - private static void OnConnected(string connectStats) - { - if (ServerData.CheckedLocations != null) - { - Session.Locations.CompleteLocationChecksAsync( - _ => ServerData.CheckedLocations = Session.Locations.AllLocationsChecked.ToList(), - ServerData.CheckedLocations.ToArray()); - } + attemptingConnection = false; + } - attemptingConnection = false; - } + private static void OnConnected(string outputText, SubMenuButtonInfo connectButton) + { + TextEntryPopup successPopup = InitTextEntryPopup(connectButton.addedTo, string.Empty, + _ => true, 0, null, CharsetFlags.Space); + + successPopup.Init(outputText); + successPopup.gameObject.SetActive(true); + // Object.Destroy(successPopup.transform.Find("BigFrame").Find("SymbolsGrid").gameObject); + Console.WriteLine(outputText); + attemptingConnection = false; + } - private static void OnConnected(string outputText, SubMenuButtonInfo connectButton) - { - TextEntryPopup successPopup = InitTextEntryPopup(connectButton.addedTo, string.Empty, - _ => true, 0, null, CharsetFlags.Space); + private static ArchipelagoSession CreateSession() + { + var session = ArchipelagoSessionFactory.CreateSession(ServerData.Uri, ServerData.Port); + SetupSession(session); + return session; + } - successPopup.Init(outputText); - successPopup.gameObject.SetActive(true); - // Object.Destroy(successPopup.transform.Find("BigFrame").Find("SymbolsGrid").gameObject); - Console.WriteLine(outputText); - attemptingConnection = false; - } + private static ArchipelagoSession CreateSession(Uri uri) + { + var session = ArchipelagoSessionFactory.CreateSession(uri); + SetupSession(session); + return session; + } - private static ArchipelagoSession CreateSession() - { - var session = ArchipelagoSessionFactory.CreateSession(ServerData.Uri, ServerData.Port); - SetupSession(session); - return session; - } + private static void SetupSession(ArchipelagoSession session) + { + session.MessageLog.OnMessageReceived += OnMessageReceived; + session.Socket.ErrorReceived += SessionErrorReceived; + session.Socket.SocketClosed += SessionSocketClosed; + session.Socket.PacketReceived += OnPacketReceived; + } - private static ArchipelagoSession CreateSession(Uri uri) + private static void OnPacketReceived(ArchipelagoPacketBase packet) + { + if (packet is RoomUpdatePacket) { - var session = ArchipelagoSessionFactory.CreateSession(uri); - SetupSession(session); - return session; + roomUpdate = true; } + } + + public static string Connect(Uri uri) + { + if (Authenticated) return "already connected"; - private static void SetupSession(ArchipelagoSession session) + try { - session.MessageLog.OnMessageReceived += OnMessageReceived; - session.Socket.ErrorReceived += SessionErrorReceived; - session.Socket.SocketClosed += SessionSocketClosed; - session.Socket.PacketReceived += OnPacketReceived; + Session = CreateSession(uri); } - - private static void OnPacketReceived(ArchipelagoPacketBase packet) + catch (Exception e) { - if (packet is RoomUpdatePacket) - { - roomUpdate = true; - } + Console.WriteLine($"Error: {e}"); + return e.ToString(); } - public static string Connect(Uri uri) - { - if (Authenticated) return "already connected"; + return TryConnect(); + } - try - { - Session = CreateSession(uri); - } - catch (Exception e) - { - Console.WriteLine($"Error: {e}"); - return e.ToString(); - } + public static string Connect() + { + if (Authenticated) return "already connected"; - return TryConnect(); + try + { + Session = CreateSession(); } - - public static string Connect() + catch (Exception e) { - if (Authenticated) return "already connected"; + Console.WriteLine($"Error: {e}"); + return e.ToString(); + } - try - { - Session = CreateSession(); - } - catch (Exception e) - { - Console.WriteLine($"Error: {e}"); - return e.ToString(); - } + return TryConnect(); + } + + private static string TryConnect() + { + if (ItemsAndLocationsHandler.ItemsLookup == null) ItemsAndLocationsHandler.Initialize(); + var needSlotData = ServerData.SlotData == null; + LoginResult result; - return TryConnect(); + try + { + result = Session.TryConnectAndLogin( + "The Messenger", + ServerData.SlotName, + ItemsHandlingFlags.AllItems, + new Version(ApVersion), + password: ServerData.Password, + requestSlotData: needSlotData + ); + } + catch (Exception e) + { + Console.Write($"Error: {e}"); + result = new LoginFailure(e.GetBaseException().Message); } - private static string TryConnect() + return HandleConnectResult(result, needSlotData); + } + + private static string HandleConnectResult(LoginResult result, bool needSlotData) + { + string outputText; + if (result.Successful) { - if (ItemsAndLocationsHandler.ItemsLookup == null) ItemsAndLocationsHandler.Initialize(); - var needSlotData = ServerData.SlotData == null; - LoginResult result; + var success = (LoginSuccessful)result; + if (needSlotData) + ServerData.SlotData = success.SlotData; + ServerData.SeedName = Session.RoomState.Seed; + Authenticated = true; try { - result = Session.TryConnectAndLogin( - "The Messenger", - ServerData.SlotName, - ItemsHandlingFlags.AllItems, - new Version(ApVersion), - password: ServerData.Password, - requestSlotData: needSlotData - ); + RandomizerStateManager.InitializeSeed(); } catch (Exception e) { - Console.Write($"Error: {e}"); - result = new LoginFailure(e.GetBaseException().Message); + Console.WriteLine(e); + outputText = + "Something went wrong.\n" + + "Please submit a bug report with the log.txt, " + + "which can be found by the game executable."; + Authenticated = false; + Disconnect(); + return outputText; } - return HandleConnectResult(result, needSlotData); - } + DeathLinkHandler = new DeathLinkInterface(); - private static string HandleConnectResult(LoginResult result, bool needSlotData) + ThreadPool.QueueUserWorkItem(_ => + Session.Locations.CompleteLocationChecksAsync(null, + ServerData.CheckedLocations.ToArray())); + + HasConnected = true; + outputText = $"Successfully connected to {ServerData.Uri}:{ServerData.Port} as {ServerData.SlotName}!"; + } + else { - string outputText; - if (result.Successful) - { - var success = (LoginSuccessful)result; - if (needSlotData) - ServerData.SlotData = success.SlotData; - ServerData.SeedName = Session.RoomState.Seed; - Authenticated = true; + LoginFailure failure = (LoginFailure)result; + outputText = $"Failed to connect to {ServerData.Uri}:{ServerData.Port} as {ServerData.SlotName}\n"; + outputText += + failure.Errors.Aggregate(outputText, (current, error) => current + $"\n {error}"); - try - { - RandomizerStateManager.InitializeSeed(); - } - catch (Exception e) - { - Console.WriteLine(e); - outputText = - "Something went wrong.\n" + - "Please submit a bug report with the log.txt, " + - "which can be found by the game executable."; - Authenticated = false; - Disconnect(); - return outputText; - } + Console.WriteLine(outputText); - DeathLinkHandler = new DeathLinkInterface(); + Authenticated = false; + Disconnect(); + } - ThreadPool.QueueUserWorkItem(_ => - Session.Locations.CompleteLocationChecksAsync(null, - ServerData.CheckedLocations.ToArray())); + return outputText; + } - HasConnected = true; - outputText = $"Successfully connected to {ServerData.Uri}:{ServerData.Port} as {ServerData.SlotName}!"; - } - else - { - LoginFailure failure = (LoginFailure)result; - outputText = $"Failed to connect to {ServerData.Uri}:{ServerData.Port} as {ServerData.SlotName}\n"; - outputText += - failure.Errors.Aggregate(outputText, (current, error) => current + $"\n {error}"); + private static void Connect(OnConnectAttempt attempt) + { + attempt(Connect()); + } - Console.WriteLine(outputText); + public static string ColorizePlayerName(int player) + { + var color = player.Equals(Session.ConnectionInfo.Slot) + ? UserConfig.PlayerColor + : UserConfig.OtherPlayerColor; + return $"{Session.Players.GetPlayerAlias(player)}"; + } - Authenticated = false; - Disconnect(); - } + public static string ColorizeLocation(long locID) + { + var color = UserConfig.LocationColor; + return $"{Session.Locations.GetLocationNameFromId(locID)}"; + } - return outputText; - } + private static string ConvertHintMessage(HintItemSendLogMessage hintMessage) + { + var colorizedMessage = hintMessage.ToString(); + colorizedMessage = colorizedMessage.Replace(hintMessage.Sender.Name, + ColorizePlayerName(hintMessage.Sender.Slot)); + colorizedMessage = colorizedMessage.Replace(hintMessage.Receiver.Name, + ColorizePlayerName(hintMessage.Receiver.Slot)); + colorizedMessage = colorizedMessage.Replace(hintMessage.Item.LocationDisplayName, + hintMessage.Item.ColorizeLocation()); + colorizedMessage = colorizedMessage.Replace(hintMessage.Item.ItemDisplayName, + hintMessage.Item.Colorize()); + Console.WriteLine(colorizedMessage); + return colorizedMessage; + } - private static void Connect(OnConnectAttempt attempt) + private static void OnMessageReceived(LogMessage message) + { + Console.WriteLine(message.ToString()); + if (FilterAPMessages) { - attempt(Connect()); - } - public static string ColorizePlayerName(int player) - { - var color = player.Equals(Session.ConnectionInfo.Slot) - ? UserConfig.PlayerColor - : UserConfig.OtherPlayerColor; - return $"{Session.Players.GetPlayerAlias(player)}"; - } + switch (message) + { + case HintItemSendLogMessage hintMessage: + if (hintMessage.IsFound || !hintMessage.IsRelatedToActivePlayer || !HintPopUps || + RandomizerStateManager.SeenHints.Contains(hintMessage.Item.ItemId) || + ItemsAndLocationsHandler.ShopLocation(hintMessage.Item.LocationId, out var shopLoc)) break; + RandomizerStateManager.SeenHints.Add(hintMessage.Item.ItemId); + messageQueue.Enqueue(hintMessage.ToString()); + DialogQueue.Enqueue(ConvertHintMessage(hintMessage)); + break; + case ItemSendLogMessage itemSendMessage: + if (itemSendMessage.IsRelatedToActivePlayer) + { + messageQueue.Enqueue(itemSendMessage.ToString()); + } - public static string ColorizeLocation(long locID) - { - var color = UserConfig.LocationColor; - return $"{Session.Locations.GetLocationNameFromId(locID)}"; + break; + } } - - private static string ConvertHintMessage(HintItemSendLogMessage hintMessage) + else { - var colorizedMessage = hintMessage.ToString(); - colorizedMessage = colorizedMessage.Replace(hintMessage.Sender.Name, - ColorizePlayerName(hintMessage.Sender.Slot)); - colorizedMessage = colorizedMessage.Replace(hintMessage.Receiver.Name, - ColorizePlayerName(hintMessage.Receiver.Slot)); - colorizedMessage = colorizedMessage.Replace(hintMessage.Item.LocationDisplayName, - hintMessage.Item.ColorizeLocation()); - colorizedMessage = colorizedMessage.Replace(hintMessage.Item.ItemDisplayName, - hintMessage.Item.Colorize()); - Console.WriteLine(colorizedMessage); - return colorizedMessage; + if (HintPopUps && message is HintItemSendLogMessage hintMessage && + !ItemsAndLocationsHandler.ShopLocation(hintMessage.Item.LocationId, out var shopLoc)) + DialogQueue.Enqueue(ConvertHintMessage(hintMessage)); + messageQueue.Enqueue(message.ToString()); } + } - private static void OnMessageReceived(LogMessage message) + public static void SyncLocations() + { + if (RandomizerStateManager.Instance.CurrentFileSlot == 0) return; + var checkedLocations = Session.Locations.AllLocationsChecked; + if (ServerData.CheckedLocations.Count == checkedLocations.Count) return; + foreach (var location in checkedLocations) { - Console.WriteLine(message.ToString()); - if (FilterAPMessages) + try { - - switch (message) + if (ServerData.CheckedLocations.Contains(location)) continue; + var locName = Session.Locations.GetLocationNameFromId(location); + if (locName.Contains("Seal")) { - case HintItemSendLogMessage hintMessage: - if (hintMessage.IsFound || !hintMessage.IsRelatedToActivePlayer || !HintPopUps || - RandomizerStateManager.SeenHints.Contains(hintMessage.Item.ItemId) || - ItemsAndLocationsHandler.ShopLocation(hintMessage.Item.LocationId, out var shopLoc)) break; - RandomizerStateManager.SeenHints.Add(hintMessage.Item.ItemId); - messageQueue.Enqueue(hintMessage.ToString()); - DialogQueue.Enqueue(ConvertHintMessage(hintMessage)); - break; - case ItemSendLogMessage itemSendMessage: - if (itemSendMessage.IsRelatedToActivePlayer) - { - messageQueue.Enqueue(itemSendMessage.ToString()); - } - - break; + var roomKey = + ItemsAndLocationsHandler.ArchipelagoLocations.Find( + loc => loc.PrettyLocationName.Equals(locName)).LocationName; + Manager.Instance.SetChallengeRoomAsCompleted(roomKey); } - } - else - { - if (HintPopUps && message is HintItemSendLogMessage hintMessage && - !ItemsAndLocationsHandler.ShopLocation(hintMessage.Item.LocationId, out var shopLoc)) - DialogQueue.Enqueue(ConvertHintMessage(hintMessage)); - messageQueue.Enqueue(message.ToString()); - } - } - - public static void SyncLocations() - { - if (RandomizerStateManager.Instance.CurrentFileSlot == 0) return; - var checkedLocations = Session.Locations.AllLocationsChecked; - if (ServerData.CheckedLocations.Count == checkedLocations.Count) return; - foreach (var location in checkedLocations) - { - try + else if (ItemsAndLocationsHandler.ShopLocation(location, out var shopLoc)) { - if (ServerData.CheckedLocations.Contains(location)) continue; - var locName = Session.Locations.GetLocationNameFromId(location); - if (locName.Contains("Seal")) + Debug.Log($"collecting {shopLoc.LocationName} ({shopLoc.PrettyLocationName})"); + try { - var roomKey = - ItemsAndLocationsHandler.ArchipelagoLocations.Find( - loc => loc.PrettyLocationName.Equals(locName)).LocationName; - Manager.Instance.SetChallengeRoomAsCompleted(roomKey); + var shopID = (EShopUpgradeID)Enum.Parse(typeof(EShopUpgradeID), shopLoc.LocationName); + Manager.Instance.SetShopUpgradeAsUnlocked(shopID); } - else if (ItemsAndLocationsHandler.ShopLocation(location, out var shopLoc)) + catch (Exception e1) { - Debug.Log($"collecting {shopLoc.LocationName} ({shopLoc.PrettyLocationName})"); + Debug.Log(e1); try { - var shopID = (EShopUpgradeID)Enum.Parse(typeof(EShopUpgradeID), shopLoc.LocationName); + var shopID = (EShopUpgradeID)Enum.Parse(typeof(EShopUpgradeID), + shopLoc.PrettyLocationName); Manager.Instance.SetShopUpgradeAsUnlocked(shopID); } - catch (Exception e1) + catch (Exception e2) { - Debug.Log(e1); - try - { - var shopID = (EShopUpgradeID)Enum.Parse(typeof(EShopUpgradeID), - shopLoc.PrettyLocationName); - Manager.Instance.SetShopUpgradeAsUnlocked(shopID); - } - catch (Exception e2) - { - Debug.Log(e2); - } + Debug.Log(e2); } } - else - { - RandoBossManager.TryCollectLocation(location); - } - - ServerData.CheckedLocations.Add(location); } - catch (Exception e) + else { - Console.WriteLine(e); - Console.WriteLine($"{Session.Locations.GetLocationNameFromId(location)}: {location}"); + RandoBossManager.TryCollectLocation(location); } - } - } - - public static void SyncEvents() - { - Console.WriteLine("Checking datastorage events"); - foreach (var cutscene in Session.DataStorage[Scope.Slot, "Events"].To>()) - { - Console.WriteLine(cutscene); - Manager.Instance.cutscenesPlayed.Add(cutscene); - } - } - private static void OnItemReceived(ReceivedItemsHelper helper) - { - var itemToUnlock = helper.DequeueItem(); - Console.WriteLine($"helper index: {helper.Index}"); - Console.WriteLine($"Saved index: {ServerData.Index}"); - if (helper.Index <= ServerData.Index) return; - - if (RandomizerStateManager.OnMainMenu) - { - OfflineReceivedItems++; + ServerData.CheckedLocations.Add(location); } - else + catch (Exception e) { - ServerData.Index++; + Console.WriteLine(e); + Console.WriteLine($"{Session.Locations.GetLocationNameFromId(location)}: {location}"); } - - ItemQueue.Enqueue(itemToUnlock.ItemId); - if (itemToUnlock.Player != Session.ConnectionInfo.Slot) - DialogQueue.Enqueue(itemToUnlock.ToReadableString()); } + } - private static void SessionErrorReceived(Exception e, string message) + public static void SyncEvents() + { + Console.WriteLine("Checking datastorage events"); + foreach (var cutscene in Session.DataStorage[Scope.Slot, "Events"].To>()) { - Console.WriteLine(message); - Console.WriteLine(e.GetBaseException().Message); + Console.WriteLine(cutscene); + Manager.Instance.cutscenesPlayed.Add(cutscene); } + } + + private static void OnItemReceived(ReceivedItemsHelper helper) + { + var itemToUnlock = helper.DequeueItem(); + Console.WriteLine($"helper index: {helper.Index}"); + Console.WriteLine($"Saved index: {ServerData.Index}"); + if (helper.Index <= ServerData.Index) return; - private static void SessionSocketClosed(string reason) + if (RandomizerStateManager.OnMainMenu) { - Console.WriteLine($"Connection to Archipelago lost: {reason}"); - Disconnect(); + OfflineReceivedItems++; } - - public static void Disconnect() + else { - Console.WriteLine("Disconnecting from server..."); - Session?.Socket.Disconnect(); - Session = null; - Authenticated = false; - attemptingConnection = false; - DialogQueue = new Queue(); - ItemQueue = new Queue(); - messageQueue = new Queue(); + ServerData.Index++; } - public static void UpdateArchipelagoState() - { - while (ItemQueue.Count > 0) - { - ItemsAndLocationsHandler.Unlock((long)ItemQueue.Dequeue()); - } + ItemQueue.Enqueue(itemToUnlock.ItemId); + if (itemToUnlock.Player != Session.ConnectionInfo.Slot) + DialogQueue.Enqueue(itemToUnlock.ToReadableString()); + } - if (DialogQueue.Count > 0) - { - var message = (string)DialogQueue.Dequeue(); - Console.WriteLine(message); - DialogChanger.CreateDialogBox(message); - } + private static void SessionErrorReceived(Exception e, string message) + { + Console.WriteLine(message); + Console.WriteLine(e.GetBaseException().Message); + } - TrapManager.UpdateTrapStatus(); - if (Offline) return; - if (!Authenticated) - { - Console.WriteLine("Attempting to reconnect to Archipelago Server..."); - ThreadPool.QueueUserWorkItem(_ => ConnectAsync()); - return; - } + private static void SessionSocketClosed(string reason) + { + Console.WriteLine($"Connection to Archipelago lost: {reason}"); + Disconnect(); + } - if (ServerData.Index < Session.Items.AllItemsReceived.Count) - { - ItemsAndLocationsHandler.UnlockItems(); - return; - } - if (!ItemsAndLocationsHandler.Synced) - ItemsAndLocationsHandler.ReSync(); + public static void Disconnect() + { + Console.WriteLine("Disconnecting from server..."); + Session?.Socket.Disconnect(); + Session = null; + Authenticated = false; + attemptingConnection = false; + DialogQueue = new Queue(); + ItemQueue = new Queue(); + messageQueue = new Queue(); + } + + public static void UpdateArchipelagoState() + { + while (ItemQueue.Count > 0) + { + ItemsAndLocationsHandler.Unlock((long)ItemQueue.Dequeue()); } - public static void UpdateClientStatus(ArchipelagoClientState newState) + if (DialogQueue.Count > 0) { - Console.WriteLine($"Updating client status to {newState}"); - var statusUpdatePacket = new StatusUpdatePacket { Status = newState }; - Session.Socket.SendPacket(statusUpdatePacket); + var message = (string)DialogQueue.Dequeue(); + Console.WriteLine(message); + DialogChanger.CreateDialogBox(message); } - private static bool ClientFinished() + TrapManager.UpdateTrapStatus(); + if (Offline) return; + if (!Authenticated) { - return Session.DataStorage.GetClientStatus() == ArchipelagoClientState.ClientGoal; + Console.WriteLine("Attempting to reconnect to Archipelago Server..."); + ThreadPool.QueueUserWorkItem(_ => ConnectAsync()); + return; } - public static bool CanRelease() + if (ServerData.Index < Session.Items.AllItemsReceived.Count) { - if (!Authenticated) return false; - try + ItemsAndLocationsHandler.UnlockItems(); + return; + } + if (!ItemsAndLocationsHandler.Synced) + ItemsAndLocationsHandler.ReSync(); + } + + public static void UpdateClientStatus(ArchipelagoClientState newState) + { + Console.WriteLine($"Updating client status to {newState}"); + var statusUpdatePacket = new StatusUpdatePacket { Status = newState }; + Session.Socket.SendPacket(statusUpdatePacket); + } + + private static bool ClientFinished() + { + return Session.DataStorage.GetClientStatus() == ArchipelagoClientState.ClientGoal; + } + + public static bool CanRelease() + { + if (!Authenticated) return false; + try + { + return Session.RoomState.ReleasePermissions switch { - return Session.RoomState.ReleasePermissions switch - { - Permissions.Goal => ClientFinished(), - Permissions.Enabled => true, - _ => false - }; - } - catch (Exception e) + Permissions.Goal => ClientFinished(), + Permissions.Enabled => true, + _ => false + }; + } + catch (Exception e) + { + if (e is ArchipelagoSocketClosedException) { - if (e is ArchipelagoSocketClosedException) - { - Disconnect(); - } - Debug.Log(e); - return false; + Disconnect(); } + Debug.Log(e); + return false; } + } - public static bool CanCollect() + public static bool CanCollect() + { + if (!Authenticated) return false; + try { - if (!Authenticated) return false; - try + return Session.RoomState.CollectPermissions switch { - return Session.RoomState.CollectPermissions switch - { - Permissions.Goal => ClientFinished(), - Permissions.Enabled => true, - _ => false - }; - } - catch (Exception e) + Permissions.Goal => ClientFinished(), + Permissions.Enabled => true, + _ => false + }; + } + catch (Exception e) + { + if (e is ArchipelagoSocketClosedException) { - if (e is ArchipelagoSocketClosedException) - { - Disconnect(); - } - Debug.Log(e); - return false; + Disconnect(); } + Debug.Log(e); + return false; } + } - private static int GetHintCost() - { - return Session.RoomState.HintCost; - } + private static int GetHintCost() + { + return Session.RoomState.HintCost; + } - public static bool CanHint() - { - return Authenticated && GetHintCost() <= Session.RoomState.HintPoints; - } + public static bool CanHint() + { + return Authenticated && GetHintCost() <= Session.RoomState.HintPoints; + } - public static string UpdateStatusText() - { - if (!roomUpdate) return statusText; - roomUpdate = false; - statusText = string.Empty; - if (!DisplayStatus) return statusText; - if (Authenticated) - { - statusText = $"Connected to Archipelago v{Session.RoomState.Version}"; - var hintCost = GetHintCost(); - if (hintCost > 0) - { - statusText += $"\nHint points available: {Session.RoomState.HintPoints}\nHint point cost: {hintCost}"; - } - } - else if (HasConnected) + public static string UpdateStatusText() + { + if (!roomUpdate) return statusText; + roomUpdate = false; + statusText = string.Empty; + if (!DisplayStatus) return statusText; + if (Authenticated) + { + statusText = $"Connected to Archipelago v{Session.RoomState.Version}"; + var hintCost = GetHintCost(); + if (hintCost > 0) { - statusText = "Disconnected from Archipelago server."; + statusText += $"\nHint points available: {Session.RoomState.HintPoints}\nHint point cost: {hintCost}"; } - return statusText; } - - public static string UpdateMessagesText() + else if (HasConnected) { - var text = string.Empty; - if (messageQueue.Count <= 0) return text; - if (DisplayAPMessages) - text = (string)messageQueue.Dequeue(); - return text; + statusText = "Disconnected from Archipelago server."; } + return statusText; + } - public static void SendSayPacket(string text) - { - Session.Say(text); - } + public static string UpdateMessagesText() + { + var text = string.Empty; + if (messageQueue.Count <= 0) return text; + if (DisplayAPMessages) + text = (string)messageQueue.Dequeue(); + return text; + } - public static void ClearMessages() - { - messageQueue = new Queue(); - DialogQueue = new Queue(); - } + public static void SendSayPacket(string text) + { + Session.Say(text); + } + + public static void ClearMessages() + { + messageQueue = new Queue(); + DialogQueue = new Queue(); } } diff --git a/Archipelago/ArchipelagoData.cs b/Archipelago/ArchipelagoData.cs index dff21ae..eec5d31 100644 --- a/Archipelago/ArchipelagoData.cs +++ b/Archipelago/ArchipelagoData.cs @@ -5,134 +5,133 @@ using MessengerRando.Utils; using Newtonsoft.Json; -namespace MessengerRando.Archipelago +namespace MessengerRando.Archipelago; + +public class ArchipelagoData { - public class ArchipelagoData - { - public string Uri = "archipelago.gg"; - public int Port = 38281; - public string SlotName = ""; - public string Password = ""; - public int Index; - public string SeedName = "Unknown"; - public Dictionary SlotData; - public static bool DeathLink = false; - public int PowerSealsCollected; - public List DefeatedBosses; - public List CheckedLocations; - public Dictionary ReceivedItems; - public Dictionary>> LocationData; - public List AvailableTeleports; + public string Uri = "archipelago.gg"; + public int Port = 38281; + public string SlotName = ""; + public string Password = ""; + public int Index; + public string SeedName = "Unknown"; + public Dictionary SlotData; + public static bool DeathLink = false; + public int PowerSealsCollected; + public List DefeatedBosses; + public List CheckedLocations; + public Dictionary ReceivedItems; + public Dictionary>> LocationData; + public List AvailableTeleports; - public void StartNewSeed() - { - Console.WriteLine("Creating new seed data"); - Index = ArchipelagoClient.OfflineReceivedItems; - PowerSealsCollected = 0; - DefeatedBosses = []; - CheckedLocations = []; - ReceivedItems = new Dictionary(); - AvailableTeleports = [false, false]; - } + public void StartNewSeed() + { + Console.WriteLine("Creating new seed data"); + Index = ArchipelagoClient.OfflineReceivedItems; + PowerSealsCollected = 0; + DefeatedBosses = []; + CheckedLocations = []; + ReceivedItems = new Dictionary(); + AvailableTeleports = [false, false]; + } - public override string ToString() - { - return JsonConvert.SerializeObject(this); - } + public override string ToString() + { + return JsonConvert.SerializeObject(this); + } - public static bool LoadData(int slot) - { - if (ArchipelagoClient.Offline) return false; - Console.WriteLine($"Loading Archipelago data for slot {slot}"); - ArchipelagoClient.ServerData ??= new ArchipelagoData(); - return ArchipelagoClient.ServerData.loadData(slot); - } + public static bool LoadData(int slot) + { + if (ArchipelagoClient.Offline) return false; + Console.WriteLine($"Loading Archipelago data for slot {slot}"); + ArchipelagoClient.ServerData ??= new ArchipelagoData(); + return ArchipelagoClient.ServerData.loadData(slot); + } - // ReSharper disable once InconsistentNaming - private bool loadData(int slot) + // ReSharper disable once InconsistentNaming + private bool loadData(int slot) + { + if (!RandomizerStateManager.Instance.APSave.TryGetValue(slot, out var tempServerData) || + tempServerData.SeedName == null || tempServerData.SeedName.Equals("Unknown")) + return false; + try { - if (!RandomizerStateManager.Instance.APSave.TryGetValue(slot, out var tempServerData) || - tempServerData.SeedName == null || tempServerData.SeedName.Equals("Unknown")) - return false; - try + var i = 0; + if (ArchipelagoClient.Authenticated) { - var i = 0; - if (ArchipelagoClient.Authenticated) + //we're already connected to an archipelago server, but have a save file, so disconnect to clean up + ArchipelagoClient.Disconnect(); + if (tempServerData.SeedName.Equals(SeedName) && tempServerData.SlotName.Equals(SlotName)) { - //we're already connected to an archipelago server, but have a save file, so disconnect to clean up - ArchipelagoClient.Disconnect(); - if (tempServerData.SeedName.Equals(SeedName) && tempServerData.SlotName.Equals(SlotName)) - { - //We're continuing an existing multiworld so likely a port change. Save the new data - Index = tempServerData.Index; - PowerSealsCollected = tempServerData.PowerSealsCollected; - CheckedLocations = tempServerData.CheckedLocations ?? []; - RandoBossManager.DefeatedBosses = DefeatedBosses = - tempServerData.DefeatedBosses ?? []; - ReceivedItems = tempServerData.ReceivedItems ?? []; - AvailableTeleports = tempServerData.AvailableTeleports ?? [false, false]; + //We're continuing an existing multiworld so likely a port change. Save the new data + Index = tempServerData.Index; + PowerSealsCollected = tempServerData.PowerSealsCollected; + CheckedLocations = tempServerData.CheckedLocations ?? []; + RandoBossManager.DefeatedBosses = DefeatedBosses = + tempServerData.DefeatedBosses ?? []; + ReceivedItems = tempServerData.ReceivedItems ?? []; + AvailableTeleports = tempServerData.AvailableTeleports ?? [false, false]; - ThreadPool.QueueUserWorkItem(_ => - ArchipelagoClient.Session.Locations.CompleteLocationChecksAsync(null, - CheckedLocations.ToArray())); - Console.WriteLine("connected from main menu, but continuing a seed."); - Console.WriteLine($"items in remote queue: {ArchipelagoClient.ItemQueue.Count}"); - Console.WriteLine($"saved index: {Index}"); - while (ArchipelagoClient.ItemQueue.Count > 0 && i < Index) - { - ArchipelagoClient.ItemQueue.Dequeue(); - i += 1; - } - - Console.WriteLine($"Setting index to {ArchipelagoClient.OfflineReceivedItems}"); - Index = ArchipelagoClient.OfflineReceivedItems; - RandomizerStateManager.OnMainMenu = false; - // reconnect - ArchipelagoClient.Connect(); - return true; + ThreadPool.QueueUserWorkItem(_ => + ArchipelagoClient.Session.Locations.CompleteLocationChecksAsync(null, + CheckedLocations.ToArray())); + Console.WriteLine("connected from main menu, but continuing a seed."); + Console.WriteLine($"items in remote queue: {ArchipelagoClient.ItemQueue.Count}"); + Console.WriteLine($"saved index: {Index}"); + while (ArchipelagoClient.ItemQueue.Count > 0 && i < Index) + { + ArchipelagoClient.ItemQueue.Dequeue(); + i += 1; } - //There was archipelago save data and it doesn't match our current connection so abort. - return ArchipelagoClient.HasConnected = false; - } - //We aren't connected to an Archipelago server so attempt to use the found data - Uri = tempServerData.Uri; - Port = tempServerData.Port; - SlotName = tempServerData.SlotName; - Password = tempServerData.Password; - SeedName = tempServerData.SeedName; - Index = tempServerData.Index; - Console.WriteLine($"saved index: {Index}"); - PowerSealsCollected = tempServerData.PowerSealsCollected; - CheckedLocations = tempServerData.CheckedLocations ?? []; - RandoBossManager.DefeatedBosses = DefeatedBosses = tempServerData.DefeatedBosses ?? []; - ReceivedItems = tempServerData.ReceivedItems ?? new Dictionary(); - SlotData = tempServerData.SlotData; - LocationData = tempServerData.LocationData; - AvailableTeleports = tempServerData.AvailableTeleports ?? [false, false]; - //Attempt to connect to the server and save the new data - Console.WriteLine("Rando save found!"); - if (Uri == "offline") - { - Console.WriteLine("continuing offline seed"); - RandomizerStateManager.InitializeSeed(); - return ArchipelagoClient.HasConnected = ArchipelagoClient.Offline = true; + Console.WriteLine($"Setting index to {ArchipelagoClient.OfflineReceivedItems}"); + Index = ArchipelagoClient.OfflineReceivedItems; + RandomizerStateManager.OnMainMenu = false; + // reconnect + ArchipelagoClient.Connect(); + return true; } + //There was archipelago save data and it doesn't match our current connection so abort. + return ArchipelagoClient.HasConnected = false; + } + //We aren't connected to an Archipelago server so attempt to use the found data + Uri = tempServerData.Uri; + Port = tempServerData.Port; + SlotName = tempServerData.SlotName; + Password = tempServerData.Password; + SeedName = tempServerData.SeedName; + Index = tempServerData.Index; + Console.WriteLine($"saved index: {Index}"); + PowerSealsCollected = tempServerData.PowerSealsCollected; + CheckedLocations = tempServerData.CheckedLocations ?? []; + RandoBossManager.DefeatedBosses = DefeatedBosses = tempServerData.DefeatedBosses ?? []; + ReceivedItems = tempServerData.ReceivedItems ?? new Dictionary(); + SlotData = tempServerData.SlotData; + LocationData = tempServerData.LocationData; + AvailableTeleports = tempServerData.AvailableTeleports ?? [false, false]; - RandomizerStateManager.OnMainMenu = false; - ArchipelagoClient.Connect(); - while (ArchipelagoClient.ItemQueue.Count > 0 && i < Index) - { - ArchipelagoClient.ItemQueue.Dequeue(); - i += 1; - } - return ArchipelagoClient.HasConnected = true; + //Attempt to connect to the server and save the new data + Console.WriteLine("Rando save found!"); + if (Uri == "offline") + { + Console.WriteLine("continuing offline seed"); + RandomizerStateManager.InitializeSeed(); + return ArchipelagoClient.HasConnected = ArchipelagoClient.Offline = true; } - catch (Exception ex) + + RandomizerStateManager.OnMainMenu = false; + ArchipelagoClient.Connect(); + while (ArchipelagoClient.ItemQueue.Count > 0 && i < Index) { - Console.WriteLine(ex.ToString()); - return false; + ArchipelagoClient.ItemQueue.Dequeue(); + i += 1; } + return ArchipelagoClient.HasConnected = true; + } + catch (Exception ex) + { + Console.WriteLine(ex.ToString()); + return false; } } } \ No newline at end of file diff --git a/Archipelago/DeathLinkInterface.cs b/Archipelago/DeathLinkInterface.cs index df08ef8..f238092 100644 --- a/Archipelago/DeathLinkInterface.cs +++ b/Archipelago/DeathLinkInterface.cs @@ -1,191 +1,190 @@ -using Archipelago.MultiClient.Net.BounceFeatures.DeathLink; -using System; +using System; using System.Collections.Generic; +using Archipelago.MultiClient.Net.BounceFeatures.DeathLink; using MessengerRando.Utils; using Mod.Courier; using UnityEngine; using WebSocketSharp; -namespace MessengerRando.Archipelago +namespace MessengerRando.Archipelago; + +public class DeathLinkInterface { - public class DeathLinkInterface + public DeathLinkService DeathLinkService; + public PlayerController Player; + private readonly List deathLinks = new List(); + private bool receivedDeath; + private int deathsSent; + private List genericDeathCauses; + private List projectileDeathCauses; + private List spikeDeathCauses; + private List pitfallDeathCauses; + private List squishDeathCauses; + private List frequentDeathCauses; + + public DeathLinkInterface() { - public DeathLinkService DeathLinkService; - public PlayerController Player; - private readonly List deathLinks = new List(); - private bool receivedDeath; - private int deathsSent; - private List genericDeathCauses; - private List projectileDeathCauses; - private List spikeDeathCauses; - private List pitfallDeathCauses; - private List squishDeathCauses; - private List frequentDeathCauses; + try + { + Console.WriteLine($"Initializing death link service... Should be set to {ArchipelagoData.DeathLink}"); + DeathLinkService = ArchipelagoClient.Session.CreateDeathLinkService(); + DeathLinkService.OnDeathLinkReceived += DeathLinkReceived; + GenerateFunnyCauses(); - public DeathLinkInterface() + if (ArchipelagoData.DeathLink) + DeathLinkService.EnableDeathLink(); + else + DeathLinkService.DisableDeathLink(); + } + catch (Exception e) { - try - { - Console.WriteLine($"Initializing death link service... Should be set to {ArchipelagoData.DeathLink}"); - DeathLinkService = ArchipelagoClient.Session.CreateDeathLinkService(); - DeathLinkService.OnDeathLinkReceived += DeathLinkReceived; - GenerateFunnyCauses(); - - if (ArchipelagoData.DeathLink) - DeathLinkService.EnableDeathLink(); - else - DeathLinkService.DisableDeathLink(); - } - catch (Exception e) - { - Console.WriteLine(e); - } + Console.WriteLine(e); } + } + + public void DeathLinkReceived(DeathLink deathLink) + { + receivedDeath = true; + deathLinks.Add(deathLink); + Console.WriteLine($"Received Death Link from: {deathLink.Source} due to {deathLink.Cause}"); + } - public void DeathLinkReceived(DeathLink deathLink) + public void KillPlayer() + { + try { - receivedDeath = true; - deathLinks.Add(deathLink); - Console.WriteLine($"Received Death Link from: {deathLink.Source} due to {deathLink.Cause}"); + if (deathLinks.Count > 0) receivedDeath = true; + if (!receivedDeath) return; + var cause = deathLinks[0].Cause; + if (cause.IsNullOrEmpty()) cause = $"{deathLinks[0].Source} sent you pain from afar."; + DialogSequence receivedDeathDialog = ScriptableObject.CreateInstance(); + receivedDeathDialog.dialogID = "DEATH_LINK"; + receivedDeathDialog.name = cause; + receivedDeathDialog.choices = new List(); + AwardItemPopupParams receivedDeathParams = new AwardItemPopupParams(receivedDeathDialog, false); + Manager.Instance.ShowView(EScreenLayers.PROMPT, receivedDeathParams); + Player.Kill(EDeathType.GENERIC, null); + deathLinks.RemoveAt(0); + receivedDeath = false; } - - public void KillPlayer() + catch (Exception e) { - try - { - if (deathLinks.Count > 0) receivedDeath = true; - if (!receivedDeath) return; - var cause = deathLinks[0].Cause; - if (cause.IsNullOrEmpty()) cause = $"{deathLinks[0].Source} sent you pain from afar."; - DialogSequence receivedDeathDialog = ScriptableObject.CreateInstance(); - receivedDeathDialog.dialogID = "DEATH_LINK"; - receivedDeathDialog.name = cause; - receivedDeathDialog.choices = new List(); - AwardItemPopupParams receivedDeathParams = new AwardItemPopupParams(receivedDeathDialog, false); - Manager.Instance.ShowView(EScreenLayers.PROMPT, receivedDeathParams); - Player.Kill(EDeathType.GENERIC, null); - deathLinks.RemoveAt(0); - receivedDeath = false; - } - catch (Exception e) - { - Console.WriteLine(e.ToString()); - } + Console.WriteLine(e.ToString()); } + } - public void SendDeathLink(EDeathType deathType, Transform killer) + public void SendDeathLink(EDeathType deathType, Transform killer) + { + try { - try - { - if (!ArchipelagoData.DeathLink || receivedDeath) return; - deathsSent++; - Console.WriteLine("Sharing death with your friends..."); - var alias = ArchipelagoClient.Session.Players.GetPlayerAliasAndName(ArchipelagoClient.Session.ConnectionInfo.Slot); - // Debug.Log(killer.GetType()); - var cause = GetDeathLinkCause(deathType); - DeathLinkService.SendDeathLink(new DeathLink(ArchipelagoClient.ServerData.SlotName, alias + cause)); - } - catch (Exception e) - { - Console.WriteLine($"Error: {e}"); - } + if (!ArchipelagoData.DeathLink || receivedDeath) return; + deathsSent++; + Console.WriteLine("Sharing death with your friends..."); + var alias = ArchipelagoClient.Session.Players.GetPlayerAliasAndName(ArchipelagoClient.Session.ConnectionInfo.Slot); + // Debug.Log(killer.GetType()); + var cause = GetDeathLinkCause(deathType); + DeathLinkService.SendDeathLink(new DeathLink(ArchipelagoClient.ServerData.SlotName, alias + cause)); } + catch (Exception e) + { + Console.WriteLine($"Error: {e}"); + } + } - private void GenerateFunnyCauses() + private void GenerateFunnyCauses() + { + genericDeathCauses = new List { - genericDeathCauses = new List - { - " dropped their message.", - " forgot to jump.", - " just wanted to see Quarble.", - " thought it was a simulation.", - " blames that on input delay.", - $" has had their life saved {deathsSent} times.", - " zigged when they should have zagged.", - " let Quarble win another bet.", - " wasn't able to get a selfie with Quarble.", - " meant to do that.", - " is playing with their feet.", - }; - - projectileDeathCauses = new List - { - " thought that was a health potion.", - " didn't dodge.", - " walked into that one.", - " forgot the 5 d's of dealing with projectiles.", - " visited the Shopkeeper, but they don't carry awareness upgrades.", - " forgot to tell the enemies not to shoot The Messenger.", - }; + " dropped their message.", + " forgot to jump.", + " just wanted to see Quarble.", + " thought it was a simulation.", + " blames that on input delay.", + $" has had their life saved {deathsSent} times.", + " zigged when they should have zagged.", + " let Quarble win another bet.", + " wasn't able to get a selfie with Quarble.", + " meant to do that.", + " is playing with their feet.", + }; - spikeDeathCauses = new List - { - " didn't avoid the spikes.", - " didn't watch their step.", - " lacks aichmophobia.", - " needs an item to reduce spike damage.", - " saved Quarble from a very boring dinner.", - }; + projectileDeathCauses = new List + { + " thought that was a health potion.", + " didn't dodge.", + " walked into that one.", + " forgot the 5 d's of dealing with projectiles.", + " visited the Shopkeeper, but they don't carry awareness upgrades.", + " forgot to tell the enemies not to shoot The Messenger.", + }; - pitfallDeathCauses = new List - { - " just fell in a pit.", - " definitely fell due to input lag.", - " thought that was a secret passage.", - " wanted to see how long until the death quotes loop.", - }; + spikeDeathCauses = new List + { + " didn't avoid the spikes.", + " didn't watch their step.", + " lacks aichmophobia.", + " needs an item to reduce spike damage.", + " saved Quarble from a very boring dinner.", + }; - squishDeathCauses = new List - { - " died in a painful way.", - " had to confirm that one.", - " wasn't forgiven by the moving blocks.", - " got crushed.", - " was pressed.", - }; + pitfallDeathCauses = new List + { + " just fell in a pit.", + " definitely fell due to input lag.", + " thought that was a secret passage.", + " wanted to see how long until the death quotes loop.", + }; - frequentDeathCauses = new List - { - " deserves a discount at this point.", - " won't give Quarble a break.", - " is considering the package offer.", - " is keeping Quarble busy.", - " is overheating Quarble's ring.", - " is letting Quarble do all the work.", - " is keeping Quarble from his family.", - }; - } + squishDeathCauses = new List + { + " died in a painful way.", + " had to confirm that one.", + " wasn't forgiven by the moving blocks.", + " got crushed.", + " was pressed.", + }; - private string GetDeathLinkCause(EDeathType deathType) + frequentDeathCauses = new List { - var random = RandomizerStateManager.SeedRandom; - try - { - switch (deathType) - { - case EDeathType.INTRO: - return " is a new customer!"; - case EDeathType.GENERIC: - return genericDeathCauses[random.Next(genericDeathCauses.Count)]; - case EDeathType.PROJECTILE: - return projectileDeathCauses[random.Next(projectileDeathCauses.Count)]; - case EDeathType.SPIKES: - return spikeDeathCauses[random.Next(spikeDeathCauses.Count)]; - case EDeathType.PITFALL: - return pitfallDeathCauses[random.Next(pitfallDeathCauses.Count)]; - case EDeathType.SQUISH: - return squishDeathCauses[random.Next(squishDeathCauses.Count)]; - case EDeathType.FREQUENT: - return frequentDeathCauses[random.Next(frequentDeathCauses.Count)]; - default: - throw new ArgumentOutOfRangeException(nameof(deathType)); - } - } - catch (Exception e) + " deserves a discount at this point.", + " won't give Quarble a break.", + " is considering the package offer.", + " is keeping Quarble busy.", + " is overheating Quarble's ring.", + " is letting Quarble do all the work.", + " is keeping Quarble from his family.", + }; + } + + private string GetDeathLinkCause(EDeathType deathType) + { + var random = RandomizerStateManager.SeedRandom; + try + { + switch (deathType) { - e.LogDetailed(); - return " is a menace"; + case EDeathType.INTRO: + return " is a new customer!"; + case EDeathType.GENERIC: + return genericDeathCauses[random.Next(genericDeathCauses.Count)]; + case EDeathType.PROJECTILE: + return projectileDeathCauses[random.Next(projectileDeathCauses.Count)]; + case EDeathType.SPIKES: + return spikeDeathCauses[random.Next(spikeDeathCauses.Count)]; + case EDeathType.PITFALL: + return pitfallDeathCauses[random.Next(pitfallDeathCauses.Count)]; + case EDeathType.SQUISH: + return squishDeathCauses[random.Next(squishDeathCauses.Count)]; + case EDeathType.FREQUENT: + return frequentDeathCauses[random.Next(frequentDeathCauses.Count)]; + default: + throw new ArgumentOutOfRangeException(nameof(deathType)); } } + catch (Exception e) + { + e.LogDetailed(); + return " is a menace"; + } } } diff --git a/Archipelago/ItemsAndLocationsHandler.cs b/Archipelago/ItemsAndLocationsHandler.cs index da36ef4..e1877b9 100644 --- a/Archipelago/ItemsAndLocationsHandler.cs +++ b/Archipelago/ItemsAndLocationsHandler.cs @@ -6,566 +6,565 @@ using MessengerRando.RO; using MessengerRando.Utils; -namespace MessengerRando.Archipelago -{ - public static class ItemsAndLocationsHandler - { - public static Dictionary ItemsLookup; - public static Dictionary LocationsLookup; - private static Dictionary EItemsLocationsLookup; - public static Dictionary IDtoLocationsLookup; +namespace MessengerRando.Archipelago; - public static RandomizerStateManager RandoStateManager; - public static SkylandsGeneratorManager SkylandsGeneratorManager; +public static class ItemsAndLocationsHandler +{ + public static Dictionary ItemsLookup; + public static Dictionary LocationsLookup; + private static Dictionary EItemsLocationsLookup; + public static Dictionary IDtoLocationsLookup; - public const int APQuantity = 69; - public const long BaseOffset = 0xADD_000; + public static RandomizerStateManager RandoStateManager; + public static SkylandsGeneratorManager SkylandsGeneratorManager; - public static bool Synced; - public static TrackerManager TrackerManager; + public const int APQuantity = 69; + public const long BaseOffset = 0xADD_000; - /// - /// Builds the item and lookup dictionaries for converting to and from AP checks. Will always make every location - /// a check, whether they are or not, for simplicity's sake. - /// - public static void Initialize() - { - - long offset = BaseOffset; - Console.WriteLine("Building ItemsLookup..."); - ItemsLookup = new Dictionary(); - foreach (var figurine in Enum.GetValues(typeof(EFigurine))) - ArchipelagoItems.Add(new RandoItemRO(figurine.ToString(), EItems.NONE)); - ArchipelagoItems.AddRange(new List - { - new RandoItemRO("Money Wrench", EItems.MONEY_WRENCH), - new RandoItemRO("Teleport Trap", EItems.NONE), - new RandoItemRO("Prophecy Trap", EItems.NONE), - new RandoItemRO("Progressive Generator Shutdown", EItems.NONE), - new RandoItemRO("Darkness Trap", EItems.NONE), - new RandoItemRO("Health", EItems.POTION), - new RandoItemRO("Mana", EItems.MANA), - new RandoItemRO("Feather", EItems.FEATHER), - new RandoItemRO("Mask Fragment", EItems.MASK_PIECE), - }); - - foreach (var item in ArchipelagoItems) - { - ItemsLookup.Add(offset, item); - // Console.WriteLine($"{item.Name}: {offset}"); - ++offset; - } + public static bool Synced; + public static TrackerManager TrackerManager; - offset = BaseOffset; - Console.WriteLine("Building LocationsLookup..."); - LocationsLookup = new Dictionary(); - EItemsLocationsLookup = new Dictionary(); - IDtoLocationsLookup = new Dictionary(); - - var megaShards = RandoTimeShardManager.MegaShardLookup.Select(item => item.Loc).ToList(); - ArchipelagoLocations.AddRange(megaShards); - ArchipelagoLocations.AddRange(BossLocations); - ArchipelagoLocations.AddRange(ShopLocations); - foreach (var figurine in Enum.GetValues(typeof(EFigurine))) - ArchipelagoLocations.Add(new LocationRO(figurine.ToString())); - ArchipelagoLocations.Add(new LocationRO("Money Wrench", EItems.MONEY_WRENCH)); - - ArchipelagoLocations.Add(new LocationRO("Elemental Skylands - Shutdown Air Generator")); - ArchipelagoLocations.Add(new LocationRO("Elemental Skylands - Shutdown Earth Generator")); - ArchipelagoLocations.Add(new LocationRO("Elemental Skylands - Shutdown Water Generator")); - ArchipelagoLocations.Add(new LocationRO("Elemental Skylands - Shutdown Fire Generator")); - - foreach (var progLocation in ArchipelagoLocations) - { - LocationsLookup.Add(progLocation, offset); - IDtoLocationsLookup.Add(offset, progLocation); - Console.WriteLine($"{progLocation.PrettyLocationName}: {offset}"); - if (progLocation.VanillaItem != EItems.NONE && - !EItemsLocationsLookup.ContainsKey(progLocation.VanillaItem)) - EItemsLocationsLookup.Add(progLocation.VanillaItem, offset); - ++offset; - } - } + /// + /// Builds the item and lookup dictionaries for converting to and from AP checks. Will always make every location + /// a check, whether they are or not, for simplicity's sake. + /// + public static void Initialize() + { - private static readonly List ArchipelagoItems = - [ - new RandoItemRO("Key_Of_Hope", EItems.KEY_OF_HOPE), - new RandoItemRO("Key_Of_Chaos", EItems.KEY_OF_CHAOS), - new RandoItemRO("Key_Of_Courage", EItems.KEY_OF_COURAGE), - new RandoItemRO("Key_Of_Love", EItems.KEY_OF_LOVE), - new RandoItemRO("Key_Of_Strength", EItems.KEY_OF_STRENGTH), - new RandoItemRO("Key_Of_Symbiosis", EItems.KEY_OF_SYMBIOSIS), - //upgrades - new RandoItemRO("Windmill_Shuriken", EItems.WINDMILL_SHURIKEN), - new RandoItemRO("Wingsuit", EItems.WINGSUIT), - new RandoItemRO("Rope_Dart", EItems.GRAPLOU), - new RandoItemRO("Ninja_Tabis", EItems.MAGIC_BOOTS), - //quest items - //new RandoItemRO("Astral_Seed", EItems.TEA_SEED), - //new RandoItemRO("Astral_Tea_Leaves", EItems.TEA_LEAVES), - new RandoItemRO("Candle", EItems.CANDLE), - new RandoItemRO("Seashell", EItems.SEASHELL), - new RandoItemRO("Power_Thistle", EItems.POWER_THISTLE), - new RandoItemRO("Demon_King_Crown", EItems.DEMON_KING_CROWN), - new RandoItemRO("Ruxxtin_Amulet", EItems.RUXXTIN_AMULET), - new RandoItemRO("Fairy_Bottle", EItems.FAIRY_BOTTLE), - new RandoItemRO("Sun_Crest", EItems.SUN_CREST), - new RandoItemRO("Moon_Crest", EItems.MOON_CREST), - //Phobekins - new RandoItemRO("Necro", EItems.NECROPHOBIC_WORKER), - new RandoItemRO("Pyro", EItems.PYROPHOBIC_WORKER), - new RandoItemRO("Claustro", EItems.CLAUSTROPHOBIC_WORKER), - new RandoItemRO("Acro", EItems.ACROPHOBIC_WORKER), - //Power seals - new RandoItemRO("PowerSeal", EItems.POWER_SEAL), - //time shards - new RandoItemRO("Timeshard", EItems.TIME_SHARD), - new RandoItemRO("Timeshard (10)", EItems.TIME_SHARD), - new RandoItemRO("Timeshard (50)", EItems.TIME_SHARD), - new RandoItemRO("Timeshard (100)", EItems.TIME_SHARD), - new RandoItemRO("Timeshard (300)", EItems.TIME_SHARD), - new RandoItemRO("Timeshard (500)", EItems.TIME_SHARD), - //shop items - new RandoItemRO("Karuta Plates", EItems.HEART_CONTAINER), - new RandoItemRO("Serendipitous Bodies", EItems.ENEMY_DROP_HP), - new RandoItemRO("Path of Resilience", EItems.DAMAGE_REDUCTION), - new RandoItemRO("Kusari Jacket", EItems.HEART_CONTAINER), - new RandoItemRO("Energy Shuriken", EItems.SHURIKEN), - new RandoItemRO("Serendipitous Minds", EItems.ENEMY_DROP_MANA), - new RandoItemRO("Prepared Mind", EItems.SHURIKEN_UPGRADE), - new RandoItemRO("Meditation", EItems.CHECKPOINT_UPGRADE), - new RandoItemRO("Rejuvenative Spirit", EItems.POTION_FULL_HEAL_AND_HP_UPGRADE), - new RandoItemRO("Centered Mind", EItems.SHURIKEN_UPGRADE), - new RandoItemRO("Strike of the Ninja", EItems.ATTACK_PROJECTILES), - new RandoItemRO("Second Wind", EItems.AIR_RECOVER), - new RandoItemRO("Currents Master", EItems.SWIM_DASH), - new RandoItemRO("Aerobatics Warrior", EItems.GLIDE_ATTACK), - new RandoItemRO("Demon's Bane", EItems.CHARGED_ATTACK), - new RandoItemRO("Devil's Due", EItems.QUARBLE_DISCOUNT_50), - new RandoItemRO("Time Sense", EItems.MAP_TIME_WARP), - new RandoItemRO("Power Sense", EItems.MAP_POWER_SEAL_TOTAL), - new RandoItemRO("Focused Power Sense", EItems.MAP_POWER_SEAL_PINS) - ]; - - public static readonly List ArchipelagoLocations = - [ - new LocationRO("Key_Of_Love", EItems.KEY_OF_LOVE), - new LocationRO("Key_Of_Courage", EItems.KEY_OF_COURAGE), - new LocationRO("Key_Of_Chaos", EItems.KEY_OF_CHAOS), - new LocationRO("Key_Of_Symbiosis", EItems.KEY_OF_SYMBIOSIS), - new LocationRO("Key_Of_Strength", EItems.KEY_OF_STRENGTH), - new LocationRO("Key_Of_Hope", EItems.KEY_OF_HOPE), - //upgrades - new LocationRO("Wingsuit", EItems.WINGSUIT), - new LocationRO("Rope_Dart", EItems.GRAPLOU), - new LocationRO("Ninja_Tabis", EItems.MAGIC_BOOTS), - new LocationRO("Climbing_Claws", EItems.CLIMBING_CLAWS), - //quest items - new LocationRO("Astral_Seed", EItems.TEA_SEED), - new LocationRO("Astral_Tea_Leaves", EItems.TEA_LEAVES), - new LocationRO("Candle", EItems.CANDLE), - new LocationRO("Seashell", EItems.SEASHELL), - new LocationRO("Power_Thistle", EItems.POWER_THISTLE), - new LocationRO("Demon_King_Crown", EItems.DEMON_KING_CROWN), - new LocationRO("Ruxxtin_Amulet", EItems.RUXXTIN_AMULET), - new LocationRO("Fairy_Bottle", EItems.FAIRY_BOTTLE), - new LocationRO("Sun_Crest", EItems.SUN_CREST), - new LocationRO("Moon_Crest", EItems.MOON_CREST), - //Phobekins - new LocationRO("Necro", EItems.NECROPHOBIC_WORKER), - new LocationRO("Pyro", EItems.PYROPHOBIC_WORKER), - new LocationRO("Claustro", EItems.CLAUSTROPHOBIC_WORKER), - new LocationRO("Acro", EItems.ACROPHOBIC_WORKER), - //power seals - //Ninja Village - new LocationRO("-436-404-44-28", "Ninja Village Seal - Tree House"), - //Autumn Hills - new LocationRO("-52-20-60-44", "Autumn Hills Seal - Trip Saws"), - new LocationRO("556588-44-28", "Autumn Hills Seal - Double Swing Saws"), - new LocationRO("748780-76-60", "Autumn Hills Seal - Spike Ball Swing"), - new LocationRO("748780-108-76", "Autumn Hills Seal - Spike Ball Darts"), - //Catacombs - new LocationRO("236268-44-28", "Catacombs Seal - Triple Spike Crushers"), - new LocationRO("492524-44-28", "Catacombs Seal - Crusher Gauntlet"), - new LocationRO("556588-60-44", "Catacombs Seal - Dirty Pond"), - //Bamboo Creek - new LocationRO("-84-52-28-12", "Bamboo Creek Seal - Spike Crushers and Doors"), - new LocationRO("172236-44-28", "Bamboo Creek Seal - Spike Ball Pits"), - new LocationRO("300332-1236", "Bamboo Creek Seal - Spike Crushers and Doors v2"), - //Howling Grotto - new LocationRO("108140-28-12", "Howling Grotto Seal - Windy Saws and Balls"), - new LocationRO("300332-92-76", "Howling Grotto Seal - Crushing Pits"), - new LocationRO("460492-172-156", "Howling Grotto Seal - Breezy Crushers"), - //Quillshroom Marsh - new LocationRO("204236-28-12", "Quillshroom Marsh Seal - Spikey Window"), - new LocationRO("652684-60-28", "Quillshroom Marsh Seal - Sand Trap"), - new LocationRO("940972-28-12", "Quillshroom Marsh Seal - Do the Spike Wave"), - //Searing Crags - new LocationRO("761085268", "Searing Crags Seal - Triple Ball Spinner"), - new LocationRO("300332196212", "Searing Crags Seal - Raining Rocks"), - new LocationRO("364396292308", "Searing Crags Seal - Rhythm Rocks"), - //Glacial Peak - new LocationRO("140172-492-476", "Glacial Peak Seal - Ice Climbers"), - new LocationRO("236268-396-380", "Glacial Peak Seal - Projectile Spike Pit"), - new LocationRO("236268-156-140", "Glacial Peak Seal - Glacial Air Swag"), - //Tower Of Time - new LocationRO("-84-522036", "Tower Of Time Seal - Time Waster Seal"), - new LocationRO("7610852116", "Tower Of Time Seal - Lantern Climb"), - new LocationRO("-52-20116132", "Tower Of Time Seal - Arcane Orbs"), - //Cloud Ruins - new LocationRO("-148-116420", "Cloud Ruins Seal - Ghost Pit"), - new LocationRO("108140-44-28", "Cloud Ruins Seal - Toothbrush Alley"), - new LocationRO("748780-44-28", "Cloud Ruins Seal - Saw Pit"), - new LocationRO("11321164-124", "Cloud Ruins Seal - Money Farm Room"), - //Underworld - new LocationRO("-276-244-444", "Underworld Seal - Sharp and Windy Climb"), - new LocationRO("-180-148-44-28", "Underworld Seal - Spike Wall"), - new LocationRO("-180-148-60-44", "Underworld Seal - Fireball Wave"), - new LocationRO("-2012-124", "Underworld Seal - Rising Fanta"), - //Forlorn Temple - new LocationRO("172268-284", "Forlorn Temple Seal - Rocket Maze"), - new LocationRO("140172100164", "Forlorn Temple Seal - Rocket Sunset"), - //Sunken Shrine - new LocationRO("204236-124", "Sunken Shrine Seal - Ultra Lifeguard"), - new LocationRO("172268-188-172", "Sunken Shrine Seal - Waterfall Paradise"), - new LocationRO("-148-116-124-60", "Sunken Shrine Seal - Tabi Gauntlet"), - //Riviere Turquoise - new LocationRO("844876-284", "Riviere Turquoise Seal - Bounces and Balls"), - new LocationRO("460492-124-108", "Riviere Turquoise Seal - Launch of Faith"), - new LocationRO("-180-1483668", "Riviere Turquoise Seal - Flower Power"), - //Elemental Skylands - new LocationRO("-52-20420436", "Elemental Skylands Seal - Air Seal"), - new LocationRO("18361868372388", "Elemental Skylands Seal - Water Seal"), - new LocationRO("28602892356388", "Elemental Skylands Seal - Fire Seal"), - ]; - - private static readonly List BossLocations = - [ - new LocationRO("LeafGolem"), - new LocationRO("Necromancer"), - new LocationRO("EmeraldGolem"), - new LocationRO("QueenOfQuills") - ]; - - private static readonly List ShopLocations = - [ - new LocationRO("HP_UPGRADE_1", EItems.HEART_CONTAINER), - new LocationRO("ENEMY_DROP_HP", EItems.ENEMY_DROP_HP), - new LocationRO("DAMAGE_REDUCTION", EItems.DAMAGE_REDUCTION), - new LocationRO("HP_UPGRADE_2", EItems.HEART_CONTAINER), - new LocationRO("SHURIKEN", EItems.SHURIKEN), - new LocationRO("ENEMY_DROP_MANA", EItems.ENEMY_DROP_MANA), - new LocationRO("SHURIKEN_UPGRADE_1", EItems.SHURIKEN_UPGRADE), - new LocationRO("CHECKPOINT_FULL", EItems.CHECKPOINT_UPGRADE), - new LocationRO("POTION_FULL_HEAL_AND_HP", EItems.POTION_FULL_HEAL_AND_HP_UPGRADE), - new LocationRO("SHURIKEN_UPGRADE_2", EItems.SHURIKEN_UPGRADE), - new LocationRO("ATTACK_PROJECTILE", EItems.ATTACK_PROJECTILES), - new LocationRO("AIR_RECOVER", EItems.AIR_RECOVER), - new LocationRO("SWIM_DASH", EItems.SWIM_DASH), - new LocationRO("GLIDE_ATTACK", EItems.GLIDE_ATTACK), - new LocationRO("CHARGED_ATTACK", EItems.CHARGED_ATTACK), - new LocationRO("QUARBLE_DISCOUNT_50", EItems.QUARBLE_DISCOUNT_50), - new LocationRO("TIME_WARP", EItems.MAP_TIME_WARP), - new LocationRO("POWER_SEAL_WORLD_MAP", EItems.MAP_POWER_SEAL_TOTAL), - new LocationRO("POWER_SEAL", EItems.MAP_POWER_SEAL_PINS) - ]; - - private static readonly Dictionary SpecialNames = new() + long offset = BaseOffset; + Console.WriteLine("Building ItemsLookup..."); + ItemsLookup = new Dictionary(); + foreach (var figurine in Enum.GetValues(typeof(EFigurine))) + ArchipelagoItems.Add(new RandoItemRO(figurine.ToString(), EItems.NONE)); + ArchipelagoItems.AddRange(new List { - { "HP_UPGRADE_1", "HP_UPGRADE_2" }, - { "SHURIKEN_UPGRADE_1", "SHURIKEN_UPGRADE_2" }, - }; - - private static bool ShopItem(EItems item) + new RandoItemRO("Money Wrench", EItems.MONEY_WRENCH), + new RandoItemRO("Teleport Trap", EItems.NONE), + new RandoItemRO("Prophecy Trap", EItems.NONE), + new RandoItemRO("Progressive Generator Shutdown", EItems.NONE), + new RandoItemRO("Darkness Trap", EItems.NONE), + new RandoItemRO("Health", EItems.POTION), + new RandoItemRO("Mana", EItems.MANA), + new RandoItemRO("Feather", EItems.FEATHER), + new RandoItemRO("Mask Fragment", EItems.MASK_PIECE), + }); + + foreach (var item in ArchipelagoItems) { - var shopItems = new List - { - EItems.HEART_CONTAINER, - EItems.SHURIKEN, - EItems.SHURIKEN_UPGRADE, - EItems.CHECKPOINT_UPGRADE, - EItems.POTION_FULL_HEAL_AND_HP_UPGRADE, - EItems.MAP_TIME_WARP, - EItems.MAP_POWER_SEAL_TOTAL, - EItems.MAP_POWER_SEAL_PINS, - }; - return shopItems.Contains(item); + ItemsLookup.Add(offset, item); + // Console.WriteLine($"{item.Name}: {offset}"); + ++offset; } - public static long ItemFromEItem(EItems item) + offset = BaseOffset; + Console.WriteLine("Building LocationsLookup..."); + LocationsLookup = new Dictionary(); + EItemsLocationsLookup = new Dictionary(); + IDtoLocationsLookup = new Dictionary(); + + var megaShards = RandoTimeShardManager.MegaShardLookup.Select(item => item.Loc).ToList(); + ArchipelagoLocations.AddRange(megaShards); + ArchipelagoLocations.AddRange(BossLocations); + ArchipelagoLocations.AddRange(ShopLocations); + foreach (var figurine in Enum.GetValues(typeof(EFigurine))) + ArchipelagoLocations.Add(new LocationRO(figurine.ToString())); + ArchipelagoLocations.Add(new LocationRO("Money Wrench", EItems.MONEY_WRENCH)); + + ArchipelagoLocations.Add(new LocationRO("Elemental Skylands - Shutdown Air Generator")); + ArchipelagoLocations.Add(new LocationRO("Elemental Skylands - Shutdown Earth Generator")); + ArchipelagoLocations.Add(new LocationRO("Elemental Skylands - Shutdown Water Generator")); + ArchipelagoLocations.Add(new LocationRO("Elemental Skylands - Shutdown Fire Generator")); + + foreach (var progLocation in ArchipelagoLocations) { - return ItemsLookup.First(x => x.Value.Equals(item)).Key; + LocationsLookup.Add(progLocation, offset); + IDtoLocationsLookup.Add(offset, progLocation); + Console.WriteLine($"{progLocation.PrettyLocationName}: {offset}"); + if (progLocation.VanillaItem != EItems.NONE && + !EItemsLocationsLookup.ContainsKey(progLocation.VanillaItem)) + EItemsLocationsLookup.Add(progLocation.VanillaItem, offset); + ++offset; } + } + + private static readonly List ArchipelagoItems = + [ + new RandoItemRO("Key_Of_Hope", EItems.KEY_OF_HOPE), + new RandoItemRO("Key_Of_Chaos", EItems.KEY_OF_CHAOS), + new RandoItemRO("Key_Of_Courage", EItems.KEY_OF_COURAGE), + new RandoItemRO("Key_Of_Love", EItems.KEY_OF_LOVE), + new RandoItemRO("Key_Of_Strength", EItems.KEY_OF_STRENGTH), + new RandoItemRO("Key_Of_Symbiosis", EItems.KEY_OF_SYMBIOSIS), + //upgrades + new RandoItemRO("Windmill_Shuriken", EItems.WINDMILL_SHURIKEN), + new RandoItemRO("Wingsuit", EItems.WINGSUIT), + new RandoItemRO("Rope_Dart", EItems.GRAPLOU), + new RandoItemRO("Ninja_Tabis", EItems.MAGIC_BOOTS), + //quest items + //new RandoItemRO("Astral_Seed", EItems.TEA_SEED), + //new RandoItemRO("Astral_Tea_Leaves", EItems.TEA_LEAVES), + new RandoItemRO("Candle", EItems.CANDLE), + new RandoItemRO("Seashell", EItems.SEASHELL), + new RandoItemRO("Power_Thistle", EItems.POWER_THISTLE), + new RandoItemRO("Demon_King_Crown", EItems.DEMON_KING_CROWN), + new RandoItemRO("Ruxxtin_Amulet", EItems.RUXXTIN_AMULET), + new RandoItemRO("Fairy_Bottle", EItems.FAIRY_BOTTLE), + new RandoItemRO("Sun_Crest", EItems.SUN_CREST), + new RandoItemRO("Moon_Crest", EItems.MOON_CREST), + //Phobekins + new RandoItemRO("Necro", EItems.NECROPHOBIC_WORKER), + new RandoItemRO("Pyro", EItems.PYROPHOBIC_WORKER), + new RandoItemRO("Claustro", EItems.CLAUSTROPHOBIC_WORKER), + new RandoItemRO("Acro", EItems.ACROPHOBIC_WORKER), + //Power seals + new RandoItemRO("PowerSeal", EItems.POWER_SEAL), + //time shards + new RandoItemRO("Timeshard", EItems.TIME_SHARD), + new RandoItemRO("Timeshard (10)", EItems.TIME_SHARD), + new RandoItemRO("Timeshard (50)", EItems.TIME_SHARD), + new RandoItemRO("Timeshard (100)", EItems.TIME_SHARD), + new RandoItemRO("Timeshard (300)", EItems.TIME_SHARD), + new RandoItemRO("Timeshard (500)", EItems.TIME_SHARD), + //shop items + new RandoItemRO("Karuta Plates", EItems.HEART_CONTAINER), + new RandoItemRO("Serendipitous Bodies", EItems.ENEMY_DROP_HP), + new RandoItemRO("Path of Resilience", EItems.DAMAGE_REDUCTION), + new RandoItemRO("Kusari Jacket", EItems.HEART_CONTAINER), + new RandoItemRO("Energy Shuriken", EItems.SHURIKEN), + new RandoItemRO("Serendipitous Minds", EItems.ENEMY_DROP_MANA), + new RandoItemRO("Prepared Mind", EItems.SHURIKEN_UPGRADE), + new RandoItemRO("Meditation", EItems.CHECKPOINT_UPGRADE), + new RandoItemRO("Rejuvenative Spirit", EItems.POTION_FULL_HEAL_AND_HP_UPGRADE), + new RandoItemRO("Centered Mind", EItems.SHURIKEN_UPGRADE), + new RandoItemRO("Strike of the Ninja", EItems.ATTACK_PROJECTILES), + new RandoItemRO("Second Wind", EItems.AIR_RECOVER), + new RandoItemRO("Currents Master", EItems.SWIM_DASH), + new RandoItemRO("Aerobatics Warrior", EItems.GLIDE_ATTACK), + new RandoItemRO("Demon's Bane", EItems.CHARGED_ATTACK), + new RandoItemRO("Devil's Due", EItems.QUARBLE_DISCOUNT_50), + new RandoItemRO("Time Sense", EItems.MAP_TIME_WARP), + new RandoItemRO("Power Sense", EItems.MAP_POWER_SEAL_TOTAL), + new RandoItemRO("Focused Power Sense", EItems.MAP_POWER_SEAL_PINS) + ]; + + public static readonly List ArchipelagoLocations = + [ + new LocationRO("Key_Of_Love", EItems.KEY_OF_LOVE), + new LocationRO("Key_Of_Courage", EItems.KEY_OF_COURAGE), + new LocationRO("Key_Of_Chaos", EItems.KEY_OF_CHAOS), + new LocationRO("Key_Of_Symbiosis", EItems.KEY_OF_SYMBIOSIS), + new LocationRO("Key_Of_Strength", EItems.KEY_OF_STRENGTH), + new LocationRO("Key_Of_Hope", EItems.KEY_OF_HOPE), + //upgrades + new LocationRO("Wingsuit", EItems.WINGSUIT), + new LocationRO("Rope_Dart", EItems.GRAPLOU), + new LocationRO("Ninja_Tabis", EItems.MAGIC_BOOTS), + new LocationRO("Climbing_Claws", EItems.CLIMBING_CLAWS), + //quest items + new LocationRO("Astral_Seed", EItems.TEA_SEED), + new LocationRO("Astral_Tea_Leaves", EItems.TEA_LEAVES), + new LocationRO("Candle", EItems.CANDLE), + new LocationRO("Seashell", EItems.SEASHELL), + new LocationRO("Power_Thistle", EItems.POWER_THISTLE), + new LocationRO("Demon_King_Crown", EItems.DEMON_KING_CROWN), + new LocationRO("Ruxxtin_Amulet", EItems.RUXXTIN_AMULET), + new LocationRO("Fairy_Bottle", EItems.FAIRY_BOTTLE), + new LocationRO("Sun_Crest", EItems.SUN_CREST), + new LocationRO("Moon_Crest", EItems.MOON_CREST), + //Phobekins + new LocationRO("Necro", EItems.NECROPHOBIC_WORKER), + new LocationRO("Pyro", EItems.PYROPHOBIC_WORKER), + new LocationRO("Claustro", EItems.CLAUSTROPHOBIC_WORKER), + new LocationRO("Acro", EItems.ACROPHOBIC_WORKER), + //power seals + //Ninja Village + new LocationRO("-436-404-44-28", "Ninja Village Seal - Tree House"), + //Autumn Hills + new LocationRO("-52-20-60-44", "Autumn Hills Seal - Trip Saws"), + new LocationRO("556588-44-28", "Autumn Hills Seal - Double Swing Saws"), + new LocationRO("748780-76-60", "Autumn Hills Seal - Spike Ball Swing"), + new LocationRO("748780-108-76", "Autumn Hills Seal - Spike Ball Darts"), + //Catacombs + new LocationRO("236268-44-28", "Catacombs Seal - Triple Spike Crushers"), + new LocationRO("492524-44-28", "Catacombs Seal - Crusher Gauntlet"), + new LocationRO("556588-60-44", "Catacombs Seal - Dirty Pond"), + //Bamboo Creek + new LocationRO("-84-52-28-12", "Bamboo Creek Seal - Spike Crushers and Doors"), + new LocationRO("172236-44-28", "Bamboo Creek Seal - Spike Ball Pits"), + new LocationRO("300332-1236", "Bamboo Creek Seal - Spike Crushers and Doors v2"), + //Howling Grotto + new LocationRO("108140-28-12", "Howling Grotto Seal - Windy Saws and Balls"), + new LocationRO("300332-92-76", "Howling Grotto Seal - Crushing Pits"), + new LocationRO("460492-172-156", "Howling Grotto Seal - Breezy Crushers"), + //Quillshroom Marsh + new LocationRO("204236-28-12", "Quillshroom Marsh Seal - Spikey Window"), + new LocationRO("652684-60-28", "Quillshroom Marsh Seal - Sand Trap"), + new LocationRO("940972-28-12", "Quillshroom Marsh Seal - Do the Spike Wave"), + //Searing Crags + new LocationRO("761085268", "Searing Crags Seal - Triple Ball Spinner"), + new LocationRO("300332196212", "Searing Crags Seal - Raining Rocks"), + new LocationRO("364396292308", "Searing Crags Seal - Rhythm Rocks"), + //Glacial Peak + new LocationRO("140172-492-476", "Glacial Peak Seal - Ice Climbers"), + new LocationRO("236268-396-380", "Glacial Peak Seal - Projectile Spike Pit"), + new LocationRO("236268-156-140", "Glacial Peak Seal - Glacial Air Swag"), + //Tower Of Time + new LocationRO("-84-522036", "Tower Of Time Seal - Time Waster Seal"), + new LocationRO("7610852116", "Tower Of Time Seal - Lantern Climb"), + new LocationRO("-52-20116132", "Tower Of Time Seal - Arcane Orbs"), + //Cloud Ruins + new LocationRO("-148-116420", "Cloud Ruins Seal - Ghost Pit"), + new LocationRO("108140-44-28", "Cloud Ruins Seal - Toothbrush Alley"), + new LocationRO("748780-44-28", "Cloud Ruins Seal - Saw Pit"), + new LocationRO("11321164-124", "Cloud Ruins Seal - Money Farm Room"), + //Underworld + new LocationRO("-276-244-444", "Underworld Seal - Sharp and Windy Climb"), + new LocationRO("-180-148-44-28", "Underworld Seal - Spike Wall"), + new LocationRO("-180-148-60-44", "Underworld Seal - Fireball Wave"), + new LocationRO("-2012-124", "Underworld Seal - Rising Fanta"), + //Forlorn Temple + new LocationRO("172268-284", "Forlorn Temple Seal - Rocket Maze"), + new LocationRO("140172100164", "Forlorn Temple Seal - Rocket Sunset"), + //Sunken Shrine + new LocationRO("204236-124", "Sunken Shrine Seal - Ultra Lifeguard"), + new LocationRO("172268-188-172", "Sunken Shrine Seal - Waterfall Paradise"), + new LocationRO("-148-116-124-60", "Sunken Shrine Seal - Tabi Gauntlet"), + //Riviere Turquoise + new LocationRO("844876-284", "Riviere Turquoise Seal - Bounces and Balls"), + new LocationRO("460492-124-108", "Riviere Turquoise Seal - Launch of Faith"), + new LocationRO("-180-1483668", "Riviere Turquoise Seal - Flower Power"), + //Elemental Skylands + new LocationRO("-52-20420436", "Elemental Skylands Seal - Air Seal"), + new LocationRO("18361868372388", "Elemental Skylands Seal - Water Seal"), + new LocationRO("28602892356388", "Elemental Skylands Seal - Fire Seal"), + ]; + + private static readonly List BossLocations = + [ + new LocationRO("LeafGolem"), + new LocationRO("Necromancer"), + new LocationRO("EmeraldGolem"), + new LocationRO("QueenOfQuills") + ]; + + private static readonly List ShopLocations = + [ + new LocationRO("HP_UPGRADE_1", EItems.HEART_CONTAINER), + new LocationRO("ENEMY_DROP_HP", EItems.ENEMY_DROP_HP), + new LocationRO("DAMAGE_REDUCTION", EItems.DAMAGE_REDUCTION), + new LocationRO("HP_UPGRADE_2", EItems.HEART_CONTAINER), + new LocationRO("SHURIKEN", EItems.SHURIKEN), + new LocationRO("ENEMY_DROP_MANA", EItems.ENEMY_DROP_MANA), + new LocationRO("SHURIKEN_UPGRADE_1", EItems.SHURIKEN_UPGRADE), + new LocationRO("CHECKPOINT_FULL", EItems.CHECKPOINT_UPGRADE), + new LocationRO("POTION_FULL_HEAL_AND_HP", EItems.POTION_FULL_HEAL_AND_HP_UPGRADE), + new LocationRO("SHURIKEN_UPGRADE_2", EItems.SHURIKEN_UPGRADE), + new LocationRO("ATTACK_PROJECTILE", EItems.ATTACK_PROJECTILES), + new LocationRO("AIR_RECOVER", EItems.AIR_RECOVER), + new LocationRO("SWIM_DASH", EItems.SWIM_DASH), + new LocationRO("GLIDE_ATTACK", EItems.GLIDE_ATTACK), + new LocationRO("CHARGED_ATTACK", EItems.CHARGED_ATTACK), + new LocationRO("QUARBLE_DISCOUNT_50", EItems.QUARBLE_DISCOUNT_50), + new LocationRO("TIME_WARP", EItems.MAP_TIME_WARP), + new LocationRO("POWER_SEAL_WORLD_MAP", EItems.MAP_POWER_SEAL_TOTAL), + new LocationRO("POWER_SEAL", EItems.MAP_POWER_SEAL_PINS) + ]; + + private static readonly Dictionary SpecialNames = new() + { + { "HP_UPGRADE_1", "HP_UPGRADE_2" }, + { "SHURIKEN_UPGRADE_1", "SHURIKEN_UPGRADE_2" }, + }; - public static long LocationFromEItem(EItems location) + private static bool ShopItem(EItems item) + { + var shopItems = new List { - if (EItemsLocationsLookup == null) - Initialize(); - return !EItemsLocationsLookup.TryGetValue(location, out var value) ? 0 : value; - } + EItems.HEART_CONTAINER, + EItems.SHURIKEN, + EItems.SHURIKEN_UPGRADE, + EItems.CHECKPOINT_UPGRADE, + EItems.POTION_FULL_HEAL_AND_HP_UPGRADE, + EItems.MAP_TIME_WARP, + EItems.MAP_POWER_SEAL_TOTAL, + EItems.MAP_POWER_SEAL_PINS, + }; + return shopItems.Contains(item); + } + + public static long ItemFromEItem(EItems item) + { + return ItemsLookup.First(x => x.Value.Equals(item)).Key; + } + + public static long LocationFromEItem(EItems location) + { + if (EItemsLocationsLookup == null) + Initialize(); + return !EItemsLocationsLookup.TryGetValue(location, out var value) ? 0 : value; + } - public static bool ShopLocation(long locationID, out LocationRO shopLocation) + public static bool ShopLocation(long locationID, out LocationRO shopLocation) + { + shopLocation = LocationFromID(locationID); + return ShopLocations.Contains(shopLocation); + } + + private static LocationRO LocationFromID(long locationID) + { + return IDtoLocationsLookup[locationID]; + } + + public static bool HasDialog(long locationID) + { + Console.WriteLine($"Checking if {locationID} has associated dialog"); + if (!IDtoLocationsLookup.ContainsKey(locationID)) return false; + var location = LocationFromID(locationID).PrettyLocationName; + try { - shopLocation = LocationFromID(locationID); - return ShopLocations.Contains(shopLocation); + var locationEnum = (EItems)Enum.Parse(typeof(EItems), location); + Console.WriteLine($"{locationEnum}"); + return DialogChanger.ItemDialogID.ContainsKey(locationEnum); } - - private static LocationRO LocationFromID(long locationID) + catch { - return IDtoLocationsLookup[locationID]; + return false; } + } - public static bool HasDialog(long locationID) + /// + /// We received an item from the server so add it to our inventory. Set the quantity to an absurd number here so we can differentiate. + /// + /// + /// + public static void Unlock(long itemToUnlock, int quantity = APQuantity) + { + if (!ItemsLookup.TryGetValue(itemToUnlock, out var randoItem) || RandoStateManager.CurrentFileSlot == 0) { - Console.WriteLine($"Checking if {locationID} has associated dialog"); - if (!IDtoLocationsLookup.ContainsKey(locationID)) return false; - var location = LocationFromID(locationID).PrettyLocationName; - try - { - var locationEnum = (EItems)Enum.Parse(typeof(EItems), location); - Console.WriteLine($"{locationEnum}"); - return DialogChanger.ItemDialogID.ContainsKey(locationEnum); - } - catch - { - return false; - } + Console.WriteLine($"Couldn't find {itemToUnlock} or not currently in game"); + return; } + Console.WriteLine($"Unlocking {itemToUnlock}, {randoItem.Item}"); - /// - /// We received an item from the server so add it to our inventory. Set the quantity to an absurd number here so we can differentiate. - /// - /// - /// - public static void Unlock(long itemToUnlock, int quantity = APQuantity) + switch (randoItem.Item) { - if (!ItemsLookup.TryGetValue(itemToUnlock, out var randoItem) || RandoStateManager.CurrentFileSlot == 0) - { - Console.WriteLine($"Couldn't find {itemToUnlock} or not currently in game"); - return; - } - Console.WriteLine($"Unlocking {itemToUnlock}, {randoItem.Item}"); - - switch (randoItem.Item) - { - case EItems.WINDMILL_SHURIKEN: - var shurikenID = ItemFromEItem(EItems.SHURIKEN); - if (!ArchipelagoClient.ServerData.ReceivedItems.ContainsKey(shurikenID)) + case EItems.WINDMILL_SHURIKEN: + var shurikenID = ItemFromEItem(EItems.SHURIKEN); + if (!ArchipelagoClient.ServerData.ReceivedItems.ContainsKey(shurikenID)) + { + Manager.Instance.AddItem(EItems.SHURIKEN, APQuantity); + } + APRandomizerMain.OnToggleWindmillShuriken(); + break; + case EItems.TIME_SHARD: + switch (randoItem.Name) + { + case "Timeshard": + quantity = ArchipelagoClient.ServerData.SlotData.ContainsKey("shop") ? 1 : 100; + break; + case "Timeshard (10)": + quantity = 10; + break; + case "Timeshard (50)": + quantity = 50; + break; + case "Timeshard (100)": + quantity = 100; + break; + case "Timeshard (300)": + quantity = 300; + break; + case "Timeshard (500)": + quantity = 500; + break; + } + Console.WriteLine($"Unlocking time shards... {quantity}"); + Manager.Instance.CollectTimeShard(quantity); + break; + case EItems.POWER_SEAL: + RandoStateManager.PowerSealManager.AddPowerSeal(); + break; + case EItems.NONE: + try + { + var figurine = (EFigurine)Enum.Parse(typeof(EFigurine), randoItem.Name); + RandoShopManager.UnlockFigurine(figurine); + } + catch + { + if (randoItem.Name.EndsWith("Generator Shutdown")) { - Manager.Instance.AddItem(EItems.SHURIKEN, APQuantity); + SkylandsGeneratorManager.ReceiveGeneratorShutdown(randoItem.Name); + break; } - APRandomizerMain.OnToggleWindmillShuriken(); - break; - case EItems.TIME_SHARD: switch (randoItem.Name) { - case "Timeshard": - quantity = ArchipelagoClient.ServerData.SlotData.ContainsKey("shop") ? 1 : 100; - break; - case "Timeshard (10)": - quantity = 10; - break; - case "Timeshard (50)": - quantity = 50; - break; - case "Timeshard (100)": - quantity = 100; + case "Darkness Trap": + TrapManager.StartDarkness(); break; - case "Timeshard (300)": - quantity = 300; + case "Teleport Trap": + TrapManager.TryTeleportPlayer(); break; - case "Timeshard (500)": - quantity = 500; + case "Prophecy Trap": + TrapManager.StartProphecyCutscene(); break; } - Console.WriteLine($"Unlocking time shards... {quantity}"); - Manager.Instance.CollectTimeShard(quantity); - break; - case EItems.POWER_SEAL: - RandoStateManager.PowerSealManager.AddPowerSeal(); - break; - case EItems.NONE: - try - { - var figurine = (EFigurine)Enum.Parse(typeof(EFigurine), randoItem.Name); - RandoShopManager.UnlockFigurine(figurine); - } - catch - { - if (randoItem.Name.EndsWith("Generator Shutdown")) - { - SkylandsGeneratorManager.ReceiveGeneratorShutdown(randoItem.Name); - break; - } - switch (randoItem.Name) - { - case "Darkness Trap": - TrapManager.StartDarkness(); - break; - case "Teleport Trap": - TrapManager.TryTeleportPlayer(); - break; - case "Prophecy Trap": - TrapManager.StartProphecyCutscene(); - break; - } - } + } - break; - default: - Console.WriteLine($"Checking if {randoItem.Item} is a shop item: {ShopItem(randoItem.Item)}"); - if (ShopItem(randoItem.Item)) + break; + default: + Console.WriteLine($"Checking if {randoItem.Item} is a shop item: {ShopItem(randoItem.Item)}"); + if (ShopItem(randoItem.Item)) + { + // don't award shuriken twice if we already got it from windmill shuriken + if (randoItem.Item.Equals(EItems.SHURIKEN) & + ArchipelagoClient.ServerData.ReceivedItems.ContainsKey(itemToUnlock)) return; + if (!new List { EItems.HEART_CONTAINER, EItems.SHURIKEN_UPGRADE }.Contains( + randoItem.Item)) { - // don't award shuriken twice if we already got it from windmill shuriken - if (randoItem.Item.Equals(EItems.SHURIKEN) & - ArchipelagoClient.ServerData.ReceivedItems.ContainsKey(itemToUnlock)) return; - if (!new List { EItems.HEART_CONTAINER, EItems.SHURIKEN_UPGRADE }.Contains( - randoItem.Item)) + Console.WriteLine($"checking if {itemToUnlock} has been received already"); + if (ArchipelagoClient.ServerData.ReceivedItems.ContainsKey(itemToUnlock)) { - Console.WriteLine($"checking if {itemToUnlock} has been received already"); - if (ArchipelagoClient.ServerData.ReceivedItems.ContainsKey(itemToUnlock)) - { - Console.WriteLine("bailing"); - return; - } + Console.WriteLine("bailing"); + return; } - else if (ArchipelagoClient.ServerData.ReceivedItems.TryGetValue(itemToUnlock, out var count) && - count > 1) return; - Manager.Instance.AddItem(randoItem.Item, quantity); - var view = Manager.Instance.GetView(); - view.UpdateMaxHeart(); - view.UpdateMaxMana(); - view.UpdateShurikenVisibility(); } - else if (!ArchipelagoClient.ServerData.ReceivedItems.ContainsKey(itemToUnlock)) - Manager.Instance.AddItem(randoItem.Item, quantity); - break; - } - - if (ArchipelagoClient.ServerData.ReceivedItems.ContainsKey(itemToUnlock)) - ArchipelagoClient.ServerData.ReceivedItems[itemToUnlock] += 1; - else - ArchipelagoClient.ServerData.ReceivedItems.Add(itemToUnlock, 1); + else if (ArchipelagoClient.ServerData.ReceivedItems.TryGetValue(itemToUnlock, out var count) && + count > 1) return; + Manager.Instance.AddItem(randoItem.Item, quantity); + var view = Manager.Instance.GetView(); + view.UpdateMaxHeart(); + view.UpdateMaxMana(); + view.UpdateShurikenVisibility(); + } + else if (!ArchipelagoClient.ServerData.ReceivedItems.ContainsKey(itemToUnlock)) + Manager.Instance.AddItem(randoItem.Item, quantity); + break; } - public static bool IsLocationChecked(LocationRO location) + if (ArchipelagoClient.ServerData.ReceivedItems.ContainsKey(itemToUnlock)) + ArchipelagoClient.ServerData.ReceivedItems[itemToUnlock] += 1; + else + ArchipelagoClient.ServerData.ReceivedItems.Add(itemToUnlock, 1); + } + + public static bool IsLocationChecked(LocationRO location) + { + LocationsLookup.TryGetValue(location, out var locationID); + return RandomizerStateManager.HasCompletedCheck(locationID); + } + + public static void SendLocationCheck(LocationRO checkedLocation) + { + LocationsLookup.TryGetValue(checkedLocation, out var locationID); + if (ArchipelagoClient.ServerData.CheckedLocations.Contains(locationID)) return; + try { - LocationsLookup.TryGetValue(location, out var locationID); - return RandomizerStateManager.HasCompletedCheck(locationID); + SendLocationCheck(locationID); } + catch (Exception e) + { + Console.WriteLine(e); + ArchipelagoClient.Disconnect(); + } + } - public static void SendLocationCheck(LocationRO checkedLocation) + public static void SendLocationCheck(long locationID) + { + if (!LocationsLookup.Values.Contains(locationID)) return; + Console.WriteLine($"Checking if we need to modify the location {locationID} before sending"); + if (ArchipelagoClient.ServerData.CheckedLocations.Contains(locationID)) { - LocationsLookup.TryGetValue(checkedLocation, out var locationID); - if (ArchipelagoClient.ServerData.CheckedLocations.Contains(locationID)) return; - try + var loc = LocationFromID(locationID); + if (SpecialNames.TryGetValue(loc.LocationName, out var name)) { - SendLocationCheck(locationID); - } - catch (Exception e) - { - Console.WriteLine(e); - ArchipelagoClient.Disconnect(); + LocationsLookup.TryGetValue(new LocationRO(name, + (EItems)Enum.Parse(typeof(EItems), loc.PrettyLocationName)), out locationID); } + else return; } + ArchipelagoClient.ServerData.CheckedLocations.Add(locationID); - public static void SendLocationCheck(long locationID) + Console.WriteLine("Sending location checks"); + if (ArchipelagoClient.Authenticated) { - if (!LocationsLookup.Values.Contains(locationID)) return; - Console.WriteLine($"Checking if we need to modify the location {locationID} before sending"); - if (ArchipelagoClient.ServerData.CheckedLocations.Contains(locationID)) + ThreadPool.QueueUserWorkItem(_ => + ArchipelagoClient.Session.Locations.CompleteLocationChecksAsync(null, + ArchipelagoClient.ServerData.CheckedLocations.ToArray())); + if (!RandoStateManager.ScoutedLocations.TryGetValue(locationID, out var item)) return; + if (!HasDialog(locationID)) { - var loc = LocationFromID(locationID); - if (SpecialNames.TryGetValue(loc.LocationName, out var name)) + string dialog; + if (item.OwnItem()) { - LocationsLookup.TryGetValue(new LocationRO(name, - (EItems)Enum.Parse(typeof(EItems), loc.PrettyLocationName)), out locationID); + dialog = item.ToReadableString(); } - else return; - } - ArchipelagoClient.ServerData.CheckedLocations.Add(locationID); - - Console.WriteLine("Sending location checks"); - if (ArchipelagoClient.Authenticated) - { - ThreadPool.QueueUserWorkItem(_ => - ArchipelagoClient.Session.Locations.CompleteLocationChecksAsync(null, - ArchipelagoClient.ServerData.CheckedLocations.ToArray())); - if (!RandoStateManager.ScoutedLocations.TryGetValue(locationID, out var item)) return; - if (!HasDialog(locationID)) + else { - string dialog; - if (item.OwnItem()) - { - dialog = item.ToReadableString(); - } - else - { - var otherPlayer = ArchipelagoClient.Session.Players.GetPlayerAlias(item.Player); - dialog = item.ToReadableString(otherPlayer); - } - if (RandomizerStateManager.IsSafeTeleportState()) - DialogChanger.CreateDialogBox(dialog); - else - ArchipelagoClient.DialogQueue.Enqueue(dialog); + var otherPlayer = ArchipelagoClient.Session.Players.GetPlayerAlias(item.Player); + dialog = item.ToReadableString(otherPlayer); } - } - else if (ArchipelagoClient.Offline) - { - var itemToUnlock = ArchipelagoClient.ServerData.LocationData[locationID].First().Value[0]; if (RandomizerStateManager.IsSafeTeleportState()) - Unlock(itemToUnlock); + DialogChanger.CreateDialogBox(dialog); else - ArchipelagoClient.ItemQueue.Enqueue(itemToUnlock); - - if (!HasDialog(locationID)) - { - var dialog = SeedGenerator.GetOfflineDialog(locationID); - if (RandomizerStateManager.IsSafeTeleportState()) - DialogChanger.CreateDialogBox(dialog); - else - ArchipelagoClient.DialogQueue.Enqueue(dialog); - } + ArchipelagoClient.DialogQueue.Enqueue(dialog); } - Manager.Instance.SaveGame(); } - - public static void UnlockItems() + else if (ArchipelagoClient.Offline) { - while (ArchipelagoClient.ServerData.Index < ArchipelagoClient.Session.Items.AllItemsReceived.Count) + var itemToUnlock = ArchipelagoClient.ServerData.LocationData[locationID].First().Value[0]; + if (RandomizerStateManager.IsSafeTeleportState()) + Unlock(itemToUnlock); + else + ArchipelagoClient.ItemQueue.Enqueue(itemToUnlock); + + if (!HasDialog(locationID)) { - var item = ArchipelagoClient.Session.Items.AllItemsReceived[ArchipelagoClient.ServerData.Index++]; - Unlock(item.ItemId); - if (item.Player.Slot != ArchipelagoClient.Session.ConnectionInfo.Slot) - ArchipelagoClient.DialogQueue.Enqueue(item.ToReadableString()); + var dialog = SeedGenerator.GetOfflineDialog(locationID); + if (RandomizerStateManager.IsSafeTeleportState()) + DialogChanger.CreateDialogBox(dialog); + else + ArchipelagoClient.DialogQueue.Enqueue(dialog); } - - Synced = false; } + Manager.Instance.SaveGame(); + } - public static void ReSync() + public static void UnlockItems() + { + while (ArchipelagoClient.ServerData.Index < ArchipelagoClient.Session.Items.AllItemsReceived.Count) { - Synced = true; - ArchipelagoClient.SyncEvents(); - TrackerManager.ReconciliateUnlockedPortals(); + var item = ArchipelagoClient.Session.Items.AllItemsReceived[ArchipelagoClient.ServerData.Index++]; + Unlock(item.ItemId); + if (item.Player.Slot != ArchipelagoClient.Session.ConnectionInfo.Slot) + ArchipelagoClient.DialogQueue.Enqueue(item.ToReadableString()); + } - var receivedItems = new Dictionary(); + Synced = false; + } - for (int i = 0; i < ArchipelagoClient.ServerData.Index; i++) - { - var itemToUnlock = ArchipelagoClient.Session.Items.AllItemsReceived[i]; - var currentItem = itemToUnlock.ItemId; - if (!receivedItems.ContainsKey(currentItem)) receivedItems.Add(currentItem, 1); - else receivedItems[currentItem] += 1; - if (ArchipelagoClient.ServerData.ReceivedItems.ContainsKey(currentItem) && - ArchipelagoClient.ServerData.ReceivedItems[currentItem] >= receivedItems[currentItem]) continue; - Console.WriteLine($"Determined {currentItem} missing while resyncing."); - Unlock(currentItem); - if (itemToUnlock.OwnItem() && - HasDialog(itemToUnlock.LocationId)) - continue; - ArchipelagoClient.DialogQueue.Enqueue(itemToUnlock.ToReadableString()); - } + public static void ReSync() + { + Synced = true; + ArchipelagoClient.SyncEvents(); + TrackerManager.ReconciliateUnlockedPortals(); + + var receivedItems = new Dictionary(); + + for (int i = 0; i < ArchipelagoClient.ServerData.Index; i++) + { + var itemToUnlock = ArchipelagoClient.Session.Items.AllItemsReceived[i]; + var currentItem = itemToUnlock.ItemId; + if (!receivedItems.ContainsKey(currentItem)) receivedItems.Add(currentItem, 1); + else receivedItems[currentItem] += 1; + if (ArchipelagoClient.ServerData.ReceivedItems.ContainsKey(currentItem) && + ArchipelagoClient.ServerData.ReceivedItems[currentItem] >= receivedItems[currentItem]) continue; + Console.WriteLine($"Determined {currentItem} missing while resyncing."); + Unlock(currentItem); + if (itemToUnlock.OwnItem() && + HasDialog(itemToUnlock.LocationId)) + continue; + ArchipelagoClient.DialogQueue.Enqueue(itemToUnlock.ToReadableString()); } } } diff --git a/Archipelago/TrackerManager.cs b/Archipelago/TrackerManager.cs index 4dce507..edeedd6 100644 --- a/Archipelago/TrackerManager.cs +++ b/Archipelago/TrackerManager.cs @@ -4,41 +4,40 @@ using Archipelago.MultiClient.Net.Enums; using MessengerRando.GameOverrideManagers; -namespace MessengerRando.Archipelago +namespace MessengerRando.Archipelago; + +public class TrackerManager { - public class TrackerManager - { - private List VisitedEntrances = []; + private List VisitedEntrances = []; - public void AddVisitedEntrance(string entrance) - { - if (VisitedEntrances.Contains(entrance)) return; + public void AddVisitedEntrance(string entrance) + { + if (VisitedEntrances.Contains(entrance)) return; - if (!ArchipelagoClient.Authenticated) return; - VisitedEntrances = ArchipelagoClient.Session.DataStorage[Scope.Slot, "VisitedEntrances"].To>() ?? []; - if (VisitedEntrances.Contains(entrance)) return; + if (!ArchipelagoClient.Authenticated) return; + VisitedEntrances = ArchipelagoClient.Session.DataStorage[Scope.Slot, "VisitedEntrances"].To>() ?? []; + if (VisitedEntrances.Contains(entrance)) return; - Console.WriteLine("Adding visited entrance: " + entrance); - VisitedEntrances.Add(entrance); - VisitedEntrances.Sort(); - ArchipelagoClient.Session.DataStorage[Scope.Slot, "VisitedEntrances"] = VisitedEntrances; + Console.WriteLine("Adding visited entrance: " + entrance); + VisitedEntrances.Add(entrance); + VisitedEntrances.Sort(); + ArchipelagoClient.Session.DataStorage[Scope.Slot, "VisitedEntrances"] = VisitedEntrances; - return; - } + return; + } - public void ReconciliateUnlockedPortals() - { - if (!ArchipelagoClient.Authenticated) return; + public void ReconciliateUnlockedPortals() + { + if (!ArchipelagoClient.Authenticated) return; - var unlockedPortals = RandoPortalManager.UnlockedPortals; - unlockedPortals.UnionWith(ArchipelagoClient.Session.DataStorage[Scope.Slot, "UnlockedPortals"].To>() ?? []); + var unlockedPortals = RandoPortalManager.UnlockedPortals; + unlockedPortals.UnionWith(ArchipelagoClient.Session.DataStorage[Scope.Slot, "UnlockedPortals"].To>() ?? []); - var unlockedPortalsList = unlockedPortals.ToList(); - unlockedPortalsList.Sort(); - Console.WriteLine($"Updating unlocked portals with Data Storage. Unlocked portals are\n\t{string.Join("\n\t", [.. unlockedPortalsList])}"); - ArchipelagoClient.Session.DataStorage[Scope.Slot, "UnlockedPortals"] = unlockedPortalsList; - } + var unlockedPortalsList = unlockedPortals.ToList(); + unlockedPortalsList.Sort(); + Console.WriteLine($"Updating unlocked portals with Data Storage. Unlocked portals are\n\t{string.Join("\n\t", [.. unlockedPortalsList])}"); + ArchipelagoClient.Session.DataStorage[Scope.Slot, "UnlockedPortals"] = unlockedPortalsList; } } diff --git a/Exceptions/RandomizerException.cs b/Exceptions/RandomizerException.cs index f33fcc5..44f86c1 100644 --- a/Exceptions/RandomizerException.cs +++ b/Exceptions/RandomizerException.cs @@ -1,27 +1,26 @@ using System; using System.Runtime.Serialization; -namespace MessengerRando.Exceptions +namespace MessengerRando.Exceptions; + +/// +/// Empty rando exception class used to keep track of errors +/// +public class RandomizerException : Exception { - /// - /// Empty rando exception class used to keep track of errors - /// - public class RandomizerException : Exception + public RandomizerException() { - public RandomizerException() - { - } + } - public RandomizerException(string message) : base(message) - { - } + public RandomizerException(string message) : base(message) + { + } - public RandomizerException(string message, Exception innerException) : base(message, innerException) - { - } + public RandomizerException(string message, Exception innerException) : base(message, innerException) + { + } - protected RandomizerException(SerializationInfo info, StreamingContext context) : base(info, context) - { - } + protected RandomizerException(SerializationInfo info, StreamingContext context) : base(info, context) + { } } diff --git a/GameOverrideManagers/FlavorDialogManager.cs b/GameOverrideManagers/FlavorDialogManager.cs index b863a83..fbd4145 100644 --- a/GameOverrideManagers/FlavorDialogManager.cs +++ b/GameOverrideManagers/FlavorDialogManager.cs @@ -1,153 +1,152 @@ using System.Collections.Generic; using MessengerRando.Utils; -namespace MessengerRando.GameOverrideManagers +namespace MessengerRando.GameOverrideManagers; + +public static class FlavorDialogManager { - public static class FlavorDialogManager + private struct DialogBox { - private struct DialogBox - { - public string Text; - public CharacterDefinition Speaker; - public int Delay; + public string Text; + public CharacterDefinition Speaker; + public int Delay; - public DialogBox(string text, ECharacter speaker, int delay) - { - Text = text; - Speaker = Manager.Instance.GetCharacterDefinition(speaker); - Delay = delay; - } + public DialogBox(string text, ECharacter speaker, int delay) + { + Text = text; + Speaker = Manager.Instance.GetCharacterDefinition(speaker); + Delay = delay; } + } - public static CharacterDefinition ProphetDefinition; - public static CharacterDefinition MessengerDefinition; + public static CharacterDefinition ProphetDefinition; + public static CharacterDefinition MessengerDefinition; - static List ModifyDialogInfo(string locID, List infoToReplace) + static List ModifyDialogInfo(string locID, List infoToReplace) + { + switch (locID) { - switch (locID) - { - case "PROPHET_HEY": - var prophetHey = infoToReplace[0]; - prophetHey.text = - ProphetHeyReplacements[RandomizerStateManager.SeedRandom.Next(ProphetHeyReplacements.Count)]; - prophetHey.skippable = false; - break; - case "PROPHET_INTRO_3": - ProphetDefinition = infoToReplace[0].characterDefinition; - MessengerDefinition = infoToReplace[1].characterDefinition; - var newText = - ProphetIntroReplacements[ - RandomizerStateManager.SeedRandom.Next(ProphetIntroReplacements.Count)]; - // var toRemove = 0; - var newInfoList = new List(); - foreach (var kvp in newText) + case "PROPHET_HEY": + var prophetHey = infoToReplace[0]; + prophetHey.text = + ProphetHeyReplacements[RandomizerStateManager.SeedRandom.Next(ProphetHeyReplacements.Count)]; + prophetHey.skippable = false; + break; + case "PROPHET_INTRO_3": + ProphetDefinition = infoToReplace[0].characterDefinition; + MessengerDefinition = infoToReplace[1].characterDefinition; + var newText = + ProphetIntroReplacements[ + RandomizerStateManager.SeedRandom.Next(ProphetIntroReplacements.Count)]; + // var toRemove = 0; + var newInfoList = new List(); + foreach (var kvp in newText) + { + CharacterDefinition replaceChar; + switch (kvp.Value) { - CharacterDefinition replaceChar; - switch (kvp.Value) - { - case "Prophet": - replaceChar = ProphetDefinition; - break; - case "Messenger": - replaceChar = MessengerDefinition; - break; - default: - replaceChar = ProphetDefinition; - break; - } - - var newInfo = new DialogInfo - { - text = kvp.Key, - textID = "PROPHET_INTRO_3", - characterDefinition = replaceChar, - skippable = false, - autoClose = true, - }; - newInfoList.Add(newInfo); + case "Prophet": + replaceChar = ProphetDefinition; + break; + case "Messenger": + replaceChar = MessengerDefinition; + break; + default: + replaceChar = ProphetDefinition; + break; } - newInfoList[newInfoList.Count - 1].autoCloseDelay = 2.0f; - infoToReplace = newInfoList; - break; - } + var newInfo = new DialogInfo + { + text = kvp.Key, + textID = "PROPHET_INTRO_3", + characterDefinition = replaceChar, + skippable = false, + autoClose = true, + }; + newInfoList.Add(newInfo); + } + newInfoList[newInfoList.Count - 1].autoCloseDelay = 2.0f; - return infoToReplace; + infoToReplace = newInfoList; + break; } - public static void UpdateLoc(Dictionary> loc) + return infoToReplace; + } + + public static void UpdateLoc(Dictionary> loc) + { + foreach (var textID in DialogToReplace) { - foreach (var textID in DialogToReplace) - { - loc[textID] = ModifyDialogInfo(textID, loc[textID]); - } + loc[textID] = ModifyDialogInfo(textID, loc[textID]); } + } - static readonly List DialogToReplace = new List - { - "PROPHET_HEY", - "PROPHET_INTRO_3", - }; + static readonly List DialogToReplace = new List + { + "PROPHET_HEY", + "PROPHET_INTRO_3", + }; - static readonly List ProphetHeyReplacements = new List - { - "You have been randomized.", - "Echo!", - "Shoutouts to Simpleflips.", - }; + static readonly List ProphetHeyReplacements = new List + { + "You have been randomized.", + "Echo!", + "Shoutouts to Simpleflips.", + }; - static readonly List> ProphetIntroReplacements = new List> + static readonly List> ProphetIntroReplacements = new List> + { + new Dictionary { - new Dictionary - { - { "Do you have any extra die?", "Prophet" }, - { "What? I have Quarble I guess.", "Messenger" }, - { "No, like for rolling. I haven't been able to find mine.", "Prophet" }, - { "For what?", "Messenger" }, - { "Well I figure I'll have to make a perception check at some point with all these texts.", "Prophet" }, - { "...", "Messenger" }, - { "Can you at least have a look around to see if you can find them?", "Prophet" }, - { "Sure.", "Messenger" }, - { - "*ahem* BEHOLD, and may you see success on your journey oh yee valiant Messenger.", - "Prophet" - }, - { "Uh. Right. Thanks.", "Messenger" }, - }, - new Dictionary - { - { "I don't think we're in Kansas anymore.", "Prophet" }, - { "And I forgot my red shoes.", "Messenger" }, - }, - new Dictionary + { "Do you have any extra die?", "Prophet" }, + { "What? I have Quarble I guess.", "Messenger" }, + { "No, like for rolling. I haven't been able to find mine.", "Prophet" }, + { "For what?", "Messenger" }, + { "Well I figure I'll have to make a perception check at some point with all these texts.", "Prophet" }, + { "...", "Messenger" }, + { "Can you at least have a look around to see if you can find them?", "Prophet" }, + { "Sure.", "Messenger" }, { - { "Do you ever think about what we're doing here?", "Prophet" }, - { "Something about this Music Box thing, right?", "Messenger" }, - { "Nevermind. *ahem* AND THUS THE WHEEL OF TIME CONTINUED TO TURN.", "Prophet" }, - { - "AND ALL THOSE WITHIN CONTINUED UNABATED, UNRELENTING ALONG THE CHARIOT OF THEIR ULTIMATE DESTINY.", - "Prophet" - }, - { "...", "Messenger" }, - { "Look just go find the things, ok?", "Prophet" }, - { "...Right.", "Messenger" }, + "*ahem* BEHOLD, and may you see success on your journey oh yee valiant Messenger.", + "Prophet" }, - new Dictionary + { "Uh. Right. Thanks.", "Messenger" }, + }, + new Dictionary + { + { "I don't think we're in Kansas anymore.", "Prophet" }, + { "And I forgot my red shoes.", "Messenger" }, + }, + new Dictionary + { + { "Do you ever think about what we're doing here?", "Prophet" }, + { "Something about this Music Box thing, right?", "Messenger" }, + { "Nevermind. *ahem* AND THUS THE WHEEL OF TIME CONTINUED TO TURN.", "Prophet" }, { - { "I could really go for a pizza right now.", "Prophet" }, - { "Get me anchovies.", "Messenger" }, + "AND ALL THOSE WITHIN CONTINUED UNABATED, UNRELENTING ALONG THE CHARIOT OF THEIR ULTIMATE DESTINY.", + "Prophet" }, - new Dictionary - { - { "Welcome, young Messenger", "Prophet" }, - { "Who are you?" , "Messenger" }, - { "I am your sister's cousin's father's brother's dog's veterinarian's nephew's parole officer's " + - "evil twin's best friend's long lost roommate's third favorite singer's tax consultant's " + - "chef's architect's dungeon master", "Prophet" }, - { "And what does that make us?", "Messenger" }, - { "-CHARACTER LIMIT EXCEEDED-", "Prophet" }, - { "OVERFLOW ERROR", "Prophet" }, - } - }; - } + { "...", "Messenger" }, + { "Look just go find the things, ok?", "Prophet" }, + { "...Right.", "Messenger" }, + }, + new Dictionary + { + { "I could really go for a pizza right now.", "Prophet" }, + { "Get me anchovies.", "Messenger" }, + }, + new Dictionary + { + { "Welcome, young Messenger", "Prophet" }, + { "Who are you?" , "Messenger" }, + { "I am your sister's cousin's father's brother's dog's veterinarian's nephew's parole officer's " + + "evil twin's best friend's long lost roommate's third favorite singer's tax consultant's " + + "chef's architect's dungeon master", "Prophet" }, + { "And what does that make us?", "Messenger" }, + { "-CHARACTER LIMIT EXCEEDED-", "Prophet" }, + { "OVERFLOW ERROR", "Prophet" }, + } + }; } \ No newline at end of file diff --git a/GameOverrideManagers/LostWoodsManager.cs b/GameOverrideManagers/LostWoodsManager.cs index 0feef12..017a325 100644 --- a/GameOverrideManagers/LostWoodsManager.cs +++ b/GameOverrideManagers/LostWoodsManager.cs @@ -2,46 +2,45 @@ using System.Reflection; using Object = UnityEngine.Object; -namespace MessengerRando.GameOverrideManagers +namespace MessengerRando.GameOverrideManagers; + +public static class LostWoodsManager { - public static class LostWoodsManager - { - public static bool ShouldBeSolved; - public static bool NeedsSolved; - private static bool tempSolve; - public static bool NeedsUnsolved; + public static bool ShouldBeSolved; + public static bool NeedsSolved; + private static bool tempSolve; + public static bool NeedsUnsolved; - public static void OnSetAsSolved(On.LostWoods.orig_SetAsSolved orig, LostWoods self) + public static void OnSetAsSolved(On.LostWoods.orig_SetAsSolved orig, LostWoods self) + { + // if (ShouldBeSolved || tempSolve) + orig(self); + } + public static void SolveLostWoods() + { + tempSolve = true; + NeedsUnsolved = !ShouldBeSolved; + try { - // if (ShouldBeSolved || tempSolve) - orig(self); + LostWoods.Instance.SetAsSolved(); + tempSolve = NeedsSolved = false; } - public static void SolveLostWoods() + catch (Exception e) { - tempSolve = true; - NeedsUnsolved = !ShouldBeSolved; - try - { - LostWoods.Instance.SetAsSolved(); - tempSolve = NeedsSolved = false; - } - catch (Exception e) - { - Console.WriteLine(e); - NeedsSolved = ShouldBeSolved; - tempSolve = false; - } + Console.WriteLine(e); + NeedsSolved = ShouldBeSolved; + tempSolve = false; } + } - public static void UnsolveLostWoods() + public static void UnsolveLostWoods() + { + var lostWoodsSolved = + typeof(LostWoods).GetField("solved", BindingFlags.NonPublic | BindingFlags.Instance); + if (lostWoodsSolved != null) { - var lostWoodsSolved = - typeof(LostWoods).GetField("solved", BindingFlags.NonPublic | BindingFlags.Instance); - if (lostWoodsSolved != null) - { - lostWoodsSolved.SetValue(Object.FindObjectsOfType(), true); - NeedsUnsolved = false; - } + lostWoodsSolved.SetValue(Object.FindObjectsOfType(), true); + NeedsUnsolved = false; } } } \ No newline at end of file diff --git a/GameOverrideManagers/RandoBossManager.cs b/GameOverrideManagers/RandoBossManager.cs index a353f02..26a5727 100644 --- a/GameOverrideManagers/RandoBossManager.cs +++ b/GameOverrideManagers/RandoBossManager.cs @@ -8,256 +8,255 @@ using Object = UnityEngine.Object; // ReSharper disable StringLiteralTypo -namespace MessengerRando.GameOverrideManagers +namespace MessengerRando.GameOverrideManagers; + +public abstract class RandoBossManager { - public abstract class RandoBossManager - { - public static List DefeatedBosses = []; + public static List DefeatedBosses = []; - private readonly Dictionary origToNewBoss; - private static bool bossOverride; + private readonly Dictionary origToNewBoss; + private static bool bossOverride; - private struct BossLocation - { - public readonly ELevel BossRegion; - public readonly Vector2 PlayerPosition; - public readonly EBits PlayerDimension; + private struct BossLocation + { + public readonly ELevel BossRegion; + public readonly Vector2 PlayerPosition; + public readonly EBits PlayerDimension; - public BossLocation(ELevel area, Vector2 pos, EBits dim) - { - BossRegion = area; - PlayerPosition = pos; - PlayerDimension = dim; - } + public BossLocation(ELevel area, Vector2 pos, EBits dim) + { + BossRegion = area; + PlayerPosition = pos; + PlayerDimension = dim; } + } - private static readonly List VanillaBossNames = new List - { - "LeafGolem", - "Necromancer", - "EmeraldGolem", - "QueenOfQuills", - // "Colos_Susses", - "Manfred", - // "TowerGolem", - "DemonGeneral", - "DemonArtificier", - "ButterflyMatriarch", - "ClockworkConcierge", - "Phantom" - }; - - private static readonly Dictionary IDToBossMap = new Dictionary - { - { 11391075, "LeafGolem" }, - { 11391076, "Necromancer" }, - { 11391077, "EmeraldGolem" }, - { 11391078, "QueenOfQuills" }, - }; + private static readonly List VanillaBossNames = new List + { + "LeafGolem", + "Necromancer", + "EmeraldGolem", + "QueenOfQuills", + // "Colos_Susses", + "Manfred", + // "TowerGolem", + "DemonGeneral", + "DemonArtificier", + "ButterflyMatriarch", + "ClockworkConcierge", + "Phantom" + }; - public static readonly Dictionary BossCutscenes = new Dictionary - { - { "LeafGolem", "LeafGolemIntroCutscene" }, - { "Necromancer", "NecromancerIntroCutscene" }, - { "EmeraldGolem", "EmeraldGolemIntroCutscene" }, - { "QueenOfQuills", "QueenOfQuillsIntroCutscene" }, - // {"Colos_Susses", }, - { "Manfred", "ManfredIntroCutscene" }, - // {"TowerGolem", }, - { "DemonGeneral", "DemonGeneralIntroCutscene" }, - { "DemonArtificier", "DemonArtificierIntroCutscene" }, - { "ButterflyMatriarch", "ButterflyMatriarchIntroCutscene" }, - { "Phantom", "PhantomIntroCutscene" } - }; + private static readonly Dictionary IDToBossMap = new Dictionary + { + { 11391075, "LeafGolem" }, + { 11391076, "Necromancer" }, + { 11391077, "EmeraldGolem" }, + { 11391078, "QueenOfQuills" }, + }; - private static readonly Dictionary RoomToVanillaBoss = new Dictionary - { - { "908940-28-12", "LeafGolem" }, - { "748780-76-60", "Necromancer" }, - { "556588-140-60", "EmeraldGolem" }, - { "11001132-44-28", "QueenOfQuills" }, - { "332364308324", "Colos_Susses" }, - { "11641228-28-12", "Manfred" }, - // { "108140228244", "TowerGolem" }, - { "140172-44-28", "DemonGeneral" }, - { "396428-12436", "DemonArtificier" }, - { "-308-276420", "ButterflyMatriarch" } - }; + public static readonly Dictionary BossCutscenes = new Dictionary + { + { "LeafGolem", "LeafGolemIntroCutscene" }, + { "Necromancer", "NecromancerIntroCutscene" }, + { "EmeraldGolem", "EmeraldGolemIntroCutscene" }, + { "QueenOfQuills", "QueenOfQuillsIntroCutscene" }, + // {"Colos_Susses", }, + { "Manfred", "ManfredIntroCutscene" }, + // {"TowerGolem", }, + { "DemonGeneral", "DemonGeneralIntroCutscene" }, + { "DemonArtificier", "DemonArtificierIntroCutscene" }, + { "ButterflyMatriarch", "ButterflyMatriarchIntroCutscene" }, + { "Phantom", "PhantomIntroCutscene" } + }; - private static readonly Dictionary BossLocations = new Dictionary - { - { "LeafGolem", new BossLocation(ELevel.Level_02_AutumnHills, new Vector2(908, -27), EBits.BITS_8) }, - { "Necromancer", new BossLocation(ELevel.Level_04_Catacombs, new Vector2(752, -75), EBits.BITS_8) }, - { "EmeraldGolem", new BossLocation(ELevel.Level_05_A_HowlingGrotto, new Vector2(560, -123), EBits.BITS_8) }, - { "QueenOfQuills", new BossLocation( ELevel.Level_07_QuillshroomMarsh, new Vector2(1100, -43), EBits.BITS_8) }, - // { "Colos_Susses", new BossLocation(ELevel.Level_08_SearingCrags, new Vector2(364, 311), EBits.BITS_8) }, - // { "Manfred", new BossLocation(ELevel.Level_11_A_CloudRuins, new Vector2(1165, -26), EBits.BITS_16)}, - // { "Tower Golem", new BossLocation(ELevel.Level_10_A_TowerOfTime, new Vector2(108, 237), EBits.BITS_16) }, - // { "DemonGeneral", new BossLocation(ELevel.Level_12_UnderWorld, new Vector2(140, -43), EBits.BITS_16) }, - // { "DemonArtificier", new BossLocation(ELevel.Level_03_ForlornTemple, new Vector2(396, -11), EBits.BITS_16)}, - // { "ButterflyMatriarch", new BossLocation(ELevel.Level_04_C_RiviereTurquoise, new Vector2(-276, 6), EBits.BITS_16) } - }; + private static readonly Dictionary RoomToVanillaBoss = new Dictionary + { + { "908940-28-12", "LeafGolem" }, + { "748780-76-60", "Necromancer" }, + { "556588-140-60", "EmeraldGolem" }, + { "11001132-44-28", "QueenOfQuills" }, + { "332364308324", "Colos_Susses" }, + { "11641228-28-12", "Manfred" }, + // { "108140228244", "TowerGolem" }, + { "140172-44-28", "DemonGeneral" }, + { "396428-12436", "DemonArtificier" }, + { "-308-276420", "ButterflyMatriarch" } + }; - private static readonly List BossRoomKeys = new List - { - "908940-28-12", - "748780-76-60", - "556588-140-60", - "11001132-44-28", - "332364308324", - "11641228-28-12", - "108140228244", - "140172-44-28", - "396428-12436", - "-308-276420", - }; + private static readonly Dictionary BossLocations = new Dictionary + { + { "LeafGolem", new BossLocation(ELevel.Level_02_AutumnHills, new Vector2(908, -27), EBits.BITS_8) }, + { "Necromancer", new BossLocation(ELevel.Level_04_Catacombs, new Vector2(752, -75), EBits.BITS_8) }, + { "EmeraldGolem", new BossLocation(ELevel.Level_05_A_HowlingGrotto, new Vector2(560, -123), EBits.BITS_8) }, + { "QueenOfQuills", new BossLocation( ELevel.Level_07_QuillshroomMarsh, new Vector2(1100, -43), EBits.BITS_8) }, + // { "Colos_Susses", new BossLocation(ELevel.Level_08_SearingCrags, new Vector2(364, 311), EBits.BITS_8) }, + // { "Manfred", new BossLocation(ELevel.Level_11_A_CloudRuins, new Vector2(1165, -26), EBits.BITS_16)}, + // { "Tower Golem", new BossLocation(ELevel.Level_10_A_TowerOfTime, new Vector2(108, 237), EBits.BITS_16) }, + // { "DemonGeneral", new BossLocation(ELevel.Level_12_UnderWorld, new Vector2(140, -43), EBits.BITS_16) }, + // { "DemonArtificier", new BossLocation(ELevel.Level_03_ForlornTemple, new Vector2(396, -11), EBits.BITS_16)}, + // { "ButterflyMatriarch", new BossLocation(ELevel.Level_04_C_RiviereTurquoise, new Vector2(-276, 6), EBits.BITS_16) } + }; + + private static readonly List BossRoomKeys = new List + { + "908940-28-12", + "748780-76-60", + "556588-140-60", + "11001132-44-28", + "332364308324", + "11641228-28-12", + "108140228244", + "140172-44-28", + "396428-12436", + "-308-276420", + }; - private static string GetVanillaBoss(string roomKey) + private static string GetVanillaBoss(string roomKey) + { + return RoomToVanillaBoss[roomKey]; + } + + private static void AdjustPlayerInBossRoom(string bossName) + { + if (!BossLocations.TryGetValue(bossName, out var newLocation)) return; + if (Manager.Instance.GetCurrentLevelEnum().Equals(newLocation.BossRegion)) + { + Manager.Instance.Player.transform.position = newLocation.PlayerPosition; + Manager.Instance.SetDimension(newLocation.PlayerDimension); + } + else { - return RoomToVanillaBoss[roomKey]; + bossOverride = true; + RandoLevelManager.TeleportInArea(newLocation.BossRegion, newLocation.PlayerPosition, + newLocation.PlayerDimension); } + } - private static void AdjustPlayerInBossRoom(string bossName) + public static bool HasBossDefeated(string bossName) + { + if (bossOverride) + bossName = RandomizerStateManager.Instance.BossManager.origToNewBoss + .First(name => name.Value.Equals(bossName)).Key; +#if DEBUG + Console.WriteLine($"Checking if {bossName} is defeated."); +#endif + try { - if (!BossLocations.TryGetValue(bossName, out var newLocation)) return; - if (Manager.Instance.GetCurrentLevelEnum().Equals(newLocation.BossRegion)) - { - Manager.Instance.Player.transform.position = newLocation.PlayerPosition; - Manager.Instance.SetDimension(newLocation.PlayerDimension); - } - else - { - bossOverride = true; - RandoLevelManager.TeleportInArea(newLocation.BossRegion, newLocation.PlayerPosition, - newLocation.PlayerDimension); - } + return !VanillaBossNames.Contains(bossName) || DefeatedBosses.Contains(bossName); } - - public static bool HasBossDefeated(string bossName) + catch (Exception e) { - if (bossOverride) - bossName = RandomizerStateManager.Instance.BossManager.origToNewBoss - .First(name => name.Value.Equals(bossName)).Key; - #if DEBUG - Console.WriteLine($"Checking if {bossName} is defeated."); - #endif - try - { - return !VanillaBossNames.Contains(bossName) || DefeatedBosses.Contains(bossName); - } - catch (Exception e) - { - Console.WriteLine(e); - return true; - } + Console.WriteLine(e); + return true; } + } - public static void SetBossAsDefeated(string bossName) + public static void SetBossAsDefeated(string bossName) + { + if (DefeatedBosses.Contains(bossName)) + return; + if (bossOverride) { - if (DefeatedBosses.Contains(bossName)) - return; - if (bossOverride) - { - bossName = RandomizerStateManager.Instance.BossManager.origToNewBoss[bossName]; - bossOverride = false; - } - if (ArchipelagoClient.HasConnected) + bossName = RandomizerStateManager.Instance.BossManager.origToNewBoss[bossName]; + bossOverride = false; + } + if (ArchipelagoClient.HasConnected) + { + ArchipelagoClient.ServerData.DefeatedBosses.Add(bossName); + if (BossLocations.ContainsKey(bossName)) { - ArchipelagoClient.ServerData.DefeatedBosses.Add(bossName); - if (BossLocations.ContainsKey(bossName)) + var bossLoc = new LocationRO(bossName); + ItemsAndLocationsHandler.SendLocationCheck(bossLoc); + if (bossName.Equals("EmeraldGolem")) { - var bossLoc = new LocationRO(bossName); - ItemsAndLocationsHandler.SendLocationCheck(bossLoc); - if (bossName.Equals("EmeraldGolem")) - { - Manager.Instance.cutscenesPlayed.Add("EmeraldGolemOutroCutscene"); - } + Manager.Instance.cutscenesPlayed.Add("EmeraldGolemOutroCutscene"); } } - DefeatedBosses.Add(bossName); - if (RandomizerStateManager.Instance.BossManager != null) - { - var newPosition = BossLocations[bossName]; - - RandoLevelManager.TeleportInArea(newPosition.BossRegion, newPosition.PlayerPosition, - newPosition.PlayerDimension); - } } + DefeatedBosses.Add(bossName); + if (RandomizerStateManager.Instance.BossManager != null) + { + var newPosition = BossLocations[bossName]; - public static bool ShouldFightBoss(string bossName) + RandoLevelManager.TeleportInArea(newPosition.BossRegion, newPosition.PlayerPosition, + newPosition.PlayerDimension); + } + } + + public static bool ShouldFightBoss(string bossName) + { + if (bossOverride) return false; + var currentLevel = Manager.Instance.GetCurrentLevelEnum(); + Console.WriteLine($"Entered {bossName}'s room. Has Defeated: {HasBossDefeated(bossName)}"); + if (HasBossDefeated(bossName) || !currentLevel.Equals(BossLocations[bossName].BossRegion)) return false; + + var teleporting = RandomizerStateManager.Instance.BossManager != null; + Console.WriteLine($"Should teleport: {teleporting}"); + if (teleporting) { - if (bossOverride) return false; - var currentLevel = Manager.Instance.GetCurrentLevelEnum(); - Console.WriteLine($"Entered {bossName}'s room. Has Defeated: {HasBossDefeated(bossName)}"); - if (HasBossDefeated(bossName) || !currentLevel.Equals(BossLocations[bossName].BossRegion)) return false; - - var teleporting = RandomizerStateManager.Instance.BossManager != null; - Console.WriteLine($"Should teleport: {teleporting}"); - if (teleporting) + try { - try + foreach (var cutscene in Object.FindObjectsOfType()) { - foreach (var cutscene in Object.FindObjectsOfType()) + try { - try - { - if (cutscene.IsInvoking()) - { - Console.WriteLine($"Ending cutscene: {cutscene.name}"); - cutscene.EndCutScene(); - } - } - catch (Exception e) + if (cutscene.IsInvoking()) { - Console.WriteLine($"{e}\n{cutscene.name}"); + Console.WriteLine($"Ending cutscene: {cutscene.name}"); + cutscene.EndCutScene(); } } + catch (Exception e) + { + Console.WriteLine($"{e}\n{cutscene.name}"); + } + } - foreach (var cutscene in Object.FindObjectsOfType()) + foreach (var cutscene in Object.FindObjectsOfType()) + { + try { - try + if (cutscene.IsInvoking()) { - if (cutscene.IsInvoking()) - { - Console.WriteLine($"Ending cutscene: {cutscene.name}"); - cutscene.EndCutScene(); - } - } - catch (Exception e) - { - Console.WriteLine($"{e}\n{cutscene.name}"); + Console.WriteLine($"Ending cutscene: {cutscene.name}"); + cutscene.EndCutScene(); } } + catch (Exception e) + { + Console.WriteLine($"{e}\n{cutscene.name}"); + } } - catch (Exception e) - { - Console.WriteLine(e); - } - bossName = RandomizerStateManager.Instance.BossManager.GetActualBoss(bossName); } - AdjustPlayerInBossRoom(bossName); - return teleporting; - } - - public static void TryCollectLocation(long locationID) - { - if (IDToBossMap.TryGetValue(locationID, out var boss)) + catch (Exception e) { - SetBossAsDefeated(boss); + Console.WriteLine(e); } + bossName = RandomizerStateManager.Instance.BossManager.GetActualBoss(bossName); } + AdjustPlayerInBossRoom(bossName); + return teleporting; + } - protected RandoBossManager(Dictionary bossMapping) + public static void TryCollectLocation(long locationID) + { + if (IDToBossMap.TryGetValue(locationID, out var boss)) { - Manager.Instance.bossesDefeated = - Manager.Instance.allTimeBossesDefeated = new List(); - origToNewBoss = bossMapping; + SetBossAsDefeated(boss); } + } - private string GetActualBoss(string vanillaBoss) - { - Console.WriteLine($"requested {vanillaBoss}, going to {origToNewBoss[vanillaBoss]}"); - return origToNewBoss[vanillaBoss]; - } + protected RandoBossManager(Dictionary bossMapping) + { + Manager.Instance.bossesDefeated = + Manager.Instance.allTimeBossesDefeated = new List(); + origToNewBoss = bossMapping; + } + + private string GetActualBoss(string vanillaBoss) + { + Console.WriteLine($"requested {vanillaBoss}, going to {origToNewBoss[vanillaBoss]}"); + return origToNewBoss[vanillaBoss]; } } \ No newline at end of file diff --git a/GameOverrideManagers/RandoMusicManager.cs b/GameOverrideManagers/RandoMusicManager.cs index ca36120..9e716a5 100644 --- a/GameOverrideManagers/RandoMusicManager.cs +++ b/GameOverrideManagers/RandoMusicManager.cs @@ -3,65 +3,64 @@ using UnityEngine; using Random = System.Random; -namespace MessengerRando.GameOverrideManagers +namespace MessengerRando.GameOverrideManagers; + +public static class RandoMusicManager { - public static class RandoMusicManager - { - private static Random random; - public static bool ShuffleMusic; + private static Random random; + public static bool ShuffleMusic; - public static Dictionary NameToMusic; - public static List ShopTracks; - public static List LevelTracks; + public static Dictionary NameToMusic; + public static List ShopTracks; + public static List LevelTracks; - public static void BuildMusicLibrary() + public static void BuildMusicLibrary() + { + try { - try - { - random = new Random(); - ShopTracks = Manager.Instance.ShopJukeboxTracks; - LevelTracks = Manager.Instance.LevelJukeboxTracks; - } - catch (Exception e) - { - Debug.Log(e); - } + random = new Random(); + ShopTracks = Manager.Instance.ShopJukeboxTracks; + LevelTracks = Manager.Instance.LevelJukeboxTracks; } - - public static MusicAudioObject OnPlayMusic( - On.AudioManager.orig_PlayMusic orig, - AudioManager self, - AudioObjectDefinition audioObjectDefinition, - bool loop, - float fadeInDuration, - float playbackTime, - GameObject customAudioObject) + catch (Exception e) { - if (audioObjectDefinition == null) - return null; + Debug.Log(e); + } + } + + public static MusicAudioObject OnPlayMusic( + On.AudioManager.orig_PlayMusic orig, + AudioManager self, + AudioObjectDefinition audioObjectDefinition, + bool loop, + float fadeInDuration, + float playbackTime, + GameObject customAudioObject) + { + if (audioObjectDefinition == null) + return null; #if DEBUG - Debug.Log("playing music"); - Debug.Log(audioObjectDefinition.GetInstanceID()); - Debug.Log(audioObjectDefinition.GetInstanceID()); + Debug.Log("playing music"); + Debug.Log(audioObjectDefinition.GetInstanceID()); + Debug.Log(audioObjectDefinition.GetInstanceID()); #endif - if (Manager.Instance.GetCurrentLevelEnum().Equals(ELevel.Level_05_B_SunkenShrine)) - { - self.levelMusicShuffle = false; - } - else - { - self.levelMusicShuffle = ShuffleMusic; - } - if (!audioObjectDefinition.IsMusic() || !ShuffleMusic || - !Manager.Instance.GetCurrentLevelEnum().Equals(ELevel.Level_13_TowerOfTimeHQ)) - { - return orig(self, audioObjectDefinition, loop, fadeInDuration, playbackTime, customAudioObject); - } - var newAudio = self.GetRandomLevelTrack(); - var dimension = random.Next(0, 2); - audioObjectDefinition = dimension == 0 ? newAudio.track_8 : newAudio.track_16; - self.StopMusic(); + if (Manager.Instance.GetCurrentLevelEnum().Equals(ELevel.Level_05_B_SunkenShrine)) + { + self.levelMusicShuffle = false; + } + else + { + self.levelMusicShuffle = ShuffleMusic; + } + if (!audioObjectDefinition.IsMusic() || !ShuffleMusic || + !Manager.Instance.GetCurrentLevelEnum().Equals(ELevel.Level_13_TowerOfTimeHQ)) + { return orig(self, audioObjectDefinition, loop, fadeInDuration, playbackTime, customAudioObject); } + var newAudio = self.GetRandomLevelTrack(); + var dimension = random.Next(0, 2); + audioObjectDefinition = dimension == 0 ? newAudio.track_8 : newAudio.track_16; + self.StopMusic(); + return orig(self, audioObjectDefinition, loop, fadeInDuration, playbackTime, customAudioObject); } } \ No newline at end of file diff --git a/GameOverrideManagers/RandoPortalManager.cs b/GameOverrideManagers/RandoPortalManager.cs index 2e98ce5..fc309e4 100644 --- a/GameOverrideManagers/RandoPortalManager.cs +++ b/GameOverrideManagers/RandoPortalManager.cs @@ -4,469 +4,468 @@ using MessengerRando.Utils.Constants; using UnityEngine; -namespace MessengerRando.GameOverrideManagers +namespace MessengerRando.GameOverrideManagers; + +public static class RandoPortalManager { - public static class RandoPortalManager + public readonly struct Portal { - public readonly struct Portal + public readonly int Region; + public readonly int PortalType; + public readonly int Index; + + public Portal(int portalWarp) { - public readonly int Region; - public readonly int PortalType; - public readonly int Index; + var modWarp = portalWarp.ToString(); + if (modWarp.Length == 4) + { + Region = int.Parse(modWarp.Substring(0, 2)); + PortalType = int.Parse(modWarp[2].ToString()); + Index = int.Parse(modWarp[3].ToString()); + } + else if (modWarp.Length == 3) + { + Region = int.Parse(modWarp[0].ToString()); + PortalType = int.Parse(modWarp[1].ToString()); + Index = int.Parse(modWarp[2].ToString()); + } + else if (modWarp.Length == 2) + { + Region = 0; + PortalType = int.Parse(modWarp[0].ToString()); + Index = int.Parse(modWarp[1].ToString()); + } + else + { + Region = 0; + PortalType = 0; + Index = int.Parse(modWarp); + } + } + } - public Portal(int portalWarp) + public static bool LeftHQPortal; + public static bool ForceTeleport; + public static bool EnteredTower; + public static List StartingPortals; + public static List PortalMapping; + public static TrackerManager TrackerManager; + + static readonly List>> AreaCheckpoints = + new List>> + { + new List> { - var modWarp = portalWarp.ToString(); - if (modWarp.Length == 4) + new List + { + new LevelConstants.RandoLevel(ELevel.Level_02_AutumnHills, new Vector3(485, -102)), + }, + new List { - Region = int.Parse(modWarp.Substring(0, 2)); - PortalType = int.Parse(modWarp[2].ToString()); - Index = int.Parse(modWarp[3].ToString()); + new LevelConstants.RandoLevel(ELevel.Level_02_AutumnHills, new Vector3(-45.5f, -89)), + new LevelConstants.RandoLevel(ELevel.Level_02_AutumnHills, new Vector3(68.5f, -111)), + new LevelConstants.RandoLevel(ELevel.Level_02_AutumnHills, new Vector3(407.5f, -74)), + new LevelConstants.RandoLevel(ELevel.Level_02_AutumnHills, new Vector3(892.5f, -27)), + }, + new List + { + new LevelConstants.RandoLevel(ELevel.Level_02_AutumnHills, new Vector3(175, -148)), + new LevelConstants.RandoLevel(ELevel.Level_02_AutumnHills, new Vector3(91.5f, -87)), + new LevelConstants.RandoLevel(ELevel.Level_02_AutumnHills, new Vector3(238.5f, -74)), + new LevelConstants.RandoLevel(ELevel.Level_02_AutumnHills, new Vector3(607.48f, -35)), + new LevelConstants.RandoLevel(ELevel.Level_02_AutumnHills, new Vector3(718.5f, -73), EBits.BITS_8), } - else if (modWarp.Length == 3) + }, + new List> + { + new List(), + new List + { + new LevelConstants.RandoLevel(ELevel.Level_03_ForlornTemple, new Vector3(0.5f, -11)), + new LevelConstants.RandoLevel(ELevel.Level_03_ForlornTemple, new Vector3(88.5f, -10)), + new LevelConstants.RandoLevel(ELevel.Level_03_ForlornTemple, new Vector3(251.5f, 53)), + new LevelConstants.RandoLevel(ELevel.Level_03_ForlornTemple, new Vector3(156, 85)), + new LevelConstants.RandoLevel(ELevel.Level_03_ForlornTemple, new Vector3(271.5f, 61)), + new LevelConstants.RandoLevel(ELevel.Level_03_ForlornTemple, new Vector3(347.5f, 31)), + new LevelConstants.RandoLevel(ELevel.Level_03_ForlornTemple, new Vector3(354.5f, -11)), + }, + new List { - Region = int.Parse(modWarp[0].ToString()); - PortalType = int.Parse(modWarp[1].ToString()); - Index = int.Parse(modWarp[2].ToString()); + new LevelConstants.RandoLevel(ELevel.Level_03_ForlornTemple, new Vector3(124.5f, 47)), + new LevelConstants.RandoLevel(ELevel.Level_03_ForlornTemple, new Vector3(260.5f, 24)), } - else if (modWarp.Length == 2) + }, + new List> + { + new List(), + new List + { + new LevelConstants.RandoLevel(ELevel.Level_04_Catacombs, new Vector3(241.5f, -25)), + new LevelConstants.RandoLevel(ELevel.Level_04_Catacombs, new Vector3(731.5f, -75)), + }, + new List { - Region = 0; - PortalType = int.Parse(modWarp[0].ToString()); - Index = int.Parse(modWarp[1].ToString()); + new LevelConstants.RandoLevel(ELevel.Level_04_Catacombs, new Vector3(379.5f, -23)), + new LevelConstants.RandoLevel(ELevel.Level_04_Catacombs, new Vector3(529.5f, -75), EBits.BITS_16), + new LevelConstants.RandoLevel(ELevel.Level_04_Catacombs, new Vector3(499.5f, -43)), } - else + }, + new List> + { + new List(), + new List { - Region = 0; - PortalType = 0; - Index = int.Parse(modWarp); + new LevelConstants.RandoLevel(ELevel.Level_06_A_BambooCreek, new Vector3(-28.5f, -19)), + new LevelConstants.RandoLevel(ELevel.Level_06_A_BambooCreek, new Vector3(92.5f, 25)), + new LevelConstants.RandoLevel(ELevel.Level_06_A_BambooCreek, new Vector3(379.5f, 25)), + }, + new List + { + new LevelConstants.RandoLevel(ELevel.Level_06_A_BambooCreek, new Vector3(227.5f, -41)), + new LevelConstants.RandoLevel(ELevel.Level_06_A_BambooCreek, new Vector3(210.5f, 29)), } - } - } - - public static bool LeftHQPortal; - public static bool ForceTeleport; - public static bool EnteredTower; - public static List StartingPortals; - public static List PortalMapping; - public static TrackerManager TrackerManager; - - static readonly List>> AreaCheckpoints = - new List>> + }, + new List> + { + new List + { + new LevelConstants.RandoLevel(ELevel.Level_05_A_HowlingGrotto, new Vector3(241f, -196f)), + }, + new List + { + new LevelConstants.RandoLevel(ELevel.Level_05_A_HowlingGrotto, new Vector3(26.5f, -27)), + new LevelConstants.RandoLevel(ELevel.Level_05_A_HowlingGrotto, new Vector3(310.5f, -115)), + new LevelConstants.RandoLevel(ELevel.Level_05_A_HowlingGrotto, new Vector3(541.5f, -123)), + }, + new List + { + new LevelConstants.RandoLevel(ELevel.Level_05_A_HowlingGrotto, new Vector3(138.5f, -90)), + new LevelConstants.RandoLevel(ELevel.Level_05_A_HowlingGrotto, new Vector3(439, -170)), + } + }, + new List> { - new List> - { - new List - { - new LevelConstants.RandoLevel(ELevel.Level_02_AutumnHills, new Vector3(485, -102)), - }, - new List - { - new LevelConstants.RandoLevel(ELevel.Level_02_AutumnHills, new Vector3(-45.5f, -89)), - new LevelConstants.RandoLevel(ELevel.Level_02_AutumnHills, new Vector3(68.5f, -111)), - new LevelConstants.RandoLevel(ELevel.Level_02_AutumnHills, new Vector3(407.5f, -74)), - new LevelConstants.RandoLevel(ELevel.Level_02_AutumnHills, new Vector3(892.5f, -27)), - }, - new List - { - new LevelConstants.RandoLevel(ELevel.Level_02_AutumnHills, new Vector3(175, -148)), - new LevelConstants.RandoLevel(ELevel.Level_02_AutumnHills, new Vector3(91.5f, -87)), - new LevelConstants.RandoLevel(ELevel.Level_02_AutumnHills, new Vector3(238.5f, -74)), - new LevelConstants.RandoLevel(ELevel.Level_02_AutumnHills, new Vector3(607.48f, -35)), - new LevelConstants.RandoLevel(ELevel.Level_02_AutumnHills, new Vector3(718.5f, -73), EBits.BITS_8), - } + new List(), + new List + { + new LevelConstants.RandoLevel(ELevel.Level_07_QuillshroomMarsh, new Vector3(193.5f, -37)), + new LevelConstants.RandoLevel(ELevel.Level_07_QuillshroomMarsh, new Vector3(663.5f, -27)), + new LevelConstants.RandoLevel(ELevel.Level_07_QuillshroomMarsh, new Vector3(1085.5f, -43)), }, - new List> - { - new List(), - new List - { - new LevelConstants.RandoLevel(ELevel.Level_03_ForlornTemple, new Vector3(0.5f, -11)), - new LevelConstants.RandoLevel(ELevel.Level_03_ForlornTemple, new Vector3(88.5f, -10)), - new LevelConstants.RandoLevel(ELevel.Level_03_ForlornTemple, new Vector3(251.5f, 53)), - new LevelConstants.RandoLevel(ELevel.Level_03_ForlornTemple, new Vector3(156, 85)), - new LevelConstants.RandoLevel(ELevel.Level_03_ForlornTemple, new Vector3(271.5f, 61)), - new LevelConstants.RandoLevel(ELevel.Level_03_ForlornTemple, new Vector3(347.5f, 31)), - new LevelConstants.RandoLevel(ELevel.Level_03_ForlornTemple, new Vector3(354.5f, -11)), - }, - new List - { - new LevelConstants.RandoLevel(ELevel.Level_03_ForlornTemple, new Vector3(124.5f, 47)), - new LevelConstants.RandoLevel(ELevel.Level_03_ForlornTemple, new Vector3(260.5f, 24)), - } + new List + { + new LevelConstants.RandoLevel(ELevel.Level_07_QuillshroomMarsh, new Vector3(161.5f, -54)), + new LevelConstants.RandoLevel(ELevel.Level_07_QuillshroomMarsh, new Vector3(409.5f, -42)), + new LevelConstants.RandoLevel(ELevel.Level_07_QuillshroomMarsh, new Vector3(916.5f, -26)), + } + }, + new List> + { + new List + { + new LevelConstants.RandoLevel(ELevel.Level_08_SearingCrags, new Vector3(384.5f, 135f)), }, - new List> - { - new List(), - new List - { - new LevelConstants.RandoLevel(ELevel.Level_04_Catacombs, new Vector3(241.5f, -25)), - new LevelConstants.RandoLevel(ELevel.Level_04_Catacombs, new Vector3(731.5f, -75)), - }, - new List - { - new LevelConstants.RandoLevel(ELevel.Level_04_Catacombs, new Vector3(379.5f, -23)), - new LevelConstants.RandoLevel(ELevel.Level_04_Catacombs, new Vector3(529.5f, -75), EBits.BITS_16), - new LevelConstants.RandoLevel(ELevel.Level_04_Catacombs, new Vector3(499.5f, -43)), - } + new List + { + new LevelConstants.RandoLevel(ELevel.Level_08_SearingCrags, new Vector3(61, -27)), + new LevelConstants.RandoLevel(ELevel.Level_08_SearingCrags, new Vector3(147.5f, 69)), + new LevelConstants.RandoLevel(ELevel.Level_08_SearingCrags, new Vector3(226.5f, 151)), + new LevelConstants.RandoLevel(ELevel.Level_08_SearingCrags, new Vector3(282, 237)), + new LevelConstants.RandoLevel(ELevel.Level_08_SearingCrags, new Vector3(380.5f, 309)), + new LevelConstants.RandoLevel(ELevel.Level_08_SearingCrags, new Vector3(119.5f, 248), EBits.BITS_8), }, - new List> - { - new List(), - new List - { - new LevelConstants.RandoLevel(ELevel.Level_06_A_BambooCreek, new Vector3(-28.5f, -19)), - new LevelConstants.RandoLevel(ELevel.Level_06_A_BambooCreek, new Vector3(92.5f, 25)), - new LevelConstants.RandoLevel(ELevel.Level_06_A_BambooCreek, new Vector3(379.5f, 25)), - }, - new List - { - new LevelConstants.RandoLevel(ELevel.Level_06_A_BambooCreek, new Vector3(227.5f, -41)), - new LevelConstants.RandoLevel(ELevel.Level_06_A_BambooCreek, new Vector3(210.5f, 29)), - } + new List + { + new LevelConstants.RandoLevel(ELevel.Level_08_SearingCrags, new Vector3(109.5f, 63)), + new LevelConstants.RandoLevel(ELevel.Level_08_SearingCrags, new Vector3(296.5f, 189f), EBits.BITS_8), + } + }, + new List> + { + new List + { + new LevelConstants.RandoLevel(ELevel.Level_09_A_GlacialPeak, new Vector3(220.6f, -67)), }, - new List> - { - new List - { - new LevelConstants.RandoLevel(ELevel.Level_05_A_HowlingGrotto, new Vector3(241f, -196f)), - }, - new List - { - new LevelConstants.RandoLevel(ELevel.Level_05_A_HowlingGrotto, new Vector3(26.5f, -27)), - new LevelConstants.RandoLevel(ELevel.Level_05_A_HowlingGrotto, new Vector3(310.5f, -115)), - new LevelConstants.RandoLevel(ELevel.Level_05_A_HowlingGrotto, new Vector3(541.5f, -123)), - }, - new List - { - new LevelConstants.RandoLevel(ELevel.Level_05_A_HowlingGrotto, new Vector3(138.5f, -90)), - new LevelConstants.RandoLevel(ELevel.Level_05_A_HowlingGrotto, new Vector3(439, -170)), - } + new List + { + new LevelConstants.RandoLevel(ELevel.Level_09_A_GlacialPeak, new Vector3(216.5f, -456)), + new LevelConstants.RandoLevel(ELevel.Level_09_A_GlacialPeak, new Vector3(259.5f, -297)), + new LevelConstants.RandoLevel(ELevel.Level_09_A_GlacialPeak, new Vector3(156.5f, -27)), }, - new List> - { - new List(), - new List - { - new LevelConstants.RandoLevel(ELevel.Level_07_QuillshroomMarsh, new Vector3(193.5f, -37)), - new LevelConstants.RandoLevel(ELevel.Level_07_QuillshroomMarsh, new Vector3(663.5f, -27)), - new LevelConstants.RandoLevel(ELevel.Level_07_QuillshroomMarsh, new Vector3(1085.5f, -43)), - }, - new List - { - new LevelConstants.RandoLevel(ELevel.Level_07_QuillshroomMarsh, new Vector3(161.5f, -54)), - new LevelConstants.RandoLevel(ELevel.Level_07_QuillshroomMarsh, new Vector3(409.5f, -42)), - new LevelConstants.RandoLevel(ELevel.Level_07_QuillshroomMarsh, new Vector3(916.5f, -26)), - } + new List + { + new LevelConstants.RandoLevel(ELevel.Level_09_A_GlacialPeak, new Vector3(227.5f, -405)), + new LevelConstants.RandoLevel(ELevel.Level_09_A_GlacialPeak, new Vector3(251.5f, -235)), + new LevelConstants.RandoLevel(ELevel.Level_09_A_GlacialPeak, new Vector3(195.5f, -131)), + } + }, + new List> + { + new List(), + new List + { + new LevelConstants.RandoLevel(ELevel.Level_10_A_TowerOfTime, new Vector3(71.5f, -11), EBits.BITS_8), + new LevelConstants.RandoLevel(ELevel.Level_10_A_TowerOfTime, new Vector3(84.5f, 237), EBits.BITS_8), }, - new List> - { - new List - { - new LevelConstants.RandoLevel(ELevel.Level_08_SearingCrags, new Vector3(384.5f, 135f)), - }, - new List - { - new LevelConstants.RandoLevel(ELevel.Level_08_SearingCrags, new Vector3(61, -27)), - new LevelConstants.RandoLevel(ELevel.Level_08_SearingCrags, new Vector3(147.5f, 69)), - new LevelConstants.RandoLevel(ELevel.Level_08_SearingCrags, new Vector3(226.5f, 151)), - new LevelConstants.RandoLevel(ELevel.Level_08_SearingCrags, new Vector3(282, 237)), - new LevelConstants.RandoLevel(ELevel.Level_08_SearingCrags, new Vector3(380.5f, 309)), - new LevelConstants.RandoLevel(ELevel.Level_08_SearingCrags, new Vector3(119.5f, 248), EBits.BITS_8), - }, - new List - { - new LevelConstants.RandoLevel(ELevel.Level_08_SearingCrags, new Vector3(109.5f, 63)), - new LevelConstants.RandoLevel(ELevel.Level_08_SearingCrags, new Vector3(296.5f, 189f), EBits.BITS_8), - } + new List + { + new LevelConstants.RandoLevel(ELevel.Level_10_A_TowerOfTime, new Vector3(38.5f, 21.5f), EBits.BITS_8), + new LevelConstants.RandoLevel(ELevel.Level_10_A_TowerOfTime, new Vector3(5.5f, 37), EBits.BITS_8), + new LevelConstants.RandoLevel(ELevel.Level_10_A_TowerOfTime, new Vector3(50.5f, 77), EBits.BITS_8), + new LevelConstants.RandoLevel(ELevel.Level_10_A_TowerOfTime, new Vector3(57.5f, 85), EBits.BITS_8), + new LevelConstants.RandoLevel(ELevel.Level_10_A_TowerOfTime, new Vector3(31.5f, 133), EBits.BITS_8), + new LevelConstants.RandoLevel(ELevel.Level_10_A_TowerOfTime, new Vector3(58.5f, 165), EBits.BITS_8), + } + }, + new List> + { + new List(), + new List + { + new LevelConstants.RandoLevel(ELevel.Level_11_A_CloudRuins, new Vector3(-368.5f, -26), EBits.BITS_8), + new LevelConstants.RandoLevel(ELevel.Level_11_A_CloudRuins, new Vector3(-140.5f, -26), EBits.BITS_8), + new LevelConstants.RandoLevel(ELevel.Level_11_A_CloudRuins, new Vector3(116.5f, -25)), + new LevelConstants.RandoLevel(ELevel.Level_11_A_CloudRuins, new Vector3(366.5f, -27), EBits.BITS_8), + new LevelConstants.RandoLevel(ELevel.Level_11_A_CloudRuins, new Vector3(721.5f, -22), EBits.BITS_8), + new LevelConstants.RandoLevel(ELevel.Level_11_A_CloudRuins, new Vector3(816.5f, -26), EBits.BITS_8), + new LevelConstants.RandoLevel(ELevel.Level_11_A_CloudRuins, new Vector3(1148.5f, -27), EBits.BITS_8), }, - new List> - { - new List - { - new LevelConstants.RandoLevel(ELevel.Level_09_A_GlacialPeak, new Vector3(220.6f, -67)), - }, - new List - { - new LevelConstants.RandoLevel(ELevel.Level_09_A_GlacialPeak, new Vector3(216.5f, -456)), - new LevelConstants.RandoLevel(ELevel.Level_09_A_GlacialPeak, new Vector3(259.5f, -297)), - new LevelConstants.RandoLevel(ELevel.Level_09_A_GlacialPeak, new Vector3(156.5f, -27)), - }, - new List - { - new LevelConstants.RandoLevel(ELevel.Level_09_A_GlacialPeak, new Vector3(227.5f, -405)), - new LevelConstants.RandoLevel(ELevel.Level_09_A_GlacialPeak, new Vector3(251.5f, -235)), - new LevelConstants.RandoLevel(ELevel.Level_09_A_GlacialPeak, new Vector3(195.5f, -131)), - } + new List + { + new LevelConstants.RandoLevel(ELevel.Level_11_A_CloudRuins, new Vector3(-146, 24), EBits.BITS_8), + new LevelConstants.RandoLevel(ELevel.Level_11_A_CloudRuins, new Vector3(164, -21)), + new LevelConstants.RandoLevel(ELevel.Level_11_A_CloudRuins, new Vector3(769.5f, -26)), + new LevelConstants.RandoLevel(ELevel.Level_11_A_CloudRuins, new Vector3(-251, 13)), + } + }, + new List> + { + new List(), + new List + { + new LevelConstants.RandoLevel(ELevel.Level_12_UnderWorld, new Vector3(-305, -51), EBits.BITS_8), + new LevelConstants.RandoLevel(ELevel.Level_12_UnderWorld, new Vector3(-186.5f, -24), EBits.BITS_8), + new LevelConstants.RandoLevel(ELevel.Level_12_UnderWorld, new Vector3(-125.5f, -91), EBits.BITS_8), + //new LevelConstants.RandoLevel(ELevel.Level_12_UnderWorld, new Vector3(124.5f, -43)), // barm'athazel which isn't accessible in second quest + new LevelConstants.RandoLevel(ELevel.Level_12_UnderWorld, new Vector3(132.5f, -130)), }, - new List> - { - new List(), - new List - { - new LevelConstants.RandoLevel(ELevel.Level_10_A_TowerOfTime, new Vector3(71.5f, -11), EBits.BITS_8), - new LevelConstants.RandoLevel(ELevel.Level_10_A_TowerOfTime, new Vector3(84.5f, 237), EBits.BITS_8), - }, - new List - { - new LevelConstants.RandoLevel(ELevel.Level_10_A_TowerOfTime, new Vector3(38.5f, 21.5f), EBits.BITS_8), - new LevelConstants.RandoLevel(ELevel.Level_10_A_TowerOfTime, new Vector3(5.5f, 37), EBits.BITS_8), - new LevelConstants.RandoLevel(ELevel.Level_10_A_TowerOfTime, new Vector3(50.5f, 77), EBits.BITS_8), - new LevelConstants.RandoLevel(ELevel.Level_10_A_TowerOfTime, new Vector3(57.5f, 85), EBits.BITS_8), - new LevelConstants.RandoLevel(ELevel.Level_10_A_TowerOfTime, new Vector3(31.5f, 133), EBits.BITS_8), - new LevelConstants.RandoLevel(ELevel.Level_10_A_TowerOfTime, new Vector3(58.5f, 165), EBits.BITS_8), - } + new List + { + new LevelConstants.RandoLevel(ELevel.Level_12_UnderWorld, new Vector3(-226.5f, -89), EBits.BITS_8), + new LevelConstants.RandoLevel(ELevel.Level_12_UnderWorld, new Vector3(0.5f, 72), EBits.BITS_8), + new LevelConstants.RandoLevel(ELevel.Level_12_UnderWorld, new Vector3(-110.5f, -98), EBits.BITS_8), + } + }, + new List> + { + new List + { + new LevelConstants.RandoLevel(ELevel.Level_04_C_RiviereTurquoise, new Vector3(837, 13.5f)), }, - new List> - { - new List(), - new List - { - new LevelConstants.RandoLevel(ELevel.Level_11_A_CloudRuins, new Vector3(-368.5f, -26), EBits.BITS_8), - new LevelConstants.RandoLevel(ELevel.Level_11_A_CloudRuins, new Vector3(-140.5f, -26), EBits.BITS_8), - new LevelConstants.RandoLevel(ELevel.Level_11_A_CloudRuins, new Vector3(116.5f, -25)), - new LevelConstants.RandoLevel(ELevel.Level_11_A_CloudRuins, new Vector3(366.5f, -27), EBits.BITS_8), - new LevelConstants.RandoLevel(ELevel.Level_11_A_CloudRuins, new Vector3(721.5f, -22), EBits.BITS_8), - new LevelConstants.RandoLevel(ELevel.Level_11_A_CloudRuins, new Vector3(816.5f, -26), EBits.BITS_8), - new LevelConstants.RandoLevel(ELevel.Level_11_A_CloudRuins, new Vector3(1148.5f, -27), EBits.BITS_8), - }, - new List - { - new LevelConstants.RandoLevel(ELevel.Level_11_A_CloudRuins, new Vector3(-146, 24), EBits.BITS_8), - new LevelConstants.RandoLevel(ELevel.Level_11_A_CloudRuins, new Vector3(164, -21)), - new LevelConstants.RandoLevel(ELevel.Level_11_A_CloudRuins, new Vector3(769.5f, -26)), - new LevelConstants.RandoLevel(ELevel.Level_11_A_CloudRuins, new Vector3(-251, 13)), - } + new List + { + new LevelConstants.RandoLevel(ELevel.Level_04_C_RiviereTurquoise, new Vector3(804.5f, -40)), + new LevelConstants.RandoLevel(ELevel.Level_04_C_RiviereTurquoise, new Vector3(499, -132), EBits.BITS_8), + new LevelConstants.RandoLevel(ELevel.Level_04_C_RiviereTurquoise, new Vector3(337.5f, -131)), + new LevelConstants.RandoLevel(ELevel.Level_04_C_RiviereTurquoise, new Vector3(149.5f, -89)), + new LevelConstants.RandoLevel(ELevel.Level_04_C_RiviereTurquoise, new Vector3(-8.5f, 13)), + new LevelConstants.RandoLevel(ELevel.Level_04_C_RiviereTurquoise, new Vector3(-259, 7)), }, - new List> - { - new List(), - new List - { - new LevelConstants.RandoLevel(ELevel.Level_12_UnderWorld, new Vector3(-305, -51), EBits.BITS_8), - new LevelConstants.RandoLevel(ELevel.Level_12_UnderWorld, new Vector3(-186.5f, -24), EBits.BITS_8), - new LevelConstants.RandoLevel(ELevel.Level_12_UnderWorld, new Vector3(-125.5f, -91), EBits.BITS_8), - //new LevelConstants.RandoLevel(ELevel.Level_12_UnderWorld, new Vector3(124.5f, -43)), // barm'athazel which isn't accessible in second quest - new LevelConstants.RandoLevel(ELevel.Level_12_UnderWorld, new Vector3(132.5f, -130)), - }, - new List - { - new LevelConstants.RandoLevel(ELevel.Level_12_UnderWorld, new Vector3(-226.5f, -89), EBits.BITS_8), - new LevelConstants.RandoLevel(ELevel.Level_12_UnderWorld, new Vector3(0.5f, 72), EBits.BITS_8), - new LevelConstants.RandoLevel(ELevel.Level_12_UnderWorld, new Vector3(-110.5f, -98), EBits.BITS_8), - } + new List + { + new LevelConstants.RandoLevel(ELevel.Level_04_C_RiviereTurquoise, new Vector3(648.5f, -83), EBits.BITS_8), + } + }, + new List> + { + new List(), + new List + { + new LevelConstants.RandoLevel(ELevel.Level_09_B_ElementalSkylands, new Vector3(-35, 359)), + new LevelConstants.RandoLevel(ELevel.Level_09_B_ElementalSkylands, new Vector3(87.5f, 407)), + new LevelConstants.RandoLevel(ELevel.Level_09_B_ElementalSkylands, new Vector3(864.5f, 381)), + new LevelConstants.RandoLevel(ELevel.Level_09_B_ElementalSkylands, new Vector3(966.3f, 409.4f)), + new LevelConstants.RandoLevel(ELevel.Level_09_B_ElementalSkylands, new Vector3(1763.5f, 381)), + new LevelConstants.RandoLevel(ELevel.Level_09_B_ElementalSkylands, new Vector3(1909, 411)), + new LevelConstants.RandoLevel(ELevel.Level_09_B_ElementalSkylands, new Vector3(2755.5f, 376), EBits.BITS_8), + new LevelConstants.RandoLevel(ELevel.Level_09_B_ElementalSkylands, new Vector3(2926.5f, 406)), }, - new List> - { - new List - { - new LevelConstants.RandoLevel(ELevel.Level_04_C_RiviereTurquoise, new Vector3(837, 13.5f)), - }, - new List - { - new LevelConstants.RandoLevel(ELevel.Level_04_C_RiviereTurquoise, new Vector3(804.5f, -40)), - new LevelConstants.RandoLevel(ELevel.Level_04_C_RiviereTurquoise, new Vector3(499, -132), EBits.BITS_8), - new LevelConstants.RandoLevel(ELevel.Level_04_C_RiviereTurquoise, new Vector3(337.5f, -131)), - new LevelConstants.RandoLevel(ELevel.Level_04_C_RiviereTurquoise, new Vector3(149.5f, -89)), - new LevelConstants.RandoLevel(ELevel.Level_04_C_RiviereTurquoise, new Vector3(-8.5f, 13)), - new LevelConstants.RandoLevel(ELevel.Level_04_C_RiviereTurquoise, new Vector3(-259, 7)), - }, - new List - { - new LevelConstants.RandoLevel(ELevel.Level_04_C_RiviereTurquoise, new Vector3(648.5f, -83), EBits.BITS_8), - } + new List + { + new LevelConstants.RandoLevel(ELevel.Level_09_B_ElementalSkylands, new Vector3(-22.5f, 417)), + } + }, + new List> + { + new List + { + new LevelConstants.RandoLevel(ELevel.Level_05_B_SunkenShrine, new Vector3(29f, -55f)), }, - new List> - { - new List(), - new List - { - new LevelConstants.RandoLevel(ELevel.Level_09_B_ElementalSkylands, new Vector3(-35, 359)), - new LevelConstants.RandoLevel(ELevel.Level_09_B_ElementalSkylands, new Vector3(87.5f, 407)), - new LevelConstants.RandoLevel(ELevel.Level_09_B_ElementalSkylands, new Vector3(864.5f, 381)), - new LevelConstants.RandoLevel(ELevel.Level_09_B_ElementalSkylands, new Vector3(966.3f, 409.4f)), - new LevelConstants.RandoLevel(ELevel.Level_09_B_ElementalSkylands, new Vector3(1763.5f, 381)), - new LevelConstants.RandoLevel(ELevel.Level_09_B_ElementalSkylands, new Vector3(1909, 411)), - new LevelConstants.RandoLevel(ELevel.Level_09_B_ElementalSkylands, new Vector3(2755.5f, 376), EBits.BITS_8), - new LevelConstants.RandoLevel(ELevel.Level_09_B_ElementalSkylands, new Vector3(2926.5f, 406)), - }, - new List - { - new LevelConstants.RandoLevel(ELevel.Level_09_B_ElementalSkylands, new Vector3(-22.5f, 417)), - } + new List + { + new LevelConstants.RandoLevel(ELevel.Level_05_B_SunkenShrine, new Vector3(36.5f, -41)), + new LevelConstants.RandoLevel(ELevel.Level_05_B_SunkenShrine, new Vector3(186.5f, -9), EBits.BITS_8), + new LevelConstants.RandoLevel(ELevel.Level_05_B_SunkenShrine, new Vector3(8, -65), EBits.BITS_8), + new LevelConstants.RandoLevel(ELevel.Level_05_B_SunkenShrine, new Vector3(-102.5f, -121), EBits.BITS_8), + new LevelConstants.RandoLevel(ELevel.Level_05_B_SunkenShrine, new Vector3(100, -81), EBits.BITS_8), }, - new List> - { - new List - { - new LevelConstants.RandoLevel(ELevel.Level_05_B_SunkenShrine, new Vector3(29f, -55f)), - }, - new List - { - new LevelConstants.RandoLevel(ELevel.Level_05_B_SunkenShrine, new Vector3(36.5f, -41)), - new LevelConstants.RandoLevel(ELevel.Level_05_B_SunkenShrine, new Vector3(186.5f, -9), EBits.BITS_8), - new LevelConstants.RandoLevel(ELevel.Level_05_B_SunkenShrine, new Vector3(8, -65), EBits.BITS_8), - new LevelConstants.RandoLevel(ELevel.Level_05_B_SunkenShrine, new Vector3(-102.5f, -121), EBits.BITS_8), - new LevelConstants.RandoLevel(ELevel.Level_05_B_SunkenShrine, new Vector3(100, -81), EBits.BITS_8), - }, - new List - { - new LevelConstants.RandoLevel(ELevel.Level_05_B_SunkenShrine, new Vector3(53.5f, -25), EBits.BITS_8), - new LevelConstants.RandoLevel(ELevel.Level_05_B_SunkenShrine, new Vector3(29.5f, -87), EBits.BITS_8), - new LevelConstants.RandoLevel(ELevel.Level_05_B_SunkenShrine, new Vector3(166, -178), EBits.BITS_8), - new LevelConstants.RandoLevel(ELevel.Level_05_B_SunkenShrine, new Vector3(92.5f, -100), EBits.BITS_8), - } + new List + { + new LevelConstants.RandoLevel(ELevel.Level_05_B_SunkenShrine, new Vector3(53.5f, -25), EBits.BITS_8), + new LevelConstants.RandoLevel(ELevel.Level_05_B_SunkenShrine, new Vector3(29.5f, -87), EBits.BITS_8), + new LevelConstants.RandoLevel(ELevel.Level_05_B_SunkenShrine, new Vector3(166, -178), EBits.BITS_8), + new LevelConstants.RandoLevel(ELevel.Level_05_B_SunkenShrine, new Vector3(92.5f, -100), EBits.BITS_8), } - }; - - private static readonly List Portals = new List - { - "Autumn Hills - Portal", - "Riviere Turquoise - Portal", - "Howling Grotto - Portal", - "Sunken Shrine - Portal", - "Searing Crags - Portal", - "Glacial Peak - Portal", + } }; - private static readonly List AccessedStartingPortals = new List(); + private static readonly List Portals = new List + { + "Autumn Hills - Portal", + "Riviere Turquoise - Portal", + "Howling Grotto - Portal", + "Sunken Shrine - Portal", + "Searing Crags - Portal", + "Glacial Peak - Portal", + }; + + private static readonly List AccessedStartingPortals = new List(); - public static HashSet UnlockedPortals + public static HashSet UnlockedPortals + { + get { - get + var unlockedPortals = new HashSet(); + + var progressManager = Manager.Instance; + if (progressManager.cutscenesPlayed.Contains("PortalOpeningCutscene")) + { + unlockedPortals.Add("Autumn Hills Portal"); + unlockedPortals.Add("Howling Grotto Portal"); + unlockedPortals.Add("Glacial Peak Portal"); + } + if (progressManager.cutscenesPlayed.Contains("SunkenShrinePortalOpeningCutscene")) + { + unlockedPortals.Add("Sunken Shrine Portal"); + } + if (progressManager.cutscenesPlayed.Contains("SearingCragsPortalOpeningCutscene")) + { + unlockedPortals.Add("Searing Crags Portal"); + } + if (progressManager.cutscenesPlayed.Contains("RiviereTurquoisePortalOpeningCutscene")) { - var unlockedPortals = new HashSet(); + unlockedPortals.Add("Riviere Turquoise Portal"); + } - var progressManager = Manager.Instance; - if (progressManager.cutscenesPlayed.Contains("PortalOpeningCutscene")) - { - unlockedPortals.Add("Autumn Hills Portal"); - unlockedPortals.Add("Howling Grotto Portal"); - unlockedPortals.Add("Glacial Peak Portal"); - } - if (progressManager.cutscenesPlayed.Contains("SunkenShrinePortalOpeningCutscene")) + return unlockedPortals; + } + } + + public static bool ShouldPortalBeOpen(string portal) + { + return AccessedStartingPortals.Contains(portal); + } + + public static void OpenPortalEvent(On.PortalOpeningCutscene.orig_OnOpenPortalEvent orig, + PortalOpeningCutscene self, string eventid) + { + switch (eventid) + { + case "AutumnHills": + if (StartingPortals.Contains("Autumn Hills Portal")) { - unlockedPortals.Add("Sunken Shrine Portal"); + orig(self, eventid); + AccessedStartingPortals.Add(eventid); } - if (progressManager.cutscenesPlayed.Contains("SearingCragsPortalOpeningCutscene")) + break; + case "HowlingGrotto": + if (StartingPortals.Contains("Howling Grotto Portal")) { - unlockedPortals.Add("Searing Crags Portal"); + orig(self, eventid); + AccessedStartingPortals.Add(eventid); } - if (progressManager.cutscenesPlayed.Contains("RiviereTurquoisePortalOpeningCutscene")) + break; + case "GlacialPeak": + if (StartingPortals.Contains("Glacial Peak Portal")) { - unlockedPortals.Add("Riviere Turquoise Portal"); + orig(self, eventid); + AccessedStartingPortals.Add(eventid); } - - return unlockedPortals; - } + break; + default: + orig(self, eventid); + break; } + } - public static bool ShouldPortalBeOpen(string portal) + private static LevelConstants.RandoLevel GetPortalExit(string enteredPortal) + { + Console.WriteLine($"getting portal. entered {enteredPortal}"); + var portalExit = PortalMapping[Portals.IndexOf(enteredPortal)]; + Console.WriteLine($"{portalExit.Region}, {portalExit.PortalType}, {portalExit.Index}"); + return AreaCheckpoints[portalExit.Region][portalExit.PortalType][portalExit.Index]; + } + + public static void Teleport() + { + var currentLevel = Manager.Instance.GetCurrentLevelEnum(); + if (!LevelConstants.TransitionToEntranceName.TryGetValue( + new LevelConstants.Transition(ELevel.Level_13_TowerOfTimeHQ, + currentLevel), out var portal)) { - return AccessedStartingPortals.Contains(portal); + Console.WriteLine($"unable to find portal for {currentLevel}"); } - - public static void OpenPortalEvent(On.PortalOpeningCutscene.orig_OnOpenPortalEvent orig, - PortalOpeningCutscene self, string eventid) + else { - switch (eventid) + if (portal.Equals("Tower of Time - Left") || portal.Equals("Corrupted Future")) { - case "AutumnHills": - if (StartingPortals.Contains("Autumn Hills Portal")) - { - orig(self, eventid); - AccessedStartingPortals.Add(eventid); - } - break; - case "HowlingGrotto": - if (StartingPortals.Contains("Howling Grotto Portal")) - { - orig(self, eventid); - AccessedStartingPortals.Add(eventid); - } - break; - case "GlacialPeak": - if (StartingPortals.Contains("Glacial Peak Portal")) - { - orig(self, eventid); - AccessedStartingPortals.Add(eventid); - } - break; - default: - orig(self, eventid); - break; + if (portal.Equals("Tower of Time - Left")) + EnteredTower = true; + LeftHQPortal = false; + var newLevel = RandoLevelManager.FindEntrance(); + if (RandoLevelManager.RandoLevelMapping != null && RandoLevelManager.RandoLevelMapping.Count > 0) + { + RandoLevelManager.TeleportInArea(newLevel.LevelName, newLevel.PlayerPos, newLevel.Dimension); + } + return; } - } - - private static LevelConstants.RandoLevel GetPortalExit(string enteredPortal) - { - Console.WriteLine($"getting portal. entered {enteredPortal}"); - var portalExit = PortalMapping[Portals.IndexOf(enteredPortal)]; - Console.WriteLine($"{portalExit.Region}, {portalExit.PortalType}, {portalExit.Index}"); - return AreaCheckpoints[portalExit.Region][portalExit.PortalType][portalExit.Index]; - } - public static void Teleport() - { - var currentLevel = Manager.Instance.GetCurrentLevelEnum(); - if (!LevelConstants.TransitionToEntranceName.TryGetValue( - new LevelConstants.Transition(ELevel.Level_13_TowerOfTimeHQ, - currentLevel), out var portal)) + if (PortalMapping is null || PortalMapping.Count == 0) { - Console.WriteLine($"unable to find portal for {currentLevel}"); + LeftHQPortal = false; + return; } - else + try { - if (portal.Equals("Tower of Time - Left") || portal.Equals("Corrupted Future")) - { - if (portal.Equals("Tower of Time - Left")) - EnteredTower = true; - LeftHQPortal = false; - var newLevel = RandoLevelManager.FindEntrance(); - if (RandoLevelManager.RandoLevelMapping != null && RandoLevelManager.RandoLevelMapping.Count > 0) - { - RandoLevelManager.TeleportInArea(newLevel.LevelName, newLevel.PlayerPos, newLevel.Dimension); - } - return; - } - - if (PortalMapping is null || PortalMapping.Count == 0) + var newLevel = GetPortalExit(portal); + switch (newLevel.LevelName) { - LeftHQPortal = false; - return; + case ELevel.Level_09_B_ElementalSkylands: + RandoLevelManager.KillManfred = true; + break; + case ELevel.NONE: + LeftHQPortal = false; + return; } - try - { - var newLevel = GetPortalExit(portal); - switch (newLevel.LevelName) - { - case ELevel.Level_09_B_ElementalSkylands: - RandoLevelManager.KillManfred = true; - break; - case ELevel.NONE: - LeftHQPortal = false; - return; - } - TrackerManager.AddVisitedEntrance("HQ - " + portal.Replace("- ", "")); - RandoLevelManager.TeleportInArea(newLevel.LevelName, newLevel.PlayerPos, newLevel.Dimension); - } - catch (Exception e) - { - Console.WriteLine(e); - } + TrackerManager.AddVisitedEntrance("HQ - " + portal.Replace("- ", "")); + RandoLevelManager.TeleportInArea(newLevel.LevelName, newLevel.PlayerPos, newLevel.Dimension); + } + catch (Exception e) + { + Console.WriteLine(e); } - - LeftHQPortal = false; } - public static void LeaveHQ(On.TotHQ.orig_LeaveToLevel orig, TotHQ self, bool playLevelMusic, bool loadingNewLevel) - { - Console.WriteLine("leaving hq..."); - LeftHQPortal = true; - ForceTeleport = !loadingNewLevel; - Console.WriteLine($"Force teleport: {ForceTeleport}"); - orig(self, playLevelMusic, loadingNewLevel); - } + LeftHQPortal = false; + } + + public static void LeaveHQ(On.TotHQ.orig_LeaveToLevel orig, TotHQ self, bool playLevelMusic, bool loadingNewLevel) + { + Console.WriteLine("leaving hq..."); + LeftHQPortal = true; + ForceTeleport = !loadingNewLevel; + Console.WriteLine($"Force teleport: {ForceTeleport}"); + orig(self, playLevelMusic, loadingNewLevel); } } diff --git a/GameOverrideManagers/RandoPowerSealManager.cs b/GameOverrideManagers/RandoPowerSealManager.cs index ef0c3e5..cdaf3a6 100644 --- a/GameOverrideManagers/RandoPowerSealManager.cs +++ b/GameOverrideManagers/RandoPowerSealManager.cs @@ -3,69 +3,68 @@ using UnityEngine; using Object = UnityEngine.Object; -namespace MessengerRando.GameOverrideManagers +namespace MessengerRando.GameOverrideManagers; + +public class RandoPowerSealManager { - public class RandoPowerSealManager + public RandoPowerSealManager(int requiredPowerSeals) { - public RandoPowerSealManager(int requiredPowerSeals) - { - if (requiredPowerSeals == 0) - requiredPowerSeals = 45; - Manager.Instance.powerSealTotal = requiredPowerSeals; - } + if (requiredPowerSeals == 0) + requiredPowerSeals = 45; + Manager.Instance.powerSealTotal = requiredPowerSeals; + } - public void AddPowerSeal() => ArchipelagoClient.ServerData.PowerSealsCollected++; + public void AddPowerSeal() => ArchipelagoClient.ServerData.PowerSealsCollected++; - public void OnShopChestOpen(On.ShopChestOpenCutscene.orig_OnChestOpened orig, ShopChestOpenCutscene self) + public void OnShopChestOpen(On.ShopChestOpenCutscene.orig_OnChestOpened orig, ShopChestOpenCutscene self) + { + try { - try - { - //going to attempt to teleport the player to the ending sequence when they open the chest - OnShopChestOpen(); - self.EndCutScene(); - } - catch (Exception e) - { - Console.WriteLine(e); - orig(self); - } + //going to attempt to teleport the player to the ending sequence when they open the chest + OnShopChestOpen(); + self.EndCutScene(); } - - public void OnShopChestOpen(On.ShopChestChangeShurikenCutscene.orig_Play orig, ShopChestChangeShurikenCutscene self) + catch (Exception e) { - try - { - //going to attempt to teleport the player to the ending sequence when they open the chest - OnShopChestOpen(); - self.EndCutScene(); - } - catch (Exception e) - { - Console.WriteLine(e); - orig(self); - } + Console.WriteLine(e); + orig(self); } + } - private void OnShopChestOpen() + public void OnShopChestOpen(On.ShopChestChangeShurikenCutscene.orig_Play orig, ShopChestChangeShurikenCutscene self) + { + try { - try - { - Debug.Log("Opening the shop chest..."); - Object.FindObjectOfType().LeaveToCurrentLevel(); - RandoLevelManager.SkipMusicBox(); - } - catch (Exception e) - { - Console.WriteLine(e); - } + //going to attempt to teleport the player to the ending sequence when they open the chest + OnShopChestOpen(); + self.EndCutScene(); } + catch (Exception e) + { + Console.WriteLine(e); + orig(self); + } + } - /// - /// Assigns our total power seal count to the game and then returns the value. Unsure if the assignment is safe - /// here, but trying it so it'll show the required count in the dialog. - /// - /// - public int AmountPowerSealsCollected() => ArchipelagoClient.ServerData.PowerSealsCollected; + private void OnShopChestOpen() + { + try + { + Debug.Log("Opening the shop chest..."); + Object.FindObjectOfType().LeaveToCurrentLevel(); + RandoLevelManager.SkipMusicBox(); + } + catch (Exception e) + { + Console.WriteLine(e); + } } + + /// + /// Assigns our total power seal count to the game and then returns the value. Unsure if the assignment is safe + /// here, but trying it so it'll show the required count in the dialog. + /// + /// + public int AmountPowerSealsCollected() => ArchipelagoClient.ServerData.PowerSealsCollected; } \ No newline at end of file diff --git a/GameOverrideManagers/RandoRoomManager.cs b/GameOverrideManagers/RandoRoomManager.cs index 43cc829..73a4544 100644 --- a/GameOverrideManagers/RandoRoomManager.cs +++ b/GameOverrideManagers/RandoRoomManager.cs @@ -1,123 +1,120 @@ using System; using System.Collections.Generic; -using Archipelago.MultiClient.Net.Enums; using MessengerRando.Archipelago; -using MessengerRando.Utils; using MessengerRando.Utils.Constants; using WebSocketSharp; -namespace MessengerRando.GameOverrideManagers +namespace MessengerRando.GameOverrideManagers; + +public static class RandoRoomManager { - public static class RandoRoomManager + public static bool RoomRando; + private static bool roomOverride; + private static Dictionary roomMap; // old room name - new room name + + private static readonly List TeleportRoomKeys = ["-500 -148 -60 -44", "364 396 308 324"]; + + static string GetRoomKey(ScreenEdge left, ScreenEdge right, ScreenEdge bottom, ScreenEdge top) { - public static bool RoomRando; - private static bool roomOverride; - private static Dictionary roomMap; // old room name - new room name + return $"{left.edgeIdX} {right.edgeIdX} {bottom.edgeIdY} {top.edgeIdY}"; + } - private static readonly List TeleportRoomKeys = ["-500 -148 -60 -44", "364 396 308 324"]; - - static string GetRoomKey(ScreenEdge left, ScreenEdge right, ScreenEdge bottom, ScreenEdge top) + static void SetRoomKey(ScreenEdge left, ScreenEdge right, ScreenEdge bottom, ScreenEdge top, + string roomKey) + { + var edges = roomKey.Split(' '); + left.edgeIdX = edges[0]; right.edgeIdX = edges[1]; bottom.edgeIdY = edges[2]; top.edgeIdY = edges[3]; + } + + static bool IsBossRoom(string roomKey, out string bossName) + { + Console.WriteLine($"Checking if {roomKey} is a boss room"); + bossName = string.Empty; + return roomKey != null && BossConstants.RoomToVanillaBoss.TryGetValue(roomKey, out bossName) && + BossConstants.BossLocations.TryGetValue(bossName, out var bossLocation) && + bossLocation.BossRegion.Equals(Manager.Instance.GetCurrentLevelEnum()); + } + + public static void Level_ChangeRoom(On.Level.orig_ChangeRoom orig, Level self, + ScreenEdge leftEdge, ScreenEdge rightEdge, + ScreenEdge bottomEdge, ScreenEdge topEdge, + bool teleportedInRoom) + { + var oldRoomKey = GetRoomKey(leftEdge, rightEdge, bottomEdge, topEdge); +#if DEBUG + Console.WriteLine("Changing rooms."); + Console.WriteLine($"Last Level: {Manager.Instance.lastLevelLoaded}"); + Console.WriteLine($"Current Level: {Manager.Instance.GetCurrentLevelEnum()}"); + Console.WriteLine($"new roomKey: {oldRoomKey}"); + Console.WriteLine(self.CurrentRoom != null + ? $"currentRoom roomKey: {self.CurrentRoom.roomKey}" + : "currentRoom does not exist."); + Console.WriteLine($"teleported: {teleportedInRoom}"); + var position = Manager.Instance.Player.transform.position; + Console.WriteLine("Player position: " + + $"{position.x} " + + $"{position.y} " + + $"{position.z}"); +#endif + //This func checks if the new roomKey exists within levelRooms before changing and checks if currentRoom exists + //if we're in a room, it leaves the current room then enters the new room with the teleported bool + //no idea what the teleported bool does currently + orig(self, leftEdge, rightEdge, bottomEdge, topEdge, teleportedInRoom); + if (TeleportRoomKeys.Contains(oldRoomKey)) { - return $"{left.edgeIdX} {right.edgeIdX} {bottom.edgeIdY} {top.edgeIdY}"; + var index = TeleportRoomKeys.IndexOf(oldRoomKey); + ArchipelagoClient.ServerData.AvailableTeleports[index] = true; } - - static void SetRoomKey(ScreenEdge left, ScreenEdge right, ScreenEdge bottom, ScreenEdge top, - string roomKey) + if (roomOverride) { - var edges = roomKey.Split(' '); - left.edgeIdX = edges[0]; right.edgeIdX = edges[1]; bottom.edgeIdY = edges[2]; top.edgeIdY = edges[3]; + roomOverride = false; + return; } - static bool IsBossRoom(string roomKey, out string bossName) + var currentLevel = Manager.Instance.GetCurrentLevelEnum(); + var bossRoomKey = oldRoomKey.Replace(" ", string.Empty); + if (IsBossRoom(bossRoomKey, out var bossName)) { - Console.WriteLine($"Checking if {roomKey} is a boss room"); - bossName = string.Empty; - return roomKey != null && BossConstants.RoomToVanillaBoss.TryGetValue(roomKey, out bossName) && - BossConstants.BossLocations.TryGetValue(bossName, out var bossLocation) && - bossLocation.BossRegion.Equals(Manager.Instance.GetCurrentLevelEnum()); + RandoBossManager.ShouldFightBoss(bossName); } - - public static void Level_ChangeRoom(On.Level.orig_ChangeRoom orig, Level self, - ScreenEdge leftEdge, ScreenEdge rightEdge, - ScreenEdge bottomEdge, ScreenEdge topEdge, - bool teleportedInRoom) + else if (RoomRando) { - var oldRoomKey = GetRoomKey(leftEdge, rightEdge, bottomEdge, topEdge); - #if DEBUG - Console.WriteLine("Changing rooms."); - Console.WriteLine($"Last Level: {Manager.Instance.lastLevelLoaded}"); - Console.WriteLine($"Current Level: {Manager.Instance.GetCurrentLevelEnum()}"); - Console.WriteLine($"new roomKey: {oldRoomKey}"); - Console.WriteLine(self.CurrentRoom != null - ? $"currentRoom roomKey: {self.CurrentRoom.roomKey}" - : "currentRoom does not exist."); - Console.WriteLine($"teleported: {teleportedInRoom}"); - var position = Manager.Instance.Player.transform.position; - Console.WriteLine("Player position: " + - $"{position.x} " + - $"{position.y} " + - $"{position.z}"); - #endif - //This func checks if the new roomKey exists within levelRooms before changing and checks if currentRoom exists - //if we're in a room, it leaves the current room then enters the new room with the teleported bool - //no idea what the teleported bool does currently - orig(self, leftEdge, rightEdge, bottomEdge, topEdge, teleportedInRoom); - if (TeleportRoomKeys.Contains(oldRoomKey)) - { - var index = TeleportRoomKeys.IndexOf(oldRoomKey); - ArchipelagoClient.ServerData.AvailableTeleports[index] = true; - } - if (roomOverride) - { - roomOverride = false; - return; - } + var newRoom = PlaceInRoom(oldRoomKey, currentLevel, out var transition); + if (newRoom.RoomKey.IsNullOrEmpty() || transition.Direction.IsNullOrEmpty()) return; - var currentLevel = Manager.Instance.GetCurrentLevelEnum(); - var bossRoomKey = oldRoomKey.Replace(" ", string.Empty); - if (IsBossRoom(bossRoomKey, out var bossName)) - { - RandoBossManager.ShouldFightBoss(bossName); - } - else if (RoomRando) - { - var newRoom = PlaceInRoom(oldRoomKey, currentLevel, out var transition); - if (newRoom.RoomKey.IsNullOrEmpty() || transition.Direction.IsNullOrEmpty()) return; - - SetRoomKey(leftEdge, rightEdge, bottomEdge, topEdge, newRoom.RoomKey); - roomOverride = true; - if (newRoom.Region.Equals(currentLevel)) - Manager.Instance.ChangeRoom(leftEdge, rightEdge, bottomEdge, topEdge, teleportedInRoom); - else - RandoLevelManager.TeleportInArea(newRoom.Region, transition.Position, transition.Dimension); - } - } - - static bool WithinRange(float pos1, float pos2) - { - var comparison = pos2 - pos1; - if (comparison < 0) comparison *= -1; - return comparison <= 10; + SetRoomKey(leftEdge, rightEdge, bottomEdge, topEdge, newRoom.RoomKey); + roomOverride = true; + if (newRoom.Region.Equals(currentLevel)) + Manager.Instance.ChangeRoom(leftEdge, rightEdge, bottomEdge, topEdge, teleportedInRoom); + else + RandoLevelManager.TeleportInArea(newRoom.Region, transition.Position, transition.Dimension); } + } - static RoomConstants.RandoRoom PlaceInRoom(string oldRoomKey, ELevel currentLevel, out RoomConstants.RoomTransition newTransition) - { - newTransition = new RoomConstants.RoomTransition(); - if (!RoomConstants.RoomNameLookup.TryGetValue(new RoomConstants.RandoRoom(oldRoomKey, currentLevel), - out var oldRoomName) - || !RoomConstants.TransitionLookup.TryGetValue(oldRoomName, out var oldTransitions) - || !roomMap.TryGetValue(oldRoomName, out var newName) - || !RoomConstants.TransitionLookup.TryGetValue(newName, out var newTransitions)) - return new RoomConstants.RandoRoom(); - - var currentPosX = Manager.Instance.Player.transform.position.x; - var currentTransition = - oldTransitions.Find(transition => WithinRange(currentPosX, transition.Position.x)); - newTransition = newTransitions.Find(transition => currentTransition.Equals(transition)); + static bool WithinRange(float pos1, float pos2) + { + var comparison = pos2 - pos1; + if (comparison < 0) comparison *= -1; + return comparison <= 10; + } - return !RoomConstants.RoomLookup.TryGetValue(newName, out var newRoom) - ? new RoomConstants.RandoRoom() - : newRoom; - } + static RoomConstants.RandoRoom PlaceInRoom(string oldRoomKey, ELevel currentLevel, out RoomConstants.RoomTransition newTransition) + { + newTransition = new RoomConstants.RoomTransition(); + if (!RoomConstants.RoomNameLookup.TryGetValue(new RoomConstants.RandoRoom(oldRoomKey, currentLevel), + out var oldRoomName) + || !RoomConstants.TransitionLookup.TryGetValue(oldRoomName, out var oldTransitions) + || !roomMap.TryGetValue(oldRoomName, out var newName) + || !RoomConstants.TransitionLookup.TryGetValue(newName, out var newTransitions)) + return new RoomConstants.RandoRoom(); + + var currentPosX = Manager.Instance.Player.transform.position.x; + var currentTransition = + oldTransitions.Find(transition => WithinRange(currentPosX, transition.Position.x)); + newTransition = newTransitions.Find(transition => currentTransition.Equals(transition)); + + return !RoomConstants.RoomLookup.TryGetValue(newName, out var newRoom) + ? new RoomConstants.RandoRoom() + : newRoom; } } \ No newline at end of file diff --git a/GameOverrideManagers/RandoShopManager.cs b/GameOverrideManagers/RandoShopManager.cs index 33c1784..e4a9fd7 100644 --- a/GameOverrideManagers/RandoShopManager.cs +++ b/GameOverrideManagers/RandoShopManager.cs @@ -10,231 +10,230 @@ using UnityEngine; using Object = UnityEngine.Object; -namespace MessengerRando.GameOverrideManagers +namespace MessengerRando.GameOverrideManagers; + +public static class RandoShopManager { - public static class RandoShopManager + public static Dictionary ShopPrices; + public static Dictionary FigurePrices; + private static readonly Queue FigurineQueue = new Queue(); + private static bool figurineOverride; + private static int wrenchPrice; + public static bool RaceMode; + public static bool ShopHints = true; + + public static int GetPrice(On.UpgradeButtonData.orig_GetPrice orig, UpgradeButtonData self) + { + //modify shop prices here + if (ShopPrices != null && ShopPrices.TryGetValue(self.upgradeID, out var price)) return price; + return orig(self); + } + + public static void ShopInit(On.Shop.orig_Init orig, Shop self, ShopParameters parameters, bool fake) + { + orig(self, parameters, fake); + self.armoireInteractionTrigger.gameObject.SetActive(false); + self.armoire.SetActive(false); + self.jukebox.SetActive(true); + } + + public static void UnlockFigurine(On.SousSol.orig_UnlockFigurine orig, SousSol self, EFigurine figurine) { - public static Dictionary ShopPrices; - public static Dictionary FigurePrices; - private static readonly Queue FigurineQueue = new Queue(); - private static bool figurineOverride; - private static int wrenchPrice; - public static bool RaceMode; - public static bool ShopHints = true; - - public static int GetPrice(On.UpgradeButtonData.orig_GetPrice orig, UpgradeButtonData self) + if (ShopPrices != null && !figurineOverride) { - //modify shop prices here - if (ShopPrices != null && ShopPrices.TryGetValue(self.upgradeID, out var price)) return price; - return orig(self); + ItemsAndLocationsHandler.SendLocationCheck(new LocationRO(figurine.ToString())); } - - public static void ShopInit(On.Shop.orig_Init orig, Shop self, ShopParameters parameters, bool fake) + else { - orig(self, parameters, fake); - self.armoireInteractionTrigger.gameObject.SetActive(false); - self.armoire.SetActive(false); - self.jukebox.SetActive(true); + figurineOverride = false; + orig(self, figurine); } + } + + public static void UnlockFigurine(EFigurine figurine) + { + figurineOverride = true; + Object.FindObjectOfType().UnlockFigurine(figurine); + } - public static void UnlockFigurine(On.SousSol.orig_UnlockFigurine orig, SousSol self, EFigurine figurine) + public static void GoToSousSol(On.GoToSousSolCutscene.orig_EndCutScene orig, GoToSousSolCutscene self, + bool camera, bool borders, bool transition) + { + orig(self, camera, borders, transition); + + try { - if (ShopPrices != null && !figurineOverride) - { - ItemsAndLocationsHandler.SendLocationCheck(new LocationRO(figurine.ToString())); - } - else + while (FigurineQueue.Count > 0) { - figurineOverride = false; - orig(self, figurine); + var figurine = (EFigurine)FigurineQueue.Dequeue(); + Debug.Log($"Unlocking {figurine}"); + UnlockFigurine(figurine); } } - - public static void UnlockFigurine(EFigurine figurine) + catch (Exception e) { - figurineOverride = true; - Object.FindObjectOfType().UnlockFigurine(figurine); + Console.WriteLine(e); } + } - public static void GoToSousSol(On.GoToSousSolCutscene.orig_EndCutScene orig, GoToSousSolCutscene self, - bool camera, bool borders, bool transition) - { - orig(self, camera, borders, transition); + public static ShopListItemData GetFigurineData(On.IronHoodShopScreen.orig_GetFigurineData orig, + IronHoodShopScreen self, + FigurineDefinition figurineDefinition) + { + var figurine = figurineDefinition.figurineID; + if (FigurePrices.TryGetValue(figurine, out var cost)) figurineDefinition.cost = cost; + return orig(self, figurineDefinition); + } - try - { - while (FigurineQueue.Count > 0) - { - var figurine = (EFigurine)FigurineQueue.Dequeue(); - Debug.Log($"Unlocking {figurine}"); - UnlockFigurine(figurine); - } - } - catch (Exception e) - { - Console.WriteLine(e); - } + public static void BuyMoneyWrench(On.BuyMoneyWrenchCutscene.orig_OnBuyWrenchChoice orig, + BuyMoneyWrenchCutscene self, DialogChoice choice) + { + orig(self, choice); + if (ArchipelagoClient.HasConnected && choice.ChoiceInfo.choiceId == "Yes") + { + wrenchPrice = Manager.Instance.timeShardsDroppedInSink; } + } + + public static void EndMoneyWrenchCutscene(On.BuyMoneyWrenchCutscene.orig_EndCutsceneOnDialogDone orig, + BuyMoneyWrenchCutscene self, View dialogBox) + { + orig(self, dialogBox); + Manager.Instance.CollectTimeShard(wrenchPrice); + wrenchPrice = 0; + } + + public static void UnclogSink(On.MoneySinkUnclogCutscene.orig_OnDialogOutDone orig, + MoneySinkUnclogCutscene self, View dialog) + { + orig(self, dialog); + Debug.Log("Unclogged that dang sink"); + var wrenchID = ItemsAndLocationsHandler.ItemFromEItem(EItems.MONEY_WRENCH); + if (!ArchipelagoClient.ServerData.ReceivedItems + .ContainsKey(wrenchID)) + Manager.Instance.UnsetFlag(Flags.MoneySinkUnclogged); + } + + public static bool IsStoryUnlocked(On.UpgradeButtonData.orig_IsStoryUnlocked orig, UpgradeButtonData self) + { + //Checking if this particular upgrade is the glide attack + //Unlock the glide attack (no need to keep it hidden, player can just buy it whenever they want. + var isUnlocked = EShopUpgradeID.GLIDE_ATTACK.Equals(self.upgradeID) || orig(self); + return isUnlocked; + } - public static ShopListItemData GetFigurineData(On.IronHoodShopScreen.orig_GetFigurineData orig, - IronHoodShopScreen self, - FigurineDefinition figurineDefinition) + public static void UpgradeButton_Refresh(On.UpgradeButton.orig_Refresh orig, UpgradeButton self) + { + try { - var figurine = figurineDefinition.figurineID; - if (FigurePrices.TryGetValue(figurine, out var cost)) figurineDefinition.cost = cost; - return orig(self, figurineDefinition); + orig(self); + var icon = Courier.LoadFromAssetBundles(Application.streamingAssetsPath + "/AP Icon.prefab"); + var sprite = Resources.Load(Application.streamingAssetsPath + "/AP Icon.prefab"); + self.icon.sprite = icon; } - - public static void BuyMoneyWrench(On.BuyMoneyWrenchCutscene.orig_OnBuyWrenchChoice orig, - BuyMoneyWrenchCutscene self, DialogChoice choice) + catch (Exception e) { - orig(self, choice); - if (ArchipelagoClient.HasConnected && choice.ChoiceInfo.choiceId == "Yes") - { - wrenchPrice = Manager.Instance.timeShardsDroppedInSink; - } + e.LogDetailed(); } + } - public static void EndMoneyWrenchCutscene(On.BuyMoneyWrenchCutscene.orig_EndCutsceneOnDialogDone orig, - BuyMoneyWrenchCutscene self, View dialogBox) + public static string GetText(On.LocalizationManager.orig_GetText orig, LocalizationManager self, string locid) + { + if (!ArchipelagoClient.HasConnected) return orig(self, locid); + var locType = TextType.None; + var lookupName = string.Empty; + if (locid.Contains("DESCRIPTION")) { - orig(self, dialogBox); - Manager.Instance.CollectTimeShard(wrenchPrice); - wrenchPrice = 0; + Console.WriteLine("description"); + locType = TextType.Description; + lookupName = locid.Replace("_DESCRIPTION", string.Empty); } - - public static void UnclogSink(On.MoneySinkUnclogCutscene.orig_OnDialogOutDone orig, - MoneySinkUnclogCutscene self, View dialog) + else if (locid.Contains("NAME")) { - orig(self, dialog); - Debug.Log("Unclogged that dang sink"); - var wrenchID = ItemsAndLocationsHandler.ItemFromEItem(EItems.MONEY_WRENCH); - if (!ArchipelagoClient.ServerData.ReceivedItems - .ContainsKey(wrenchID)) - Manager.Instance.UnsetFlag(Flags.MoneySinkUnclogged); + Console.WriteLine("name"); + locType = TextType.Name; + lookupName = locid.Replace("_NAME", string.Empty); } - public static bool IsStoryUnlocked(On.UpgradeButtonData.orig_IsStoryUnlocked orig, UpgradeButtonData self) + if (locType.Equals(TextType.None)) + return orig(self, locid); + + if (!ShopTextToItems.TryGetValue(lookupName, out var itemType)) { - //Checking if this particular upgrade is the glide attack - //Unlock the glide attack (no need to keep it hidden, player can just buy it whenever they want. - var isUnlocked = EShopUpgradeID.GLIDE_ATTACK.Equals(self.upgradeID) || orig(self); - return isUnlocked; + return orig(self, locid); } - public static void UpgradeButton_Refresh(On.UpgradeButton.orig_Refresh orig, UpgradeButton self) + if (RaceMode || !ShopHints) return locType.Equals(TextType.Name) ? "Unknown Item" : "???"; + + var locationID = ItemsAndLocationsHandler.LocationFromEItem(itemType); + switch (itemType) { - try - { - orig(self); - var icon = Courier.LoadFromAssetBundles(Application.streamingAssetsPath + "/AP Icon.prefab"); - var sprite = Resources.Load(Application.streamingAssetsPath + "/AP Icon.prefab"); - self.icon.sprite = icon; - } - catch (Exception e) - { - e.LogDetailed(); - } + case EItems.HEART_CONTAINER when lookupName.Contains("SECOND"): + ItemsAndLocationsHandler.LocationsLookup.TryGetValue( + new LocationRO("HP_UPGRADE_2", EItems.HEART_CONTAINER), out locationID); + break; + case EItems.SHURIKEN_UPGRADE when lookupName.Contains("SECOND"): + ItemsAndLocationsHandler.LocationsLookup.TryGetValue(new LocationRO("SHURIKEN_UPGRADE_2", + EItems.SHURIKEN_UPGRADE), out locationID); + break; } - public static string GetText(On.LocalizationManager.orig_GetText orig, LocalizationManager self, string locid) + if (ArchipelagoClient.Offline) { - if (!ArchipelagoClient.HasConnected) return orig(self, locid); - var locType = TextType.None; - var lookupName = string.Empty; - if (locid.Contains("DESCRIPTION")) - { - Console.WriteLine("description"); - locType = TextType.Description; - lookupName = locid.Replace("_DESCRIPTION", string.Empty); - } - else if (locid.Contains("NAME")) - { - Console.WriteLine("name"); - locType = TextType.Name; - lookupName = locid.Replace("_NAME", string.Empty); - } - - if (locType.Equals(TextType.None)) - return orig(self, locid); - - if (!ShopTextToItems.TryGetValue(lookupName, out var itemType)) - { - return orig(self, locid); - } - - if (RaceMode || !ShopHints) return locType.Equals(TextType.Name) ? "Unknown Item" : "???"; - - var locationID = ItemsAndLocationsHandler.LocationFromEItem(itemType); - switch (itemType) - { - case EItems.HEART_CONTAINER when lookupName.Contains("SECOND"): - ItemsAndLocationsHandler.LocationsLookup.TryGetValue( - new LocationRO("HP_UPGRADE_2", EItems.HEART_CONTAINER), out locationID); - break; - case EItems.SHURIKEN_UPGRADE when lookupName.Contains("SECOND"): - ItemsAndLocationsHandler.LocationsLookup.TryGetValue(new LocationRO("SHURIKEN_UPGRADE_2", - EItems.SHURIKEN_UPGRADE), out locationID); - break; - } - - if (ArchipelagoClient.Offline) - { - return locType.Equals(TextType.Description) - ? SeedGenerator.GetOfflineShopDescription(locationID) - : SeedGenerator.GetOfflineShopText(locationID); - } + return locType.Equals(TextType.Description) + ? SeedGenerator.GetOfflineShopDescription(locationID) + : SeedGenerator.GetOfflineShopText(locationID); + } - var itemOnLocation = RandomizerStateManager.Instance.ScoutedLocations[locationID]; - if (locType.Equals(TextType.Name) && ArchipelagoClient.Authenticated) + var itemOnLocation = RandomizerStateManager.Instance.ScoutedLocations[locationID]; + if (locType.Equals(TextType.Name) && ArchipelagoClient.Authenticated) + { + if (!ArchipelagoClient.ServerData.CheckedLocations.Contains(locationID)) { - if (!ArchipelagoClient.ServerData.CheckedLocations.Contains(locationID)) - { - ThreadPool.QueueUserWorkItem(_ => - ArchipelagoClient.Session.Locations.ScoutLocationsAsync( - null, HintCreationPolicy.CreateAndAnnounceOnce, locationID)); - } + ThreadPool.QueueUserWorkItem(_ => + ArchipelagoClient.Session.Locations.ScoutLocationsAsync( + null, HintCreationPolicy.CreateAndAnnounceOnce, locationID)); } - - return locType.Equals(TextType.Name) - ? itemOnLocation.Colorize() - : itemOnLocation.GetShopDescription(); } - private enum TextType - { - None, - Name, - Description, - } + return locType.Equals(TextType.Name) + ? itemOnLocation.Colorize() + : itemOnLocation.GetShopDescription(); + } - private static readonly Dictionary ShopTextToItems = new() - { - { "MAP_PORTALS", EItems.MAP_TIME_WARP }, - { "CHALLENGE_ROOM_WORLDMAP", EItems.MAP_POWER_SEAL_TOTAL }, - { "CHALLENGE_ROOM_LOCALMAP", EItems.MAP_POWER_SEAL_PINS }, - { "DAMAGE_REDUCTION", EItems.DAMAGE_REDUCTION }, - { "ENEMY_HP_DROP", EItems.ENEMY_DROP_HP }, - { "ENEMY_KI_DROP", EItems.ENEMY_DROP_MANA }, - { "CHECKPOINT_UPGRADE", EItems.CHECKPOINT_UPGRADE }, - { "FIRST_HP_UPGRADE", EItems.HEART_CONTAINER }, - { "SECOND_HP_UPGRADE", EItems.HEART_CONTAINER }, - { "LAST_HP_UPGRADE", EItems.POTION_FULL_HEAL_AND_HP_UPGRADE }, - { "FIRST_KI_UPGRADE", EItems.SHURIKEN_UPGRADE }, - { "SECOND_KI_UPGRADE", EItems.SHURIKEN_UPGRADE }, - { "QUARBLE_DISCOUNT", EItems.QUARBLE_DISCOUNT_50 }, - { "AIR_RECOVER", EItems.AIR_RECOVER }, - { "UNLOCK_SHURIKEN", EItems.SHURIKEN }, - { "ATTACK_PROJECTILE", EItems.ATTACK_PROJECTILES }, - { "POWER_ATTACK", EItems.CHARGED_ATTACK }, - { "SWIM_DASH", EItems.SWIM_DASH }, - { "GLIDE_ATTACK", EItems.GLIDE_ATTACK }, - }; - - private static bool InShop() - { - var currentLev = Manager.Instance.GetCurrentLevelEnum(); - return currentLev is ELevel.NONE or ELevel.Level_13_TowerOfTimeHQ; - } + private enum TextType + { + None, + Name, + Description, + } + + private static readonly Dictionary ShopTextToItems = new() + { + { "MAP_PORTALS", EItems.MAP_TIME_WARP }, + { "CHALLENGE_ROOM_WORLDMAP", EItems.MAP_POWER_SEAL_TOTAL }, + { "CHALLENGE_ROOM_LOCALMAP", EItems.MAP_POWER_SEAL_PINS }, + { "DAMAGE_REDUCTION", EItems.DAMAGE_REDUCTION }, + { "ENEMY_HP_DROP", EItems.ENEMY_DROP_HP }, + { "ENEMY_KI_DROP", EItems.ENEMY_DROP_MANA }, + { "CHECKPOINT_UPGRADE", EItems.CHECKPOINT_UPGRADE }, + { "FIRST_HP_UPGRADE", EItems.HEART_CONTAINER }, + { "SECOND_HP_UPGRADE", EItems.HEART_CONTAINER }, + { "LAST_HP_UPGRADE", EItems.POTION_FULL_HEAL_AND_HP_UPGRADE }, + { "FIRST_KI_UPGRADE", EItems.SHURIKEN_UPGRADE }, + { "SECOND_KI_UPGRADE", EItems.SHURIKEN_UPGRADE }, + { "QUARBLE_DISCOUNT", EItems.QUARBLE_DISCOUNT_50 }, + { "AIR_RECOVER", EItems.AIR_RECOVER }, + { "UNLOCK_SHURIKEN", EItems.SHURIKEN }, + { "ATTACK_PROJECTILE", EItems.ATTACK_PROJECTILES }, + { "POWER_ATTACK", EItems.CHARGED_ATTACK }, + { "SWIM_DASH", EItems.SWIM_DASH }, + { "GLIDE_ATTACK", EItems.GLIDE_ATTACK }, + }; + + private static bool InShop() + { + var currentLev = Manager.Instance.GetCurrentLevelEnum(); + return currentLev is ELevel.NONE or ELevel.Level_13_TowerOfTimeHQ; } } \ No newline at end of file diff --git a/GameOverrideManagers/RandoTimeShardManager.cs b/GameOverrideManagers/RandoTimeShardManager.cs index bdb4e95..c6cbb11 100644 --- a/GameOverrideManagers/RandoTimeShardManager.cs +++ b/GameOverrideManagers/RandoTimeShardManager.cs @@ -4,126 +4,125 @@ using MessengerRando.Archipelago; using MessengerRando.RO; -namespace MessengerRando.GameOverrideManagers +namespace MessengerRando.GameOverrideManagers; + +public class RandoTimeShardManager { - public class RandoTimeShardManager + public struct MegaShard { - public struct MegaShard - { - private readonly ELevel shardRegion; - private readonly string roomKey; - public readonly LocationRO Loc; - - public MegaShard(ELevel area, string key, LocationRO loc) - { - shardRegion = area; - roomKey = key; - Loc = loc; - } + private readonly ELevel shardRegion; + private readonly string roomKey; + public readonly LocationRO Loc; - public MegaShard(ELevel area, string key) - { - shardRegion = area; - roomKey = key; - Loc = null; - } - - public bool Equals(MegaShard other) - { - return roomKey == other.roomKey && shardRegion == other.shardRegion; - } - - public override bool Equals(object obj) - { - return obj is MegaShard other && Equals(other); - } - - public override int GetHashCode() - { - unchecked - { - return ((int)shardRegion * 397) ^ (roomKey != null ? roomKey.GetHashCode() : 0); - } - } + public MegaShard(ELevel area, string key, LocationRO loc) + { + shardRegion = area; + roomKey = key; + Loc = loc; } - - public static readonly List MegaShardLookup = new List + + public MegaShard(ELevel area, string key) { - new MegaShard(ELevel.Level_02_AutumnHills, "268300-108-92", new LocationRO("Autumn Hills Mega Shard")), - new MegaShard(ELevel.Level_03_ForlornTemple, "-2044420", new LocationRO("Hidden Entrance Mega Shard")), - new MegaShard(ELevel.Level_04_Catacombs, "108172420", new LocationRO("Catacombs Mega Shard")), - new MegaShard(ELevel.Level_06_A_BambooCreek, "-84-20420", new LocationRO("Above Entrance Mega Shard")), - new MegaShard(ELevel.Level_06_A_BambooCreek, "-52-202052", new LocationRO("Abandoned Mega Shard")), - new MegaShard(ELevel.Level_06_A_BambooCreek, "364396420", new LocationRO("Time Loop Mega Shard")), - new MegaShard(ELevel.Level_05_A_HowlingGrotto, "108140-108-92", new LocationRO("Bottom Left Mega Shard")), - new MegaShard(ELevel.Level_05_A_HowlingGrotto, "332364-172-156", new LocationRO("Near Portal Mega Shard")), - new MegaShard(ELevel.Level_05_A_HowlingGrotto, "460492-76-60", new LocationRO("Pie in the Sky Mega Shard")), - new MegaShard(ELevel.Level_07_QuillshroomMarsh, "4476-28-12", new LocationRO("Quillshroom Marsh Mega Shard")), - new MegaShard(ELevel.Level_08_SearingCrags, "236268116132", new LocationRO("Searing Crags Mega Shard")), - new MegaShard(ELevel.Level_09_A_GlacialPeak, "268300-284-268", new LocationRO("Glacial Peak Mega Shard")), - new MegaShard(ELevel.Level_11_A_CloudRuins, "-404-372-60-44", new LocationRO("Cloud Entrance Mega Shard")), - new MegaShard(ELevel.Level_11_A_CloudRuins, "-308-276-44-28", new LocationRO("Time Warp Mega Shard")), - new MegaShard(ELevel.Level_11_A_CloudRuins, "11321164-124", new LocationRO("Money Farm Room Mega Shard 1")), - new MegaShard(ELevel.Level_11_A_CloudRuins, "11321164-124", new LocationRO("Money Farm Room Mega Shard 2")), - new MegaShard(ELevel.Level_12_UnderWorld, "-436-308-60-44", new LocationRO("Under Entrance Mega Shard")), - new MegaShard(ELevel.Level_12_UnderWorld, "44766884", new LocationRO("Hot Tub Mega Shard")), - new MegaShard(ELevel.Level_12_UnderWorld, "76108-4420", new LocationRO("Projectile Pit Mega Shard")), - new MegaShard(ELevel.Level_03_ForlornTemple, "761402036", new LocationRO("Sunny Day Mega Shard")), - new MegaShard(ELevel.Level_03_ForlornTemple, "268300-44-28", new LocationRO("Down Under Mega Shard")), - new MegaShard(ELevel.Level_05_B_SunkenShrine, "4476-172-156", new LocationRO("Mega Shard of the Moon")), - new MegaShard(ELevel.Level_05_B_SunkenShrine, "108140-60-44", new LocationRO("Beginner's Mega Shard")), - new MegaShard(ELevel.Level_05_B_SunkenShrine, "4476420", new LocationRO("Mega Shard of the Stars")), - new MegaShard(ELevel.Level_05_B_SunkenShrine, "-52-20-92-76", new LocationRO("Mega Shard of the Sun")), - new MegaShard(ELevel.Level_04_C_RiviereTurquoise, "780812-124", new LocationRO("Waterfall Mega Shard")), - new MegaShard(ELevel.Level_04_C_RiviereTurquoise, "1244-124", new LocationRO("Quick Restock Mega Shard 1")), - new MegaShard(ELevel.Level_04_C_RiviereTurquoise, "1244-124", new LocationRO("Quick Restock Mega Shard 2")), - new MegaShard(ELevel.Level_09_B_ElementalSkylands, "876908340356", new LocationRO("Earth Mega Shard")), - new MegaShard(ELevel.Level_09_B_ElementalSkylands, "18361868388404", new LocationRO("Water Mega Shard")), - }; + shardRegion = area; + roomKey = key; + Loc = null; + } - private static LocationRO ShardLocation(MegaShard shard) + public bool Equals(MegaShard other) { - return MegaShardLookup.First(loc => loc.Equals(shard)).Loc; + return roomKey == other.roomKey && shardRegion == other.shardRegion; } - public static void BreakShard(MegaShard shardToBreak) + public override bool Equals(object obj) { - var location = ShardLocation(shardToBreak); - Console.WriteLine($"Broke Shard {location.LocationName}"); - if (!ArchipelagoClient.HasConnected) return; - - if (location.Equals(new LocationRO("Money Farm Room Mega Shard 1")) && - ArchipelagoClient.ServerData.CheckedLocations.Contains( - ItemsAndLocationsHandler.LocationsLookup[new LocationRO("Money Farm Room Mega Shard 1")])) - location = new LocationRO("Money Farm Room Mega Shard 2"); - else if (location.Equals(new LocationRO("Quick Restock Mega Shard 1")) && - ArchipelagoClient.ServerData.CheckedLocations.Contains( - ItemsAndLocationsHandler.LocationsLookup[new LocationRO("Quick Restock Mega Shard 1")])) - location = new LocationRO("Quick Restock Mega Shard 2"); - ItemsAndLocationsHandler.SendLocationCheck(location); + return obj is MegaShard other && Equals(other); } - public static void NextState(On.MegaTimeShard.orig_NextState orig, MegaTimeShard self, HitData hitData) + public override int GetHashCode() { - var currentLevel = Manager.Instance.GetCurrentLevelEnum(); - var currentRoom = Manager.Instance.CurrentRoom.roomKey; - var location = ShardLocation(new MegaShard(currentLevel, currentRoom)); - if (!location.Equals(new LocationRO("Money Farm Room Mega Shard 1")) && - !location.Equals(new LocationRO("Quick Restock Mega Shard 1")) && - ArchipelagoClient.ServerData.CheckedLocations. - Contains(ItemsAndLocationsHandler.LocationsLookup[location])) + unchecked { - self.SetHP(self.maxHP); - return; + return ((int)shardRegion * 397) ^ (roomKey != null ? roomKey.GetHashCode() : 0); } - orig(self, hitData); } + } + + public static readonly List MegaShardLookup = new List + { + new MegaShard(ELevel.Level_02_AutumnHills, "268300-108-92", new LocationRO("Autumn Hills Mega Shard")), + new MegaShard(ELevel.Level_03_ForlornTemple, "-2044420", new LocationRO("Hidden Entrance Mega Shard")), + new MegaShard(ELevel.Level_04_Catacombs, "108172420", new LocationRO("Catacombs Mega Shard")), + new MegaShard(ELevel.Level_06_A_BambooCreek, "-84-20420", new LocationRO("Above Entrance Mega Shard")), + new MegaShard(ELevel.Level_06_A_BambooCreek, "-52-202052", new LocationRO("Abandoned Mega Shard")), + new MegaShard(ELevel.Level_06_A_BambooCreek, "364396420", new LocationRO("Time Loop Mega Shard")), + new MegaShard(ELevel.Level_05_A_HowlingGrotto, "108140-108-92", new LocationRO("Bottom Left Mega Shard")), + new MegaShard(ELevel.Level_05_A_HowlingGrotto, "332364-172-156", new LocationRO("Near Portal Mega Shard")), + new MegaShard(ELevel.Level_05_A_HowlingGrotto, "460492-76-60", new LocationRO("Pie in the Sky Mega Shard")), + new MegaShard(ELevel.Level_07_QuillshroomMarsh, "4476-28-12", new LocationRO("Quillshroom Marsh Mega Shard")), + new MegaShard(ELevel.Level_08_SearingCrags, "236268116132", new LocationRO("Searing Crags Mega Shard")), + new MegaShard(ELevel.Level_09_A_GlacialPeak, "268300-284-268", new LocationRO("Glacial Peak Mega Shard")), + new MegaShard(ELevel.Level_11_A_CloudRuins, "-404-372-60-44", new LocationRO("Cloud Entrance Mega Shard")), + new MegaShard(ELevel.Level_11_A_CloudRuins, "-308-276-44-28", new LocationRO("Time Warp Mega Shard")), + new MegaShard(ELevel.Level_11_A_CloudRuins, "11321164-124", new LocationRO("Money Farm Room Mega Shard 1")), + new MegaShard(ELevel.Level_11_A_CloudRuins, "11321164-124", new LocationRO("Money Farm Room Mega Shard 2")), + new MegaShard(ELevel.Level_12_UnderWorld, "-436-308-60-44", new LocationRO("Under Entrance Mega Shard")), + new MegaShard(ELevel.Level_12_UnderWorld, "44766884", new LocationRO("Hot Tub Mega Shard")), + new MegaShard(ELevel.Level_12_UnderWorld, "76108-4420", new LocationRO("Projectile Pit Mega Shard")), + new MegaShard(ELevel.Level_03_ForlornTemple, "761402036", new LocationRO("Sunny Day Mega Shard")), + new MegaShard(ELevel.Level_03_ForlornTemple, "268300-44-28", new LocationRO("Down Under Mega Shard")), + new MegaShard(ELevel.Level_05_B_SunkenShrine, "4476-172-156", new LocationRO("Mega Shard of the Moon")), + new MegaShard(ELevel.Level_05_B_SunkenShrine, "108140-60-44", new LocationRO("Beginner's Mega Shard")), + new MegaShard(ELevel.Level_05_B_SunkenShrine, "4476420", new LocationRO("Mega Shard of the Stars")), + new MegaShard(ELevel.Level_05_B_SunkenShrine, "-52-20-92-76", new LocationRO("Mega Shard of the Sun")), + new MegaShard(ELevel.Level_04_C_RiviereTurquoise, "780812-124", new LocationRO("Waterfall Mega Shard")), + new MegaShard(ELevel.Level_04_C_RiviereTurquoise, "1244-124", new LocationRO("Quick Restock Mega Shard 1")), + new MegaShard(ELevel.Level_04_C_RiviereTurquoise, "1244-124", new LocationRO("Quick Restock Mega Shard 2")), + new MegaShard(ELevel.Level_09_B_ElementalSkylands, "876908340356", new LocationRO("Earth Mega Shard")), + new MegaShard(ELevel.Level_09_B_ElementalSkylands, "18361868388404", new LocationRO("Water Mega Shard")), + }; - public static bool ReceiveHit(On.MegaTimeShard.orig_ReceiveHit orig, MegaTimeShard self, HitData hitData) + private static LocationRO ShardLocation(MegaShard shard) + { + return MegaShardLookup.First(loc => loc.Equals(shard)).Loc; + } + + public static void BreakShard(MegaShard shardToBreak) + { + var location = ShardLocation(shardToBreak); + Console.WriteLine($"Broke Shard {location.LocationName}"); + if (!ArchipelagoClient.HasConnected) return; + + if (location.Equals(new LocationRO("Money Farm Room Mega Shard 1")) && + ArchipelagoClient.ServerData.CheckedLocations.Contains( + ItemsAndLocationsHandler.LocationsLookup[new LocationRO("Money Farm Room Mega Shard 1")])) + location = new LocationRO("Money Farm Room Mega Shard 2"); + else if (location.Equals(new LocationRO("Quick Restock Mega Shard 1")) && + ArchipelagoClient.ServerData.CheckedLocations.Contains( + ItemsAndLocationsHandler.LocationsLookup[new LocationRO("Quick Restock Mega Shard 1")])) + location = new LocationRO("Quick Restock Mega Shard 2"); + ItemsAndLocationsHandler.SendLocationCheck(location); + } + + public static void NextState(On.MegaTimeShard.orig_NextState orig, MegaTimeShard self, HitData hitData) + { + var currentLevel = Manager.Instance.GetCurrentLevelEnum(); + var currentRoom = Manager.Instance.CurrentRoom.roomKey; + var location = ShardLocation(new MegaShard(currentLevel, currentRoom)); + if (!location.Equals(new LocationRO("Money Farm Room Mega Shard 1")) && + !location.Equals(new LocationRO("Quick Restock Mega Shard 1")) && + ArchipelagoClient.ServerData.CheckedLocations. + Contains(ItemsAndLocationsHandler.LocationsLookup[location])) { - self.shardsPerHit = 50; - - return orig(self, hitData); + self.SetHP(self.maxHP); + return; } + orig(self, hitData); + } + + public static bool ReceiveHit(On.MegaTimeShard.orig_ReceiveHit orig, MegaTimeShard self, HitData hitData) + { + self.shardsPerHit = 50; + + return orig(self, hitData); } } \ No newline at end of file diff --git a/GameOverrideManagers/SkylandsGeneratorManager.cs b/GameOverrideManagers/SkylandsGeneratorManager.cs index f5a3933..dc1d363 100644 --- a/GameOverrideManagers/SkylandsGeneratorManager.cs +++ b/GameOverrideManagers/SkylandsGeneratorManager.cs @@ -5,237 +5,236 @@ using MessengerRando.RO; using MessengerRando.Utils; -namespace MessengerRando.GameOverrideManagers +namespace MessengerRando.GameOverrideManagers; + +public class SkylandsGeneratorManager { - public class SkylandsGeneratorManager + + private readonly Dictionary LoadedGenerators = []; + private readonly Dictionary FlagsByGenerator = new() + { + { GeneratorType.AIR, Flags.AirGeneratorDeactivated }, + { GeneratorType.EARTH, Flags.EarthGeneratorDeactivated }, + { GeneratorType.WATER, Flags.WaterGeneratorDeactivated }, + { GeneratorType.FIRE, Flags.FireGeneratorDeactivated }, + }; + private readonly Dictionary LocationsByGenerator = new() { + { GeneratorType.AIR, new LocationRO("Elemental Skylands - Shutdown Air Generator") }, + { GeneratorType.EARTH, new LocationRO("Elemental Skylands - Shutdown Earth Generator") }, + { GeneratorType.WATER, new LocationRO("Elemental Skylands - Shutdown Water Generator") }, + { GeneratorType.FIRE, new LocationRO("Elemental Skylands - Shutdown Fire Generator") }, + }; - private readonly Dictionary LoadedGenerators = []; - private readonly Dictionary FlagsByGenerator = new() - { - { GeneratorType.AIR, Flags.AirGeneratorDeactivated }, - { GeneratorType.EARTH, Flags.EarthGeneratorDeactivated }, - { GeneratorType.WATER, Flags.WaterGeneratorDeactivated }, - { GeneratorType.FIRE, Flags.FireGeneratorDeactivated }, - }; - private readonly Dictionary LocationsByGenerator = new() - { - { GeneratorType.AIR, new LocationRO("Elemental Skylands - Shutdown Air Generator") }, - { GeneratorType.EARTH, new LocationRO("Elemental Skylands - Shutdown Earth Generator") }, - { GeneratorType.WATER, new LocationRO("Elemental Skylands - Shutdown Water Generator") }, - { GeneratorType.FIRE, new LocationRO("Elemental Skylands - Shutdown Fire Generator") }, - }; + public bool AreGeneratorsShuffled = false; + + public void ApplyHooks() + { + On.ElementalSkylandGenerator.Start += ElementalSkylandGenerator_Start; + On.ElementalSkylandGenerator.SetState += ElementalSkylandGenerator_SetState; + On.ElementalSkylandGenerator.OnLanternHit += ElementalSkylandGenerator_OnLanternHit; + On.ElementalSkylandGenerator.Shutdown += ElementalSkylandGenerator_Shutdown; + On.ElementalSkylandGenerator.OnDeactivateDone += ElementalSkylandGenerator_OnDeactivateDone; + On.ElementalSkylandGenerator.OnDisable += ElementalSkylandGenerator_OnDisable; + } - public bool AreGeneratorsShuffled = false; + public void ReceiveGeneratorShutdown(string generatorShutdownItem) + { + Console.WriteLine($"Received {generatorShutdownItem}"); - public void ApplyHooks() + if (AreAllGeneratorsShutdownReceived()) { - On.ElementalSkylandGenerator.Start += ElementalSkylandGenerator_Start; - On.ElementalSkylandGenerator.SetState += ElementalSkylandGenerator_SetState; - On.ElementalSkylandGenerator.OnLanternHit += ElementalSkylandGenerator_OnLanternHit; - On.ElementalSkylandGenerator.Shutdown += ElementalSkylandGenerator_Shutdown; - On.ElementalSkylandGenerator.OnDeactivateDone += ElementalSkylandGenerator_OnDeactivateDone; - On.ElementalSkylandGenerator.OnDisable += ElementalSkylandGenerator_OnDisable; + Console.WriteLine($"All generators already deactivated, so ignoring received shutdown"); + return; } - public void ReceiveGeneratorShutdown(string generatorShutdownItem) - { - Console.WriteLine($"Received {generatorShutdownItem}"); + var generatorType = FindNextGeneratorToShutdown(); + var generatorFlag = FlagsByGenerator[generatorType]; + Manager.Instance.SetFlag(generatorFlag, false); + Console.WriteLine($"Current flags are [{string.Join(", ", [.. Manager.Instance.flags])}]"); - if (AreAllGeneratorsShutdownReceived()) - { - Console.WriteLine($"All generators already deactivated, so ignoring received shutdown"); - return; - } + if (LoadedGenerators.TryGetValue(generatorType, out var generator) && generator != null) + { + Console.WriteLine($"Generator loaded, so playing animation"); + Manager.Instance.PlaySoundEffect(generator.shutdownSFX); + generator.animator.SetTrigger("Deactivate"); + } + } - var generatorType = FindNextGeneratorToShutdown(); - var generatorFlag = FlagsByGenerator[generatorType]; - Manager.Instance.SetFlag(generatorFlag, false); - Console.WriteLine($"Current flags are [{string.Join(", ", [.. Manager.Instance.flags])}]"); + private void ElementalSkylandGenerator_Start(On.ElementalSkylandGenerator.orig_Start orig, global::ElementalSkylandGenerator self) + { + if (!AreGeneratorsShuffled) { orig(self); return; } - if (LoadedGenerators.TryGetValue(generatorType, out var generator) && generator != null) - { - Console.WriteLine($"Generator loaded, so playing animation"); - Manager.Instance.PlaySoundEffect(generator.shutdownSFX); - generator.animator.SetTrigger("Deactivate"); - } - } + var generatorType = ToGeneratorType(self.name); + LoadedGenerators[generatorType] = self; + Console.WriteLine($"Registered {generatorType} generator"); - private void ElementalSkylandGenerator_Start(On.ElementalSkylandGenerator.orig_Start orig, global::ElementalSkylandGenerator self) - { - if (!AreGeneratorsShuffled) { orig(self); return; } + orig(self); + } - var generatorType = ToGeneratorType(self.name); - LoadedGenerators[generatorType] = self; - Console.WriteLine($"Registered {generatorType} generator"); + private void ElementalSkylandGenerator_SetState(On.ElementalSkylandGenerator.orig_SetState orig, global::ElementalSkylandGenerator self) + { + if (!AreGeneratorsShuffled) { orig(self); return; } + if (!ArchipelagoClient.HasConnected) { orig(self); return; } - orig(self); + var generatorType = ToGeneratorType(self.name); + if (Manager.Instance.IsFlagSet(self.deactivatedFlag)) + { + Console.WriteLine($"Deactivating {self.name}"); + self.animator.SetTrigger("DeactivateInstant"); } - private void ElementalSkylandGenerator_SetState(On.ElementalSkylandGenerator.orig_SetState orig, global::ElementalSkylandGenerator self) + bool isLocationSent = IsLocationSent(generatorType); + if ((generatorType == GeneratorType.FIRE && AreAllGeneratorsShutdownReceived()) + || (generatorType != GeneratorType.FIRE && (isLocationSent || Manager.Instance.IsFlagSet(self.deactivatedFlag)))) { - if (!AreGeneratorsShuffled) { orig(self); return; } - if (!ArchipelagoClient.HasConnected) { orig(self); return; } - - var generatorType = ToGeneratorType(self.name); - if (Manager.Instance.IsFlagSet(self.deactivatedFlag)) - { - Console.WriteLine($"Deactivating {self.name}"); - self.animator.SetTrigger("DeactivateInstant"); - } - - bool isLocationSent = IsLocationSent(generatorType); - if ((generatorType == GeneratorType.FIRE && AreAllGeneratorsShutdownReceived()) - || (generatorType != GeneratorType.FIRE && (isLocationSent || Manager.Instance.IsFlagSet(self.deactivatedFlag)))) - { - Console.WriteLine($"Opening door for {self.name}"); - self.wall.gameObject.SetActive(value: false); - } - - for (int i = 0; i < self.powerLanterns.Count; i++) - { - self.powerLanterns[i].SetFull(full: !isLocationSent); - } + Console.WriteLine($"Opening door for {self.name}"); + self.wall.gameObject.SetActive(value: false); } - private void ElementalSkylandGenerator_OnLanternHit(On.ElementalSkylandGenerator.orig_OnLanternHit orig, global::ElementalSkylandGenerator self, global::Hittable lantern, global::HitData hitData) + for (int i = 0; i < self.powerLanterns.Count; i++) { - if (!AreGeneratorsShuffled) { orig(self, lantern, hitData); return; } - - if (!(lantern as Lantern).Full) - { - return; - } + self.powerLanterns[i].SetFull(full: !isLocationSent); + } + } - Manager.Instance.PlaySoundEffect(self.powerSourceHitSFX); - bool flag = true; - for (int i = 0; i < self.powerLanterns.Count; i++) - { - if (self.powerLanterns[i].Full && self.powerLanterns[i] != lantern) - { - flag = false; - break; - } - } + private void ElementalSkylandGenerator_OnLanternHit(On.ElementalSkylandGenerator.orig_OnLanternHit orig, global::ElementalSkylandGenerator self, global::Hittable lantern, global::HitData hitData) + { + if (!AreGeneratorsShuffled) { orig(self, lantern, hitData); return; } - if (!Manager.Instance.IsFlagSet(self.deactivatedFlag)) - { - self.animator.SetTrigger("ReceiveHit"); - } - if (flag) - { - ReflectionHelpers.InvokeMethod(self, "Shutdown"); - } + if (!(lantern as Lantern).Full) + { + return; } - private void ElementalSkylandGenerator_Shutdown(On.ElementalSkylandGenerator.orig_Shutdown orig, global::ElementalSkylandGenerator self) + Manager.Instance.PlaySoundEffect(self.powerSourceHitSFX); + bool flag = true; + for (int i = 0; i < self.powerLanterns.Count; i++) { - if (!AreGeneratorsShuffled) { orig(self); return; } - if (!ArchipelagoClient.HasConnected) { orig(self); return; } - - SendLocation(self); - - if (ToGeneratorType(self.name) != GeneratorType.FIRE && self.wall.activeSelf) + if (self.powerLanterns[i].Full && self.powerLanterns[i] != lantern) { - Manager.Instance.PlaySoundEffect(self.wallDisappearSFX); - self.wall.SetActive(value: false); + flag = false; + break; } } - private void ElementalSkylandGenerator_OnDeactivateDone(On.ElementalSkylandGenerator.orig_OnDeactivateDone orig, global::ElementalSkylandGenerator self) + if (!Manager.Instance.IsFlagSet(self.deactivatedFlag)) { - if (!AreGeneratorsShuffled) { orig(self); return; } - if (AreAllGeneratorsShutdownReceived()) - { - OpenFireGeneratorDoor(); - } - - if (ToGeneratorType(self.name) != GeneratorType.FIRE && self.wall.activeSelf) - { - Manager.Instance.PlaySoundEffect(self.wallDisappearSFX); - self.wall.SetActive(value: false); - } - - self.StartCoroutine((IEnumerator)ReflectionHelpers.InvokeMethodWithReturn(self, "ShakeCamCoroutine")); + self.animator.SetTrigger("ReceiveHit"); } - - private void ElementalSkylandGenerator_OnDisable(On.ElementalSkylandGenerator.orig_OnDisable orig, global::ElementalSkylandGenerator self) + if (flag) { - if (!AreGeneratorsShuffled) { orig(self); return; } + ReflectionHelpers.InvokeMethod(self, "Shutdown"); + } + } - var generatorType = ToGeneratorType(self.name); - LoadedGenerators[generatorType] = null; - Console.WriteLine($"Cleaned up {generatorType} generator"); + private void ElementalSkylandGenerator_Shutdown(On.ElementalSkylandGenerator.orig_Shutdown orig, global::ElementalSkylandGenerator self) + { + if (!AreGeneratorsShuffled) { orig(self); return; } + if (!ArchipelagoClient.HasConnected) { orig(self); return; } - orig(self); - } + SendLocation(self); - private void SendLocation(ElementalSkylandGenerator generator) + if (ToGeneratorType(self.name) != GeneratorType.FIRE && self.wall.activeSelf) { - var generatorType = ToGeneratorType(generator.name); - var location = LocationsByGenerator[generatorType]; - Console.WriteLine($"Sending location {location.LocationName}"); - ItemsAndLocationsHandler.SendLocationCheck(location); + Manager.Instance.PlaySoundEffect(self.wallDisappearSFX); + self.wall.SetActive(value: false); } + } - private bool IsLocationSent(GeneratorType generatorType) + private void ElementalSkylandGenerator_OnDeactivateDone(On.ElementalSkylandGenerator.orig_OnDeactivateDone orig, global::ElementalSkylandGenerator self) + { + if (!AreGeneratorsShuffled) { orig(self); return; } + if (AreAllGeneratorsShutdownReceived()) { - return ItemsAndLocationsHandler.IsLocationChecked(LocationsByGenerator[generatorType]); + OpenFireGeneratorDoor(); } - private bool AreAllGeneratorsShutdownReceived() + if (ToGeneratorType(self.name) != GeneratorType.FIRE && self.wall.activeSelf) { - var manager = Manager.Instance; - return manager.IsFlagSet(Flags.AirGeneratorDeactivated) - && manager.IsFlagSet(Flags.EarthGeneratorDeactivated) - && manager.IsFlagSet(Flags.WaterGeneratorDeactivated) - && manager.IsFlagSet(Flags.FireGeneratorDeactivated); + Manager.Instance.PlaySoundEffect(self.wallDisappearSFX); + self.wall.SetActive(value: false); } - private void OpenFireGeneratorDoor() + self.StartCoroutine((IEnumerator)ReflectionHelpers.InvokeMethodWithReturn(self, "ShakeCamCoroutine")); + } + + private void ElementalSkylandGenerator_OnDisable(On.ElementalSkylandGenerator.orig_OnDisable orig, global::ElementalSkylandGenerator self) + { + if (!AreGeneratorsShuffled) { orig(self); return; } + + var generatorType = ToGeneratorType(self.name); + LoadedGenerators[generatorType] = null; + Console.WriteLine($"Cleaned up {generatorType} generator"); + + orig(self); + } + + private void SendLocation(ElementalSkylandGenerator generator) + { + var generatorType = ToGeneratorType(generator.name); + var location = LocationsByGenerator[generatorType]; + Console.WriteLine($"Sending location {location.LocationName}"); + ItemsAndLocationsHandler.SendLocationCheck(location); + } + + private bool IsLocationSent(GeneratorType generatorType) + { + return ItemsAndLocationsHandler.IsLocationChecked(LocationsByGenerator[generatorType]); + } + + private bool AreAllGeneratorsShutdownReceived() + { + var manager = Manager.Instance; + return manager.IsFlagSet(Flags.AirGeneratorDeactivated) + && manager.IsFlagSet(Flags.EarthGeneratorDeactivated) + && manager.IsFlagSet(Flags.WaterGeneratorDeactivated) + && manager.IsFlagSet(Flags.FireGeneratorDeactivated); + } + + private void OpenFireGeneratorDoor() + { + var fireGenerator = LoadedGenerators[GeneratorType.FIRE]; + Manager.Instance.PlaySoundEffect(fireGenerator.wallDisappearSFX); + fireGenerator.wall.SetActive(value: false); + } + private GeneratorType FindNextGeneratorToShutdown() + { + var manager = Manager.Instance; + if (manager.IsFlagSet(Flags.WaterGeneratorDeactivated)) { - var fireGenerator = LoadedGenerators[GeneratorType.FIRE]; - Manager.Instance.PlaySoundEffect(fireGenerator.wallDisappearSFX); - fireGenerator.wall.SetActive(value: false); + Console.WriteLine($"Water generator already deactivated, so shutting down Fire generator"); + return GeneratorType.FIRE; } - private GeneratorType FindNextGeneratorToShutdown() + if (manager.IsFlagSet(Flags.EarthGeneratorDeactivated)) { - var manager = Manager.Instance; - if (manager.IsFlagSet(Flags.WaterGeneratorDeactivated)) - { - Console.WriteLine($"Water generator already deactivated, so shutting down Fire generator"); - return GeneratorType.FIRE; - } - if (manager.IsFlagSet(Flags.EarthGeneratorDeactivated)) - { - Console.WriteLine($"Earth generator already deactivated, so shutting down Water generator"); - return GeneratorType.WATER; - } - if (manager.IsFlagSet(Flags.AirGeneratorDeactivated)) - { - Console.WriteLine($"Air generator already deactivated, so shutting down Earth generator"); - return GeneratorType.EARTH; - } - - Console.WriteLine($"No generators already deactivated, so shutting down Air generator"); - return GeneratorType.AIR; + Console.WriteLine($"Earth generator already deactivated, so shutting down Water generator"); + return GeneratorType.WATER; } - - private static GeneratorType ToGeneratorType(string generator) + if (manager.IsFlagSet(Flags.AirGeneratorDeactivated)) { - return generator switch - { - var g when g.Contains("Air") => GeneratorType.AIR, - var g when g.Contains("Water") => GeneratorType.WATER, - var g when g.Contains("Earth") => GeneratorType.EARTH, - var g when g.Contains("Fire") => GeneratorType.FIRE, - _ => throw new Exception($"Unknown generator type for generator with name {generator}") - }; + Console.WriteLine($"Air generator already deactivated, so shutting down Earth generator"); + return GeneratorType.EARTH; } + + Console.WriteLine($"No generators already deactivated, so shutting down Air generator"); + return GeneratorType.AIR; } - enum GeneratorType + private static GeneratorType ToGeneratorType(string generator) { - AIR, EARTH, WATER, FIRE + return generator switch + { + var g when g.Contains("Air") => GeneratorType.AIR, + var g when g.Contains("Water") => GeneratorType.WATER, + var g when g.Contains("Earth") => GeneratorType.EARTH, + var g when g.Contains("Fire") => GeneratorType.FIRE, + _ => throw new Exception($"Unknown generator type for generator with name {generator}") + }; } } + +enum GeneratorType +{ + AIR, EARTH, WATER, FIRE +} diff --git a/GameOverrideManagers/TrapManager.cs b/GameOverrideManagers/TrapManager.cs index 4003dc6..57cccc1 100644 --- a/GameOverrideManagers/TrapManager.cs +++ b/GameOverrideManagers/TrapManager.cs @@ -1,5 +1,4 @@ using System; -using System.Collections; using System.Collections.Generic; using System.Linq; using System.Reflection; @@ -8,202 +7,201 @@ using Mod.Courier; using UnityEngine; -namespace MessengerRando.GameOverrideManagers +namespace MessengerRando.GameOverrideManagers; + +public static class TrapManager { - public static class TrapManager + private static bool teleTrapped; + public static float TrapTimer; + private static float trapTime = 10.0f; + private static PlayerController player; + private static bool currentlyDark; + private static int queuedDarkness; + private static int queuedTeleports; + private static string darknessPath = $"{Courier.ModsFolder}\\TheMessengerRandomizerAP\\Darkness Test.prefab"; + public static Vector3 PreTeleLocation; + + public static void StartProphecyCutscene() { - private static bool teleTrapped; - public static float TrapTimer; - private static float trapTime = 10.0f; - private static PlayerController player; - private static bool currentlyDark; - private static int queuedDarkness; - private static int queuedTeleports; - private static string darknessPath = $"{Courier.ModsFolder}\\TheMessengerRandomizerAP\\Darkness Test.prefab"; - public static Vector3 PreTeleLocation; - - public static void StartProphecyCutscene() + try { - try - { - Console.WriteLine("doing a prophecy"); - player = Manager.Instance.Player; - player.graplou.Cancel(); - player.Unduck(); - player.SetInvincibility("prophecy trap", true); - player.StateMachine.SetState(); - player.StopRunning(); - player.BlockInputs("prophecy"); - DoProphecyDialog(); - } - catch (Exception e) - { - e.LogDetailed(); - } + Console.WriteLine("doing a prophecy"); + player = Manager.Instance.Player; + player.graplou.Cancel(); + player.Unduck(); + player.SetInvincibility("prophecy trap", true); + player.StateMachine.SetState(); + player.StopRunning(); + player.BlockInputs("prophecy"); + DoProphecyDialog(); } - - private static void EndProphecyCutscene(View view) + catch (Exception e) { - player.SetInvincibility("prophecy trap", false); - player.StateMachine.SetState(); - player.UnblockInputs("prophecy"); - Manager.Instance.onScreenOutDone -= EndProphecyCutscene; + e.LogDetailed(); } + } - private static void DoProphecyDialog() - { - var dialogBox = ScriptableObject.CreateInstance(); - dialogBox.dialogID = "PROPHECY_TRAP"; - dialogBox.name = "*ahem*"; - dialogBox.choices = new List(); - var dialogInfoList = new List(); - var dialogToAdd = ProphecyTrapDialog[RandomizerStateManager.SeedRandom.Next(ProphecyTrapDialog.Count)]; - var count = 0; - foreach (var info in dialogToAdd.Select(text => new DialogInfo - { - text = text, - textID = $"PROPHECY_{count}", - characterDefinition = FlavorDialogManager.ProphetDefinition, - skippable = false, - autoClose = true, - autoCloseDelay = 1 - })) - { - count++; - - dialogInfoList.Add(info); - } - FieldInfo dialogInfoListField = - typeof(DialogSequence).GetField("dialogInfoList", BindingFlags.NonPublic | BindingFlags.Instance); - dialogInfoListField.SetValue(dialogBox, dialogInfoList); - - var popupParams = new DialogBoxParams(dialogBox); - Manager.Instance.ShowView(EScreenLayers.PROMPT, popupParams); - - Manager.Instance.onScreenOutDone += EndProphecyCutscene; - } + private static void EndProphecyCutscene(View view) + { + player.SetInvincibility("prophecy trap", false); + player.StateMachine.SetState(); + player.UnblockInputs("prophecy"); + Manager.Instance.onScreenOutDone -= EndProphecyCutscene; + } - public static void TryTeleportPlayer() + private static void DoProphecyDialog() + { + var dialogBox = ScriptableObject.CreateInstance(); + dialogBox.dialogID = "PROPHECY_TRAP"; + dialogBox.name = "*ahem*"; + dialogBox.choices = new List(); + var dialogInfoList = new List(); + var dialogToAdd = ProphecyTrapDialog[RandomizerStateManager.SeedRandom.Next(ProphecyTrapDialog.Count)]; + var count = 0; + foreach (var info in dialogToAdd.Select(text => new DialogInfo + { + text = text, + textID = $"PROPHECY_{count}", + characterDefinition = FlavorDialogManager.ProphetDefinition, + skippable = false, + autoClose = true, + autoCloseDelay = 1 + })) { - var level = Manager.Instance; - if (AvailableTrapLevels.Contains(level.GetCurrentLevelEnum()) && - RandomizerStateManager.IsSafeTeleportState()) - { - PreTeleLocation = Manager.Instance.checkpointSaveInfo.loadedLevelPlayerPosition; - teleTrapped = true; - var teleportLoc = - TeleportTrapLocations.Where(randoLevel => - randoLevel.LevelName.Equals(level.GetCurrentLevelEnum())).ToList()[0]; - RandoLevelManager.TeleportInArea(teleportLoc); - } - else - { - queuedTeleports++; - } + count++; + + dialogInfoList.Add(info); } + FieldInfo dialogInfoListField = + typeof(DialogSequence).GetField("dialogInfoList", BindingFlags.NonPublic | BindingFlags.Instance); + dialogInfoListField.SetValue(dialogBox, dialogInfoList); + + var popupParams = new DialogBoxParams(dialogBox); + Manager.Instance.ShowView(EScreenLayers.PROMPT, popupParams); - private static void CheckQueuedTeleport() + Manager.Instance.onScreenOutDone += EndProphecyCutscene; + } + + public static void TryTeleportPlayer() + { + var level = Manager.Instance; + if (AvailableTrapLevels.Contains(level.GetCurrentLevelEnum()) && + RandomizerStateManager.IsSafeTeleportState()) { - if (queuedTeleports == 0) return; - if (!RandomizerStateManager.IsSafeTeleportState()) return; - var level = Manager.Instance; - if (!AvailableTrapLevels.Contains(level.GetCurrentLevelEnum())) return; PreTeleLocation = Manager.Instance.checkpointSaveInfo.loadedLevelPlayerPosition; teleTrapped = true; - queuedTeleports--; - var teleportLoc = TeleportTrapLocations - .Where(randoLevel => randoLevel.LevelName.Equals(level.GetCurrentLevelEnum())).ToList()[0]; + var teleportLoc = + TeleportTrapLocations.Where(randoLevel => + randoLevel.LevelName.Equals(level.GetCurrentLevelEnum())).ToList()[0]; RandoLevelManager.TeleportInArea(teleportLoc); } + else + { + queuedTeleports++; + } + } - public static void ResetPlayerState() + private static void CheckQueuedTeleport() + { + if (queuedTeleports == 0) return; + if (!RandomizerStateManager.IsSafeTeleportState()) return; + var level = Manager.Instance; + if (!AvailableTrapLevels.Contains(level.GetCurrentLevelEnum())) return; + PreTeleLocation = Manager.Instance.checkpointSaveInfo.loadedLevelPlayerPosition; + teleTrapped = true; + queuedTeleports--; + var teleportLoc = TeleportTrapLocations + .Where(randoLevel => randoLevel.LevelName.Equals(level.GetCurrentLevelEnum())).ToList()[0]; + RandoLevelManager.TeleportInArea(teleportLoc); + } + + public static void ResetPlayerState() + { + if (!teleTrapped) return; + Manager.Instance.checkpointSaveInfo.loadedLevelPlayerPosition = PreTeleLocation; + teleTrapped = false; + } + + public static void StartDarkness() + { + if (currentlyDark) { - if (!teleTrapped) return; - Manager.Instance.checkpointSaveInfo.loadedLevelPlayerPosition = PreTeleLocation; - teleTrapped = false; + queuedDarkness++; + return; } - public static void StartDarkness() + try + { + var darkness = AssetBundle.LoadFromFile(darknessPath); + UnityEngine.Object.Instantiate(darkness, Manager.Instance.Player.transform); + } + catch (Exception e) { - if (currentlyDark) - { - queuedDarkness++; - return; - } - - try - { - var darkness = AssetBundle.LoadFromFile(darknessPath); - UnityEngine.Object.Instantiate(darkness, Manager.Instance.Player.transform); - } - catch (Exception e) - { - e.LogDetailed(); - } - currentlyDark = true; + e.LogDetailed(); } + currentlyDark = true; + } - public static void EndDarkness() + public static void EndDarkness() + { + if (!currentlyDark) return; + if (queuedDarkness > 0) { - if (!currentlyDark) return; - if (queuedDarkness > 0) - { - queuedDarkness--; - return; - } - - Manager.Instance.CloseAllScreensOfType(false); - Manager.Instance.CloseAllScreensOfType(false); - Manager.Instance.CloseAllScreensOfType(false); - Manager.Instance.CloseAllScreensOfType(false); - Manager.Instance.CloseAllScreensOfType(false); + queuedDarkness--; + return; } - private static readonly List> ProphecyTrapDialog = new List> + Manager.Instance.CloseAllScreensOfType(false); + Manager.Instance.CloseAllScreensOfType(false); + Manager.Instance.CloseAllScreensOfType(false); + Manager.Instance.CloseAllScreensOfType(false); + Manager.Instance.CloseAllScreensOfType(false); + } + + private static readonly List> ProphecyTrapDialog = new List> + { + new() + { + "*ahem* AS WAS FORETOLD IN THE VISIONS. HE CARRIES FORTH THE MESSAGE FOR ALL THOSE TO BEAR WITNESS", + "AND THUS HE MASTERED TIME ITSELF (though maybe not those pesky pits as much)." + }, + new() { - new() - { - "*ahem* AS WAS FORETOLD IN THE VISIONS. HE CARRIES FORTH THE MESSAGE FOR ALL THOSE TO BEAR WITNESS", - "AND THUS HE MASTERED TIME ITSELF (though maybe not those pesky pits as much)." - }, - new() - { - "*ahem* THE MISTS OF LEGEND ARE QUITE COMPLEX AND FOGGY, BUT WE ARE HERE TO GUIDE YOU FURTHER.", - "ASK THUS AND BE THUSLY PROVIDED YE OF THE SHALLOW CUP FOR HE SHALL JUMP OVER THAT PROJECTILE.", - }, - new() - { - "*ahem* DID YOU EVER HEAR THE TRAGEDY OF DARTH PLAGUEIS THE WISE?", - "I THOUGHT NOT. IT'S NOT A STORY THE JEDI WOULD TELL YOU.", - "IT'S A SITH LEGEND. DARTH PLAGUEIS WAS A DARK LORD OF THE SITH, SO POWERFUL AND SO WISE, HE COULD USE THE FORCE TO INFLUENCE THE MIDICHLORIANS TO CREATE LIFE...", - "HE HAD SUCH A KNOWLEDGE OF THE DARK SIDE THAT HE COULD EVEN KEEP THE ONES HE CARED ABOUT FROM DYING.", - "THE DARK SIDE OF THE FORCE IS A PATHWAY TO MANY ABILITIES SOME CONSIDER TO BE UNNATURAL.", - "HE BECAME SO POWERFUL... THE ONLY THING HE WAS AFRAID OF WAS LOSING HIS POWER, WHICH EVENTUALLY, OF COURSE, HE DID.", - "UNFORTUNATELY, HE TAUGHT HIS APPRENTICE EVERYTHING HE KNEW, THEN HIS APPRENTICE KILLED HIM IN HIS SLEEP.", - "IRONIC.", - "HE COULD SAVE OTHERS FROM DEATH, BUT NOT HIMSELF." - } - }; - - private static readonly List TeleportTrapLocations = - [ - new LevelConstants.RandoLevel(ELevel.Level_09_A_GlacialPeak, new Vector3(127, -55)), - // new LevelConstants.RandoLevel(ELevel.Level_08_SearingCrags, new Vector3(456, 136)), - new LevelConstants.RandoLevel(ELevel.Level_07_QuillshroomMarsh, new Vector3(797, -38)), - new LevelConstants.RandoLevel(ELevel.Level_05_B_SunkenShrine, new Vector3(162, -109)), - new LevelConstants.RandoLevel(ELevel.Level_05_A_HowlingGrotto, new Vector3(253, -75)), - new LevelConstants.RandoLevel(ELevel.Level_02_AutumnHills, new Vector3(458, -50)) - ]; - - private static readonly List AvailableTrapLevels = - TeleportTrapLocations.Select(level => level.LevelName).ToList(); - - public static void UpdateTrapStatus() + "*ahem* THE MISTS OF LEGEND ARE QUITE COMPLEX AND FOGGY, BUT WE ARE HERE TO GUIDE YOU FURTHER.", + "ASK THUS AND BE THUSLY PROVIDED YE OF THE SHALLOW CUP FOR HE SHALL JUMP OVER THAT PROJECTILE.", + }, + new() { - if (TrapTimer < trapTime) return; - TrapTimer = 0; - EndDarkness(); - CheckQueuedTeleport(); + "*ahem* DID YOU EVER HEAR THE TRAGEDY OF DARTH PLAGUEIS THE WISE?", + "I THOUGHT NOT. IT'S NOT A STORY THE JEDI WOULD TELL YOU.", + "IT'S A SITH LEGEND. DARTH PLAGUEIS WAS A DARK LORD OF THE SITH, SO POWERFUL AND SO WISE, HE COULD USE THE FORCE TO INFLUENCE THE MIDICHLORIANS TO CREATE LIFE...", + "HE HAD SUCH A KNOWLEDGE OF THE DARK SIDE THAT HE COULD EVEN KEEP THE ONES HE CARED ABOUT FROM DYING.", + "THE DARK SIDE OF THE FORCE IS A PATHWAY TO MANY ABILITIES SOME CONSIDER TO BE UNNATURAL.", + "HE BECAME SO POWERFUL... THE ONLY THING HE WAS AFRAID OF WAS LOSING HIS POWER, WHICH EVENTUALLY, OF COURSE, HE DID.", + "UNFORTUNATELY, HE TAUGHT HIS APPRENTICE EVERYTHING HE KNEW, THEN HIS APPRENTICE KILLED HIM IN HIS SLEEP.", + "IRONIC.", + "HE COULD SAVE OTHERS FROM DEATH, BUT NOT HIMSELF." } + }; + + private static readonly List TeleportTrapLocations = + [ + new LevelConstants.RandoLevel(ELevel.Level_09_A_GlacialPeak, new Vector3(127, -55)), + // new LevelConstants.RandoLevel(ELevel.Level_08_SearingCrags, new Vector3(456, 136)), + new LevelConstants.RandoLevel(ELevel.Level_07_QuillshroomMarsh, new Vector3(797, -38)), + new LevelConstants.RandoLevel(ELevel.Level_05_B_SunkenShrine, new Vector3(162, -109)), + new LevelConstants.RandoLevel(ELevel.Level_05_A_HowlingGrotto, new Vector3(253, -75)), + new LevelConstants.RandoLevel(ELevel.Level_02_AutumnHills, new Vector3(458, -50)) + ]; + + private static readonly List AvailableTrapLevels = + TeleportTrapLocations.Select(level => level.LevelName).ToList(); + + public static void UpdateTrapStatus() + { + if (TrapTimer < trapTime) return; + TrapTimer = 0; + EndDarkness(); + CheckQueuedTeleport(); } } \ No newline at end of file diff --git a/Overrides/RandoCatacombLevelInitializer.cs b/Overrides/RandoCatacombLevelInitializer.cs index a2bcd4e..0cac8e9 100644 --- a/Overrides/RandoCatacombLevelInitializer.cs +++ b/Overrides/RandoCatacombLevelInitializer.cs @@ -1,31 +1,30 @@ using System.Collections.Generic; using UnityEngine; -namespace MessengerRando.Overrides +namespace MessengerRando.Overrides; + +/// +/// This class is meant to override functions of CatacombLevelInitializer for ease of access. +/// +static class RandoCatacombLevelInitializer { - /// - /// This class is meant to override functions of CatacombLevelInitializer for ease of access. - /// - static class RandoCatacombLevelInitializer + /// + /// Overriding FixPlayerStuckInChallengeRoom method that is private in orig code. No changes made to orig code. + /// + public static void FixPlayerStuckInChallengeRoom() { - /// - /// Overriding FixPlayerStuckInChallengeRoom method that is private in orig code. No changes made to orig code. - /// - public static void FixPlayerStuckInChallengeRoom() - { - if (Manager.Instance.CurrentRoom.roomKey == "492524-44-28" && - Manager.Instance.LevelRooms.TryGetValue("492524-60-44", out var room)) - { - List roomObjects = room.roomObjects; - for (int i = roomObjects.Count - 1; i >= 0; i--) - { - BreakableCollision component = roomObjects[i].GetComponent(); - if (component != null) - { - component.BreakInstant(); - } - } - } - } - } + if (Manager.Instance.CurrentRoom.roomKey == "492524-44-28" && + Manager.Instance.LevelRooms.TryGetValue("492524-60-44", out var room)) + { + List roomObjects = room.roomObjects; + for (int i = roomObjects.Count - 1; i >= 0; i--) + { + BreakableCollision component = roomObjects[i].GetComponent(); + if (component != null) + { + component.BreakInstant(); + } + } + } + } } diff --git a/RO/LocationRO.cs b/RO/LocationRO.cs index 9d16f15..9237d02 100644 --- a/RO/LocationRO.cs +++ b/RO/LocationRO.cs @@ -1,37 +1,36 @@ -namespace MessengerRando.RO +namespace MessengerRando.RO; + +public class LocationRO { - public class LocationRO - { - public string LocationName { get; private set; } - public string PrettyLocationName { get; private set; } //Can be same as LocationName, used for logging and spoiler log - public EItems VanillaItem; + public string LocationName { get; private set; } + public string PrettyLocationName { get; private set; } //Can be same as LocationName, used for logging and spoiler log + public EItems VanillaItem; - public LocationRO(string name, string prettyName, EItems item = EItems.NONE) - { - LocationName = name; - PrettyLocationName = prettyName; - VanillaItem = item; - } + public LocationRO(string name, string prettyName, EItems item = EItems.NONE) + { + LocationName = name; + PrettyLocationName = prettyName; + VanillaItem = item; + } - public LocationRO(string name) : this(name, name){} + public LocationRO(string name) : this(name, name) { } - //overrides for archipelago since logic is already handled - public LocationRO(string name, EItems item) : this(name, item.ToString(), item){} + //overrides for archipelago since logic is already handled + public LocationRO(string name, EItems item) : this(name, item.ToString(), item) { } - public override bool Equals(object obj) - { - return obj is LocationRO rO && - LocationName == rO.LocationName; - } + public override bool Equals(object obj) + { + return obj is LocationRO rO && + LocationName == rO.LocationName; + } - public bool Equals(string locName) - { - return LocationName == locName || PrettyLocationName == locName; - } + public bool Equals(string locName) + { + return LocationName == locName || PrettyLocationName == locName; + } - public override int GetHashCode() - { - return 771690509 + LocationName.GetHashCode(); - } + public override int GetHashCode() + { + return 771690509 + LocationName.GetHashCode(); } } diff --git a/RO/RandoItemRO.cs b/RO/RandoItemRO.cs index f8210a3..30ea6ac 100644 --- a/RO/RandoItemRO.cs +++ b/RO/RandoItemRO.cs @@ -1,71 +1,70 @@ using System; using System.Collections.Generic; -namespace MessengerRando.RO +namespace MessengerRando.RO; + +public struct RandoItemRO { - public struct RandoItemRO + //some kind of unique identifier + public string Name { get; } + //the in game item they represent + public EItems Item { get; } + //amount to give + public int Quantity { get; } + + public RandoItemRO(string name, EItems item, int quantity = 1) { - //some kind of unique identifier - public string Name { get; } - //the in game item they represent - public EItems Item { get; } - //amount to give - public int Quantity { get; } + Name = name; + Item = item; + Quantity = quantity; + } - public RandoItemRO(string name, EItems item, int quantity = 1) - { - Name = name; - Item = item; - Quantity = quantity; - } + public override string ToString() + { + return $"{Name}-{Item}-{Quantity}"; + } - public override string ToString() - { - return $"{Name}-{Item}-{Quantity}"; - } + public override bool Equals(object obj) + { + return obj is RandoItemRO rO && + Name == rO.Name && + Item == rO.Item; + } - public override bool Equals(object obj) - { - return obj is RandoItemRO rO && - Name == rO.Name && - Item == rO.Item; - } + public bool Equals(EItems item) + { + return Item == item; + } + + public override int GetHashCode() + { + var hashCode = 1065740796; + hashCode = hashCode * -1521134295 + EqualityComparer.Default.GetHashCode(Name); + hashCode = hashCode * -1521134295 + Item.GetHashCode(); + return hashCode; + } - public bool Equals(EItems item) + /// + /// Expect three values in format 'name-item-quantity'. + /// + /// + /// RandoItemRO with the values passed in. + public static RandoItemRO ParseString(string itemToParse) + { + + if (itemToParse == null) { - return Item == item; + throw new ArgumentNullException(nameof(itemToParse)); } - public override int GetHashCode() + string[] randoItemDetails = itemToParse.Split('-'); + if (randoItemDetails.Length == 3 && Enum.IsDefined(typeof(EItems), randoItemDetails[1]) && int.TryParse(randoItemDetails[2], out var quantity)) { - var hashCode = 1065740796; - hashCode = hashCode * -1521134295 + EqualityComparer.Default.GetHashCode(Name); - hashCode = hashCode * -1521134295 + Item.GetHashCode(); - return hashCode; + return new RandoItemRO(randoItemDetails[0], (EItems)Enum.Parse(typeof(EItems), randoItemDetails[1], true), quantity); } - - /// - /// Expect three values in format 'name-item-quantity'. - /// - /// - /// RandoItemRO with the values passed in. - public static RandoItemRO ParseString(string itemToParse) + else { - - if(itemToParse == null) - { - throw new ArgumentNullException(nameof(itemToParse)); - } - - string[] randoItemDetails = itemToParse.Split('-'); - if (randoItemDetails.Length == 3 && Enum.IsDefined(typeof(EItems), randoItemDetails[1]) && int.TryParse(randoItemDetails[2], out var quantity)) - { - return new RandoItemRO(randoItemDetails[0], (EItems)Enum.Parse(typeof(EItems), randoItemDetails[1], true), quantity); - } - else - { - throw new ArgumentException($"Passed string '{itemToParse}' invalid for parsing. Expect three values in format 'name-item-quantity'."); - } + throw new ArgumentException($"Passed string '{itemToParse}' invalid for parsing. Expect three values in format 'name-item-quantity'."); } } } diff --git a/Utils/Constants/BossConstants.cs b/Utils/Constants/BossConstants.cs index 11a2e24..3dd5023 100644 --- a/Utils/Constants/BossConstants.cs +++ b/Utils/Constants/BossConstants.cs @@ -1,80 +1,79 @@ using System.Collections.Generic; using UnityEngine; -namespace MessengerRando.Utils.Constants +namespace MessengerRando.Utils.Constants; + +public static class BossConstants { - public static class BossConstants + public struct BossLocation { - public struct BossLocation - { - public readonly ELevel BossRegion; - public readonly Vector2 PlayerPosition; - public readonly EBits PlayerDimension; + public readonly ELevel BossRegion; + public readonly Vector2 PlayerPosition; + public readonly EBits PlayerDimension; - public BossLocation(ELevel area, Vector2 pos, EBits dim) - { - BossRegion = area; - PlayerPosition = pos; - PlayerDimension = dim; - } + public BossLocation(ELevel area, Vector2 pos, EBits dim) + { + BossRegion = area; + PlayerPosition = pos; + PlayerDimension = dim; } + } - public static readonly List VanillaBossNames = new List - { - "LeafGolem", - "Necromancer", - "EmeraldGolem", - "QueenOfQuills", - // "Colos_Susses", - "Manfred", - // "TowerGolem", - "DemonGeneral", - "DemonArtificier", - "ButterflyMatriarch", - "Phantom" - }; + public static readonly List VanillaBossNames = new List + { + "LeafGolem", + "Necromancer", + "EmeraldGolem", + "QueenOfQuills", + // "Colos_Susses", + "Manfred", + // "TowerGolem", + "DemonGeneral", + "DemonArtificier", + "ButterflyMatriarch", + "Phantom" + }; - public static readonly Dictionary BossCutscenes = new Dictionary - { - { "LeafGolem", "LeafGolemIntroCutscene" }, - { "Necromancer", "NecromancerIntroCutscene" }, - { "EmeraldGolem", "EmeraldGolemIntroCutscene" }, - { "QueenOfQuills", "QueenOfQuillsIntroCutscene" }, - // {"Colos_Susses", }, - { "Manfred", "ManfredIntroCutscene" }, - // {"TowerGolem", }, - { "DemonGeneral", "DemonGeneralIntroCutscene" }, - { "DemonArtificier", "DemonArtificierIntroCutscene" }, - { "ButterflyMatriarch", "ButterflyMatriarchIntroCutscene" }, - { "Phantom", "PhantomIntroCutscene" } - }; + public static readonly Dictionary BossCutscenes = new Dictionary + { + { "LeafGolem", "LeafGolemIntroCutscene" }, + { "Necromancer", "NecromancerIntroCutscene" }, + { "EmeraldGolem", "EmeraldGolemIntroCutscene" }, + { "QueenOfQuills", "QueenOfQuillsIntroCutscene" }, + // {"Colos_Susses", }, + { "Manfred", "ManfredIntroCutscene" }, + // {"TowerGolem", }, + { "DemonGeneral", "DemonGeneralIntroCutscene" }, + { "DemonArtificier", "DemonArtificierIntroCutscene" }, + { "ButterflyMatriarch", "ButterflyMatriarchIntroCutscene" }, + { "Phantom", "PhantomIntroCutscene" } + }; - public static readonly Dictionary RoomToVanillaBoss = new Dictionary - { - { "908940-28-12", "LeafGolem" }, - { "748780-76-60", "Necromancer" }, - { "556588-140-60", "EmeraldGolem" }, - { "11001132-44-28", "QueenOfQuills" }, - { "332364308324", "Colos_Susses" }, - { "11641228-28-12", "Manfred" }, - // { "108140228244", "TowerGolem" }, - { "140172-44-28", "DemonGeneral" }, - { "396428-12436", "DemonArtificier" }, - { "-308-276420", "ButterflyMatriarch" } - }; + public static readonly Dictionary RoomToVanillaBoss = new Dictionary + { + { "908940-28-12", "LeafGolem" }, + { "748780-76-60", "Necromancer" }, + { "556588-140-60", "EmeraldGolem" }, + { "11001132-44-28", "QueenOfQuills" }, + { "332364308324", "Colos_Susses" }, + { "11641228-28-12", "Manfred" }, + // { "108140228244", "TowerGolem" }, + { "140172-44-28", "DemonGeneral" }, + { "396428-12436", "DemonArtificier" }, + { "-308-276420", "ButterflyMatriarch" } + }; - public static readonly Dictionary BossLocations = new Dictionary - { - { "LeafGolem", new BossLocation(ELevel.Level_02_AutumnHills, new Vector2(908, -27), EBits.BITS_8) }, - { "Necromancer", new BossLocation(ELevel.Level_04_Catacombs, new Vector2(752, -75), EBits.BITS_8) }, - { "EmeraldGolem", new BossLocation(ELevel.Level_05_A_HowlingGrotto, new Vector2(560, -123), EBits.BITS_8) }, - { "QueenOfQuills", new BossLocation( ELevel.Level_07_QuillshroomMarsh, new Vector2(1100, -43), EBits.BITS_8) }, - // { "Colos_Susses", new BossLocation(ELevel.Level_08_SearingCrags, new Vector2(364, 311), EBits.BITS_8) }, - { "Manfred", new BossLocation(ELevel.Level_11_A_CloudRuins, new Vector2(1165, -26), EBits.BITS_16)}, - // { "Tower Golem", new BossLocation(ELevel.Level_10_A_TowerOfTime, new Vector2(108, 237), EBits.BITS_16) }, - { "DemonGeneral", new BossLocation(ELevel.Level_12_UnderWorld, new Vector2(140, -43), EBits.BITS_16) }, - { "DemonArtificier", new BossLocation(ELevel.Level_03_ForlornTemple, new Vector2(396, -11), EBits.BITS_16)}, - { "ButterflyMatriarch", new BossLocation(ELevel.Level_04_C_RiviereTurquoise, new Vector2(-276, 6), EBits.BITS_16) } - }; - } + public static readonly Dictionary BossLocations = new Dictionary + { + { "LeafGolem", new BossLocation(ELevel.Level_02_AutumnHills, new Vector2(908, -27), EBits.BITS_8) }, + { "Necromancer", new BossLocation(ELevel.Level_04_Catacombs, new Vector2(752, -75), EBits.BITS_8) }, + { "EmeraldGolem", new BossLocation(ELevel.Level_05_A_HowlingGrotto, new Vector2(560, -123), EBits.BITS_8) }, + { "QueenOfQuills", new BossLocation( ELevel.Level_07_QuillshroomMarsh, new Vector2(1100, -43), EBits.BITS_8) }, + // { "Colos_Susses", new BossLocation(ELevel.Level_08_SearingCrags, new Vector2(364, 311), EBits.BITS_8) }, + { "Manfred", new BossLocation(ELevel.Level_11_A_CloudRuins, new Vector2(1165, -26), EBits.BITS_16)}, + // { "Tower Golem", new BossLocation(ELevel.Level_10_A_TowerOfTime, new Vector2(108, 237), EBits.BITS_16) }, + { "DemonGeneral", new BossLocation(ELevel.Level_12_UnderWorld, new Vector2(140, -43), EBits.BITS_16) }, + { "DemonArtificier", new BossLocation(ELevel.Level_03_ForlornTemple, new Vector2(396, -11), EBits.BITS_16)}, + { "ButterflyMatriarch", new BossLocation(ELevel.Level_04_C_RiviereTurquoise, new Vector2(-276, 6), EBits.BITS_16) } + }; } \ No newline at end of file diff --git a/Utils/Constants/LevelConstants.cs b/Utils/Constants/LevelConstants.cs index ebee3a2..f201c08 100644 --- a/Utils/Constants/LevelConstants.cs +++ b/Utils/Constants/LevelConstants.cs @@ -3,522 +3,521 @@ using System.Linq; using UnityEngine; -namespace MessengerRando.Utils.Constants +namespace MessengerRando.Utils.Constants; + +public static class LevelConstants { - public static class LevelConstants + public readonly struct RandoLevel : IEquatable { - public readonly struct RandoLevel : IEquatable + public ELevel LevelName { get; } + public Vector3 PlayerPos { get; } + public EBits Dimension { get; } + + public RandoLevel(ELevel levelName, Vector3 playerPos) { - public ELevel LevelName { get; } - public Vector3 PlayerPos { get; } - public EBits Dimension { get; } + LevelName = levelName; + PlayerPos = playerPos; + Dimension = EBits.NONE; + } - public RandoLevel(ELevel levelName, Vector3 playerPos) - { - LevelName = levelName; - PlayerPos = playerPos; - Dimension = EBits.NONE; - } + public RandoLevel(ELevel levelName, Vector3 playerPos, EBits dimension) + { + LevelName = levelName; + PlayerPos = playerPos; + Dimension = dimension; + } - public RandoLevel(ELevel levelName, Vector3 playerPos, EBits dimension) - { - LevelName = levelName; - PlayerPos = playerPos; - Dimension = dimension; - } + public bool Equals(RandoLevel other) + { + return LevelName == other.LevelName && PlayerPos.Equals(other.PlayerPos); + } - public bool Equals(RandoLevel other) - { - return LevelName == other.LevelName && PlayerPos.Equals(other.PlayerPos); - } + public bool Equals(ELevel level) + { + return LevelName == level; + } - public bool Equals(ELevel level) - { - return LevelName == level; - } + public override bool Equals(object obj) + { + return obj is RandoLevel other && Equals(other); + } - public override bool Equals(object obj) + public override int GetHashCode() + { + unchecked { - return obj is RandoLevel other && Equals(other); - } - - public override int GetHashCode() - { - unchecked - { - var hashCode = (int)LevelName; - hashCode = (hashCode * 397) ^ PlayerPos.GetHashCode(); - return hashCode; - } + var hashCode = (int)LevelName; + hashCode = (hashCode * 397) ^ PlayerPos.GetHashCode(); + return hashCode; } } + } - public struct Transition : IEquatable - { - public ELevel Leaving { get; } - public ELevel Entering { get; } + public struct Transition : IEquatable + { + public ELevel Leaving { get; } + public ELevel Entering { get; } - public Transition(ELevel leaving, ELevel entering) - { - Leaving = leaving; - Entering = entering; - } + public Transition(ELevel leaving, ELevel entering) + { + Leaving = leaving; + Entering = entering; + } - public bool Equals(Transition other) - { - return Leaving == other.Leaving && Entering == other.Entering; - } + public bool Equals(Transition other) + { + return Leaving == other.Leaving && Entering == other.Entering; + } - public override bool Equals(object obj) - { - return obj is Transition other && Equals(other); - } + public override bool Equals(object obj) + { + return obj is Transition other && Equals(other); + } - public override int GetHashCode() + public override int GetHashCode() + { + unchecked { - unchecked - { - return ((int)Leaving * 397) ^ (int)Entering; - } + return ((int)Leaving * 397) ^ (int)Entering; } } + } - public static readonly Dictionary EntranceNameToRandoLevel = - new Dictionary - { - { - "Ninja Village - Right", - new RandoLevel(ELevel.Level_01_NinjaVillage, new Vector3(-153.32f, -57f)) - }, - { - "Autumn Hills - Left", - new RandoLevel(ELevel.Level_02_AutumnHills, new Vector3(-304.7717f, -72.99999f)) - }, - { - "Autumn Hills - Right", - new RandoLevel(ELevel.Level_02_AutumnHills, new Vector3(968.5283f, -27f), EBits.BITS_8) - }, - { - "Autumn Hills - Bottom", new RandoLevel(ELevel.Level_02_AutumnHills, new Vector3(679.6884f, -139f), EBits.BITS_16) - }, // Must be 16 - { - "Forlorn Temple - Left", - new RandoLevel(ELevel.Level_03_ForlornTemple, new Vector3(-17.13942f, -11f)) - }, - { - "Forlorn Temple - Bottom", - new RandoLevel(ELevel.Level_03_ForlornTemple, new Vector3(30, -20), EBits.BITS_16) - }, // Must be 16 - { - "Forlorn Temple - Right", - new RandoLevel(ELevel.Level_03_ForlornTemple, new Vector3(454.4301f, -11f), EBits.BITS_16) - }, - { - "Catacombs - Top Left", - new RandoLevel(ELevel.Level_04_Catacombs, new Vector3(48.5f, -11)) - }, - { - "Catacombs - Right", - new RandoLevel(ELevel.Level_04_Catacombs, new Vector3(809.5f, -74.5f)) - }, - { - "Catacombs - Bottom", - new RandoLevel(ELevel.Level_04_Catacombs, new Vector3(511, -123), EBits.BITS_16) - }, // Must be 16 - { - "Catacombs - Bottom Left", - new RandoLevel(ELevel.Level_04_Catacombs, new Vector3(144.5119f, -59f), EBits.BITS_16) - }, // Must be 16 - { - "Dark Cave - Right", - new RandoLevel(ELevel.Level_04_B_DarkCave, new Vector3(-4.059998f, -4f), EBits.BITS_16) - }, // This needs to be forced to 16 bit to not soft lock the player - // { "Dark Cave - Left", new RandoLevel(ELevel.Level_04_B_DarkCave, new Vector3()) }, // This may or may not be possible. This is a drop down into riviere in vanilla and you can't return from riviere - { - "Riviere Turquoise - Portal", - new RandoLevel(ELevel.Level_04_C_RiviereTurquoise, new Vector3(837f, 13f)) - }, //TOT D - { - "Riviere Turquoise - Right", - new RandoLevel(ELevel.Level_04_C_RiviereTurquoise, new Vector3(997.7f, 5.999998f), EBits.BITS_8) - }, // This needs to be forced to 8 bit - { - "Howling Grotto - Left", - new RandoLevel(ELevel.Level_05_A_HowlingGrotto, new Vector3(-46.82001f, -11f)) - }, - { - "Howling Grotto - Right", - new RandoLevel(ELevel.Level_05_A_HowlingGrotto, new Vector3(584.21f, -123f)) - }, // Emerald Golem is here. Scene loaded gets called before the check, but level loaded is after - { - "Howling Grotto - Top", - new RandoLevel(ELevel.Level_05_A_HowlingGrotto, new Vector3(419.95f, -58.66491f), EBits.BITS_16) - }, // This needs to be forced to 16 bit - { - "Howling Grotto - Bottom", - new RandoLevel(ELevel.Level_05_A_HowlingGrotto, new Vector3(194.9271f, -151.665f), EBits.BITS_16) - }, // needs to be 16 - { - "Sunken Shrine - Left", - new RandoLevel(ELevel.Level_05_B_SunkenShrine, new Vector3(-46.41f, -58.66499f), EBits.BITS_16) - }, // This needs to be forced to 16 bit - { - "Bamboo Creek - Top Left", - new RandoLevel(ELevel.Level_06_A_BambooCreek, new Vector3(-50.09212f, 45f), EBits.BITS_16) - }, - { - "Bamboo Creek - Bottom Left", - new RandoLevel(ELevel.Level_06_A_BambooCreek, new Vector3(-177.0621f, -11f)) - }, - { - "Bamboo Creek - Right", - new RandoLevel(ELevel.Level_06_A_BambooCreek, new Vector3(488.4079f, -91f)) - }, - { - "Quillshroom Marsh - Top Left", - new RandoLevel(ELevel.Level_07_QuillshroomMarsh, new Vector3(-16.80286f, -11f)) - }, - { - "Quillshroom Marsh - Bottom Left", - new RandoLevel(ELevel.Level_07_QuillshroomMarsh, new Vector3(598.1053f, -75.66499f), EBits.BITS_16) - }, // This needs to be forced to 16 bit - { - "Quillshroom Marsh - Top Right", - new RandoLevel(ELevel.Level_07_QuillshroomMarsh, new Vector3(1160.79f, -43f)) - }, - { - "Quillshroom Marsh - Bottom Right", - new RandoLevel(ELevel.Level_07_QuillshroomMarsh, new Vector3(841.3f, -121f), EBits.BITS_16) - }, // 16 - { - "Searing Crags - Left", - new RandoLevel(ELevel.Level_08_SearingCrags, new Vector3(-17.23438f, -27f)) - }, - { - "Searing Crags - Bottom", - new RandoLevel(ELevel.Level_08_SearingCrags, new Vector3(303.3f, 39f), EBits.BITS_16) - }, - { - "Searing Crags - Right", - new RandoLevel(ELevel.Level_08_SearingCrags, new Vector3(521.8f, 71f), EBits.BITS_8) - }, // Force 8 bit - { - "Searing Crags - Top", - new RandoLevel(ELevel.Level_08_SearingCrags, new Vector3(351.5f, 324.2888f)) - }, - { - "Glacial Peak - Bottom", - new RandoLevel(ELevel.Level_09_A_GlacialPeak, new Vector3(202, -519)) - }, - { - "Glacial Peak - Left", new RandoLevel(ELevel.Level_09_A_GlacialPeak, new Vector3(180, -307)) - }, - { - "Glacial Peak - Top", - new RandoLevel(ELevel.Level_09_A_GlacialPeak, new Vector3(176.04f, -13.71676f)) - }, - { - "Elemental Skylands - Air Shmup", - new RandoLevel(ELevel.Level_09_B_ElementalSkylands, new Vector3(-37.4f, 359.5f), EBits.BITS_16) - }, - { - "Tower of Time - Left", - new RandoLevel(ELevel.Level_10_A_TowerOfTime, new Vector3(-18f, -11f), EBits.BITS_8) - }, // 8 - { - "Cloud Ruins - Left", - new RandoLevel(ELevel.Level_11_A_CloudRuins, new Vector3(-486f, -57f), EBits.BITS_16) - }, - { - "Music Box - Left", - new RandoLevel(ELevel.Level_11_B_MusicBox, new Vector3(-428, -55)) - }, - { - "Underworld - Left", - new RandoLevel(ELevel.Level_12_UnderWorld, new Vector3(-337.5526f, -25f), EBits.BITS_8) - }, // Force 8 bit - // { - // "Underworld - Bottom Left", - // new RandoLevel(ELevel.Level_12_UnderWorld, new Vector3(-431.7626f, -57f), EBits.BITS_16) - // }, // force 16 bit - one time and one way only - after defeating manfred - might be able to force it by calling ManfredBossOutroCutscene? - { - "Corrupted Future", - new RandoLevel(ELevel.Level_14_CorruptedFuture, new Vector3(-100, -9.5f), EBits.BITS_16) - }, // 16 - { - "Ruxxtin Surfin'", - new RandoLevel(ELevel.Level_15_Surf, new Vector3(-472.191f, 472f), EBits.BITS_8) - }, // 8 - { - "Beach - Left", - new RandoLevel(ELevel.Level_16_Beach, new Vector3(-431.7f, -9f)) - }, - { - "Fire Mountain - Bottom", - new RandoLevel(ELevel.Level_17_Volcano, new Vector3(-443.5f, -34f)) - }, - { - "Voodoo Heart - Left", - new RandoLevel(ELevel.Level_18_Volcano_Chase, new Vector3(-165.5f, 104.5551f), EBits.BITS_8) - }, // 8 - }; - - public static readonly Dictionary TransitionToEntranceName = - new Dictionary - { - { - new Transition(ELevel.Level_02_AutumnHills, ELevel.Level_01_NinjaVillage), - "Ninja Village - Right" - }, - { - new Transition(ELevel.Level_01_NinjaVillage, ELevel.Level_02_AutumnHills), - "Autumn Hills - Left" - }, - { - new Transition(ELevel.Level_03_ForlornTemple, ELevel.Level_02_AutumnHills), - "Autumn Hills - Right" - }, - { - new Transition(ELevel.Level_04_Catacombs, ELevel.Level_02_AutumnHills), - "Autumn Hills - Bottom" - }, - { - new Transition(ELevel.Level_02_AutumnHills, ELevel.Level_03_ForlornTemple), - "Forlorn Temple - Left" - }, - { - new Transition(ELevel.Level_04_Catacombs, ELevel.Level_03_ForlornTemple), - "Forlorn Temple - Bottom" - }, - { - new Transition(ELevel.Level_06_A_BambooCreek, ELevel.Level_03_ForlornTemple), - "Forlorn Temple - Right" - }, - { - new Transition(ELevel.Level_03_ForlornTemple, ELevel.Level_04_Catacombs), - "Catacombs - Top Left" - }, - { - new Transition(ELevel.Level_02_AutumnHills, ELevel.Level_04_Catacombs), - "Catacombs - Bottom Left" - }, - { - new Transition(ELevel.Level_04_B_DarkCave, ELevel.Level_04_Catacombs), - "Catacombs - Bottom" - }, - { - new Transition(ELevel.Level_06_A_BambooCreek, ELevel.Level_04_Catacombs), - "Catacombs - Right" - }, - { - new Transition(ELevel.Level_04_Catacombs, ELevel.Level_04_B_DarkCave), - "Dark Cave - Right" - }, - { - new Transition(ELevel.Level_04_B_DarkCave, ELevel.Level_04_C_RiviereTurquoise), - "Riviere Turquoise - Right" - }, - { - new Transition(ELevel.Level_04_Catacombs, ELevel.Level_06_A_BambooCreek), - "Bamboo Creek - Bottom Left" - }, - { - new Transition(ELevel.Level_03_ForlornTemple, ELevel.Level_06_A_BambooCreek), - "Bamboo Creek - Top Left" - }, - { - new Transition(ELevel.Level_05_A_HowlingGrotto, ELevel.Level_06_A_BambooCreek), - "Bamboo Creek - Right" - }, - { - new Transition(ELevel.Level_06_A_BambooCreek, ELevel.Level_05_A_HowlingGrotto), - "Howling Grotto - Left" - }, - { - new Transition(ELevel.Level_05_B_SunkenShrine, ELevel.Level_05_A_HowlingGrotto), - "Howling Grotto - Bottom" - }, - { - new Transition(ELevel.Level_07_QuillshroomMarsh, ELevel.Level_05_A_HowlingGrotto), - "Howling Grotto - Right" - }, // This could be either Top Right or Bottom Right. Probably need to check the position and see if it's within ~10 of one of the positions. - { - new Transition(ELevel.Level_05_A_HowlingGrotto, ELevel.Level_07_QuillshroomMarsh), - "Quillshroom Marsh - Left" - }, // Same issue as above - { - new Transition(ELevel.Level_08_SearingCrags, ELevel.Level_07_QuillshroomMarsh), - "Quillshroom Marsh - Right" - }, // same issue again - { - new Transition(ELevel.Level_07_QuillshroomMarsh, ELevel.Level_08_SearingCrags), - "Searing Crags - Left" - }, // again - { - new Transition(ELevel.Level_09_A_GlacialPeak, ELevel.Level_08_SearingCrags), - "Searing Crags - Top" - }, - { - new Transition(ELevel.Level_12_UnderWorld, ELevel.Level_08_SearingCrags), - "Searing Crags - Right" - }, - { - new Transition(ELevel.Level_08_SearingCrags, ELevel.Level_09_A_GlacialPeak), - "Glacial Peak - Bottom" - }, - { - new Transition(ELevel.Level_09_B_ElementalSkylands, ELevel.Level_09_A_GlacialPeak), - "Glacial Peak - Left" - }, - { - new Transition(ELevel.Level_11_A_CloudRuins, ELevel.Level_09_A_GlacialPeak), - "Glacial Peak - Top" - }, - { - new Transition(ELevel.Level_09_A_GlacialPeak, ELevel.Level_11_A_CloudRuins), - "Cloud Ruins - Left" - }, - { - new Transition(ELevel.Level_08_SearingCrags, ELevel.Level_12_UnderWorld), - "Underworld - Left" - }, - { - new Transition(ELevel.Level_11_A_CloudRuins, ELevel.Level_12_UnderWorld), - "Underworld - Bottom Left" - }, // one way after beating manny - { - new Transition(ELevel.Level_05_A_HowlingGrotto, ELevel.Level_05_B_SunkenShrine), - "Sunken Shrine - Left" - }, // not sure if I can make these transitions require seashell - { - new Transition(ELevel.Level_09_A_GlacialPeak, ELevel.Level_09_B_ElementalSkylands), - "Elemental Skylands - Air Shmup" - }, - { - new Transition(ELevel.Level_13_TowerOfTimeHQ, ELevel.Level_11_B_MusicBox), - "Music Box - Left" - }, - { - new Transition(ELevel.Level_13_TowerOfTimeHQ, ELevel.Level_02_AutumnHills), - "Autumn Hills - Portal" - }, - { - new Transition(ELevel.Level_13_TowerOfTimeHQ, ELevel.Level_05_A_HowlingGrotto), - "Howling Grotto - Portal" - }, - { - new Transition(ELevel.Level_13_TowerOfTimeHQ, ELevel.Level_08_SearingCrags), - "Searing Crags - Portal" - }, - { - new Transition(ELevel.Level_13_TowerOfTimeHQ, ELevel.Level_09_A_GlacialPeak), - "Glacial Peak - Portal" - }, - { - new Transition(ELevel.Level_13_TowerOfTimeHQ, ELevel.Level_04_C_RiviereTurquoise), - "Riviere Turquoise - Portal" - }, - { - new Transition(ELevel.Level_13_TowerOfTimeHQ, ELevel.Level_05_B_SunkenShrine), - "Sunken Shrine - Portal" - }, - { - new Transition(ELevel.Level_13_TowerOfTimeHQ, ELevel.Level_10_A_TowerOfTime), - "Tower of Time - Left" - }, - { - new Transition(ELevel.Level_13_TowerOfTimeHQ, ELevel.Level_14_CorruptedFuture), - "Corrupted Future" - }, - { - new Transition(ELevel.Level_01_NinjaVillage, ELevel.Level_15_Surf), - "Ruxxtin Surfin'" - }, - { - new Transition(ELevel.Level_15_Surf, ELevel.Level_16_Beach), - "Beach - Left" - }, - { - new Transition(ELevel.Level_16_Beach, ELevel.Level_17_Volcano), - "Fire Mountain - Bottom" - }, - { - new Transition(ELevel.Level_17_Volcano, ELevel.Level_18_Volcano_Chase), - "Voodoo Heart - Left" - }, - }; - - public static Transition TransitionFromName(string name) + public static readonly Dictionary EntranceNameToRandoLevel = + new Dictionary { - return TransitionToEntranceName.FirstOrDefault(x => x.Value == name).Key; - } + { + "Ninja Village - Right", + new RandoLevel(ELevel.Level_01_NinjaVillage, new Vector3(-153.32f, -57f)) + }, + { + "Autumn Hills - Left", + new RandoLevel(ELevel.Level_02_AutumnHills, new Vector3(-304.7717f, -72.99999f)) + }, + { + "Autumn Hills - Right", + new RandoLevel(ELevel.Level_02_AutumnHills, new Vector3(968.5283f, -27f), EBits.BITS_8) + }, + { + "Autumn Hills - Bottom", new RandoLevel(ELevel.Level_02_AutumnHills, new Vector3(679.6884f, -139f), EBits.BITS_16) + }, // Must be 16 + { + "Forlorn Temple - Left", + new RandoLevel(ELevel.Level_03_ForlornTemple, new Vector3(-17.13942f, -11f)) + }, + { + "Forlorn Temple - Bottom", + new RandoLevel(ELevel.Level_03_ForlornTemple, new Vector3(30, -20), EBits.BITS_16) + }, // Must be 16 + { + "Forlorn Temple - Right", + new RandoLevel(ELevel.Level_03_ForlornTemple, new Vector3(454.4301f, -11f), EBits.BITS_16) + }, + { + "Catacombs - Top Left", + new RandoLevel(ELevel.Level_04_Catacombs, new Vector3(48.5f, -11)) + }, + { + "Catacombs - Right", + new RandoLevel(ELevel.Level_04_Catacombs, new Vector3(809.5f, -74.5f)) + }, + { + "Catacombs - Bottom", + new RandoLevel(ELevel.Level_04_Catacombs, new Vector3(511, -123), EBits.BITS_16) + }, // Must be 16 + { + "Catacombs - Bottom Left", + new RandoLevel(ELevel.Level_04_Catacombs, new Vector3(144.5119f, -59f), EBits.BITS_16) + }, // Must be 16 + { + "Dark Cave - Right", + new RandoLevel(ELevel.Level_04_B_DarkCave, new Vector3(-4.059998f, -4f), EBits.BITS_16) + }, // This needs to be forced to 16 bit to not soft lock the player + // { "Dark Cave - Left", new RandoLevel(ELevel.Level_04_B_DarkCave, new Vector3()) }, // This may or may not be possible. This is a drop down into riviere in vanilla and you can't return from riviere + { + "Riviere Turquoise - Portal", + new RandoLevel(ELevel.Level_04_C_RiviereTurquoise, new Vector3(837f, 13f)) + }, //TOT D + { + "Riviere Turquoise - Right", + new RandoLevel(ELevel.Level_04_C_RiviereTurquoise, new Vector3(997.7f, 5.999998f), EBits.BITS_8) + }, // This needs to be forced to 8 bit + { + "Howling Grotto - Left", + new RandoLevel(ELevel.Level_05_A_HowlingGrotto, new Vector3(-46.82001f, -11f)) + }, + { + "Howling Grotto - Right", + new RandoLevel(ELevel.Level_05_A_HowlingGrotto, new Vector3(584.21f, -123f)) + }, // Emerald Golem is here. Scene loaded gets called before the check, but level loaded is after + { + "Howling Grotto - Top", + new RandoLevel(ELevel.Level_05_A_HowlingGrotto, new Vector3(419.95f, -58.66491f), EBits.BITS_16) + }, // This needs to be forced to 16 bit + { + "Howling Grotto - Bottom", + new RandoLevel(ELevel.Level_05_A_HowlingGrotto, new Vector3(194.9271f, -151.665f), EBits.BITS_16) + }, // needs to be 16 + { + "Sunken Shrine - Left", + new RandoLevel(ELevel.Level_05_B_SunkenShrine, new Vector3(-46.41f, -58.66499f), EBits.BITS_16) + }, // This needs to be forced to 16 bit + { + "Bamboo Creek - Top Left", + new RandoLevel(ELevel.Level_06_A_BambooCreek, new Vector3(-50.09212f, 45f), EBits.BITS_16) + }, + { + "Bamboo Creek - Bottom Left", + new RandoLevel(ELevel.Level_06_A_BambooCreek, new Vector3(-177.0621f, -11f)) + }, + { + "Bamboo Creek - Right", + new RandoLevel(ELevel.Level_06_A_BambooCreek, new Vector3(488.4079f, -91f)) + }, + { + "Quillshroom Marsh - Top Left", + new RandoLevel(ELevel.Level_07_QuillshroomMarsh, new Vector3(-16.80286f, -11f)) + }, + { + "Quillshroom Marsh - Bottom Left", + new RandoLevel(ELevel.Level_07_QuillshroomMarsh, new Vector3(598.1053f, -75.66499f), EBits.BITS_16) + }, // This needs to be forced to 16 bit + { + "Quillshroom Marsh - Top Right", + new RandoLevel(ELevel.Level_07_QuillshroomMarsh, new Vector3(1160.79f, -43f)) + }, + { + "Quillshroom Marsh - Bottom Right", + new RandoLevel(ELevel.Level_07_QuillshroomMarsh, new Vector3(841.3f, -121f), EBits.BITS_16) + }, // 16 + { + "Searing Crags - Left", + new RandoLevel(ELevel.Level_08_SearingCrags, new Vector3(-17.23438f, -27f)) + }, + { + "Searing Crags - Bottom", + new RandoLevel(ELevel.Level_08_SearingCrags, new Vector3(303.3f, 39f), EBits.BITS_16) + }, + { + "Searing Crags - Right", + new RandoLevel(ELevel.Level_08_SearingCrags, new Vector3(521.8f, 71f), EBits.BITS_8) + }, // Force 8 bit + { + "Searing Crags - Top", + new RandoLevel(ELevel.Level_08_SearingCrags, new Vector3(351.5f, 324.2888f)) + }, + { + "Glacial Peak - Bottom", + new RandoLevel(ELevel.Level_09_A_GlacialPeak, new Vector3(202, -519)) + }, + { + "Glacial Peak - Left", new RandoLevel(ELevel.Level_09_A_GlacialPeak, new Vector3(180, -307)) + }, + { + "Glacial Peak - Top", + new RandoLevel(ELevel.Level_09_A_GlacialPeak, new Vector3(176.04f, -13.71676f)) + }, + { + "Elemental Skylands - Air Shmup", + new RandoLevel(ELevel.Level_09_B_ElementalSkylands, new Vector3(-37.4f, 359.5f), EBits.BITS_16) + }, + { + "Tower of Time - Left", + new RandoLevel(ELevel.Level_10_A_TowerOfTime, new Vector3(-18f, -11f), EBits.BITS_8) + }, // 8 + { + "Cloud Ruins - Left", + new RandoLevel(ELevel.Level_11_A_CloudRuins, new Vector3(-486f, -57f), EBits.BITS_16) + }, + { + "Music Box - Left", + new RandoLevel(ELevel.Level_11_B_MusicBox, new Vector3(-428, -55)) + }, + { + "Underworld - Left", + new RandoLevel(ELevel.Level_12_UnderWorld, new Vector3(-337.5526f, -25f), EBits.BITS_8) + }, // Force 8 bit + // { + // "Underworld - Bottom Left", + // new RandoLevel(ELevel.Level_12_UnderWorld, new Vector3(-431.7626f, -57f), EBits.BITS_16) + // }, // force 16 bit - one time and one way only - after defeating manfred - might be able to force it by calling ManfredBossOutroCutscene? + { + "Corrupted Future", + new RandoLevel(ELevel.Level_14_CorruptedFuture, new Vector3(-100, -9.5f), EBits.BITS_16) + }, // 16 + { + "Ruxxtin Surfin'", + new RandoLevel(ELevel.Level_15_Surf, new Vector3(-472.191f, 472f), EBits.BITS_8) + }, // 8 + { + "Beach - Left", + new RandoLevel(ELevel.Level_16_Beach, new Vector3(-431.7f, -9f)) + }, + { + "Fire Mountain - Bottom", + new RandoLevel(ELevel.Level_17_Volcano, new Vector3(-443.5f, -34f)) + }, + { + "Voodoo Heart - Left", + new RandoLevel(ELevel.Level_18_Volcano_Chase, new Vector3(-165.5f, 104.5551f), EBits.BITS_8) + }, // 8 + }; - /// - /// I'm doing the magic by determining where the player teleported from as that's definitely the easiest way to - /// do this. These areas connect to each other twice so I need to use the player pos to determine which one - /// we're actually using - /// - public static readonly List SpecialEntranceNames = new List + public static readonly Dictionary TransitionToEntranceName = + new Dictionary { - "Howling Grotto - Right", "Quillshroom Marsh - Left", - "Quillshroom Marsh - Right", "Searing Crags - Left" + { + new Transition(ELevel.Level_02_AutumnHills, ELevel.Level_01_NinjaVillage), + "Ninja Village - Right" + }, + { + new Transition(ELevel.Level_01_NinjaVillage, ELevel.Level_02_AutumnHills), + "Autumn Hills - Left" + }, + { + new Transition(ELevel.Level_03_ForlornTemple, ELevel.Level_02_AutumnHills), + "Autumn Hills - Right" + }, + { + new Transition(ELevel.Level_04_Catacombs, ELevel.Level_02_AutumnHills), + "Autumn Hills - Bottom" + }, + { + new Transition(ELevel.Level_02_AutumnHills, ELevel.Level_03_ForlornTemple), + "Forlorn Temple - Left" + }, + { + new Transition(ELevel.Level_04_Catacombs, ELevel.Level_03_ForlornTemple), + "Forlorn Temple - Bottom" + }, + { + new Transition(ELevel.Level_06_A_BambooCreek, ELevel.Level_03_ForlornTemple), + "Forlorn Temple - Right" + }, + { + new Transition(ELevel.Level_03_ForlornTemple, ELevel.Level_04_Catacombs), + "Catacombs - Top Left" + }, + { + new Transition(ELevel.Level_02_AutumnHills, ELevel.Level_04_Catacombs), + "Catacombs - Bottom Left" + }, + { + new Transition(ELevel.Level_04_B_DarkCave, ELevel.Level_04_Catacombs), + "Catacombs - Bottom" + }, + { + new Transition(ELevel.Level_06_A_BambooCreek, ELevel.Level_04_Catacombs), + "Catacombs - Right" + }, + { + new Transition(ELevel.Level_04_Catacombs, ELevel.Level_04_B_DarkCave), + "Dark Cave - Right" + }, + { + new Transition(ELevel.Level_04_B_DarkCave, ELevel.Level_04_C_RiviereTurquoise), + "Riviere Turquoise - Right" + }, + { + new Transition(ELevel.Level_04_Catacombs, ELevel.Level_06_A_BambooCreek), + "Bamboo Creek - Bottom Left" + }, + { + new Transition(ELevel.Level_03_ForlornTemple, ELevel.Level_06_A_BambooCreek), + "Bamboo Creek - Top Left" + }, + { + new Transition(ELevel.Level_05_A_HowlingGrotto, ELevel.Level_06_A_BambooCreek), + "Bamboo Creek - Right" + }, + { + new Transition(ELevel.Level_06_A_BambooCreek, ELevel.Level_05_A_HowlingGrotto), + "Howling Grotto - Left" + }, + { + new Transition(ELevel.Level_05_B_SunkenShrine, ELevel.Level_05_A_HowlingGrotto), + "Howling Grotto - Bottom" + }, + { + new Transition(ELevel.Level_07_QuillshroomMarsh, ELevel.Level_05_A_HowlingGrotto), + "Howling Grotto - Right" + }, // This could be either Top Right or Bottom Right. Probably need to check the position and see if it's within ~10 of one of the positions. + { + new Transition(ELevel.Level_05_A_HowlingGrotto, ELevel.Level_07_QuillshroomMarsh), + "Quillshroom Marsh - Left" + }, // Same issue as above + { + new Transition(ELevel.Level_08_SearingCrags, ELevel.Level_07_QuillshroomMarsh), + "Quillshroom Marsh - Right" + }, // same issue again + { + new Transition(ELevel.Level_07_QuillshroomMarsh, ELevel.Level_08_SearingCrags), + "Searing Crags - Left" + }, // again + { + new Transition(ELevel.Level_09_A_GlacialPeak, ELevel.Level_08_SearingCrags), + "Searing Crags - Top" + }, + { + new Transition(ELevel.Level_12_UnderWorld, ELevel.Level_08_SearingCrags), + "Searing Crags - Right" + }, + { + new Transition(ELevel.Level_08_SearingCrags, ELevel.Level_09_A_GlacialPeak), + "Glacial Peak - Bottom" + }, + { + new Transition(ELevel.Level_09_B_ElementalSkylands, ELevel.Level_09_A_GlacialPeak), + "Glacial Peak - Left" + }, + { + new Transition(ELevel.Level_11_A_CloudRuins, ELevel.Level_09_A_GlacialPeak), + "Glacial Peak - Top" + }, + { + new Transition(ELevel.Level_09_A_GlacialPeak, ELevel.Level_11_A_CloudRuins), + "Cloud Ruins - Left" + }, + { + new Transition(ELevel.Level_08_SearingCrags, ELevel.Level_12_UnderWorld), + "Underworld - Left" + }, + { + new Transition(ELevel.Level_11_A_CloudRuins, ELevel.Level_12_UnderWorld), + "Underworld - Bottom Left" + }, // one way after beating manny + { + new Transition(ELevel.Level_05_A_HowlingGrotto, ELevel.Level_05_B_SunkenShrine), + "Sunken Shrine - Left" + }, // not sure if I can make these transitions require seashell + { + new Transition(ELevel.Level_09_A_GlacialPeak, ELevel.Level_09_B_ElementalSkylands), + "Elemental Skylands - Air Shmup" + }, + { + new Transition(ELevel.Level_13_TowerOfTimeHQ, ELevel.Level_11_B_MusicBox), + "Music Box - Left" + }, + { + new Transition(ELevel.Level_13_TowerOfTimeHQ, ELevel.Level_02_AutumnHills), + "Autumn Hills - Portal" + }, + { + new Transition(ELevel.Level_13_TowerOfTimeHQ, ELevel.Level_05_A_HowlingGrotto), + "Howling Grotto - Portal" + }, + { + new Transition(ELevel.Level_13_TowerOfTimeHQ, ELevel.Level_08_SearingCrags), + "Searing Crags - Portal" + }, + { + new Transition(ELevel.Level_13_TowerOfTimeHQ, ELevel.Level_09_A_GlacialPeak), + "Glacial Peak - Portal" + }, + { + new Transition(ELevel.Level_13_TowerOfTimeHQ, ELevel.Level_04_C_RiviereTurquoise), + "Riviere Turquoise - Portal" + }, + { + new Transition(ELevel.Level_13_TowerOfTimeHQ, ELevel.Level_05_B_SunkenShrine), + "Sunken Shrine - Portal" + }, + { + new Transition(ELevel.Level_13_TowerOfTimeHQ, ELevel.Level_10_A_TowerOfTime), + "Tower of Time - Left" + }, + { + new Transition(ELevel.Level_13_TowerOfTimeHQ, ELevel.Level_14_CorruptedFuture), + "Corrupted Future" + }, + { + new Transition(ELevel.Level_01_NinjaVillage, ELevel.Level_15_Surf), + "Ruxxtin Surfin'" + }, + { + new Transition(ELevel.Level_15_Surf, ELevel.Level_16_Beach), + "Beach - Left" + }, + { + new Transition(ELevel.Level_16_Beach, ELevel.Level_17_Volcano), + "Fire Mountain - Bottom" + }, + { + new Transition(ELevel.Level_17_Volcano, ELevel.Level_18_Volcano_Chase), + "Voodoo Heart - Left" + }, }; - public static readonly Dictionary SpecialConnectionSourceExits = - new Dictionary - { - { "Howling Grotto - Right", "Quillshroom Marsh - Top Left" }, - { "Howling Grotto - Top", "Quillshroom Marsh - Bottom Left" }, - { "Quillshroom Marsh - Bottom Left", "Howling Grotto - Top" }, - { "Quillshroom Marsh - Top Left", "Howling Grotto - Right" }, - { "Quillshroom Marsh - Top Right", "Searing Crags - Left" }, - { "Quillshroom Marsh - Bottom Right", "Searing Crags - Bottom" }, - { "Searing Crags - Left", "Quillshroom Marsh - Top Right" }, - { "Searing Crags - Bottom", "Quillshroom Marsh - Bottom Right" }, - }; + public static Transition TransitionFromName(string name) + { + return TransitionToEntranceName.FirstOrDefault(x => x.Value == name).Key; + } + + /// + /// I'm doing the magic by determining where the player teleported from as that's definitely the easiest way to + /// do this. These areas connect to each other twice so I need to use the player pos to determine which one + /// we're actually using + /// + public static readonly List SpecialEntranceNames = new List + { + "Howling Grotto - Right", "Quillshroom Marsh - Left", + "Quillshroom Marsh - Right", "Searing Crags - Left" + }; - public static readonly List TransitionNames = new List + public static readonly Dictionary SpecialConnectionSourceExits = + new Dictionary { - "Ninja Village - Right", - "Autumn Hills - Left", - "Autumn Hills - Right", - "Autumn Hills - Bottom", - "Forlorn Temple - Left", - "Forlorn Temple - Bottom", - "Forlorn Temple - Right", - "Catacombs - Top Left", - "Catacombs - Right", - "Catacombs - Bottom", - "Catacombs - Bottom Left", - "Dark Cave - Right", - "Dark Cave - Left", - "Riviere Turquoise - Right", - "Howling Grotto - Left", - "Howling Grotto - Right", - "Howling Grotto - Top", - "Howling Grotto - Bottom", - "Sunken Shrine - Left", - "Bamboo Creek - Top Left", - "Bamboo Creek - Bottom Left", - "Bamboo Creek - Right", - "Quillshroom Marsh - Top Left", - "Quillshroom Marsh - Bottom Left", - "Quillshroom Marsh - Top Right", - "Quillshroom Marsh - Bottom Right", - "Searing Crags - Left", - "Searing Crags - Bottom", - "Searing Crags - Right", - "Searing Crags - Top", - "Glacial Peak - Bottom", - "Glacial Peak - Top", - "Glacial Peak - Left", - "Elemental Skylands - Air Shmup", - "Elemental Skylands - Right", - "Tower HQ", - "Tower of Time - Left", - "Corrupted Future", - "Cloud Ruins - Left", - "Underworld - Left", + { "Howling Grotto - Right", "Quillshroom Marsh - Top Left" }, + { "Howling Grotto - Top", "Quillshroom Marsh - Bottom Left" }, + { "Quillshroom Marsh - Bottom Left", "Howling Grotto - Top" }, + { "Quillshroom Marsh - Top Left", "Howling Grotto - Right" }, + { "Quillshroom Marsh - Top Right", "Searing Crags - Left" }, + { "Quillshroom Marsh - Bottom Right", "Searing Crags - Bottom" }, + { "Searing Crags - Left", "Quillshroom Marsh - Top Right" }, + { "Searing Crags - Bottom", "Quillshroom Marsh - Bottom Right" }, }; - } + + public static readonly List TransitionNames = new List + { + "Ninja Village - Right", + "Autumn Hills - Left", + "Autumn Hills - Right", + "Autumn Hills - Bottom", + "Forlorn Temple - Left", + "Forlorn Temple - Bottom", + "Forlorn Temple - Right", + "Catacombs - Top Left", + "Catacombs - Right", + "Catacombs - Bottom", + "Catacombs - Bottom Left", + "Dark Cave - Right", + "Dark Cave - Left", + "Riviere Turquoise - Right", + "Howling Grotto - Left", + "Howling Grotto - Right", + "Howling Grotto - Top", + "Howling Grotto - Bottom", + "Sunken Shrine - Left", + "Bamboo Creek - Top Left", + "Bamboo Creek - Bottom Left", + "Bamboo Creek - Right", + "Quillshroom Marsh - Top Left", + "Quillshroom Marsh - Bottom Left", + "Quillshroom Marsh - Top Right", + "Quillshroom Marsh - Bottom Right", + "Searing Crags - Left", + "Searing Crags - Bottom", + "Searing Crags - Right", + "Searing Crags - Top", + "Glacial Peak - Bottom", + "Glacial Peak - Top", + "Glacial Peak - Left", + "Elemental Skylands - Air Shmup", + "Elemental Skylands - Right", + "Tower HQ", + "Tower of Time - Left", + "Corrupted Future", + "Cloud Ruins - Left", + "Underworld - Left", + }; } \ No newline at end of file diff --git a/Utils/Constants/RoomConstants.cs b/Utils/Constants/RoomConstants.cs index 6ca789f..6528686 100644 --- a/Utils/Constants/RoomConstants.cs +++ b/Utils/Constants/RoomConstants.cs @@ -4,119 +4,118 @@ using MessengerRando.Exceptions; using UnityEngine; -namespace MessengerRando.Utils.Constants +namespace MessengerRando.Utils.Constants; + +public static class RoomConstants { - public static class RoomConstants + public struct RoomTransition : IEquatable { - public struct RoomTransition: IEquatable + private static readonly List ValidDirections = new List { "Up", "Left", "Down", "Right" }; + public string Direction; + public Vector3 Position; + public EBits Dimension; + + public RoomTransition(string direction, Vector3 position) { - private static readonly List ValidDirections = new List { "Up", "Left", "Down", "Right" }; - public string Direction; - public Vector3 Position; - public EBits Dimension; + if (!ValidDirections.Contains(direction)) + throw new RandomizerException($"{direction} is an invalid direction for a RoomTransition!"); + Direction = direction; + Position = position; + Dimension = EBits.NONE; + } - public RoomTransition(string direction, Vector3 position) - { - if (!ValidDirections.Contains(direction)) - throw new RandomizerException($"{direction} is an invalid direction for a RoomTransition!"); - Direction = direction; - Position = position; - Dimension = EBits.NONE; - } + public RoomTransition(string direction, Vector3 position, EBits dimension) + { + if (!ValidDirections.Contains(direction)) + throw new RandomizerException($"{direction} is invalid direction!"); + Direction = direction; + Position = position; + Dimension = dimension; + } - public RoomTransition(string direction, Vector3 position, EBits dimension) - { - if (!ValidDirections.Contains(direction)) - throw new RandomizerException($"{direction} is invalid direction!"); - Direction = direction; - Position = position; - Dimension = dimension; - } - - public bool Equals(RoomTransition other) - { - return Direction == other.Direction; - } + public bool Equals(RoomTransition other) + { + return Direction == other.Direction; + } - public override bool Equals(object obj) - { - return obj is RoomTransition other && Equals(other); - } + public override bool Equals(object obj) + { + return obj is RoomTransition other && Equals(other); + } - public override int GetHashCode() + public override int GetHashCode() + { + unchecked { - unchecked - { - return ((Direction != null ? Direction.GetHashCode() : 0) * 397) ^ Position.GetHashCode(); - } + return ((Direction != null ? Direction.GetHashCode() : 0) * 397) ^ Position.GetHashCode(); } } + } - public struct RandoRoom: IEquatable - { - public readonly ELevel Region; - public readonly string RoomKey; + public struct RandoRoom : IEquatable + { + public readonly ELevel Region; + public readonly string RoomKey; - public RandoRoom(string key, ELevel area) - { - RoomKey = key; - Region = area; - } + public RandoRoom(string key, ELevel area) + { + RoomKey = key; + Region = area; + } - public RandoRoom(string key) - { - RoomKey = key; - Region = ELevel.NONE; - } - - public bool Equals(RandoRoom other) - { - return RoomKey == other.RoomKey && Region == other.Region; - } + public RandoRoom(string key) + { + RoomKey = key; + Region = ELevel.NONE; + } - public override bool Equals(object obj) - { - return obj is RandoRoom other && Equals(other); - } + public bool Equals(RandoRoom other) + { + return RoomKey == other.RoomKey && Region == other.Region; + } - public override int GetHashCode() - { - return (RoomKey != null ? RoomKey.GetHashCode() : 0); - } + public override bool Equals(object obj) + { + return obj is RandoRoom other && Equals(other); } - - public static readonly Dictionary RoomLookup = new Dictionary + + public override int GetHashCode() { - {"room name", new RandoRoom("roomKey") }, - }; + return (RoomKey != null ? RoomKey.GetHashCode() : 0); + } + } - public static readonly Dictionary RoomNameLookup = - RoomLookup.ToDictionary(x => x.Value, x => x.Key); + public static readonly Dictionary RoomLookup = new Dictionary + { + {"room name", new RandoRoom("roomKey") }, + }; + public static readonly Dictionary RoomNameLookup = + RoomLookup.ToDictionary(x => x.Value, x => x.Key); - public static readonly Dictionary> TransitionLookup = - new Dictionary> + + public static readonly Dictionary> TransitionLookup = + new Dictionary> + { { - { - "room name", new List - { - new RoomTransition("Up", new Vector3()), - new RoomTransition("Left", new Vector3()), - new RoomTransition("Down", new Vector3()), - new RoomTransition("Right", new Vector3()) - } - }, + "room name", new List { - "room name", new List - { - new RoomTransition("Up", new Vector3()), - new RoomTransition("Down", new Vector3()), - new RoomTransition("Left", new Vector3()), - new RoomTransition("Right", new Vector3()) - } - }, - - }; + new RoomTransition("Up", new Vector3()), + new RoomTransition("Left", new Vector3()), + new RoomTransition("Down", new Vector3()), + new RoomTransition("Right", new Vector3()) + } + }, + { + "room name", new List + { + new RoomTransition("Up", new Vector3()), + new RoomTransition("Down", new Vector3()), + new RoomTransition("Left", new Vector3()), + new RoomTransition("Right", new Vector3()) + } + }, + + }; - } } \ No newline at end of file diff --git a/Utils/DialogChanger.cs b/Utils/DialogChanger.cs index 561526e..61c1d87 100644 --- a/Utils/DialogChanger.cs +++ b/Utils/DialogChanger.cs @@ -1,140 +1,139 @@ -using MessengerRando.Archipelago; -using System; +using System; using System.Collections.Generic; using System.Linq; using System.Reflection; +using MessengerRando.Archipelago; using MessengerRando.GameOverrideManagers; using UnityEngine; -namespace MessengerRando.Utils +namespace MessengerRando.Utils; + +/// +/// A static class to handle replacement of Dialogs for items. +/// Could be made better by adding the award text string to the LocationRO for each item +/// +public static class DialogChanger { - /// - /// A static class to handle replacement of Dialogs for items. - /// Could be made better by adding the award text string to the LocationRO for each item - /// - public static class DialogChanger + public static readonly Dictionary ItemDialogID = new Dictionary { - public static readonly Dictionary ItemDialogID = new Dictionary - { - { EItems.KEY_OF_LOVE, "AWARD_KEY_OF_LOVE" }, - { EItems.KEY_OF_COURAGE, "AWARD_KEY_OF_COURAGE"}, - { EItems.KEY_OF_CHAOS, "AWARD_KEY_OF_CHAOS" }, - { EItems.KEY_OF_SYMBIOSIS, "AWARD_KEY_OF_SYMBIOSIS" }, - { EItems.KEY_OF_STRENGTH, "AWARD_KEY_OF_STRENGTH" }, - { EItems.KEY_OF_HOPE, "AWARD_KEY_OF_HOPE" }, - { EItems.WINGSUIT, "AWARD_WINGSUIT" }, - { EItems.GRAPLOU, "AWARD_ROPE_DART" }, - { EItems.MAGIC_BOOTS, "AWARD_MAGIC_BOOTS" }, - { EItems.CLIMBING_CLAWS, "AWARD_GRIMPLOU" }, - { EItems.TEA_SEED, "AWARD_SEED" }, - { EItems.TEA_LEAVES, "AWARD_ASTRAL_LEAVES" }, - { EItems.CANDLE, "AWARD_CANDLE" }, - { EItems.SEASHELL, "AWARD_MAGIC_SEASHELL" }, - { EItems.POWER_THISTLE, "AWARD_THISTLE" }, - { EItems.DEMON_KING_CROWN, "AWARD_CROWN" }, - { EItems.RUXXTIN_AMULET, "AWARD_AMULET" }, - { EItems.FAIRY_BOTTLE, "AWARD_FAIRY" }, - { EItems.SUN_CREST, "AWARD_SUN_CREST" }, - { EItems.MOON_CREST, "AWARD_MOON_CREST" }, - { EItems.NECROPHOBIC_WORKER, "NECRO_PHOBEKIN_DIALOG" }, - { EItems.PYROPHOBIC_WORKER, "FIND_PYRO" }, - { EItems.CLAUSTROPHOBIC_WORKER, "FIND_CLAUSTRO" }, - { EItems.ACROPHOBIC_WORKER, "FIND_ACRO" }, - }; + { EItems.KEY_OF_LOVE, "AWARD_KEY_OF_LOVE" }, + { EItems.KEY_OF_COURAGE, "AWARD_KEY_OF_COURAGE"}, + { EItems.KEY_OF_CHAOS, "AWARD_KEY_OF_CHAOS" }, + { EItems.KEY_OF_SYMBIOSIS, "AWARD_KEY_OF_SYMBIOSIS" }, + { EItems.KEY_OF_STRENGTH, "AWARD_KEY_OF_STRENGTH" }, + { EItems.KEY_OF_HOPE, "AWARD_KEY_OF_HOPE" }, + { EItems.WINGSUIT, "AWARD_WINGSUIT" }, + { EItems.GRAPLOU, "AWARD_ROPE_DART" }, + { EItems.MAGIC_BOOTS, "AWARD_MAGIC_BOOTS" }, + { EItems.CLIMBING_CLAWS, "AWARD_GRIMPLOU" }, + { EItems.TEA_SEED, "AWARD_SEED" }, + { EItems.TEA_LEAVES, "AWARD_ASTRAL_LEAVES" }, + { EItems.CANDLE, "AWARD_CANDLE" }, + { EItems.SEASHELL, "AWARD_MAGIC_SEASHELL" }, + { EItems.POWER_THISTLE, "AWARD_THISTLE" }, + { EItems.DEMON_KING_CROWN, "AWARD_CROWN" }, + { EItems.RUXXTIN_AMULET, "AWARD_AMULET" }, + { EItems.FAIRY_BOTTLE, "AWARD_FAIRY" }, + { EItems.SUN_CREST, "AWARD_SUN_CREST" }, + { EItems.MOON_CREST, "AWARD_MOON_CREST" }, + { EItems.NECROPHOBIC_WORKER, "NECRO_PHOBEKIN_DIALOG" }, + { EItems.PYROPHOBIC_WORKER, "FIND_PYRO" }, + { EItems.CLAUSTROPHOBIC_WORKER, "FIND_CLAUSTRO" }, + { EItems.ACROPHOBIC_WORKER, "FIND_ACRO" }, + }; - public static void CreateDialogBox(string text) - { - Console.WriteLine($"Drawing text box for {text}"); - var dialogBox = ScriptableObject.CreateInstance(); - dialogBox.dialogID = "ARCHIPELAGO_ITEM"; - dialogBox.name = text; - dialogBox.choices = new List(); - var popupParams = new AwardItemPopupParams(dialogBox, true); - Manager.Instance.ShowView(EScreenLayers.PROMPT, popupParams); - } + public static void CreateDialogBox(string text) + { + Console.WriteLine($"Drawing text box for {text}"); + var dialogBox = ScriptableObject.CreateInstance(); + dialogBox.dialogID = "ARCHIPELAGO_ITEM"; + dialogBox.name = text; + dialogBox.choices = new List(); + var popupParams = new AwardItemPopupParams(dialogBox, true); + Manager.Instance.ShowView(EScreenLayers.PROMPT, popupParams); + } - /// - /// Runs whenever the locale is loaded\changed. This should allow it to work in any language. - /// Works by loading and replacing all dialogs and then using reflection to call the onlanguagechanged event on the localization manager to update all dialog to the correct text. - /// - /// - /// - /// - public static void LoadDialogs_Elanguage(On.DialogManager.orig_LoadDialogs_ELanguage orig, DialogManager self, ELanguage language) - { + /// + /// Runs whenever the locale is loaded\changed. This should allow it to work in any language. + /// Works by loading and replacing all dialogs and then using reflection to call the onlanguagechanged event on the localization manager to update all dialog to the correct text. + /// + /// + /// + /// + public static void LoadDialogs_Elanguage(On.DialogManager.orig_LoadDialogs_ELanguage orig, DialogManager self, ELanguage language) + { - //Loads all the original dialog - orig(self, language); + //Loads all the original dialog + orig(self, language); - if (!ArchipelagoClient.HasConnected) return; - //Sets the field info so we can use reflection to get and set the private field. - FieldInfo dialogByLocIDField = typeof(DialogManager).GetField("dialogByLocID", BindingFlags.NonPublic | BindingFlags.Instance); + if (!ArchipelagoClient.HasConnected) return; + //Sets the field info so we can use reflection to get and set the private field. + FieldInfo dialogByLocIDField = typeof(DialogManager).GetField("dialogByLocID", BindingFlags.NonPublic | BindingFlags.Instance); - //Gets all loaded dialogs and makes a copy - if (dialogByLocIDField != null) + //Gets all loaded dialogs and makes a copy + if (dialogByLocIDField != null) + { + Dictionary> Loc = dialogByLocIDField.GetValue(self) as Dictionary>; + if (Loc != null) { - Dictionary> Loc = dialogByLocIDField.GetValue(self) as Dictionary>; - if (Loc != null) + //Loop through each dialog replacement - Will output the replacements to log for debugging + foreach (var replaceableKey in Loc.Select(kvp => kvp.Key).Where(toBeReplaced => ItemDialogID.ContainsValue(toBeReplaced))) { - //Loop through each dialog replacement - Will output the replacements to log for debugging - foreach (var replaceableKey in Loc.Select(kvp => kvp.Key).Where(toBeReplaced => ItemDialogID.ContainsValue(toBeReplaced))) + //Sets them to be all center and no portrait (This really only applies to phobekins but was + Loc[replaceableKey][0].autoClose = true; + Loc[replaceableKey][0].autoCloseDelay = 0; + Loc[replaceableKey][0].characterDefinition = null; + Loc[replaceableKey][0].forcedPortraitOrientation = 0; + Loc[replaceableKey][0].position = EDialogPosition.CENTER; + Loc[replaceableKey][0].skippable = false; + if ((RandomizerStateManager.Instance.ScoutedLocations != null || ArchipelagoClient.Offline) && + RandomizerStateManager.Instance.IsLocationRandomized( + ItemDialogID.First(x => x.Value.Equals(replaceableKey)).Key, + out var locationID)) { - //Sets them to be all center and no portrait (This really only applies to phobekins but was - Loc[replaceableKey][0].autoClose = true; - Loc[replaceableKey][0].autoCloseDelay = 0; - Loc[replaceableKey][0].characterDefinition = null; - Loc[replaceableKey][0].forcedPortraitOrientation = 0; - Loc[replaceableKey][0].position = EDialogPosition.CENTER; - Loc[replaceableKey][0].skippable = false; - if ((RandomizerStateManager.Instance.ScoutedLocations != null || ArchipelagoClient.Offline) && - RandomizerStateManager.Instance.IsLocationRandomized( - ItemDialogID.First(x => x.Value.Equals(replaceableKey)).Key, - out var locationID)) + if (ArchipelagoClient.Offline) { - if (ArchipelagoClient.Offline) + Loc[replaceableKey][0].text = SeedGenerator.GetOfflineDialog(locationID); + } + else if (ArchipelagoClient.Authenticated) + { + var netItem = RandomizerStateManager.Instance.ScoutedLocations[locationID]; + if (netItem.Player.Slot.Equals(ArchipelagoClient.Session.ConnectionInfo.Slot)) { - Loc[replaceableKey][0].text = SeedGenerator.GetOfflineDialog(locationID); + Loc[replaceableKey][0].text = netItem.ToReadableString(); } - else if (ArchipelagoClient.Authenticated) + else { - var netItem = RandomizerStateManager.Instance.ScoutedLocations[locationID]; - if (netItem.Player.Slot.Equals(ArchipelagoClient.Session.ConnectionInfo.Slot)) - { - Loc[replaceableKey][0].text = netItem.ToReadableString(); - } - else - { - var otherPlayerName = netItem.Player.Alias; - Loc[replaceableKey][0].text = netItem.ToReadableString(otherPlayerName); - } + var otherPlayerName = netItem.Player.Alias; + Loc[replaceableKey][0].text = netItem.ToReadableString(otherPlayerName); } } - - //This will remove all additional dialog that comes after the initial reward text - if (Loc[replaceableKey].Count > 1) - { - Loc[replaceableKey].RemoveRange(1, Loc[replaceableKey].Count - 1); - } } - FlavorDialogManager.UpdateLoc(Loc); + //This will remove all additional dialog that comes after the initial reward text + if (Loc[replaceableKey].Count > 1) + { + Loc[replaceableKey].RemoveRange(1, Loc[replaceableKey].Count - 1); + } } + + FlavorDialogManager.UpdateLoc(Loc); } + } - //There is probably a better way to do this but I chose to use reflection to call all onLanguageChanged events to update the localization completely. - if (Manager.Instance != null) - { - Type type = typeof(LocalizationManager); - FieldInfo field = type.GetField("onLanguageChanged", BindingFlags.NonPublic | BindingFlags.Instance); - MulticastDelegate eventDelegate = field?.GetValue(Manager.Instance) as MulticastDelegate; + //There is probably a better way to do this but I chose to use reflection to call all onLanguageChanged events to update the localization completely. + if (Manager.Instance != null) + { + Type type = typeof(LocalizationManager); + FieldInfo field = type.GetField("onLanguageChanged", BindingFlags.NonPublic | BindingFlags.Instance); + MulticastDelegate eventDelegate = field?.GetValue(Manager.Instance) as MulticastDelegate; - if (eventDelegate != null) + if (eventDelegate != null) + { + foreach (Delegate eventHandler in eventDelegate.GetInvocationList()) { - foreach (Delegate eventHandler in eventDelegate.GetInvocationList()) - { - eventHandler.Method.Invoke(eventHandler.Target, null); - } + eventHandler.Method.Invoke(eventHandler.Target, null); } } } diff --git a/Utils/ItemRandomizerUtil.cs b/Utils/ItemRandomizerUtil.cs index c60d5d6..8b84975 100644 --- a/Utils/ItemRandomizerUtil.cs +++ b/Utils/ItemRandomizerUtil.cs @@ -2,29 +2,28 @@ using Mod.Courier.Module; -namespace MessengerRando.Utils +namespace MessengerRando.Utils; + +//This class will be responsible for handling the randomization of items to locations and generating the mapping dictionary. +public class ItemRandomizerUtil { - //This class will be responsible for handling the randomization of items to locations and generating the mapping dictionary. - public class ItemRandomizerUtil + public static string ModName = "TheMessengerRandomizerAP"; + + /// + /// Gets the current version number for the mod. + /// + /// the version number or "Unknown" if it has trouble getting the version number. + public static string GetModVersion() { - public static string ModName = "TheMessengerRandomizerAP"; - - /// - /// Gets the current version number for the mod. - /// - /// the version number or "Unknown" if it has trouble getting the version number. - public static string GetModVersion() - { - string version = "Unknown"; + string version = "Unknown"; - foreach (CourierModuleMetadata modMetadata in Courier.Mods) + foreach (CourierModuleMetadata modMetadata in Courier.Mods) + { + if (ModName.Equals(modMetadata.Name)) { - if (ModName.Equals(modMetadata.Name)) - { - version = modMetadata.VersionString; - } + version = modMetadata.VersionString; } - return version; } + return version; } } diff --git a/Utils/Menus/ArchipelagoMenu.cs b/Utils/Menus/ArchipelagoMenu.cs index 90077bf..a490580 100644 --- a/Utils/Menus/ArchipelagoMenu.cs +++ b/Utils/Menus/ArchipelagoMenu.cs @@ -13,699 +13,698 @@ using UnityEngine.EventSystems; using UnityEngine.UI; -namespace MessengerRando.Utils.Menus +namespace MessengerRando.Utils.Menus; + +/// +/// Options menu for various archipelago stuff. has options to connect to a multiworld, teleporting while playing etc +/// +public class ArchipelagoMenu { - /// - /// Options menu for various archipelago stuff. has options to connect to a multiworld, teleporting while playing etc - /// - public class ArchipelagoMenu + public static OptionsButtonInfo ArchipelagoMenuButton; + public static ArchipelagoScreen archipelagoScreen; + + public static SubMenuButtonInfo VersionButton; + public static SubMenuButtonInfo SeedNumButton; + + public static SubMenuButtonInfo SendChatMessageButton; + public static SubMenuButtonInfo WindmillShurikenToggleButton; + public static SubMenuButtonInfo TeleportToHqButton; + public static SubMenuButtonInfo TeleportToNinjaVillage; + public static SubMenuButtonInfo TeleportToSearingShop; + public static SubMenuButtonInfo ShuffleMusicButton; + + public static SubMenuButtonInfo ArchipelagoHostButton; + public static SubMenuButtonInfo ArchipelagoPortButton; + public static SubMenuButtonInfo ArchipelagoNameButton; + public static SubMenuButtonInfo ArchipelagoPassButton; + public static SubMenuButtonInfo ArchipelagoConnectButton; + + public static SubMenuButtonInfo ArchipelagoReleaseButton; + public static SubMenuButtonInfo ArchipelagoCollectButton; + public static SubMenuButtonInfo ArchipelagoToggleMessagesButton; + public static SubMenuButtonInfo ArchipelagoToggleFilterMessagesButton; + public static SubMenuButtonInfo ArchipelagoClearMessagesButton; + public static SubMenuButtonInfo ArchipelagoToggleHintPopupButton; + public static SubMenuButtonInfo ArchipelagoStatusButton; + public static SubMenuButtonInfo ArchipelagoDeathLinkButton; + public static SubMenuButtonInfo ShopHintsButton; + public static SubMenuButtonInfo ArchipelagoMessageTimerButton; + + + public static void DisplayArchipelagoMenu() { - public static OptionsButtonInfo ArchipelagoMenuButton; - public static ArchipelagoScreen archipelagoScreen; - - public static SubMenuButtonInfo VersionButton; - public static SubMenuButtonInfo SeedNumButton; - - public static SubMenuButtonInfo SendChatMessageButton; - public static SubMenuButtonInfo WindmillShurikenToggleButton; - public static SubMenuButtonInfo TeleportToHqButton; - public static SubMenuButtonInfo TeleportToNinjaVillage; - public static SubMenuButtonInfo TeleportToSearingShop; - public static SubMenuButtonInfo ShuffleMusicButton; - - public static SubMenuButtonInfo ArchipelagoHostButton; - public static SubMenuButtonInfo ArchipelagoPortButton; - public static SubMenuButtonInfo ArchipelagoNameButton; - public static SubMenuButtonInfo ArchipelagoPassButton; - public static SubMenuButtonInfo ArchipelagoConnectButton; - - public static SubMenuButtonInfo ArchipelagoReleaseButton; - public static SubMenuButtonInfo ArchipelagoCollectButton; - public static SubMenuButtonInfo ArchipelagoToggleMessagesButton; - public static SubMenuButtonInfo ArchipelagoToggleFilterMessagesButton; - public static SubMenuButtonInfo ArchipelagoClearMessagesButton; - public static SubMenuButtonInfo ArchipelagoToggleHintPopupButton; - public static SubMenuButtonInfo ArchipelagoStatusButton; - public static SubMenuButtonInfo ArchipelagoDeathLinkButton; - public static SubMenuButtonInfo ShopHintsButton; - public static SubMenuButtonInfo ArchipelagoMessageTimerButton; - - - public static void DisplayArchipelagoMenu() - { - Manager.Instance.GetView().gameObject.SetActive(false); - if (!ArchipelagoScreen.RandoScreenLoaded) - archipelagoScreen = - ArchipelagoScreen.BuildModOptionScreen(Manager.Instance.GetView()); + Manager.Instance.GetView().gameObject.SetActive(false); + if (!ArchipelagoScreen.RandoScreenLoaded) + archipelagoScreen = + ArchipelagoScreen.BuildModOptionScreen(Manager.Instance.GetView()); - Courier.UI.ShowView(archipelagoScreen, EScreenLayers.PROMPT, null, false); - } + Courier.UI.ShowView(archipelagoScreen, EScreenLayers.PROMPT, null, false); + } + + public class ArchipelagoScreen : ModOptionScreen + { + public static bool RandoScreenLoaded; + public static readonly List OptionButtons = new List(); - public class ArchipelagoScreen : ModOptionScreen + private static int OptionsCount() { - public static bool RandoScreenLoaded; - public static readonly List OptionButtons = new List(); + return OptionButtons.Count(modOptionButton => modOptionButton.gameObject.activeInHierarchy); + } - private static int OptionsCount() + private static int EnabledModOptionsBeforeButton(OptionsButtonInfo button) + { + int num = 0; + foreach (OptionsButtonInfo modOptionButton in OptionButtons) { - return OptionButtons.Count(modOptionButton => modOptionButton.gameObject.activeInHierarchy); + if (modOptionButton.Equals(button)) + return num; + if (modOptionButton.gameObject.activeInHierarchy) + ++num; } - private static int EnabledModOptionsBeforeButton(OptionsButtonInfo button) + return -1; + } + + public void InitOptionsViewWithModButtons() + { + var view = this; + OptionScreen optionScreen = Manager.Instance.GetView(); + Transform parent = view.transform.Find("Container").Find("BackgroundFrame").Find("OptionsFrame") + .Find("OptionMenuButtons"); + foreach (OptionsButtonInfo button in OptionButtons) { - int num = 0; - foreach (OptionsButtonInfo modOptionButton in OptionButtons) + switch (button) { - if (modOptionButton.Equals(button)) - return num; - if (modOptionButton.gameObject.activeInHierarchy) - ++num; + case ToggleButtonInfo _: + button.gameObject = Instantiate(optionScreen.fullscreenOption, parent); + break; + case SubMenuButtonInfo _: + button.gameObject = Instantiate(optionScreen.controlsButton.transform.parent.gameObject, + parent); + break; + case MultipleOptionButtonInfo _: + button.gameObject = Instantiate(optionScreen.languageOption, parent); + break; + default: + CourierLogger.Log(LogType.Warning, "OptionsMenu", + button.GetType() + " not a known type of OptionsButtonInfo!"); + break; } - return -1; - } - - public void InitOptionsViewWithModButtons() - { - var view = this; - OptionScreen optionScreen = Manager.Instance.GetView(); - Transform parent = view.transform.Find("Container").Find("BackgroundFrame").Find("OptionsFrame") - .Find("OptionMenuButtons"); - foreach (OptionsButtonInfo button in OptionButtons) + button.gameObject.transform.SetAsLastSibling(); + GameObject buttonGameObject = button.gameObject; + Func getText = button.GetText; + string str = getText?.Invoke() ?? "Nameless Modded Options Button"; + buttonGameObject.name = str; + button.addedTo = view; + foreach (TextMeshProUGUI componentsInChild in button.gameObject + .GetComponentsInChildren()) { - switch (button) + if (componentsInChild.name.Equals("OptionState") || componentsInChild.name.Equals("Text")) + button.stateTextMesh = componentsInChild; + if (componentsInChild.name.Equals("OptionName")) { - case ToggleButtonInfo _: - button.gameObject = Instantiate(optionScreen.fullscreenOption, parent); - break; - case SubMenuButtonInfo _: - button.gameObject = Instantiate(optionScreen.controlsButton.transform.parent.gameObject, - parent); - break; - case MultipleOptionButtonInfo _: - button.gameObject = Instantiate(optionScreen.languageOption, parent); - break; - default: - CourierLogger.Log(LogType.Warning, "OptionsMenu", - button.GetType() + " not a known type of OptionsButtonInfo!"); - break; + button.nameTextMesh = componentsInChild; + TextLocalizer component = componentsInChild.GetComponent(); + if (component != null) + component.locID = ""; } - - button.gameObject.transform.SetAsLastSibling(); - GameObject buttonGameObject = button.gameObject; - Func getText = button.GetText; - string str = getText?.Invoke() ?? "Nameless Modded Options Button"; - buttonGameObject.name = str; - button.addedTo = view; - foreach (TextMeshProUGUI componentsInChild in button.gameObject - .GetComponentsInChildren()) - { - if (componentsInChild.name.Equals("OptionState") || componentsInChild.name.Equals("Text")) - button.stateTextMesh = componentsInChild; - if (componentsInChild.name.Equals("OptionName")) - { - button.nameTextMesh = componentsInChild; - TextLocalizer component = componentsInChild.GetComponent(); - if (component != null) - component.locID = ""; - } - } - - Button component1 = button.gameObject.transform.Find("Button").GetComponent