//Used only for relics currently public static void SetPlayerDataInt(string name, int value) { PlayerData pd = PlayerData.instance; if (!RandomizerMod.instance.Settings.randomizer) { SetIntInternal(name, value); return; } if (string.IsNullOrEmpty(name)) { return; } string nameVal = name + value; if (name == "trinket1" || name == "trinket2" || name == "trinket3" || name == "trinket4") { //It would be cleaner to override this in SetPlayerDataBool, but this works just as well PlayerData.instance.SetBoolInternal("foundTrinket1", true); PlayerData.instance.SetBoolInternal("foundTrinket2", true); PlayerData.instance.SetBoolInternal("foundTrinket3", true); PlayerData.instance.SetBoolInternal("foundTrinket4", true); PlayerData.instance.SetBoolInternal("noTrinket1", false); PlayerData.instance.SetBoolInternal("noTrinket2", false); PlayerData.instance.SetBoolInternal("noTrinket3", false); PlayerData.instance.SetBoolInternal("noTrinket4", false); //Make sure the change is +1 so we don't randomize selling trinkets to Lemm int change = value - PlayerData.instance.GetIntInternal(name); if (change != 1) { SetIntInternal(name, value); return; } int trinketNum = GetTrinketForScene(); SetIntInternal("trinket" + trinketNum, PlayerData.instance.GetIntInternal("trinket" + trinketNum) + 1); return; } //Begin copy/pasted code from set bool string key; string text; //Check if var is in data before running randomizer code if (reverseLookup.TryGetValue(nameVal, out key) && RandomizerMod.instance.Settings.StringValues.TryGetValue(key, out text)) { //Randomizer breaks progression, so we need to ensure the player never gets shade cloak before mothwing cloak if (text == "Shade Cloak" && !pd.hasDash && !pd.canDash) { RandomizerMod.instance.Settings.Swap("Shade Cloak", "Mothwing Cloak"); text = "Mothwing Cloak"; } //Similar checks for dream nail if (text == "Dream Gate" && !pd.hasDreamNail) { RandomizerMod.instance.Settings.Swap("Dream Nail", "Dream Gate"); text = "Dream Nail"; } if (text == "Awoken Dream Nail" && !pd.hasDreamNail) { RandomizerMod.instance.Settings.Swap("Dream Nail", "Awoken Dream Nail"); text = "Dream Nail"; } //Similar checks for spells if (text == "Shade Soul" && RandomizerMod.instance.Settings.FireballLevel() == 0) { RandomizerMod.instance.Settings.Swap("Vengeful Spirit", "Shade Soul"); text = "Vengeful Spirit"; } if (text == "Descending Dark" && RandomizerMod.instance.Settings.QuakeLevel() == 0) { RandomizerMod.instance.Settings.Swap("Desolate Dive", "Descending Dark"); text = "Desolate Dive"; } if (text == "Abyss Shriek" && RandomizerMod.instance.Settings.ScreamLevel() == 0) { RandomizerMod.instance.Settings.Swap("Howling Wraiths", "Abyss Shriek"); text = "Howling Wraiths"; } //FSM variable is probably tracked separately, need to make sure it's accurate if (name == "hasDreamGate" && !PlayerData.instance.hasDreamGate) { FSMUtility.LocateFSM(HeroController.instance.gameObject, "Dream Nail").FsmVariables.GetFsmBool("Dream Warp Allowed").Value = false; } //Set all bools relating to the given entry for (int i = 0; i < entries[text].entries.Length; i++) { RandomizerVar var = entries[text].entries[i]; if (var.type == typeof(bool)) { SetBoolInternal(var.name, value > 0); } else { if (text == "Vengeful Spirit") { RandomizerMod.instance.Settings.fireball1 = value > 0; } else if (text == "Shade Soul") { RandomizerMod.instance.Settings.fireball2 = value > 0; } else if (text == "Desolate Dive") { RandomizerMod.instance.Settings.quake1 = value > 0; } else if (text == "Descending Dark") { RandomizerMod.instance.Settings.quake2 = value > 0; } else if (text == "Howling Wraiths") { RandomizerMod.instance.Settings.scream1 = value > 0; } else if (text == "Abyss Shriek") { RandomizerMod.instance.Settings.scream2 = value > 0; } } //FSM variable is probably tracked separately, need to make sure it's accurate if (entries[text].entries[i].name == "hasDreamGate") { FSMUtility.LocateFSM(HeroController.instance.gameObject, "Dream Nail").FsmVariables.GetFsmBool("Dream Warp Allowed").Value = true; } //Need to make the charms page accessible if the player gets their first charm from a non-charm pickup if (entries[text].type == RandomizerType.CHARM && entries[key].type != RandomizerType.CHARM) { pd.hasCharm = true; } } return; } SetIntInternal(name, value); }
//Override for PlayerData.SetBool public static void SetPlayerDataBool(string name, bool val) { PlayerData pd = PlayerData.instance; //Don't run randomizer code in non-randomizer saves if (!RandomizerMod.instance.Settings.randomizer) { SetBoolInternal(name, val); return; } if (string.IsNullOrEmpty(name)) { return; } string key; string text; //Check if bool is in data before running randomizer code if (reverseLookup.TryGetValue(name, out key) && RandomizerMod.instance.Settings.StringValues.TryGetValue(key, out text)) { //Randomizer breaks progression, so we need to ensure the player never gets shade cloak before mothwing cloak if (text == "Shade Cloak" && !pd.hasDash && !pd.canDash) { RandomizerMod.instance.Settings.Swap("Shade Cloak", "Mothwing Cloak"); text = "Mothwing Cloak"; } //Similar checks for dream nail if (text == "Dream Gate" && !pd.hasDreamNail) { RandomizerMod.instance.Settings.Swap("Dream Nail", "Dream Gate"); text = "Dream Nail"; } if (text == "Awoken Dream Nail" && !pd.hasDreamNail) { RandomizerMod.instance.Settings.Swap("Dream Nail", "Awoken Dream Nail"); text = "Dream Nail"; } //Similar checks for spells if (text == "Shade Soul" && RandomizerMod.instance.Settings.FireballLevel() == 0) { RandomizerMod.instance.Settings.Swap("Vengeful Spirit", "Shade Soul"); text = "Vengeful Spirit"; } if (text == "Descending Dark" && RandomizerMod.instance.Settings.QuakeLevel() == 0) { RandomizerMod.instance.Settings.Swap("Desolate Dive", "Descending Dark"); text = "Desolate Dive"; } if (text == "Abyss Shriek" && RandomizerMod.instance.Settings.ScreamLevel() == 0) { RandomizerMod.instance.Settings.Swap("Howling Wraiths", "Abyss Shriek"); text = "Howling Wraiths"; } //FSM variable is probably tracked separately, need to make sure it's accurate if (name == "hasDreamGate" && !PlayerData.instance.hasDreamGate) { FSMUtility.LocateFSM(HeroController.instance.gameObject, "Dream Nail").FsmVariables.GetFsmBool("Dream Warp Allowed").Value = false; } //Set all bools relating to the given entry for (int i = 0; i < entries[text].entries.Length; i++) { RandomizerVar var = entries[text].entries[i]; if (var.type == typeof(bool)) { SetBoolInternal(var.name, val); } else { switch (text) { case "Vengeful Spirit": RandomizerMod.instance.Settings.fireball1 = val; HookSetInt("fireballLevel", 1); break; case "Shade Soul": RandomizerMod.instance.Settings.fireball2 = val; HookSetInt("fireballLevel", 2); break; case "Desolate Dive": RandomizerMod.instance.Settings.quake1 = val; HookSetInt("quakeLevel", 1); break; case "Descending Dark": RandomizerMod.instance.Settings.quake2 = val; HookSetInt("quakeLevel", 2); break; case "Howling Wraiths": RandomizerMod.instance.Settings.scream1 = val; HookSetInt("screamLevel", 1); break; case "Abyss Shriek": RandomizerMod.instance.Settings.scream2 = val; HookSetInt("screamLevel", 2); break; } } //FSM variable is probably tracked separately, need to make sure it's accurate if (entries[text].entries[i].name == "hasDreamGate") { FSMUtility.LocateFSM(HeroController.instance.gameObject, "Dream Nail").FsmVariables.GetFsmBool("Dream Warp Allowed").Value = true; } //Need to make the charms page accessible if the player gets their first charm from a non-charm pickup if (entries[text].type == RandomizerType.CHARM && entries[key].type != RandomizerType.CHARM) { pd.hasCharm = true; } } return; } SetBoolInternal(name, val); }
// Token: 0x0600312E RID: 12590 RVA: 0x00127658 File Offset: 0x00125858 public static void CheckForChanges(string destScene) { if (!RandomizerMod.instance.Settings.randomizer) { return; } try { if (GameManager.instance.IsGameplayScene()) { PlayMakerFSM spell = HeroController.instance.spellControl; for (int i = 0; i < spell.FsmStates.Length; i++) { if (spell.FsmStates[i].Name == "Has Fireball?" || spell.FsmStates[i].Name == "Has Quake?" || spell.FsmStates[i].Name == "Has Scream?") { foreach (FsmString str in (List <FsmString>)fsmStringParamsField.GetValue(spell.FsmStates[i].ActionData)) { List <FsmString> val = new List <FsmString>(); if (str.Value.Contains("fireball")) { val.Add("_fireballLevel"); } else if (str.Value.Contains("quake")) { val.Add("_quakeLevel"); } else if (str.Value.Contains("scream")) { val.Add("_screamLevel"); } else { val.Add(str); } if (val.Count > 0) { fsmStringParamsField.SetValue(spell.FsmStates[i].ActionData, val); } } spell.FsmStates[i].LoadActions(); } } } } catch (Exception e) { RandomizerMod.instance.LogError("Could not modify spell fsm:\n" + e); } //Remove hard save from shade cloak platform if (destScene == "Abyss_10") { foreach (GameObject obj in GetObjectsFromScene(destScene)) { if (obj.name == "Dish Plat") { PlayMakerFSM getShadowDash = FSMUtility.LocateFSM(obj, "Get Shadow Dash"); foreach (FsmState state in getShadowDash.FsmStates) { if (state.Name == "Take Control") { state.Transitions[0].ToState = "PlayerData"; break; } } break; } } } // After defeating Soul Master, you are hard saved in the Desolate Dive tutorial. // Add a platform to prevent you from being trapped here without Mantis Claw. if (destScene == "Ruins1_32" && !PlayerData.instance.hasWalljump) { List <GameObject> objectsFromScene = SceneHandler.GetObjectsFromScene("Ruins1_32"); for (int i = 0; i < objectsFromScene.Count; i++) { if (objectsFromScene[i].name == "ruind_int_plat_float_02 (3)") { GameObject gameObject = UnityEngine.Object.Instantiate(objectsFromScene[i], objectsFromScene[i].transform.position, objectsFromScene[i].transform.rotation) as GameObject; gameObject.SetActive(true); gameObject.transform.position = new Vector3(40.5f, 72f, 0f); gameObject.name = "CustomPlatform"; gameObject.tag = "Untagged"; } } } // In case you got to the Desolate Dive tutorial without Desolate Dive, break all the floors open so you can get out. if ((destScene == "Ruins1_30" || destScene == "Ruins1_32") && RandomizerMod.instance.Settings.QuakeLevel() == 0 && PlayerData.instance.killedMageLord) { List <GameObject> objectsFromScene = SceneHandler.GetObjectsFromScene(destScene); for (int i = 0; i < objectsFromScene.Count; i++) { if (objectsFromScene[i].name.Contains("Quake Floor")) { GameObject.Destroy(objectsFromScene[i]); } } } // Instead of letting the City Crest gate to City of Tears close behind you and trap you in the City of Tears, // check the player's inventory for the City Crest, and then delete the gate. // This way, you can still get out of City of Tears after entering through this entrance. if (destScene == "Fungus2_21" && PlayerData.instance.hasCityKey) { foreach (GameObject gameObject2 in SceneHandler.GetObjectsFromScene("Fungus2_21")) { if (gameObject2.name == "City Gate Control" || gameObject2.name == "Ruins_front_gate" || gameObject2.name.Contains("Ruins_gate")) { UnityEngine.Object.Destroy(gameObject2); } } } // You can get into the Ancient Basin without a way to get out. // If this is the case, remove the bench down here to prevent you from hard locking your save. if (destScene == "Abyss_18" && !PlayerData.instance.hasWalljump) { foreach (GameObject gameObject3 in SceneHandler.GetObjectsFromScene("Abyss_18")) { if (gameObject3.name == "Toll Machine Bench") { UnityEngine.Object.Destroy(gameObject3); break; } } } // When you get Vengeful Spirit, you are hard saved in the Vengeful Spirit tutorial. // If you don't actualyl have Vengeful Spirit, reprogram the Elder Baldur's AI to never hide in its shell. // This allows you to kill it with your unmodified nail. if (destScene == "Crossroads_ShamanTemple") { foreach (GameObject obj in SceneHandler.GetObjectsFromScene("Crossroads_ShamanTemple")) { if (obj.name == "Blocker") { PlayMakerFSM fsm = FSMUtility.LocateFSM(obj, "Blocker Control"); for (int i = 0; i < fsm.FsmStates.Length; i++) { if (fsm.FsmStates[i].Name == "Idle" || fsm.FsmStates[i].Name == "Shot Anim End") { List <FsmTransition> transList = new List <FsmTransition>(); foreach (FsmTransition trans in fsm.FsmStates[i].Transitions) { if (trans.ToState != "Close") { transList.Add(trans); } } fsm.FsmStates[i].Transitions = transList.ToArray(); } } break; } } } // You can get into Royal Waterways without a way to get back out. // If this is the case, remove the bench to prevent you from hard locking your save. if (destScene == "Waterways_02" && !PlayerData.instance.hasWalljump && !PlayerData.instance.hasDoubleJump) { foreach (GameObject obj in SceneHandler.GetObjectsFromScene("Waterways_02")) { if (obj.name == "RestBench") { GameObject.Destroy(obj); break; } } } if ((destScene == "Crossroads_11_alt" || destScene == "Fungus1_28")) { RandomizerMod.instance.Log("Attempting to fix baldurs in scene " + destScene); foreach (GameObject obj in SceneHandler.GetObjectsFromScene(destScene)) { if (obj.name == "Blocker" || obj.name == "Blocker 1" || obj.name == "Blocker 2") { RandomizerMod.instance.Log("Found baldur with name \"" + obj.name + "\""); PlayMakerFSM fsm = FSMUtility.LocateFSM(obj, "Blocker Control"); for (int i = 0; i < fsm.FsmStates.Length; i++) { if (fsm.FsmStates[i].Name == "Can Roller?") { foreach (FsmString str in (List <FsmString>)fsmStringParamsField.GetValue(fsm.FsmStates[i].ActionData)) { List <FsmString> val = new List <FsmString>(); if (str.Value.Contains("fireball")) { val.Add("_true"); RandomizerMod.instance.Log("Found FsmString on \"" + obj.name + "\" with value \"" + str.Value + "\", changing to \"_true\""); } else { val.Add(str); } if (val.Count > 0) { fsmStringParamsField.SetValue(fsm.FsmStates[i].ActionData, val); } } fsm.FsmStates[i].LoadActions(); } } } } } if (destScene == "Ruins1_01" && !PlayerData.instance.hasWalljump && !PlayerData.instance.hasDoubleJump) { foreach (GameObject obj in SceneHandler.GetObjectsFromScene("Ruins1_01")) { if (obj.name == "ruind_int_plat_float_01") { GameObject gameObject = UnityEngine.Object.Instantiate(obj, obj.transform.position, obj.transform.rotation) as GameObject; gameObject.SetActive(true); gameObject.transform.position = new Vector3(116f, 14f, 0f); gameObject.name = "CustomPlatform"; gameObject.tag = "Untagged"; break; } } } if (destScene == "Ruins1_02" && !PlayerData.instance.hasWalljump && !PlayerData.instance.hasDoubleJump) { foreach (GameObject obj in SceneHandler.GetObjectsFromScene("Ruins1_02")) { if (obj.name == "ruind_int_plat_float_01") { GameObject gameObject = UnityEngine.Object.Instantiate(obj, obj.transform.position, obj.transform.rotation) as GameObject; gameObject.SetActive(true); gameObject.transform.position = new Vector3(2f, 61.5f, 0f); gameObject.name = "CustomPlatform"; gameObject.tag = "Untagged"; break; } } } // Isma's Tear has different code than other abilities for some reason. // This code here is required to make the ability randomized. if (destScene == "Waterways_13") { foreach (GameObject obj in SceneHandler.GetObjectsFromScene("Waterways_13")) { if ((obj.name.ToLower().Contains("water") || obj.name.ToLower().Contains("acid")) && obj.name != "Shiny Item Acid") { PlayMakerFSM[] fsms = obj.GetComponents <PlayMakerFSM>(); foreach (PlayMakerFSM fsm in fsms) { for (int i = 0; i < fsm.FsmStates.Length; i++) { bool foundAcid = false; foreach (FsmString str in (List <FsmString>)fsmStringParamsField.GetValue(fsm.FsmStates[i].ActionData)) { List <FsmString> val = new List <FsmString>(); if (str.Value.Contains("hasAcidArmour")) { val.Add(PlayerData.instance.hasAcidArmour ? "_true" : "_false"); foundAcid = true; } else { val.Add(str); } if (val.Count > 0) { fsmStringParamsField.SetValue(fsm.FsmStates[i].ActionData, val); } } if (foundAcid) { fsm.FsmStates[i].LoadActions(); fsm.SetState(fsm.FsmStates[i].Name); } } } } else if (obj.name.ToLower().Contains("water") || obj.name.ToLower().Contains("acid")) { if (RandomizerMod.instance.Settings.StringValues.ContainsKey("Isma's Tear")) { bool ismasReplacement; RandomizerVar var = Randomizer.entries[RandomizerMod.instance.Settings.StringValues["Isma's Tear"]].entries[0]; if (var.type == typeof(bool)) { ismasReplacement = PlayerData.instance.GetBoolInternal(var.name); } else { ismasReplacement = PlayerData.instance.GetIntInternal(var.name) > 0; } if (ismasReplacement) { GameObject.Destroy(obj); } } } } } // Enable the toll gate entrance to Crystal Peak even if you don't have the Lumafly Lantern. if (destScene == "Mines_33" && !PlayerData.instance.hasLantern) { foreach (GameObject obj in SceneHandler.GetObjectsFromScene("Mines_33")) { if (obj.name.ToLower().Contains("toll gate machine")) { PlayMakerFSM[] fsms = obj.GetComponents <PlayMakerFSM>(); foreach (PlayMakerFSM fsm in fsms) { for (int i = 0; i < fsm.FsmStates.Length; i++) { if (fsm.FsmStates[i].Name == "Check") { foreach (FsmString str in (List <FsmString>)fsmStringParamsField.GetValue(fsm.FsmStates[i].ActionData)) { List <FsmString> val = new List <FsmString>(); if (str.Value.Contains("hasLantern")) { val.Add("_true"); } else { val.Add(str); } if (val.Count > 0) { fsmStringParamsField.SetValue(fsm.FsmStates[i].ActionData, val); } } fsm.FsmStates[i].LoadActions(); } } } } } } }