diff --git a/HKMP/Game/Client/Save/SaveChanges.cs b/HKMP/Game/Client/Save/SaveChanges.cs index 85450db..90c6bb2 100644 --- a/HKMP/Game/Client/Save/SaveChanges.cs +++ b/HKMP/Game/Client/Save/SaveChanges.cs @@ -1,5 +1,7 @@ +using System.Linq; using Hkmp.Util; using HutongGames.PlayMaker.Actions; +using Modding; using UnityEngine; using Logger = Hkmp.Logging.Logger; @@ -127,6 +129,26 @@ public void ApplyPlayerDataSaveChange(string name) { return; } + // Add additional actions from different states to ensure the player gets control back if they are already + // in the FSM flow + if (IsInTollMachineDialogue(fsm.Fsm.ActiveStateName)) { + var action1 = fsm.GetFirstAction("Yes"); + fsm.InsertAction("Box Disappear Anim", action1, 0); + var action2 = fsm.GetFirstAction("Yes"); + action2.animationCompleteEvent = null; + fsm.InsertAction("Box Disappear Anim", action2, 0); + var action3 = fsm.GetFirstAction("Yes"); + fsm.InsertAction("Box Disappear Anim", action3, 0); + var action4 = fsm.GetFirstAction("Pause Before Box Drop"); + fsm.InsertAction("Box Disappear Anim", action4, 0); + var action5 = fsm.GetFirstAction("Pause Before Box Drop"); + fsm.InsertAction("Box Disappear Anim", action5, 0); + var action6 = fsm.GetAction("Pause Before Box Drop", 2); + fsm.InsertAction("Box Disappear Anim", action6, 0); + + HideDialogueBox(); + } + fsm.SetState("Box Disappear Anim"); return; } @@ -146,6 +168,24 @@ public void ApplyPlayerDataSaveChange(string name) { return; } + // Add additional actions from different states to ensure the player gets control back if they are already + // in the FSM flow + if (IsInTollMachineDialogue(fsm.Fsm.ActiveStateName)) { + var action1 = fsm.GetFirstAction("Yes"); + action1.animationCompleteEvent = null; + fsm.InsertAction("Box Down", action1, 0); + var action2 = fsm.GetFirstAction("Yes"); + fsm.InsertAction("Box Down", action2, 0); + var action3 = fsm.GetFirstAction("Pause Before Box Drop"); + fsm.InsertAction("Box Down", action3, 0); + var action4 = fsm.GetFirstAction("Pause Before Box Drop"); + fsm.InsertAction("Box Down", action4, 0); + var action5 = fsm.GetAction("Pause Before Box Drop", 3); + fsm.InsertAction("Box Down", action5, 0); + + HideDialogueBox(); + } + fsm.SetState("Box Down"); return; } @@ -241,6 +281,19 @@ public void ApplyPlayerDataSaveChange(string name) { if (fsm == null) { return; } + + string[] inDialogueStateNames = [ + "Hero Anim", "Key?", "Box Up YN", "Send Text", "Box Up", "No Key" + ]; + if (inDialogueStateNames.Contains(fsm.Fsm.ActiveStateName)) { + var action1 = fsm.GetFirstAction("Yes"); + fsm.InsertAction("Activate", action1, 0); + + HideDialogueBox(); + } + + fsm.RemoveFirstAction("Activate"); + fsm.RemoveFirstAction("Activate"); fsm.SetState("Activate"); return; @@ -257,8 +310,19 @@ public void ApplyPlayerDataSaveChange(string name) { return; } + string[] inDialogueStateNames = [ + "Hero Anim", "Key?", "Box Up YN", "Send Text", "Box Up", "No Key" + ]; + if (inDialogueStateNames.Contains(fsm.Fsm.ActiveStateName)) { + var action1 = fsm.GetFirstAction("Yes"); + fsm.InsertAction("Activate", action1, 0); + + HideDialogueBox(); + } + fsm.RemoveFirstAction("Activate"); fsm.RemoveFirstAction("Activate"); + fsm.RemoveFirstAction("Activate"); fsm.SetState("Activate"); return; @@ -285,6 +349,55 @@ public void ApplyPlayerDataSaveChange(string name) { fsm.SetState("Glow"); return; } + + if (name == "openedMageDoor_v2" && currentScene == "Ruins1_31") { + var go = GameObject.Find("Mage Door"); + if (go == null) { + return; + } + + var fsm = go.LocateMyFSM("Conversation Control"); + if (fsm == null) { + return; + } + + string[] inDialogueStateNames = [ + "Hero Anim", "Check Key", "Box Up YN", "Send Text", "Box Up", "No Key" + ]; + if (inDialogueStateNames.Contains(fsm.Fsm.ActiveStateName)) { + HideDialogueBox(); + } else { + fsm.RemoveFirstAction("Yes"); + } + + fsm.RemoveFirstAction("Yes"); + + fsm.SetState("Yes"); + return; + } + + if (name == "cityLift1" && currentScene == "Crossroads_49b") { + var go = GameObject.Find("Toll Machine Lift"); + var fsm = go.LocateMyFSM("Toll Machine"); + + // Hide the dialogue box if the local player is in the dialogue flow + if (IsInTollMachineDialogue(fsm.Fsm.ActiveStateName)) { + HideDialogueBox(); + } + + fsm.RemoveFirstAction("Send Message"); + + fsm.SetState("Yes"); + return; + } + + if (name == "nightmareLanternAppeared" && currentScene == "Cliffs_06") { + var go = GameObject.Find("Sycophant Dream"); + var fsm = go.LocateMyFSM("Activate Lantern"); + + fsm.SetState("Impact"); + return; + } } /// @@ -305,9 +418,27 @@ public void ApplyPersistentValueSaveChange(PersistentItemData itemData) { )) { var go = GameObject.Find("Toll Gate Machine"); var fsm = go.LocateMyFSM("Toll Machine"); - + + // Add additional actions from different states to ensure the player gets control back if they are already + // in the FSM flow + if (IsInTollMachineDialogue(fsm.Fsm.ActiveStateName)) { + var action1 = fsm.GetFirstAction("Yes"); + action1.animationCompleteEvent = null; + fsm.InsertAction("Box Disappear Anim", action1, 0); + var action2 = fsm.GetFirstAction("Yes"); + fsm.InsertAction("Box Disappear Anim", action2, 0); + var action3 = fsm.GetFirstAction("Pause Before Box Drop"); + fsm.InsertAction("Box Disappear Anim", action3, 0); + var action4 = fsm.GetFirstAction("Pause Before Box Drop"); + fsm.InsertAction("Box Disappear Anim", action4, 0); + var action5 = fsm.GetAction("Pause Before Box Drop", 2); + fsm.InsertAction("Box Disappear Anim", action5, 0); + + HideDialogueBox(); + } + fsm.RemoveFirstAction("Open Gates"); - + fsm.SetState("Box Disappear Anim"); return; } @@ -367,4 +498,69 @@ public void ApplyPersistentValueSaveChange(PersistentItemData itemData) { fsm.SetState("Open Audio"); } } + + /// + /// Whether the local player is currently in a toll machine dialogue prompt that has claimed control of the + /// character. + /// + /// The name of the current state of the dialogue FSM. + /// true if the player is in dialogue, false otherwise. + private bool IsInTollMachineDialogue(string currentStateName) { + string[] outOfDialogueStateNames = [ + "Out Of Range", "In Range", "Can Inspect?", "Cancel Frame", "Pause", "Activated?", "Paid?", "Get Price", "Init", + "Regain Control" + ]; + + return !outOfDialogueStateNames.Contains(currentStateName); + } + + /// + /// Hide the currently active dialogue box by setting the state of the 'Dialogue Page Control' FSM of the 'Text YN' + /// game object. Needs to be amended if this method should also hide dialogue boxes of other dialogue types. + /// + private void HideDialogueBox() { + var gc = GameCameras.instance; + if (gc == null) { + Logger.Warn("Could not find GameCameras instance"); + return; + } + + var hudCamera = gc.hudCamera; + if (hudCamera == null) { + Logger.Warn("Could not find hudCamera"); + return; + } + + var dialogManager = hudCamera.gameObject.FindGameObjectInChildren("DialogueManager"); + if (dialogManager == null) { + Logger.Warn("Could not find dialogueManager"); + return; + } + + void HideDialogueObject(string objectName, string heroDmgState) { + var obj = dialogManager.FindGameObjectInChildren(objectName); + if (obj != null) { + var dialogueBox = obj.GetComponent(); + if (dialogueBox == null) { + Logger.Warn($"Could not find {objectName} DialogueBox"); + return; + } + + var hidden = ReflectionHelper.GetField(dialogueBox, "hidden"); + if (hidden) { + return; + } + + var pageControlFsm = obj.LocateMyFSM("Dialogue Page Control"); + if (pageControlFsm == null) { + Logger.Warn($"Could not find {objectName} DialoguePageControl FSM"); + return; + } + pageControlFsm.SetState(heroDmgState); + } + } + + HideDialogueObject("Text YN", "Hero Damaged"); + HideDialogueObject("Text", "Pause"); + } } diff --git a/HKMP/Resource/save-data.json b/HKMP/Resource/save-data.json index 115d5bb..6550d08 100644 --- a/HKMP/Resource/save-data.json +++ b/HKMP/Resource/save-data.json @@ -4924,7 +4924,8 @@ }, "cityLift1": { "Sync": true, - "SyncType": "Server" + "SyncType": "Server", + "IgnoreSceneHost": true }, "cityLift1_isUp": { "Sync": true, @@ -4940,7 +4941,8 @@ }, "openedMageDoor_v2": { "Sync": true, - "SyncType": "Server" + "SyncType": "Server", + "IgnoreSceneHost": true }, "brokenMageWindow": { "Sync": true, @@ -5226,7 +5228,8 @@ }, "nightmareLanternAppeared": { "Sync": true, - "SyncType": "Server" + "SyncType": "Server", + "IgnoreSceneHost": true }, "nightmareLanternLit": { "Sync": true,