From b323b64799c969a6068b9686e2d1180cdc065980 Mon Sep 17 00:00:00 2001 From: nerthul11 <=> Date: Fri, 19 Jul 2024 13:04:06 -0300 Subject: [PATCH] Room Rando logic fixes and wall behaviour changes --- BreakableWallRandomizer.cs | 2 +- BreakableWallRandomizer.csproj | 4 +- FSM/CustomBoolCheck.cs | 30 ++++++ IC/BreakableWallItem.cs | 4 +- IC/BreakableWallLocation.cs | 120 +++++++++++------------ Resources/Data/BreakableWallObjects.json | 52 ++++++++-- Resources/Data/WallGroups.json | 2 +- 7 files changed, 137 insertions(+), 77 deletions(-) create mode 100644 FSM/CustomBoolCheck.cs diff --git a/BreakableWallRandomizer.cs b/BreakableWallRandomizer.cs index 81b348a..ae6d0e5 100644 --- a/BreakableWallRandomizer.cs +++ b/BreakableWallRandomizer.cs @@ -9,7 +9,7 @@ namespace BreakableWallRandomizer public class BreakableWallRandomizer : Mod, IGlobalSettings { new public string GetName() => "Breakable Wall Randomizer"; - public override string GetVersion() => "3.0.1.1"; + public override string GetVersion() => "3.0.1.2"; public BWR_Settings GS { get; set; } = new(); private static BreakableWallRandomizer _instance; public BreakableWallRandomizer() : base() diff --git a/BreakableWallRandomizer.csproj b/BreakableWallRandomizer.csproj index a905ad1..b3935cf 100644 --- a/BreakableWallRandomizer.csproj +++ b/BreakableWallRandomizer.csproj @@ -8,8 +8,8 @@ BreakableWallRandomizer A Randomizer add-on for wall and floor objects. Copyright ©2023 - 3.0.1.1 - 3.0.1.1 + 3.0.1.2 + 3.0.1.2 bin\$(Configuration)\ latest diff --git a/FSM/CustomBoolCheck.cs b/FSM/CustomBoolCheck.cs new file mode 100644 index 0000000..d727752 --- /dev/null +++ b/FSM/CustomBoolCheck.cs @@ -0,0 +1,30 @@ +using HutongGames.PlayMaker; + +namespace BreakableWallRandomizer.Fsm +{ + internal class CustomFsmBooleanCheck : FsmStateAction + { + private bool value; + private string trueEvent; + private string falseEvent; + + public CustomFsmBooleanCheck(bool _value, string _trueEvent, string _falseEvent) + { + value = _value; + trueEvent = _trueEvent; + falseEvent = _falseEvent; + } + public override void OnEnter() + { + if (value) + { + Fsm.Event(trueEvent); + } + else + { + Fsm.Event(falseEvent); + } + Finish(); + } + } +} \ No newline at end of file diff --git a/IC/BreakableWallItem.cs b/IC/BreakableWallItem.cs index 1db5c91..7787966 100644 --- a/IC/BreakableWallItem.cs +++ b/IC/BreakableWallItem.cs @@ -73,7 +73,7 @@ public override void GiveImmediate(GiveInfo info) if (wall.name.StartsWith("Dive_Floor") && !BreakableWallModule.Instance.UnlockedDives.Contains(name)) BreakableWallModule.Instance.UnlockedDives.Add(wall.name); - // If we're already in the same scene as the wall, break it. The wall's FSM should spawn a shiny. + // If we're already in the same scene as the wall, break it. if (GameManager.instance.sceneName == wall.sceneName) GameObject.Find(wall.gameObject).LocateMyFSM(wall.fsmType).SetState("BreakSameScene"); } @@ -89,7 +89,7 @@ public override void GiveImmediate(GiveInfo info) if (name.StartsWith("Dive_Floor") && !BreakableWallModule.Instance.UnlockedDives.Contains(name)) BreakableWallModule.Instance.UnlockedDives.Add(name); - // If we're already in the same scene as the wall, break it. The wall's FSM should spawn a shiny. + // If we're already in the same scene as the wall, break it. if (GameManager.instance.sceneName == sceneName) GameObject.Find(gameObject).LocateMyFSM(fsmType).SetState("BreakSameScene"); } diff --git a/IC/BreakableWallLocation.cs b/IC/BreakableWallLocation.cs index 5c518c9..da8047c 100644 --- a/IC/BreakableWallLocation.cs +++ b/IC/BreakableWallLocation.cs @@ -1,4 +1,5 @@ -using BreakableWallRandomizer.Modules; +using BreakableWallRandomizer.Fsm; +using BreakableWallRandomizer.Modules; using HutongGames.PlayMaker.Actions; using ItemChanger; using ItemChanger.Locations; @@ -111,7 +112,7 @@ protected override void OnUnload() } } - private void MakeWallPassable(GameObject go) + private void MakeWallPassable(GameObject go, bool destroy) { foreach (var objectName in alsoDestroy) { @@ -121,13 +122,13 @@ private void MakeWallPassable(GameObject go) GameObject.Destroy(obj); } catch { } } - Recursive_MakeWallPassable(go); + Recursive_MakeWallPassable(go, destroy); } // Recursively set all colliders as triggers on a given gameObject. // Also recursively set any SpriteRenderers on a given gameObject to 0.5 alpha. // Also remove any object called "Camera lock" or any textures beginning with msk_. - private void Recursive_MakeWallPassable(GameObject go) + private void Recursive_MakeWallPassable(GameObject go, bool destroy) { foreach (var collider in go.GetComponents()) { @@ -161,7 +162,9 @@ private void Recursive_MakeWallPassable(GameObject go) for (var i = 0; i < go.transform.childCount; i++) { - MakeWallPassable(go.transform.GetChild(i).gameObject); + MakeWallPassable(go.transform.GetChild(i).gameObject, destroy); + if (destroy) + GameObject.Destroy(go); } } @@ -184,6 +187,25 @@ private void ModifyWallBehaviour(PlayMakerFSM fsm) if (wall.fsmType != fsm.FsmName) continue; + var originalIdleStateName = wall.fsmType switch + { + "quake_floor" => "Solid", + + "Detect Quake" => "Detect", + + _ => "Idle" + }; + + // Copy sound and particles from original + var originalBreakStateName = wall.fsmType switch + { + "quake_floor" => "Glass", + + "Detect Quake" => "Break 2", + + _ => "Break" + }; + // If a location is present, it means that it's not vanilla BreakableWallModule.Instance.vanillaWalls.RemoveAll(wall => wall.name == name); @@ -210,11 +232,10 @@ private void ModifyWallBehaviour(PlayMakerFSM fsm) } else if (wall.fsmType == "quake_floor") { fsm.ChangeTransition("Init", "ACTIVATE", "Solid"); - fsm.RemoveAction("Transient", 0); // Sets the floor to a trigger + if (fsm.GetState("Transient").GetActions().Length >= 1) + fsm.RemoveAction("Transient", 0); if (fsm.GetState("Solid").GetActions().Length >= 1) - { - fsm.RemoveAction("Solid", 0); // Sets the floor to a triggern't - } + fsm.RemoveAction("Solid", 0); var collider = fsm.gameObject.GetComponent(); collider.isTrigger = true; // Make the first collider always a trigger @@ -228,6 +249,12 @@ private void ModifyWallBehaviour(PlayMakerFSM fsm) fsm.ChangeTransition("Init", "ACTIVATE", "Detect"); } + // If the wall item had been obtained when calling GiveItem, destroy the wall on trigger. + fsm.AddState("DeleteWall"); + fsm.AddCustomAction("DeleteWall", () => MakeWallPassable(fsm.gameObject, true)); + fsm.AddTransition("DeleteWall", "FINISHED", originalBreakStateName); + + // Add GiveItem state fsm.AddState("GiveItem"); fsm.AddCustomAction("GiveItem", () => { @@ -238,27 +265,18 @@ private void ModifyWallBehaviour(PlayMakerFSM fsm) }); Placement.AddVisitFlag(VisitState.Opened); - - if (BreakableWallModule.Instance.UnlockedBreakableWalls.Contains(wall.name)) - { - // Delete the wall entirely. - if (fsmType == "quake_floor") - fsm.SetState("Destroy"); - else if (fsmType == "Detect Quake") - fsm.SetState("Break 2"); - else - fsm.SetState("Break"); - } }); + fsm.AddAction("GiveItem", new CustomFsmBooleanCheck( + BreakableWallModule.Instance.UnlockedBreakableWalls.Contains(wall.name), "OBTAINED", "" + )); + fsm.AddTransition("GiveItem", "OBTAINED", "DeleteWall"); // If we already unlocked this wall, and items are still left there, make it passable. if (BreakableWallModule.Instance.UnlockedBreakableWalls.Contains(wall.name)) { - // If items are left, make wall semi-transparent and passable + // If items are left, make wall semi-transparent and passable. if (!Placement.AllObtained()) - { - MakeWallPassable(fsm.gameObject); - } + MakeWallPassable(fsm.gameObject, false); else { // Ensure the wall deletes on-load. @@ -287,25 +305,6 @@ private void ModifyWallBehaviour(PlayMakerFSM fsm) // ...and there are items left to collect: else { - var originalIdleStateName = wall.fsmType switch - { - "quake_floor" => "Solid", - - "Detect Quake" => "Detect", - - _ => "Idle" - }; - - // Copy sound and particles from original - var originalBreakStateName = wall.fsmType switch - { - "quake_floor" => "Glass", - - "Detect Quake" => "Break 2", - - _ => "Break" - }; - foreach (var action in fsm.GetState(originalBreakStateName).Actions) { if (action is AudioPlayerOneShotSingle or PlayParticleEmitter or AudioPlayerOneShot) @@ -319,25 +318,22 @@ private void ModifyWallBehaviour(PlayMakerFSM fsm) fsm.AddState("BreakSameScene"); - fsm.InsertCustomAction("BreakSameScene", () => + // In any of the cases, the wall is expected to become passable. + fsm.AddCustomAction("BreakSameScene", () => { - if (Placement.AllObtained()) - { - MakeWallPassable(fsm.gameObject); - fsm.SetState(originalIdleStateName); - } - else - { - if (wall.fsmType == "quake_floor") - { - MakeWallPassable(fsm.gameObject); - } // ensure everything is passable. - fsm.SetState(originalBreakStateName); - } - + MakeWallPassable(fsm.gameObject, Placement.AllObtained()); Placement.AddVisitFlag(VisitState.Opened); - }, 0); - } + }); + + // If placement is cleared, make the wall disappear. Otherwise, set to hittable state. + fsm.AddAction("BreakSameScene", new CustomFsmBooleanCheck( + Placement.AllObtained(), + "CLEARED", + "UNCLEARED" + )); + fsm.AddTransition("BreakSameScene", "UNCLEARED", originalIdleStateName); + fsm.AddTransition("BreakSameScene", "CLEARED", originalBreakStateName); + } } if (wall.fsmType == "breakable_wall_v2") @@ -356,7 +352,7 @@ private void ModifyWallBehaviour(PlayMakerFSM fsm) fsm.ChangeTransition("Hit", "HIT 3", "GiveItem"); } else if (wall.fsmType == "quake_floor") { - fsm.ChangeTransition("PD Bool?", "FINISHED", "GiveItem"); + fsm.ChangeTransition("Transient", "DESTROY", "GiveItem"); } else if (wall.fsmType == "Detect Quake") { fsm.ChangeTransition("Quake Hit", "FINISHED", "GiveItem"); @@ -393,4 +389,4 @@ private void ManageKPCollapse(PlayMakerFSM fsm) } } } -} +} \ No newline at end of file diff --git a/Resources/Data/BreakableWallObjects.json b/Resources/Data/BreakableWallObjects.json index b578859..1ce196f 100644 --- a/Resources/Data/BreakableWallObjects.json +++ b/Resources/Data/BreakableWallObjects.json @@ -878,7 +878,14 @@ "logicOverrides": { "White_Palace_06[left1]": "White_Palace_06[left1] | (ORIG) + Wall-Path_of_Pain_Entrance" }, - "logicSubstitutions": {} + "logicSubstitutions": { + "White_Palace_06[bot1]": { + "White_Palace_06[left1]": "White_Palace_06[left1] + Wall-Path_of_Pain_Entrance" + }, + "White_Palace_06[top1]": { + "White_Palace_06[left1]": "White_Palace_06[left1] + Wall-Path_of_Pain_Entrance" + } + } }, { "name": "Wall-White_Palace_Throne", @@ -920,6 +927,15 @@ }, "Deepnest_East_01[top1]": { "Deepnest_East_01[right1]": "Deepnest_East_01[right1] + Plank-Hive_Exit" + }, + "Geo_Rock-Lower_Kingdom's_Edge_1": { + "Deepnest_East_01[right1]": "Deepnest_East_01[right1] + Plank-Hive_Exit" + }, + "Geo_Rock-Lower_Kingdom's_Edge_2": { + "Deepnest_East_01[right1]": "Deepnest_East_01[right1] + Plank-Hive_Exit" + }, + "Soul_Totem-Lower_Kingdom's_Edge_1": { + "Deepnest_East_01[right1]": "Deepnest_East_01[right1] + Plank-Hive_Exit" } } }, @@ -1138,7 +1154,7 @@ "group": "", "logic": "(Fungus1_04[right1] + Defeated_Hornet_1 + (FULLDASH | WINGS)) | (Fungus1_04[right1] + Plank-Hornet_Exit) | (Fungus1_04[left1] + (FULLDASH | WINGS))", "logicOverrides": { - "Fungus1_04[left1]": "(ORIG) | Fungus1_04[right1] + (Plank-Hornet_Exit + (WINGS | LEFTDASH | ACID | SPELLAIRSTALL + $CASTSPELL[1,1]))", + "Fungus1_04[left1]": "(ORIG) | Fungus1_04[right1] + Plank-Hornet_Exit + (WINGS | LEFTDASH | ACID | SPELLAIRSTALL + $CASTSPELL[1,1])", "Fungus1_04[right1]": "Fungus1_04[right1] | (ORIG) + Plank-Hornet_Exit" }, "logicSubstitutions": {} @@ -1379,7 +1395,8 @@ "logic": "Deepnest_01[bot1] | (Deepnest_01[left1] | Deepnest_01[right1]) + Plank-Deepnest_Exit", "logicOverrides": { "Fungus2_20[left1]": "Fungus2_20[left1] | (ORIG) + Wall-Deepnest_Fungal", - "Deepnest_01[right1]": "Deepnest_01[right1] | (ORIG) + Wall-Deepnest_Fungal" + "Deepnest_01[right1]": "Deepnest_01[right1] | (ORIG) + Wall-Deepnest_Fungal", + "Spore_Shroom": "Fungus2_20 + ((ORIG) | (RIGHTCLAW | WINGS) + (ACID | RIGHTDASH | LEFTCLAW + RIGHTSUPERDASH) | WINGS + (RIGHTCLAW | SPELLAIRSTALL + $CASTSPELL[1,before:AREASOUL] | COMPLEXSKIPS + OBSCURESKIPS + $SHADESKIP + DAMAGEBOOSTS + $TAKEDAMAGE | OBSCURESKIPS + PRECISEMOVEMENT | $SHRIEKPOGO[2,before:AREASOUL]) | Plank-Spore_Shroom)" }, "logicSubstitutions": { "Fungus2_20": { @@ -1387,6 +1404,12 @@ }, "Deepnest_01": { "Deepnest_01[right1]": "Deepnest_01[right1] + Wall-Deepnest_Fungal" + }, + "Grub-Fungal_Spore_Shroom": { + "Fungus2_20[left1]" : "Fungus2_20[left1] + Wall-Deepnest_Fungal" + }, + "Lore_Tablet-Spore_Shroom": { + "Fungus2_20[left1]" : "Fungus2_20[left1] + Wall-Deepnest_Fungal" } } }, @@ -1907,8 +1930,8 @@ "gameObject": "/Breakable Wall", "fsmType": "breakable_wall_v2", "sceneName": "Ruins_Bathhouse", - "x": 0.0, - "y": 0.0, + "x": 0.5, + "y": -0.1, "persistentBool": "bathHouseWall", "sprite": "bath_break_wall_0deg", "alsoDestroy": [], @@ -1972,6 +1995,15 @@ "logicSubstitutions": { "Waterways_01": { "Waterways_01[right1]": "Waterways_01[right1] + Wall-Tuk" + }, + "Geo_Rock-Waterways_Tuk": { + "Waterways_01[right1]": "Waterways_01[right1] + Wall-Tuk" + }, + "Geo_Rock-Waterways_Tuk_Alcove": { + "Waterways_01[right1]": "Waterways_01[right1] + Wall-Tuk" + }, + "Soul_Totem-Waterways_Entrance": { + "Waterways_01[right1]": "Waterways_01[right1] + Wall-Tuk" } } }, @@ -2027,12 +2059,14 @@ "logic": "Waterways_05[bot1] + (ANYCLAW | WINGS) + Defeated_Dung_Defender | Waterways_05[bot2] | Waterways_05[right1] + Plank-Dung_Defender", "logicOverrides": { "Opened_Dung_Defender_Wall": "Plank-Dung_Defender", - "Lever-Dung_Defender": "ORIG | Waterways_05[right1] + Plank-Dung_Defender", "Waterways_05[right1]": "Waterways_05[right1] | (ORIG) + Plank-Dung_Defender" }, "logicSubstitutions": { "Abyss_01[left1]": { "Opened_Dung_Defender_Wall": "Plank-Dung_Defender" + }, + "Lever-Dung_Defender": { + "Waterways_05[right1]":"Waterways_05[right1] + Plank-Dung_Defender" } } }, @@ -2870,7 +2904,7 @@ "exit": false, "groupWalls": [], "group": "", - "logic": "Waterways_04[bot1] | (Waterways_04[right1] | Waterways_04[left1] + (RIGHTCLAW | WINGS | ENEMYPOGOS) | Waterways_04[left2] + (RIGHTCLAW | WINGS + ENEMYPOGOS) + (SWIM | RIGHTSKIPACID)) + Broke_Waterways_Bench_Quake_Floor_1 + QUAKE + $CASTSPELL", + "logic": "(Waterways_04[bot1] | (Waterways_04[right1] | Waterways_04[left1] + (RIGHTCLAW | WINGS | ENEMYPOGOS) | Waterways_04[left2] + (RIGHTCLAW | WINGS + ENEMYPOGOS) + (SWIM | RIGHTSKIPACID)) + Dive_Floor-Waterways_Bench_1) + QUAKE + $CASTSPELL", "logicOverrides": { "Broke_Waterways_Bench_Quake_Floor_2": "Dive_Floor-Waterways_Bench_2" }, @@ -2893,7 +2927,7 @@ "exit": false, "groupWalls": [], "group": "", - "logic": "Waterways_02[bot1] | (Waterways_02[top1] | Waterways_02[top2] + (ANYCLAW | WINGS | SWIM) | Waterways_02[top3] + Broke_Waterways_Bench_Quake_Floor_3 | Waterways_02[bot1] | Waterways_02[bot2] + (ANYCLAW | WINGS | SWIM)) + QUAKE + $CASTSPELL[before:ROOMSOUL]", + "logic": "(Waterways_02[bot1] | Waterways_02[top1] | Waterways_02[top2] + (ANYCLAW | WINGS | SWIM) | Waterways_02[top3] + Broke_Waterways_Bench_Quake_Floor_3 | Waterways_02[bot2] + (ANYCLAW | WINGS | SWIM)) + QUAKE + $CASTSPELL[before:ROOMSOUL]", "logicOverrides": { "Broke_Flukemarm_Quake_Floor": "Dive_Floor-Flukemarm" }, @@ -2956,7 +2990,7 @@ "exit": false, "groupWalls": [], "group": "", - "logic": "*Soul_Totem-White_Palace_Right", + "logic": "White_Palace_15[right1] + QUAKE + $CASTSPELL", "logicOverrides": {}, "logicSubstitutions": {} }, diff --git a/Resources/Data/WallGroups.json b/Resources/Data/WallGroups.json index 982db78..f2af9d0 100644 --- a/Resources/Data/WallGroups.json +++ b/Resources/Data/WallGroups.json @@ -146,7 +146,7 @@ "name": "Wall_Group-Inner_Sanctum", "gameObject": "", "fsmType": "", - "sceneName": "Deepnest_East_17", + "sceneName": "Ruins1_32", "x": 0.0, "y": 0.0, "persistentBool": "",