royitaqi / HollowKnight.BossAttacks

4 stars 1 forks source link

REF: How to start a GG boss fight in HoG with normal scene transition #25

Closed royitaqi closed 1 year ago

royitaqi commented 1 year ago

Anti-approach

Use GameManager.instance.ChangeToScene() won't work, because it doesn't set up all the environment (e.g. enter/leave) necessary for a GG fight. It doesn't trigger USceneManager.activeSceneChanged event for mod to detect transition, too.

The following approaches are closer to normal game, which has the benefits of covering some of the necessary environment automatically.

Source code for the following approaches:

https://github.com/royitaqi/HollowKnight.BossAttacks/blob/ad3b2a8023d9e2f00789344aad193d6ccd7486ef/BossAttacks/Utils/E2eTestUtils.cs

Approach 1: via Scene Change

Notes:

            // Death return
            PlayerData.instance.dreamReturnScene = "GG_Workshop";
            PlayerData.instance.bossReturnEntryGate = ReturnDoor;

            // Win return
            BossSceneController.SetupEvent = (self) => {
                self.BossLevel = ChallengeLevel;
                self.DreamReturnEvent = "DREAM RETURN";
                self.OnBossSceneComplete += () =>
                {
                    GameManager.instance.ChangeToScene("GG_Workshop", ReturnDoor, 0);
                };
            };

            // Start fight
            GameManager.instance.BeginSceneTransition(new GameManager.SceneLoadInfo
            {
                SceneName = BossScene,
                EntryGateName = "door_dreamEnter", // Don't miss this. Will cause fight to not start (boss and hero stuck).
                PreventCameraFadeOut = true,
                Visualization = GameManager.SceneLoadVisualizations.GodsAndGlory,
            });

Approach 2: via HoG Statue

Notes:

Assumptions:

            // Death return
            PlayerData.instance.dreamReturnScene = "GG_Workshop";
            PlayerData.instance.bossReturnEntryGate = ReturnDoor;

            // Win return
            BossSceneController.SetupEvent = (self) => {
                self.BossLevel = ChallengeLevel;
                self.DreamReturnEvent = "DREAM RETURN";
                self.OnBossSceneComplete += () =>
                {
                    GameManager.instance.ChangeToScene("GG_Workshop", ReturnDoor, 0);
                };
            };

            // Start fight
            GameObject statue = USceneManager.GetActiveScene()
                .GetRootGameObjects()
                .First(go => go.name == "GG_Statue_GreyPrince"); // statue name doesn't matter
            var statueControl = statue.transform.GetChild(0).gameObject.LocateMyFSM("GG Boss UI").Fsm;
            statueControl.GetState("Take Control").Transitions[0].ToFsmState = statueControl.GetState("Impact");
            statueControl.Variables.FindFsmString("Return Scene").Value = "GG_Workshop";
            statueControl.Variables.FindFsmString("To Scene").Value = BossScene;
            statueControl.SetState("Take Control");

Approach 3: via Challenge Menu

Notes:

Assumptions:

            // warp
            HeroController.instance.gameObject.transform.position = StatuePos;

            // interact with menu
            yield return new WaitForSeconds(0.1f);
            yield return Up(0.1f);
            yield return new WaitForSeconds(1);
            for (int i =  0; i < ChallengeLevel; i++)
            {
                yield return Down(0.1f);
            }
            yield return Jump(0.1f);