private static void CheckFireball(On.PlayMakerFSM.orig_OnEnable orig, PlayMakerFSM self) { // Wall Impact state doesn't exist in shade soul control // Fireballs get recycled so we've gotta check for the state this method adds as well if (self.FsmName != "Fireball Control" || self.GetState("Wall Impact") == null || self.GetState("Idle (No Collision)") != null) { orig(self); return; } // Store the terrain checker reference, prevent it from being enabled GameObject terrainChecker = self.GetAction <ActivateGameObject>("Pause", 3).gameObject.GameObject.Value; self.GetState("Pause").RemoveAction(3); // Create a new state before the regular idle FsmState idleNoCol = self.CopyState("R", "Idle (No Collision)"); idleNoCol.RemoveAction(0); self.GetState("L").ChangeTransition("FINISHED", "Idle (No Collision)"); self.GetState("R").ChangeTransition("FINISHED", "Idle (No Collision)"); idleNoCol.AddTransition("FINISHED", "Idle"); // New state needs to start the fireball moving idleNoCol.AddAction(new SetVelocity2d { gameObject = new FsmOwnerDefault(), vector = Vector2.zero, x = self.FsmVariables.FindFsmFloat("Velocity"), y = 0, everyFrame = false }); // Small waiting period before proceeding to the old idle state idleNoCol.AddAction(new Wait { time = NO_COLLISION_TIME, finishEvent = FsmEvent.FindEvent("FINISHED"), realTime = false }); var idle = self.GetState("Idle"); // Idle state needs to activate the collision now idle.InsertAction(new ActivateGameObject { gameObject = new FsmOwnerDefault { GameObject = terrainChecker, OwnerOption = OwnerDefaultOption.SpecifyGameObject }, activate = true, recursive = false, resetOnExit = false, everyFrame = false }, 0); // Account for the additional waiting time before Idle idle.GetAction <Wait>(8).time.Value -= NO_COLLISION_TIME; orig(self); }
public override void Process(string scene, Object changeObj) { if (scene != _sceneName || !(changeObj is PlayMakerFSM fsm) || fsm.FsmName != _fsmName || fsm.gameObject.name != _objectName) { return; } FsmState pdBool = fsm.GetState("PD Bool?"); FsmState charm = fsm.GetState("Charm?"); FsmState bigItem = fsm.GetState("Big Item?"); FsmState bigGetFlash = fsm.GetState("Big Get Flash"); FsmState trinkFlash = fsm.GetState("Trink Flash"); FsmState giveTrinket = fsm.GetState("Store Key"); // Remove actions that stop shiny from spawning pdBool.RemoveActionsOfType <StringCompare>(); // Change pd bool test to our new bool pdBool.RemoveActionsOfType <PlayerDataBoolTest>(); pdBool.AddAction( new RandomizerExecuteLambda(() => fsm.SendEvent( RandomizerMod.Instance.Settings.CheckLocationFound(_location) ? "COLLECTED" : null ))); // Charm must be preserved as the entry point for AddYNDialogueToShiny charm.ClearTransitions(); charm.AddTransition("FINISHED", "Big Item?"); // Check if each additive item has already been obtained. Give 100 geo instead of popup if so. bigItem.ClearTransitions(); bigItem.AddFirstAction(new RandomizerExecuteLambda(() => bigItem.AddTransition("FINISHED", BigItemPopup.AdditiveMaxedOut(_itemDefs) ? "Trink Flash" : "Big Get Flash"))); // if we have duplicates, the last item is not a big popup // give 300 geo for last duplicate trinkFlash.ClearTransitions(); trinkFlash.AddTransition("FINISHED", "Store Key"); fsm.GetState("Trinket Type").ClearTransitions(); trinkFlash.AddTransition("FINISHED", "Store Key"); giveTrinket.RemoveActionsOfType <SetPlayerDataBool>(); giveTrinket.AddAction(new RandomizerExecuteLambda(() => GiveItem(GiveAction.AddGeo, _item, _location, 300))); giveTrinket.GetActionsOfType <GetLanguageString>().First().convName = _itemDefs.Last().NameKey; giveTrinket.GetActionsOfType <SetSpriteRendererSprite>().First().sprite = RandomizerMod.GetSprite(LogicManager.GetItemDef(_itemDefs.Last().Name).shopSpriteKey); // Normal path for big items. Set bool and show the popup after the flash bigGetFlash.AddAction(new RandomizerCallStaticMethod( typeof(BigItemPopup), nameof(BigItemPopup.ShowAdditive), _itemDefs, fsm.gameObject, "GET ITEM MSG END")); // Don't actually need to set the skill here, that happens in BigItemPopup // Maybe change that at some point, it's not where it should happen bigGetFlash.AddAction(new RandomizerExecuteLambda(() => GiveItem(_action, _item, _location))); // Exit the fsm after the popup bigGetFlash.ClearTransitions(); bigGetFlash.AddTransition("GET ITEM MSG END", "Hero Up"); bigGetFlash.AddTransition("HERO DAMAGED", "Finish"); }
/* * Better organization someday... */ public static void MiscQoLChanges(Scene newScene) { string sceneName = newScene.name; // Make baldurs always able to spit rollers and reduce hp if (sceneName == SceneNames.Crossroads_11_alt || sceneName == SceneNames.Crossroads_ShamanTemple || sceneName == SceneNames.Fungus1_28) { foreach (GameObject obj in Object.FindObjectsOfType <GameObject>()) { if (obj.name.Contains("Blocker")) { HealthManager hm = obj.GetComponent <HealthManager>(); if (hm != null) { hm.hp = 5; } PlayMakerFSM fsm = FSMUtility.LocateFSM(obj, "Blocker Control"); if (fsm != null) { fsm.GetState("Can Roller?").RemoveActionsOfType <IntCompare>(); } } } } switch (sceneName) { // Lemm sell all /* * case SceneNames.Ruins1_05b when RandomizerMod.Instance.Settings.Lemm: * PlayMakerFSM lemm = FSMUtility.LocateFSM(GameObject.Find("Relic Dealer"), "npc_control"); * lemm.GetState("Convo End").AddAction(new RandomizerSellRelics()); * break; */ // Grubfather rewards are given out all at once case SceneNames.Crossroads_38 when RandomizerMod.Instance.Settings.Grubfather: PlayMakerFSM grubDaddy = FSMUtility.LocateFSM(GameObject.Find("Grub King"), "King Control"); grubDaddy.GetState("Final Reward?").RemoveTransitionsTo("Recover"); grubDaddy.GetState("Final Reward?").AddTransition("FINISHED", "Recheck"); grubDaddy.GetState("Recheck").RemoveTransitionsTo("Gift Anim"); grubDaddy.GetState("Recheck").AddTransition("FINISHED", "Activate Reward"); int geoTotal = 0; grubDaddy.GetState("All Given").AddAction(new RandomizerAddGeo(grubDaddy.gameObject, 0, true)); grubDaddy.GetState("Recheck").AddFirstAction(new RandomizerExecuteLambda(() => grubDaddy.GetState("All Given").GetActionsOfType <RandomizerAddGeo>()[0].SetGeo(geoTotal))); foreach (PlayMakerFSM grubFsm in grubDaddy.gameObject.GetComponentsInChildren <PlayMakerFSM>(true)) { if (grubFsm.FsmName == "grub_reward_geo") { FsmState grubGeoState = grubFsm.GetState("Remaining?"); int geo = grubGeoState.GetActionsOfType <IntCompare>()[0].integer1.Value; grubGeoState.RemoveActionsOfType <FsmStateAction>(); grubGeoState.AddAction(new RandomizerExecuteLambda(() => geoTotal += geo)); grubGeoState.AddTransition("FINISHED", "End"); } } break; // Great Hopper Easter Egg, I guess case SceneNames.Deepnest_East_16: GameObject hopper1 = newScene.FindGameObject("Giant Hopper"); GameObject hopper2 = newScene.FindGameObject("Giant Hopper (1)"); for (int i = 0; i < 10; i++) { GameObject newHopper1 = Object.Instantiate(hopper1, hopper1.transform.parent); GameObject newHopper2 = Object.Instantiate(hopper2, hopper2.transform.parent); HealthManager hopper1HM = newHopper1.GetComponent <HealthManager>(); hopper1HM.SetGeoSmall(0); hopper1HM.SetGeoMedium(0); hopper1HM.SetGeoLarge(0); HealthManager hopper2HM = newHopper2.GetComponent <HealthManager>(); hopper2HM.SetGeoSmall(0); hopper2HM.SetGeoMedium(0); hopper2HM.SetGeoLarge(0); Vector3 hopper1Pos = newHopper1.transform.localPosition; hopper1Pos = new Vector3( hopper1Pos.x + i, hopper1Pos.y, hopper1Pos.z); newHopper1.transform.localPosition = hopper1Pos; Vector3 hopper2Pos = newHopper2.transform.localPosition; hopper2Pos = new Vector3( hopper2Pos.x + i - 4, hopper2Pos.y, hopper2Pos.z); newHopper2.transform.localPosition = hopper2Pos; } break; // Skip dreamer text before Dream Nail case SceneNames.RestingGrounds_04: FsmState dreamerPlaqueInspect = FSMUtility .LocateFSM(GameObject.Find("Dreamer Plaque Inspect"), "Conversation Control") .GetState("Hero Anim"); dreamerPlaqueInspect.RemoveActionsOfType <ActivateGameObject>(); dreamerPlaqueInspect.RemoveTransitionsTo("Fade Up"); dreamerPlaqueInspect.AddTransition("FINISHED", "Map Msg?"); PlayMakerFSM dreamerScene2 = FSMUtility.LocateFSM(GameObject.Find("Dreamer Scene 2"), "Control"); dreamerScene2.GetState("Take Control").RemoveTransitionsTo("Blast"); dreamerScene2.GetState("Take Control").AddTransition("FINISHED", "Fade Out"); dreamerScene2.GetState("Fade Out").RemoveTransitionsTo("Dial Wait"); dreamerScene2.GetState("Fade Out").AddTransition("FINISHED", "Set Compass Point"); break; } }
public void Update() { if (done) { return; } // skip it if they aren't even at tier 4 grimmchild yet. or if they're especially dumb and // banished grimm if (!PlayerData.instance.GetBoolInternal("killedNightmareGrimm")) { done = true; return; } grimmchild = GameObject.FindGameObjectWithTag("Grimmchild"); if (grimmchild == null) { return; } gcFSM = FSMUtility.LocateFSM(grimmchild, "Control"); if (baseFireInterval < 0.0) { Log("Set default values for speeds"); setDefaultGCValues(); } FsmState followState = gcFSM.GetState("Follow"); FloatCompare[] followCompare = followState.GetActionsOfType <FloatCompare>(); //followCompare[0].float2 = 1.0f; followCompare[1].float2 = .5f; followState.RemoveActionsOfType <Wait>(); FsmState anticAttack = gcFSM.GetState("Antic"); RandomFloat[] anticRand = anticAttack.GetActionsOfType <RandomFloat>(); anticRand[0].max = (float)(baseFireInterval / speedModifier); anticRand[0].min = (float)(baseFireInterval / speedModifier); FsmState noTarget = gcFSM.GetState("No Target"); SetFloatValue[] noTargetWait = noTarget.GetActionsOfType <SetFloatValue>(); noTargetWait[0].floatValue = (float)(baseFireInterval / (speedModifier * 2)); gcFSM.FsmVariables.GetFsmFloat("Flameball Speed").Value = (float)(baseFBSpeed * FBSpeedModifier); grimmchild.FindGameObjectInChildren("Enemy Range").GetComponent <CircleCollider2D>().radius = (float)(baseRange * rangeModifier); tk2dSprite grimmSprite = grimmchild.GetComponent <tk2dSprite>(); Color grimmColor = grimmSprite.color; grimmColor.a = filterAlpha; grimmColor.b = filterBlue; grimmColor.g = filterGreen; grimmColor.r = filterRed; grimmSprite.color = grimmColor; FsmState shootYouFool = gcFSM.GetState("Shoot"); GrimmballFireReal.grimmchild = grimmchild; GrimmballFireReal.shootState = shootYouFool; GrimmballFireReal.ballSize = ballSize; GrimmballFireReal.damage = maxDamage; GrimmballFireReal.ghostBalls = ghostBall; CallMethod[] currentMethods = shootYouFool.GetActionsOfType <CallMethod>(); if (currentMethods.Length == 0) { SpawnObjectFromGlobalPool[] spawnObjs = shootYouFool.GetActionsOfType <SpawnObjectFromGlobalPool>(); try { GrimmballFireReal.deadShootSpawner = spawnObjs[0]; shootYouFool.RemoveActionsOfType <SpawnObjectFromGlobalPool>(); } catch { Log("Not removing shoot spawner, probs because it's length is: " + spawnObjs.Length); } CallMethod newDankShootMethod = new CallMethod { }; try { newDankShootMethod.behaviour = GameManager.instance.gameObject.GetComponent <GrimmballFireReal>(); newDankShootMethod.methodName = "GrimmballUpdater"; newDankShootMethod.parameters = new FsmVar[0]; newDankShootMethod.everyFrame = false; } catch (Exception e) { Log("Unable to add method: error " + e); } Log("Made custom call method"); shootYouFool.AddAction(newDankShootMethod); FireAtTarget currentFAT = shootYouFool.GetActionsOfType <FireAtTarget>()[0]; shootYouFool.RemoveActionsOfType <FireAtTarget>(); GrimmballFireReal.oldAttack = currentFAT; currentFAT.spread = 0.0f; GetChild currentGetChild = shootYouFool.GetActionsOfType <GetChild>()[0]; shootYouFool.RemoveActionsOfType <GetChild>(); currentGetChild.childName = "Grimmball(Clone)"; SetFsmInt currentSetFSMInt = shootYouFool.GetActionsOfType <SetFsmInt>()[0]; shootYouFool.RemoveActionsOfType <SetFsmInt>(); // Reorder these things to make sense shootYouFool.AddAction(currentGetChild); shootYouFool.AddAction(currentSetFSMInt); shootYouFool.AddAction(currentFAT); GameObject gcRangeObj = grimmchild.FindGameObjectInChildren("Enemy Range"); //GrimmEnemyRange rangeDelete = gcRangeObj.GetComponent<GrimmEnemyRange>(); //Destroy(rangeDelete); gcRangeObj.AddComponent <GrimmballFireReal>(); FsmState targetScan = gcFSM.GetState("Check For Target"); CallMethodProper rangeDetect = targetScan.GetActionsOfType <CallMethodProper>()[0]; rangeDetect.methodName.Value = "GetTarget"; rangeDetect.behaviour.Value = "GrimmballFireReal"; setVolumeLevels(); } gcFSM.SetState("Init"); //grimmchild.PrintSceneHierarchyTree("modgrimmchild.txt"); done = true; }
/* * Room changes required for the randomizer to function on any mode * For example, removing certain vanilla item locations which can't be handled by RandomizerAction */ public static void ApplyRandomizerChanges(Scene newScene) { switch (newScene.name) { // Prevent Grimm encounter which gives Grimmchild case SceneNames.Grimm_Main_Tent: PlayerData.instance.metGrimm = true; break; // Prevent reading focus tablet when focus is randomized case SceneNames.Tutorial_01 when RandomizerMod.Instance.Settings.Cursed: GameObject.Find("Tut_tablet_top").LocateMyFSM("Inspection").GetState("Init").ClearTransitions(); break; // Prevent reading tablet which gives completion percentage case SceneNames.Room_Final_Boss_Atrium: GameObject.Find("Tut_tablet_top").LocateMyFSM("Inspection").GetState("Init").ClearTransitions(); break; // Removes the prompt to donate to the 3000 geo fountain in Basin case SceneNames.Abyss_04: Object.Destroy(GameObject.Find("Fountain Donation")); break; // Opens lifeblood door in Abyss with any amount of blue health case SceneNames.Abyss_06_Core: if (PlayerData.instance.healthBlue > 0 || PlayerData.instance.joniHealthBlue > 0 || GameManager.instance.entryGateName == "left1") { PlayerData.instance.SetBoolInternal("blueVineDoor", true); PlayMakerFSM BlueDoorFSM = GameObject.Find("Blue Door").LocateMyFSM("Control"); BlueDoorFSM.GetState("Init").RemoveTransitionsTo("Got Charm"); } break; // Removes trigger for Void Heart sequence case SceneNames.Abyss_15: GameObject.Find("Dream Enter Abyss").LocateMyFSM("Control").GetState("Init").RemoveTransitionsTo("Idle"); GameObject.Find("Dream Enter Abyss").LocateMyFSM("Control").GetState("Init").AddTransition("FINISHED", "Inactive"); break; // Automatically unlock Godseeker and add an action to the Godtuner spot to remove simple key on purchase case SceneNames.GG_Waterways: PlayerData.instance.SetBool("godseekerUnlocked", true); if (GameObject.Find("Randomizer Shiny") != null) { PlayMakerFSM godtuner = GameObject.Find("Randomizer Shiny").LocateMyFSM("Shiny Control"); godtuner.GetState(godtuner.GetState("Charm?").Transitions.First(t => t.EventName == "YES").ToState).AddFirstAction(new RandomizerExecuteLambda(() => PlayerData.instance.DecrementInt("simpleKeys"))); } break; // Spawns mawlek shard out of bounds and moves it inbounds when mawlek is killed case SceneNames.Crossroads_09: if (GameObject.Find("Randomizer Shiny") is GameObject mawlekShard) { mawlekShard.transform.SetPositionY(100f); IEnumerator mawlekDead() { yield return(new WaitUntil(() => PlayerData.instance.killedMawlek)); mawlekShard.transform.SetPositionY(10f); mawlekShard.transform.SetPositionX(61.5f); } GameManager.instance.StartCoroutine(mawlekDead()); } break; // Removes Grubfather rewards corresponding to randomizer items case SceneNames.Crossroads_38: Object.Destroy(GameObject.Find("Reward 5")); //Mask Object.Destroy(GameObject.Find("Reward 10")); //Charm Object.Destroy(GameObject.Find("Reward 16")); //Rancid Egg Object.Destroy(GameObject.Find("Reward 23")); //Relic Object.Destroy(GameObject.Find("Reward 31")); //Pale Ore Object.Destroy(GameObject.Find("Reward 38")); //Relic Object.Destroy(GameObject.Find("Reward 46")); //Charm break; // Break the Goam journal entry dive floor if the player has dive and rooms are randomized to prevent soul-based locks case SceneNames.Crossroads_52: if (RandomizerMod.Instance.Settings.RandomizeRooms && Ref.PD.quakeLevel > 0) { GameManager.instance.sceneData.SaveMyState(new PersistentBoolData { sceneName = "Crossroads_52", id = "Quake Floor", activated = true, semiPersistent = false }); } break; // Remove gate from Ancestral Mound case SceneNames.Crossroads_ShamanTemple: Object.Destroy(GameObject.Find("Bone Gate")); break; // Remove Beast's Den hardsave, allow rear access from entrance, destroy Herrah case SceneNames.Deepnest_Spider_Town: GameManager.instance.sceneData.SaveMyState(new PersistentBoolData { sceneName = "Deepnest_Spider_Town", id = "Collapser Small (12)", activated = true, semiPersistent = false }); FsmState denHardSave = GameObject.Find("RestBench Spider").LocateMyFSM("Fade").GetState("Land"); denHardSave.RemoveActionsOfType <CallMethodProper>(); denHardSave.RemoveActionsOfType <SendMessage>(); denHardSave.RemoveActionsOfType <SetPlayerDataBool>(); Object.Destroy(GameObject.Find("Dreamer Hegemol")); Object.Destroy(GameObject.Find("Dream Enter")); Object.Destroy(GameObject.Find("Dream Impact")); Object.Destroy(GameObject.Find("Shield")); break; // Break the second Oro dive floor if the player has dive and both transitions AND soul totems are randomized to prevent soul-based locks case SceneNames.Deepnest_East_14: if (RandomizerMod.Instance.Settings.RandomizeSoulTotems && RandomizerMod.Instance.Settings.RandomizeTransitions && Ref.PD.quakeLevel > 0 && GameManager.instance.entryGateName == "top2") { GameManager.instance.sceneData.SaveMyState(new PersistentBoolData { sceneName = "Deepnest_East_14", id = "Quake Floor (1)", activated = true, semiPersistent = false }); } break; // Break the first two dive floors on the way to the 420 geo rock if the player has dive and rooms are randomized to prevent soul-based locks case SceneNames.Deepnest_East_17: if (RandomizerMod.Instance.Settings.RandomizeRooms && Ref.PD.quakeLevel > 0) { GameManager.instance.sceneData.SaveMyState(new PersistentBoolData { sceneName = "Deepnest_East_17", id = "Quake Floor", activated = true, semiPersistent = false }); GameManager.instance.sceneData.SaveMyState(new PersistentBoolData { sceneName = "Deepnest_East_17", id = "Quake Floor (1)", activated = true, semiPersistent = false }); } break; // Edits Dream Nail location to change scene to seer case SceneNames.Dream_Nailcollection: FSMUtility.LocateFSM(GameObject.Find("Randomizer Shiny"), "Shiny Control").GetState("Finish") .AddAction(new RandomizerChangeScene("RestingGrounds_07", "right1")); break; // Edit Hornet room to open gates after boss fight, and removes dreamer cutscene case SceneNames.Fungus1_04: foreach (PlayMakerFSM childFSM in GameObject.Find("Cloak Corpse") .GetComponentsInChildren <PlayMakerFSM>(true)) { if (childFSM.FsmName == "Shiny Control") { SendEvent openGate = new SendEvent { eventTarget = new FsmEventTarget { target = FsmEventTarget.EventTarget.BroadcastAll, excludeSelf = true }, sendEvent = FsmEvent.FindEvent("BG OPEN"), delay = 0, everyFrame = false }; childFSM.GetState("Destroy").AddFirstAction(openGate); childFSM.GetState("Finish").AddFirstAction(openGate); break; } } ObjectDestroyer.Destroy("Dreamer Scene 1"); ObjectDestroyer.Destroy("Hornet Saver"); ObjectDestroyer.Destroy("Cutscene Dreamer"); ObjectDestroyer.Destroy("Dream Scene Activate"); if (!Ref.PD.hornet1Defeated) { Object.Destroy(FSMUtility.LocateFSM(GameObject.Find("Camera Locks Boss"), "FSM")); } break; // Make city crest gate openable infinite times and not hard save // Break the dive floor if transitions are randomized and the player has dive to prevent soul-based locks case SceneNames.Fungus2_21: FSMUtility.LocateFSM(GameObject.Find("City Gate Control"), "Conversation Control") .GetState("Activate").RemoveActionsOfType <SetPlayerDataBool>(); FsmState gateSlam = FSMUtility.LocateFSM(GameObject.Find("Ruins_gate_main"), "Open") .GetState("Slam"); gateSlam.RemoveActionsOfType <SetPlayerDataBool>(); gateSlam.RemoveActionsOfType <CallMethodProper>(); gateSlam.RemoveActionsOfType <SendMessage>(); if (RandomizerMod.Instance.Settings.RandomizeTransitions && Ref.PD.quakeLevel > 0 && GameManager.instance.entryGateName == "right1") { GameManager.instance.sceneData.SaveMyState(new PersistentBoolData { sceneName = "Fungus2_21", id = "Quake Floor", activated = true, semiPersistent = false }); } break; // Removes Leg Eater dialogue tree, preventing him from dying case SceneNames.Fungus2_26: PlayMakerFSM legEater = FSMUtility.LocateFSM(GameObject.Find("Leg Eater"), "Conversation Control"); FsmState legEaterChoice = legEater.GetState("Convo Choice"); legEaterChoice.RemoveTransitionsTo("Convo 1"); legEaterChoice.RemoveTransitionsTo("Convo 2"); legEaterChoice.RemoveTransitionsTo("Convo 3"); legEaterChoice.RemoveTransitionsTo("Infected Crossroad"); legEaterChoice.RemoveTransitionsTo("Bought Charm"); legEaterChoice.RemoveTransitionsTo("Gold Convo"); legEaterChoice.RemoveTransitionsTo("All Gold"); legEaterChoice.RemoveTransitionsTo("Ready To Leave"); legEater.GetState("All Gold?").RemoveTransitionsTo("No Shop"); Ref.PD.legEaterLeft = false; break; // Destroy Monomon and remove Quirrel encounter case SceneNames.Fungus3_archive_02: PlayerData.instance.SetBool("summonedMonomon", true); Object.Destroy(GameObject.Find("Quirrel Wounded")); Object.Destroy(GameObject.Find("Quirrel")); Object.Destroy(GameObject.Find("Monomon")); Object.Destroy(GameObject.Find("Dream Enter")); Object.Destroy(GameObject.Find("Dream Impact")); Object.Destroy(GameObject.Find("Shield")); break; // Destroys original lurker key. Moves new shiny out of bounds if lurker is alive and moves it inbounds when lurker is killed case "GG_Lurker": if (PlayerData.instance.killedPaleLurker) { Object.Destroy(GameObject.Find("Shiny Item Key")); } else { GameObject.Find("New Shiny").transform.SetPositionY(200f); IEnumerator LurkerKilled() { yield return(new WaitUntil(() => PlayerData.instance.killedPaleLurker || GameManager.instance.sceneName != "GG_Lurker")); yield return(new WaitUntil(() => GameObject.Find("Shiny Item Key") is GameObject lurkerKey || GameManager.instance.sceneName != "GG_Lurker")); if (GameManager.instance.sceneName == "GG_Lurker") { Object.Destroy(GameObject.Find("Shiny Item Key")); GameObject lurkerCorpse = Object.FindObjectsOfType <GameObject>().First(obj => obj.name.StartsWith("Corpse Pale Lurker")); // Corpse Pale Lurker(Clone) GameObject.Find("New Shiny").transform.SetPosition2D(lurkerCorpse.transform.position); } } GameManager.instance.StartCoroutine(LurkerKilled()); } break; case SceneNames.Hive_03 when RandomizerMod.Instance.Settings.StartName == "Hive": GameObject hivePlatform = ObjectCache.SmallPlatform; hivePlatform.transform.SetPosition2D(58.5f, 134f); hivePlatform.SetActive(true); break; // Platforms for open mode case SceneNames.Fungus1_13 when RandomizerMod.Instance.Settings.StartName == "Far Greenpath": { GameObject leftGPQGplat = ObjectCache.SmallPlatform; leftGPQGplat.transform.SetPosition2D(45f, 16.5f); leftGPQGplat.SetActive(true); GameObject rightGPQGplat = ObjectCache.SmallPlatform; rightGPQGplat.transform.SetPosition2D(64f, 16.5f); rightGPQGplat.SetActive(true); } GameManager.instance.sceneData.SaveMyState(new PersistentBoolData { sceneName = "Fungus1_13", id = "Vine Platform (1)", activated = true, semiPersistent = false }); GameManager.instance.sceneData.SaveMyState(new PersistentBoolData { sceneName = "Fungus1_13", id = "Vine Platform (2)", activated = true, semiPersistent = false }); break; // Bounce shrooms to prevent softlock for Fungal Core start in open mode without claw case SceneNames.Fungus2_30: { GameObject bounceShroom = GameObject.Find("Bounce Shroom C"); GameObject s0 = Object.Instantiate(bounceShroom); s0.transform.SetPosition3D(12.5f, 26f, 0f); s0.SetActive(true); GameObject s1 = Object.Instantiate(bounceShroom); s1.transform.SetPosition3D(12.5f, 54f, 0f); s1.SetActive(true); GameObject s2 = Object.Instantiate(bounceShroom); s2.transform.SetPosition3D(21.7f, 133f, 0f); s2.SetActive(true); } break; // Break the Peak entrance dive floor if the player has dive and transitions are randomized to prevent soul-based locks case SceneNames.Mines_01: if (RandomizerMod.Instance.Settings.RandomizeTransitions && Ref.PD.quakeLevel > 0 && GameManager.instance.entryGateName == "left1") { GameManager.instance.sceneData.SaveMyState(new PersistentBoolData { sceneName = "Mines_01", id = "mine_1_quake_floor", activated = true, semiPersistent = false }); } break; // Make tolls always interactable, in the rare case that lantern is not randomized but RG access through the dark room is expected case SceneNames.Mines_33: if (RandomizerMod.Instance.Settings.DarkRooms && !RandomizerMod.Instance.Settings.RandomizeKeys) { GameObject[] tolls = new GameObject[] { GameObject.Find("Toll Gate Machine"), GameObject.Find("Toll Gate Machine (1)") }; foreach (GameObject toll in tolls) { Object.Destroy(FSMUtility.LocateFSM(toll, "Disable if No Lantern")); } } break; // Break the Crystallized Mound dive floor if the player has dive and transitions or soul totems are randomized to prevent soul-based locks case SceneNames.Mines_35: if ((RandomizerMod.Instance.Settings.RandomizeTransitions || RandomizerMod.Instance.Settings.RandomizeSoulTotems) && Ref.PD.quakeLevel > 0) { GameManager.instance.sceneData.SaveMyState(new PersistentBoolData { sceneName = "Mines_35", id = "mine_1_quake_floor", activated = true, semiPersistent = false }); } break; // Break the Crypts dive floor if the player has dive and soul totems are randomized to prevent soul-based locks case SceneNames.RestingGrounds_05: if (RandomizerMod.Instance.Settings.RandomizeSoulTotems && Ref.PD.quakeLevel > 0) { GameManager.instance.sceneData.SaveMyState(new PersistentBoolData { sceneName = "RestingGrounds_05", id = "Quake Floor", activated = true, semiPersistent = false }); } break; // Move Seer back to make room for items, and remove essence rewards case SceneNames.RestingGrounds_07: GameObject.Find("Dream Moth").transform.Translate(new Vector3(-5f, 0f)); PlayMakerFSM moth = FSMUtility.LocateFSM(GameObject.Find("Dream Moth"), "Conversation Control"); PlayerData.instance.dreamReward1 = true; moth.FsmVariables.GetFsmBool("Got Reward 1").Value = true; //Relic PlayerData.instance.dreamReward3 = true; moth.FsmVariables.GetFsmBool("Got Reward 3").Value = true; //Pale Ore PlayerData.instance.dreamReward4 = true; moth.FsmVariables.GetFsmBool("Got Reward 4").Value = true; //Charm PlayerData.instance.dreamReward5 = true; moth.FsmVariables.GetFsmBool("Got Reward 5").Value = true; //Vessel Fragment PlayerData.instance.dreamReward5b = true; moth.FsmVariables.GetFsmBool("Got Reward 5b").Value = true; //Skill PlayerData.instance.dreamReward6 = true; moth.FsmVariables.GetFsmBool("Got Reward 6").Value = true; //Relic PlayerData.instance.dreamReward7 = true; moth.FsmVariables.GetFsmBool("Got Reward 7").Value = true; //Mask Shard PlayerData.instance.dreamReward8 = true; moth.FsmVariables.GetFsmBool("Got Reward 8").Value = true; //Skill break; // Make Sly pickup send Sly back upstairs -- warps player out to prevent resulting softlock from trying to enter the shop from a missing transition case SceneNames.Room_Sly_Storeroom: FsmState slyFinish = FSMUtility.LocateFSM(GameObject.Find("Randomizer Shiny"), "Shiny Control").GetState("Finish"); slyFinish.AddAction(new RandomizerSetBool("SlyCharm", true)); slyFinish.AddAction(new RandomizerChangeScene("Town", "door_sly")); break; case SceneNames.Ruins1_05 + "c": GameObject platform = ObjectCache.SmallPlatform; platform.transform.SetPosition2D(26.6f, 73.2f); platform.SetActive(true); break; // Many changes to make the desolate dive pickup work properly case SceneNames.Ruins1_24: // Stop spell container from destroying itself PlayMakerFSM quakePickup = FSMUtility.LocateFSM(GameObject.Find("Quake Pickup"), "Pickup"); quakePickup.GetState("Idle").RemoveActionsOfType <IntCompare>(); foreach (PlayMakerFSM childFSM in quakePickup.gameObject.GetComponentsInChildren <PlayMakerFSM>(true)) { if (childFSM.FsmName == "Shiny Control") { // Make spell container spawn shiny instead quakePickup.GetState("Appear").GetActionsOfType <ActivateGameObject>()[1].gameObject .GameObject.Value = childFSM.gameObject; // Make shiny open gates on pickup/destroy SendEvent openGate = new SendEvent { eventTarget = new FsmEventTarget { target = FsmEventTarget.EventTarget.BroadcastAll, excludeSelf = true }, sendEvent = FsmEvent.FindEvent("BG OPEN"), delay = 0, everyFrame = false }; childFSM.GetState("Destroy").AddFirstAction(openGate); childFSM.GetState("Finish").AddFirstAction(openGate); break; } } // Stop the weird invisible floor from appearing if dive has been obtained if (Ref.PD.quakeLevel > 0) { Object.Destroy(GameObject.Find("Roof Collider Battle")); } // Change battle gate to be destroyed if Soul Master is dead instead of it the player has quake FsmState checkQuake = FSMUtility.LocateFSM(GameObject.Find("Battle Gate (1)"), "Destroy if Quake").GetState("Check"); checkQuake.RemoveActionsOfType <FsmStateAction>(); checkQuake.AddAction(new RandomizerBoolTest(nameof(PlayerData.killedMageLord), null, "DESTROY", true)); break; // Prevent simple key softlocks case SceneNames.Ruins2_04: FsmState hotSpringsKey = GameObject.Find("Inspect").LocateMyFSM("Conversation Control").GetState("Got Key?"); hotSpringsKey.RemoveActionsOfType <IntCompare>(); hotSpringsKey.AddAction(new RandomizerExecuteLambda(() => { if (GameManager.instance.GetPlayerDataInt("simpleKeys") > 1 || (PlayerData.instance.openedWaterwaysManhole && GameManager.instance.GetPlayerDataInt("simpleKeys") > 0)) { PlayMakerFSM.BroadcastEvent("YES"); } else { PlayMakerFSM.BroadcastEvent("NO"); } })); break; // Destroy Lurien case SceneNames.Ruins2_Watcher_Room: Object.Destroy(GameObject.Find("Dreamer Lurien")); Object.Destroy(GameObject.Find("Dream Enter")); Object.Destroy(GameObject.Find("Dream Impact")); Object.Destroy(GameObject.Find("Shield")); break; // Open all colosseum trials case SceneNames.Room_Colosseum_01: PlayerData.instance.colosseumBronzeOpened = true; PlayerData.instance.colosseumSilverOpened = true; PlayerData.instance.colosseumGoldOpened = true; GameObject.Find("Silver Trial Board").LocateMyFSM("Conversation Control").GetState("Hero Anim").ClearTransitions(); GameObject.Find("Silver Trial Board").LocateMyFSM("Conversation Control").GetState("Hero Anim").AddTransition("FINISHED", "Box Up YN"); GameObject.Find("Gold Trial Board").LocateMyFSM("Conversation Control").GetState("Hero Anim").ClearTransitions(); GameObject.Find("Gold Trial Board").LocateMyFSM("Conversation Control").GetState("Hero Anim").AddTransition("FINISHED", "Box Up YN"); break; // Destroy Grey Mourner after the flower has been delivered case SceneNames.Room_Mansion: if (PlayerData.instance.xunFlowerGiven) { PlayerData.instance.xunRewardGiven = true; } break; // Removes King's Brand cutscene trigger case SceneNames.Room_Wyrm: Object.Destroy(GameObject.Find("Avalanche End")); break; // Open Colosseum gates after picking up resp. items case SceneNames.Room_Colosseum_Bronze: GameObject.Find("Colosseum Manager").LocateMyFSM("Geo Pool").GetState("Open Gates").AddFirstAction(new RandomizerSetBool("colosseumBronzeCompleted", true, true)); break; case SceneNames.Room_Colosseum_Silver: GameObject.Find("Colosseum Manager").LocateMyFSM("Geo Pool").GetState("Open Gates").AddFirstAction(new RandomizerSetBool("colosseumSilverCompleted", true, true)); break; // Prevent simple key softlocks case SceneNames.Town: FsmState jijiKey = GameObject.Find("Jiji Door").LocateMyFSM("Conversation Control").GetState("Key?"); jijiKey.RemoveActionsOfType <GetPlayerDataInt>(); jijiKey.RemoveActionsOfType <IntCompare>(); jijiKey.AddAction(new RandomizerExecuteLambda(() => { if (GameManager.instance.GetPlayerDataInt("simpleKeys") > 1 || (PlayerData.instance.openedWaterwaysManhole && GameManager.instance.GetPlayerDataInt("simpleKeys") > 0)) { PlayMakerFSM.BroadcastEvent("KEY"); } else { PlayMakerFSM.BroadcastEvent("NOKEY"); } })); break; // Break the Dung Defender dive floor if the player has dive and transitions are randomized to prevent soul-based locks case SceneNames.Waterways_05: if (RandomizerMod.Instance.Settings.RandomizeTransitions && Ref.PD.quakeLevel > 0) { GameManager.instance.sceneData.SaveMyState(new PersistentBoolData { sceneName = "Waterways_05", id = "Quake Floor", activated = true, semiPersistent = false }); } break; } }
public override void Process(string scene, Object changeObj) { if (scene != _sceneName || !(changeObj is PlayMakerFSM fsm) || fsm.FsmName != _fsmName || fsm.gameObject.name != _objectName) { return; } FsmState pdBool = fsm.GetState("PD Bool?"); FsmState charm = fsm.GetState("Charm?"); FsmState bigGetFlash = fsm.GetState("Big Get Flash"); // Remove actions that stop shiny from spawning pdBool.RemoveActionsOfType <StringCompare>(); // Change pd bool test to our new bool PlayerDataBoolTest boolTest = pdBool.GetActionsOfType <PlayerDataBoolTest>()[0]; if (_playerdata) { boolTest.boolName = _boolName; } else { RandomizerBoolTest randBoolTest = new RandomizerBoolTest(_boolName, boolTest.isFalse, boolTest.isTrue); pdBool.RemoveActionsOfType <PlayerDataBoolTest>(); pdBool.AddFirstAction(randBoolTest); } string logBoolName = string.Empty; for (int i = 0; i < _itemDefs.Length; i++) { if (!Ref.PD.GetBool(_itemDefs[i].BoolName)) { logBoolName = _itemDefs[i].BoolName; break; } } // Force the FSM to show the big item flash charm.ClearTransitions(); charm.AddTransition("FINISHED", "Big Get Flash"); bigGetFlash.AddAction(new RandomizerExecuteLambda(() => RandoLogger.LogItemToTrackerByBoolName(logBoolName, _location))); bigGetFlash.AddAction(new RandomizerExecuteLambda(() => RandoLogger.UpdateHelperLog())); bigGetFlash.AddFirstAction(new RandomizerExecuteLambda(() => AreaRando.Instance.Settings.UpdateObtainedProgressionByBoolName(logBoolName))); // Set bool and show the popup after the flash bigGetFlash.AddAction(new RandomizerCallStaticMethod( typeof(BigItemPopup), nameof(BigItemPopup.ShowAdditive), _itemDefs, fsm.gameObject, "GET ITEM MSG END")); // Don't actually need to set the skill here, that happens in BigItemPopup // Maybe change that at some point, it's not where it should happen if (!_playerdata) { bigGetFlash.AddAction(new RandomizerSetBool(_boolName, true)); } // Exit the fsm after the popup bigGetFlash.ClearTransitions(); bigGetFlash.AddTransition("GET ITEM MSG END", "Hero Up"); bigGetFlash.AddTransition("HERO DAMAGED", "Finish"); }