private static void DisableSwim(On.PlayMakerFSM.orig_OnEnable orig, PlayMakerFSM self) { orig(self); if (RandomizerMod.Instance.Settings.RandomizeSwim && self.FsmName == "Surface Water Region") { if (self.gameObject.LocateFSM("Acid Armour Check") != null) { return; // acid } FsmState splash = self.GetState("Big Splash?"); FsmStateAction acidDeath = new FsmStateActions.RandomizerExecuteLambda(() => { if (!RandomizerMod.Instance.Settings.GetBool(name: "canSwim")) { // this is actually the spike death despite the enum, because the acid death splashes green stuff HeroController.instance.TakeDamage(self.gameObject, CollisionSide.other, 1, (int)HazardType.ACID); PlayMakerFSM.BroadcastEvent("SWIM DEATH"); } }); splash.AddFirstAction(acidDeath); splash.AddTransition("SWIM DEATH", "Idle"); } }
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 }); FsmState idle = self.GetState("Idle"); // Idle state needs to activate the collision now idle.InsertAction(0, new ActivateGameObject { gameObject = new FsmOwnerDefault { GameObject = terrainChecker, OwnerOption = OwnerDefaultOption.SpecifyGameObject }, activate = true, recursive = false, resetOnExit = false, everyFrame = false }); // Account for the additional waiting time before Idle idle.GetAction <Wait>(8).time.Value -= NO_COLLISION_TIME; orig(self); }
private static void ModifyFsm(On.PlayMakerFSM.orig_OnEnable orig, PlayMakerFSM self) { switch (self.FsmName) { // first spit baldurs case "Blocker Control" when self.name == "Blocker": { self.GetState("Idle").ChangeTransition("ATTACK", "Can Roller?"); break; } // gruz drop room case "Bouncer Control" when self.name.StartsWith("Fly") && GameManager.instance.sceneName == "Crossroads_07": { HeroController.instance.StartCoroutine(FixGruzDrop(self)); break; } // remove shade spells case "Shade Control" when self.name.StartsWith("Hollow Shade"): { self.GetState("Init").RemoveAction(6); self.FsmVariables.FindFsmInt("SP").Value = 0; break; } // make furious vengeflies trigger later case "Control" when self.name.StartsWith("Angry Buzzer"): { self.gameObject.GetComponentInChildren <AlertRange>().transform.localScale = new Vector3(10, 10, 1.3f); break; } } orig(self); }
private static void FixVoidHeart(On.PlayMakerFSM.orig_OnEnable orig, PlayMakerFSM self) { orig(self); if (currentSettings.blockZoteDeath && self.FsmName == "Check Zote Death") { GameObject.Destroy(self); return; } if (currentSettings.fixVoidHeart) { if (self.FsmName == "Shade Control") { if (self.gameObject?.name?.StartsWith("Hollow Shade") ?? false) { self.FsmVariables.FindFsmBool("Friendly").Value = false; self.GetState("Pause").ClearTransitions(); self.GetState("Pause").AddTransition("FINISHED", "Init"); } } else if (self.FsmName == "Control") { if (self.gameObject?.name?.StartsWith("Shade Sibling") ?? false) { self.FsmVariables.FindFsmBool("Friendly").Value = false; self.GetState("Pause").ClearTransitions(); self.GetState("Pause").AddTransition("FINISHED", "Init"); } } } }
// For the time being, let's keep some fsm scene edits here rather than in the SceneChanged function. // This way, they work even when the previous scene is a boss scene. public static void FsmSceneEdits(On.PlayMakerFSM.orig_OnEnable orig, PlayMakerFSM self) { EditStagStations(self); DisableInfectedCrossroads(self); BossRewardReplacement.DestroyGruzmomGeo(self); orig(self); }
private static void ShowSkillsInInventory(On.PlayMakerFSM.orig_OnEnable orig, PlayMakerFSM self) { orig(self); if (self.FsmName == "Build Equipment List" && self.gameObject.name == "Equipment") { self.GetState("Walljump").GetActionOfType <PlayerDataBoolTest>().boolName.Value = "hasWalljumpAny"; PlayerDataBoolTest[] dashChecks = self.GetState("Dash").GetActionsOfType <PlayerDataBoolTest>(); dashChecks[0].boolName.Value = "hasDashAny"; } }
private static void ModifyFSM(On.PlayMakerFSM.orig_OnEnable orig, PlayMakerFSM self) { switch (self.FsmName) { case "Control" when self.name == "Initial Fall Impact" && NoHardFalls: self.ChangeTransition("Idle", "LAND", "Return Control"); break; case "Call Lever" when self.name.StartsWith("Lift Call Lever") && Televator: // Don't change big elevators. if (self.GetState("Check Already Called") == null) { break; } self.ChangeTransition("Left", "FINISHED", "Send Msg"); self.ChangeTransition("Right", "FINISHED", "Send Msg"); break; case "Bottle Control" when self.GetState("Shatter") is FsmState shatter && GrubsThroughWalls: { shatter.RemoveAllOfType <BoolTest>(); break; } case "Switch Control" when self.name.Contains("Ruins Lever") && LeverSkips: { self.GetState("Range").RemoveAllOfType <BoolTest>(); self.GetState("Check If Nail").RemoveAllOfType <BoolTest>(); break; } case "Dream Nail" when self.name == "Knight" && Storage: ((ListenForDreamNail)self.GetState("Cancelable").Actions.First(a => a.GetType() == typeof(ListenForDreamNail))).activeBool = true; ((ListenForDreamNail)self.GetState("Cancelable Dash").Actions.First(a => a.GetType() == typeof(ListenForDreamNail))).activeBool = true; ((ListenForDreamNail)self.GetState("Queuing").Actions.First(a => a.GetType() == typeof(ListenForDreamNail))).activeBool = true; self.GetState("Queuing").Actions = self.GetState("Queuing").Actions.Where(a => a.GetType() != typeof(BoolTest)).ToArray(); break; } orig(self); }
// Seems to remove Zote death triggers and also affect dream nail storage? Not entirely sure. private static void ModifyFSM(On.PlayMakerFSM.orig_OnEnable orig, PlayMakerFSM self) { if (self.Fsm.FsmComponent.FsmName == "Check Zote Death") { Object.Destroy(self); return; } orig(self); if (self.gameObject.name != "Knight" || self.FsmName != "Dream Nail") { return; } self.GetState("Cancelable").GetActionsOfType <ListenForDreamNail>()[0].activeBool = true; self.GetState("Cancelable Dash").GetActionsOfType <ListenForDreamNail>()[0].activeBool = true; self.GetState("Queuing").GetActionsOfType <ListenForDreamNail>()[0].activeBool = true; self.GetState("Queuing").RemoveActionsOfType <BoolTest>(); }
private static void ModifyFsm(On.PlayMakerFSM.orig_OnEnable orig, PlayMakerFSM self) { switch (self.FsmName) { // vengful spirit pickup case "Get Fireball" when self.name == "Knight Get Fireball": self.GetState("Start").GetAction <Wait>().time = 0; self.GetState("Rumble").GetAction <Wait>().time = 0; self.GetState("Start").RemoveAllOfType <iTweenMoveBy>(); self.GetState("Rumble").RemoveAllOfType <iTweenMoveBy>(); self.GetState("Get").RemoveAllOfType <iTweenMoveBy>(); break; case "Check Fall" when self.name == "Knight Cutscene Animator": self.GetState("Black").RemoveAction <Wait>(); self.GetState("Fade Back").GetAction <Wait>().time = 3; break; // shade soul pickup case "Get Fireball" when self.name == "Knight Get Fireball Lv2": self.GetState("Start").GetAction <Wait>().time = 0; self.GetState("Start").ChangeTransition("FINISHED", "Get PlayerData"); self.GetState("Start").RemoveAllOfType <iTweenMoveBy>(); self.GetState("Rumble").RemoveAllOfType <iTweenMoveBy>(); self.GetState("Get").RemoveAllOfType <iTweenMoveBy>(); break; // howling wraiths pickup case "Get Scream" when self.name == "Knight Get Scream": self.GetState("Start").GetAction <Wait>().time = 0.1f; self.GetState("Fall").GetAction <Wait>().time = 0.3f; self.GetState("Start").ChangeTransition("FINISHED", "Get"); self.GetState("Start").RemoveAction <AudioPlayerOneShotSingle>(); self.GetState("Start").RemoveAllOfType <iTweenMoveBy>(); self.GetState("Get").RemoveAllOfType <iTweenMoveBy>(); self.gameObject.GetComponentsInChildren <Transform>().First(transform => transform.name == "Orbs").gameObject.SetActive(false); break; // shade cloak pickup case "Get Shadow Dash" when self.name == "Dish Plat": self.GetState("Fall").GetAction <Wait>().time = 1; self.GetState("Fall").ChangeTransition("FINISHED", "UI Msg"); break; // desolate dive pickup case "corpse" when self.name == "Corpse Mage Lord 2(Clone)": self.GetState("Steam").GetAction <Wait>().time = 0; self.GetState("Ready").GetAction <Wait>().time = 0; self.GetState("Pause").GetAction <Wait>().time = 0; self.GetState("Land").GetAction <Wait>().time = 0; self.gameObject.GetComponentsInChildren <Transform>().Where(transform => transform.name == "Soul Breath").ToList().ForEach(transform => transform.gameObject.SetActive(false)); break; case "Pickup" when self.name == "Quake Pickup": self.GetState("Wait").ChangeTransition("FINISHED", "Appear"); self.GetState("Wait").GetAction <Wait>().time = 0.5f; break; case "Get Quake" when self.name == "Knight Get Quake": self.GetState("Start").GetAction <Wait>().time = 0.1f; self.GetState("Fall").GetAction <Wait>().time = 0.3f; self.GetState("Start").ChangeTransition("FINISHED", "Get"); self.GetState("Start").RemoveAction <AudioPlayerOneShotSingle>(); self.GetState("Start").RemoveAllOfType <iTweenMoveBy>(); self.GetState("Get").RemoveAllOfType <iTweenMoveBy>(); self.gameObject.GetComponentsInChildren <Transform>().First(transform => transform.name == "Orbs").gameObject.SetActive(false); break; // descending dark pickup case "Control" when self.name == "Crystal Shaman": self.GetState("Land Hero").ChangeTransition("FINISHED", "Get PlayerData 2"); break; // dream nail cutscene enter case "Conversation Control" when self.name == "Dreamer Plaque Inspect": self.GetState("Hero Anim").ChangeTransition("FINISHED", "Map Msg?"); break; case "Control" when self.name == "Dreamer Scene 2": self.GetState("Fade Out").GetAction <Wait>().time = 1; self.GetState("Take Control").ChangeTransition("FINISHED", "Fade Out"); self.GetState("Fade Out").ChangeTransition("FINISHED", "Set Compass Point"); break; // gruz mother case "corpse" when self.name == "Corpse Big Fly 1(Clone)": self.GetState("Init").GetAction <Wait>().time = 0; self.GetState("Steam").GetAction <Wait>().time = 0; self.GetState("Ready").GetAction <Wait>().time = 0; break; case "burster" when self.name == "Corpse Big Fly Burster(Clone)": self.GetState("Landed").RemoveAction <Wait>(); self.GetState("Stop Emit").RemoveAction <Wait>(); self.GetState("Stop").RemoveAction <Wait>(); self.GetState("Gurg 1").RemoveAction <Wait>(); self.GetState("Burst").RemoveAction <Wait>(); self.GetState("State 1").RemoveAction <Wait>(); break; // dreamer cutscene skip case "Control" when self.name == "Dreamer NPC": self.GetState("Cinematic").RemoveAction <FindGameObject>(); self.GetState("Cinematic").RemoveAction <SendMessage>(); self.GetState("Cinematic").RemoveAction <FadeAudio>(); self.GetState("Cinematic").AddAction(new NextFrameEvent { sendEvent = self.GetState("Cinematic").Fsm.GetEvent("CINEMATIC END") }); self.GetState("Set Hegemol").ChangeTransition("FINISHED", "Return"); self.GetState("Set Lurien").ChangeTransition("FINISHED", "Return"); self.GetState("Set Monomon").ChangeTransition("FINISHED", "Return"); break; // spawn soul master on the right for all skills fight case "Mage Lord" when self.name == "Mage Lord": FsmState setEntryPoint = self.GetState("Set Entry Point"); // remove knight position check and left spawn point for (int i = 0; i < 4; i++) { setEntryPoint.RemoveAction(2); } break; // early broken vessel fight start case "IK Control" when self.name == "Infected Knight": { // 1221 early spell hits FsmState start = self.GetState("Roar Start"); FsmState end = self.GetState("Roar End"); start.AddAction(end.GetAction <SetInvincible>()); start.AddAction(end.GetAction <SetCollider>()); start.AddAction(end.GetAction <SetIsKinematic2d>()); end.RemoveAction <SetInvincible>(); end.RemoveAction <SetCollider>(); end.RemoveAction <SetIsKinematic2d>(); // use the godhome wait for normal world fight as well to allow for left side fight start self.GetState("Waiting").ChangeTransition("BATTLE START", "GG Wait"); break; } // fast toll benches case "Toll Machine Bench" when self.name == "Toll Machine Bench": { // set wait times for each state self.GetState("Pause Before Box Drop").GetAction <Wait>().time = 0.1f; self.GetState("Box Down").GetAction <Wait>().time = 0.8f; self.GetState("Bench Up").GetAction <Wait>().time = 1.3f; // fast toll disappearing self.gameObject.GetComponent <tk2dSpriteAnimator>().GetClipByName("Box_disappear").fps = 45; // 3x speed, 15 default self.GetState("Box Down").RemoveAction <AudioPlayerOneShotSingle>(); // fast bench animation, synced with audio self.GetState("Bench Up").GetAction <Tk2dPlayAnimationWithEvents>().gameObject.GameObject.Value.GetComponent <tk2dSpriteAnimator>().DefaultClip.fps = 32; // 2x speed, 16 default ((AudioPlayerOneShotSingle)self.GetState("Bench Up").Actions[6]).delay = 0.45f; ((AudioPlayerOneShotSingle)self.GetState("Bench Up").Actions[7]).delay = 0.95f; // move rise audio one state earlier to make it sync better AudioPlayerOneShotSingle rise = (AudioPlayerOneShotSingle)self.GetState("Bench Up").Actions[5]; rise.delay = 0.7f; self.GetState("Box Down").AddAction(rise); self.GetState("Bench Up").RemoveAction(5); break; } // fast trap bench case "Fade" when self.name == "RestBench Spider": { self.GetState("Idle").ChangeTransition("FIRST STRUGGLE", "Start Fade"); self.GetState("Finish Fade").ChangeTransition("FINISHED", "Capture End"); string[] waitStates = { "Start Fade", "Capture End", "Fade Up", "Land" }; foreach (string waitState in waitStates) { self.GetState(waitState).GetAction <Wait>().time = 0.5f; } break; } // fast lifeblood door case "Control" when self.name == "Blue Plinth": { self.GetState("Send Event").GetAction <Wait>().time = 0.15f; // wait inbetween blue heart count increment string[] waitStates = { "Start Pause", "Glow Start", "Complete Pause", "Final Glow" }; foreach (string waitState in waitStates) { self.GetState(waitState).RemoveAction <Wait>(); } break; } } orig(self); }