diff --git a/Assets/icon-Offgeki.png b/Assets/icon-Offgeki.png new file mode 100644 index 0000000..533792c Binary files /dev/null and b/Assets/icon-Offgeki.png differ diff --git a/Extras/Offgeki/MU3.Battle/patch_EnemyFactory.cs b/Extras/Offgeki/MU3.Battle/patch_EnemyFactory.cs new file mode 100644 index 0000000..9280d0d --- /dev/null +++ b/Extras/Offgeki/MU3.Battle/patch_EnemyFactory.cs @@ -0,0 +1,22 @@ +using MU3.Util; +namespace MU3.Battle; + + +class patch_EnemyFactory : EnemyFactory +{ + extern public Enemy orig_create(EnemyParam param, CharacterPrefab prefab); + + public new Enemy create(EnemyParam param, CharacterPrefab prefab) + { + Enemy enemy = orig_create(param, prefab); + Mod.State state = Singleton.instance; + if ( + (state.RemoveEnemy && enemy.name.Contains("Zako")) || + (state.RemoveBoss && enemy.name.Contains("Boss")) + ) + { + enemy?.gameObject.SetActive(false); + } + return enemy; + } +} diff --git a/Extras/Offgeki/MU3.Battle/patch_EnemyManager.cs b/Extras/Offgeki/MU3.Battle/patch_EnemyManager.cs new file mode 100644 index 0000000..44b007f --- /dev/null +++ b/Extras/Offgeki/MU3.Battle/patch_EnemyManager.cs @@ -0,0 +1,16 @@ +using MU3.Util; + +namespace MU3.Battle; + +class patch_EnemyManager : EnemyManager +{ + extern void orig_playEnemyDamageUI(DamageParam dp); + public new void playEnemyDamageUI(DamageParam dp) + { + Mod.State state = Singleton.instance; + if (!state.RemoveEnemy && !state.RemoveBullets) + { + orig_playEnemyDamageUI(dp); + } + } +} diff --git a/Extras/Offgeki/MU3.Battle/patch_GameEngine.cs b/Extras/Offgeki/MU3.Battle/patch_GameEngine.cs new file mode 100644 index 0000000..6d84703 --- /dev/null +++ b/Extras/Offgeki/MU3.Battle/patch_GameEngine.cs @@ -0,0 +1,36 @@ +using MU3.Util; + +namespace MU3.Battle; + +class patch_GameEngine +{ + private Player _player; + + private Ally[] _allies; + + extern public void orig_createPlayer(StartCutscenePosition startCutscenePos, int charaId); + + public void createPlayer(StartCutscenePosition startCutscenePos, int charaId) + { + orig_createPlayer(startCutscenePos, charaId); + if (Singleton.instance.RemovePlayerGeki && _player) + { + _player.gameObject.SetActive(false); + } + } + + extern public void orig_createAlly(int id, StartCutscenePosition startCutscenePos, int charaId, int allyNum); + public void createAlly(int id, StartCutscenePosition startCutscenePos, int charaId, int allyNum) + { + orig_createAlly(id, startCutscenePos, charaId, allyNum); + if (Singleton.instance.RemoveAllyGekis) + { + foreach (var a in _allies) + { + if (a) { + a.gameObject.SetActive(false); + } + } + } + } +} diff --git a/Extras/Offgeki/MU3.Mod/State.cs b/Extras/Offgeki/MU3.Mod/State.cs new file mode 100644 index 0000000..581ccc8 --- /dev/null +++ b/Extras/Offgeki/MU3.Mod/State.cs @@ -0,0 +1,111 @@ +using MU3.Util; +namespace MU3.Mod; + + +class State: Singleton { + public bool RemoveBackground { get; set; } = false; + public bool RemoveBackgroundFrame { get; set; } = false; + public bool RemoveHeader { get; set; } = false; + public bool RemoveFooter { get; set; } = false; + + public bool RemovePlayerHealthUI { get; set; } = false; + + public bool RemovePlayerBattleScoreUI { get; set; } = false; + public bool RemovePlayerScoreUI { get; set; } = false; + public bool RemoveEnemyUI { get; set; } = false; + + public bool RemovePlayerCardUI { get; set; } = false; + public bool RemovePlayerGeki { get; set; } = false; + public bool RemoveAllyGekis { get; set; } = false; + + public bool RemoveCharacterLine { get; set; } = false; + public bool RemoveEnemy { get; set; } = false; + public bool RemoveBoss { get; set; } = false; + + public bool RemoveBullets { get; set; } = false; + + public bool ReducedNoteFX { get; set; } = false; + public bool RemoveNoteFX { get; set; } = false; + + public float BackgroundR { get; set; } = 0f; + public float BackgroundG { get; set; } = 0f; + public float BackgroundB { get; set; } = 0f; + + private bool getValue(IniFile ini, string key) + { + UnityEngine.Debug.Log("Get value for key: " + key); + var value = ini.getValue("Offgeki", key, false); + UnityEngine.Debug.Log("Value: " + value); + return value; + } + private float getColorValue(IniFile ini, string key) + { + UnityEngine.Debug.Log("Get color value for key: " + key); + var value = ini.getValue("Offgeki", key, 0f); + + // Ceiling to 255 + if (value > 255) + { + value = 255; + } + + // Divide by 255 + value = value / 255.0f; + + UnityEngine.Debug.Log("Value: " + value); + return value; + } + + public void Init() + { + UnityEngine.Debug.Log("[Nogeki] Initializing State"); + using IniFile ini = new("mu3.ini"); + RemoveBackground = getValue(ini, "RemoveBackground"); + RemoveBackgroundFrame = getValue(ini, "RemoveBackgroundFrame"); + RemoveHeader = getValue(ini, "RemoveHeader"); + RemoveFooter = getValue(ini, "RemoveFooter"); + RemovePlayerHealthUI = getValue(ini, "RemovePlayerHealthUI"); + RemovePlayerBattleScoreUI = getValue(ini, "RemovePlayerBattleScoreUI"); + RemovePlayerScoreUI = getValue(ini, "RemovePlayerScoreUI"); + RemovePlayerCardUI = getValue(ini, "RemovePlayerCardUI"); + RemoveEnemyUI = getValue(ini, "RemoveEnemyUI"); + RemovePlayerGeki = getValue(ini, "RemovePlayerGeki"); + RemoveAllyGekis = getValue(ini, "RemoveAllyGekis"); + RemoveCharacterLine = getValue(ini, "RemoveCharacterLine"); + RemoveEnemy = getValue(ini, "RemoveEnemy"); + RemoveBoss = getValue(ini, "RemoveBoss"); + RemoveBullets = getValue(ini, "RemoveBullets"); + ReducedNoteFX = getValue(ini, "ReducedNoteFX"); + RemoveNoteFX = getValue(ini, "RemoveNoteFX"); + BackgroundR = getColorValue(ini, "BackgroundR"); + BackgroundG = getColorValue(ini, "BackgroundG"); + BackgroundB = getColorValue(ini, "BackgroundB"); + + UnityEngine.Debug.Log("[Nogeki] State initialized"); + } + + override public string ToString() + { + return "State: \n" + + "\tRemove Background: " + RemoveBackground + "\n" + + "\tRemove Background Frame: " + RemoveBackgroundFrame + "\n" + + "\tRemove Header: " + RemoveHeader + "\n" + + "\tRemove Footer: " + RemoveFooter + "\n" + + "\tRemove Player Health UI: " + RemovePlayerHealthUI + "\n" + + "\tRemove Player Battle Score UI: " + RemovePlayerBattleScoreUI + "\n" + + "\tRemove Player Score UI: " + RemovePlayerScoreUI + "\n" + + "\tRemove Player Card UI: " + RemovePlayerCardUI + "\n" + + "\tRemove Enemy UI: " + RemoveEnemyUI + "\n" + + "\tRemove Player Geki: " + RemovePlayerGeki + "\n" + + "\tRemove Ally Gekis: " + RemoveAllyGekis + "\n" + + "\tRemove Enemy: " + RemoveEnemy + "\n" + + "\tRemove Boss: " + RemoveBoss + "\n" + + "\tRemove Bullets: " + RemoveBullets + "\n" + + "\tRemove Bright Note FX: " + ReducedNoteFX + "\n" + + "\tRemove All Note FX: " + RemoveNoteFX + "\n" + + "\tRemove Character Line: " + RemoveCharacterLine + "\n" + + "\tBackground R: " + BackgroundR + "\n" + + "\tBackground G: " + BackgroundG + "\n" + + "\tBackground B: " + BackgroundB + "\n"; + } +} diff --git a/Extras/Offgeki/MU3.Sequence/patch_PlayMusic.cs b/Extras/Offgeki/MU3.Sequence/patch_PlayMusic.cs new file mode 100644 index 0000000..354949a --- /dev/null +++ b/Extras/Offgeki/MU3.Sequence/patch_PlayMusic.cs @@ -0,0 +1,230 @@ +using UnityEngine; +using MU3.Util; +using MU3.Game; +using UnityEngine.SceneManagement; +using System.Linq; +using System.Collections.Generic; + +namespace MU3.Sequence; + +class patch_PlayMusic : PlayMusic +{ + private SessionInfo _sessionInfo; + //private State _state = State; + private bool _nogeki_removed = false; + private bool _nogeki_enabled = false; + private GameObject _offgeki_bg; + + private void disableEffect(GameObject effect) + { + var childCount = effect.transform.childCount; + effect.transform.DetachChildren(); + effect.transform.localScale = new Vector3(0, 0, 0); + effect.SetActive(false); + } + + private extern void orig_Execute_SetupScene(); + private void Execute_SetupScene() + { + Mod.State state = Singleton.instance; + state.Init(); + orig_Execute_SetupScene(); + + if (state.RemoveBackground && _offgeki_bg == null) + { + // Create a black quad that fills the screen + GameObject bgQuad = GameObject.CreatePrimitive(PrimitiveType.Quad); + bgQuad.name = "OffgekiBackground"; + + // Scale it to cover the view + bgQuad.transform.localScale = new Vector3(10000, 10000, 1); + + // Position it far behind other elements + bgQuad.transform.position = new Vector3(0, 0, 500); + + // Assign the material + bgQuad.GetComponent().material = new(Shader.Find("Unlit/Color")) + { + color = new Color(state.BackgroundR, state.BackgroundG, state.BackgroundB) + }; + _offgeki_bg = bgQuad; + } + + // Remove canvases + SystemUI systemUI = SingletonMonoBehaviour.instance; + List disableCanvases = []; + if (state.RemoveBackground) + { + disableCanvases.Add("Canvas_P_Background"); + disableCanvases.Add("Canvas_P_FadeOut"); + } + + if (state.RemoveHeader) + { + disableCanvases.Add("Canvas_P_UserData"); + disableCanvases.Add("Canvas_P_Signage"); + } + if (state.RemoveFooter) + { + disableCanvases = [ + ..disableCanvases, + "Canvas_P_SystemButton", + "Canvas_P_ButtonGuide", + "Canvas_P_Credit" + ]; + } + + + foreach (var item in systemUI.GetComponentsInChildren()) + { + if (!item.enabled) continue; + if (disableCanvases.Contains(item.name)) + { + item.enabled = false; + } + } + + string name = $"st_{_sessionInfo.stageId:0000}"; + Scene sceneByName = SceneManager.GetSceneByName(name); + GameObject[] rootObjects = sceneByName.GetRootGameObjects(); + foreach (var obj in rootObjects) + { + if (obj.name == "BattleStage(Clone)" && state.RemoveBackgroundFrame) + { + obj.SetActive(false); + continue; + } + + + if (obj.name == "NotesPrimitiveManager(Clone)") + { + PrimitiveMesh[] childs = obj.GetComponentsInChildren(); + for (int i = 0; i < childs.Length; i++) + { + if (i == 2) + { + PrimitiveMesh child = childs[i]; + child.gameObject.SetActive(false); + } + } + } + + } + + List disableCharacterLines = state.RemoveCharacterLine ? [ + "fd_charaline", + "fd_charaline(Clone)", + "fd_charapole", + "fd_charapole (1)", + "fd_charazone", + "fd_checkpole", + "fd_checkpole (1)", + "fd_zonetry", + ] : []; + + List disableBullets = state.RemoveBullets ? [ + "FX_Bullet_03_Hit(Clone)", + "FX_Bullet_03_Break(Clone)", + "FX_Bullet_03_CBreak(Clone)", + "FX_Bullet_02_Hit(Clone)", + "FX_Bullet_02_Break(Clone)", + "FX_Bullet_02_CBreak(Clone)", + "FX_Bullet_Hit(Clone)", + "FX_Bullet_Break(Clone)", + "FX_Bullet_CBreak(Clone)", + ] : []; + + List disableHitFX = state.RemoveNoteFX ? [ + "EffectCache_attachBell", + + "EffectCache_flickHit", + "EffectCache_flickBreak", + "EffectCache_flickCBreak", + "EffectCache_flickPBreak", + + "EffectCache_crFlickHit", + "EffectCache_crFlickBreak", + "EffectCache_crFlickCBreak", + "EffectCache_crFlickPBreak", + + "EffectCache_normalHit", + "EffectCache_normalBreak", + "EffectCache_normalCBreak", + "EffectCache_normalPBreak", + + "EffectCache_holdEndHit", + "EffectCache_holdEndBreak", + "EffectCache_holdEndCBreak", + "EffectCache_holdEndPBreak", + "EffectCache_holdKeep", + + "FX_Tap_PBreak(Clone)", + "FX_Tap_CBreak(Clone)", + "FX_Tap_Break(Clone)", + "FX_Tap_Hit(Clone)", + "FX_Release_PBreak(Clone)", + ] : []; + + List reducedNoteFX = state.ReducedNoteFX ? [ + "EffectCache_holdEndCBreak", + "EffectCache_holdEndPBreak", + "EffectCache_holdKeep", + + + "EffectCache_crFlickPBreak", + + "EffectCache_flickPBreak", + ] : []; + + List disableBulletFX = state.RemoveBullets ? [ + "hitZako", + "criticalZako", + "explosionZako", + "EffectCache_explosionZako", + "EffectCache_hitZako", + "EffectCache_criticalZako", + + "hitBoss", + "criticalBoss", + "explosionBoss", + "EffectCache_explosionBoss", + "EffectCache_hitBoss", + "EffectCache_criticalBoss", + ] : []; + + List disableNames = [ + ..disableCharacterLines, + ..disableBullets, + ..disableHitFX, + ..reducedNoteFX, + ..disableBulletFX, + ]; + + + + Transform[] arrTransforms = Resources.FindObjectsOfTypeAll().Where((s) => (s.hideFlags == HideFlags.None)).ToArray(); + for (int i = 0; i < arrTransforms.Length; i++) + { + //UnityEngine.Debug.Log($"[Nogeki] Transform: {arrTransforms[i].name}"); + if (disableNames.Contains(arrTransforms[i].name)) + { + disableEffect(arrTransforms[i].gameObject); + } + } + } + + private extern void orig_Enter_DispCombo(); + private void Enter_DispCombo() + { + SystemUI systemUI = SingletonMonoBehaviour.instance; + foreach (var item in systemUI.GetComponentsInChildren()) + { + if (item.enabled) continue; + + item.enabled = true; + } + orig_Enter_DispCombo(); + } + + +} \ No newline at end of file diff --git a/Extras/Offgeki/MU3/patch_ANM_PLY_score.cs b/Extras/Offgeki/MU3/patch_ANM_PLY_score.cs new file mode 100644 index 0000000..b3c4d5c --- /dev/null +++ b/Extras/Offgeki/MU3/patch_ANM_PLY_score.cs @@ -0,0 +1,24 @@ +using MU3.CustomUI; +using MU3.Util; +using UnityEngine; + +namespace MU3; + +class patch_ANM_PLY_score : ANM_PLY_score +{ + private GameObject _baseBattleScore; + private MU3UICounter[] _scoreCountersMU3; + + extern private void orig_Awake(); + private void Awake() + { + orig_Awake(); + + + if (Singleton.instance.RemovePlayerBattleScoreUI) + { + _baseBattleScore.SetActive(value: false); + _scoreCountersMU3[0].gameObject.SetActive(value: false); + } + } +} diff --git a/Extras/Offgeki/MU3/patch_BattleUI.cs b/Extras/Offgeki/MU3/patch_BattleUI.cs new file mode 100644 index 0000000..aff9d23 --- /dev/null +++ b/Extras/Offgeki/MU3/patch_BattleUI.cs @@ -0,0 +1,53 @@ +using MU3.Util; +using UnityEngine; +using System.Collections.Generic; + +namespace MU3; + +public class patch_BattleUI : BattleUI +{ + private extern void orig_Awake(); + public extern void orig_dispFinish(); + + private void Awake() + { + orig_Awake(); + + Mod.State state = Singleton.instance; + state.Init(); + + List disabled = []; + if (state.RemoveBackground) + { + disabled.Add("CVS_SurfBoard3D"); + } + + if (state.RemoveEnemyUI) + { + disabled.Add("CVS_PLY_EnemyDamage"); + disabled.Add("CVS_PLY_Enemyinfo_00"); + } + + if (state.RemovePlayerCardUI) + { + disabled.Add("CVS_PLY_Cardinfo_00"); + } + + foreach (var item in GetComponentsInChildren()) + { + if (item.enabled && disabled.Contains(item.name)){ + item.enabled = false; + } + } + } + + public void dispFinish() + { + foreach (var item in GetComponentsInChildren()) + { + item.enabled = true; + } + + orig_dispFinish(); + } +} diff --git a/Extras/Offgeki/MU3/patch_UIPlayerInfo.cs b/Extras/Offgeki/MU3/patch_UIPlayerInfo.cs new file mode 100644 index 0000000..e67eedb --- /dev/null +++ b/Extras/Offgeki/MU3/patch_UIPlayerInfo.cs @@ -0,0 +1,17 @@ +using MU3.Util; + +namespace MU3; +class patch_UIPlayerInfo : UIPlayerInfo +{ + private ANM_PLY_life _playerLife; + extern private void orig_create(); + private new void create() + { + orig_create(); + + if(Singleton.instance.RemovePlayerHealthUI) + { + _playerLife.gameObject.SetActive(false); + } + } +} diff --git a/Extras/Offgeki/Offgeki.csproj b/Extras/Offgeki/Offgeki.csproj new file mode 100644 index 0000000..562443d --- /dev/null +++ b/Extras/Offgeki/Offgeki.csproj @@ -0,0 +1,9 @@ + + + Assembly-CSharp.Offgeki.mm + Modular removal of UI elements + 1.0.0 + extras + + + \ No newline at end of file diff --git a/Extras/Offgeki/README.md b/Extras/Offgeki/README.md new file mode 100644 index 0000000..42f88af --- /dev/null +++ b/Extras/Offgeki/README.md @@ -0,0 +1,120 @@ +# Offgeki + +Modular removal of UI elements. +Currently only supports removing elements during music play. +Potentially will support removing elements during other parts of the game. + +## Features +- Remove various UI elements during music play + - Background + - Player UI Elements + - Health + - Battle Score + - Technical Score + - Enemy UI Elements + - Health + - Bullets + - Gekis (enemies, boss, player, allies) + - NoteFX + +## Installation + +1. Install BepInEx +2. Drop the `Assembly-CSharp.Offgeki.mm.dll` file into the `BepInEx/monomod` folder +3. Launch the game + +## Configuration +Populate these values in `mu3.ini` to configure the mod. + +``` +[Offgeki] +RemoveBackground = 1 +RemoveBackgroundFrame = 1 +RemoveSignage = 1 +RemovePlayerHealthUI = 1 +RemovePlayerBattleScoreUI = 1 +RemovePlayerScoreUI = 0 +RemovePlayerCardUI = 1 +RemoveEnemyUI = 1 +RemovePlayerGeki = 1 +RemoveAllyGekis = 0 +RemoveCharacterLine = 1 +RemoveEnemy = 1 +RemoveBoss = 0 +RemoveBullets = 1 +ReducedNoteFX = 1 +RemoveNoteFX = 0 +BackgroundR = 25 +BackgroundG = 25 +BackgroundB = 25 +``` + +## Details + +### RemoveBackground +Removes the background. A blue frame is still present, but the background is removed. + +### RemoveBackgroundFrame +Removes the blue framing in the background + +### RemoveSignage +Removes the header and footer sections + +### RemovePlayerHealthUI +Removes the player's health + +### RemovePlayerBattleScoreUI +Removes the player's battle score + +### RemovePlayerScoreUI +Removes the player's technical score + +### RemovePlayerCardUI +Removes the player/ally card UI + +### RemoveEnemyUI +Removes the enemy's health + +### RemovePlayerGeki +Removes the player's geki + +### RemoveAllyGekis +Removes the ally's gekis +(Currently does not allow no player and allies) + +### RemoveCharacterLine +Removes the lines and area rendering underneath player characters. +Retains the note judgement line. + +### RemoveEnemy +Removes the enemies (Zekos) + +### RemoveBoss +Removes the boss + +### RemoveBullets +Removes the bullets + +### ReducedNoteFX +Reduces the note FX a bit by disabling a few FX but not all + +### RemoveNoteFX +Removes all note FX + +### BackgroundR +Background color red value + +### BackgroundG +Background color green value + +### BackgroundB +Background color blue value + + +## Known Issues +- Unable to show only allies and not primary character. Probably due to the allies being anchored to the primary character. +- Some stages have background overlay that color the background a bit differently. +- Signage doesn't return after play. Will need to revise when the canvas's are reactivated. +- Need to fix player damage effect + + diff --git a/Mu3Mods.sln b/Mu3Mods.sln index ad62f07..5873546 100644 --- a/Mu3Mods.sln +++ b/Mu3Mods.sln @@ -52,6 +52,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestMenuConfig", "Extras\Te EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ExclusiveAudio", "Fixes\ExclusiveAudio\ExclusiveAudio.csproj", "{0043743F-24B5-4A39-838E-964091AC7FF1}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Offgeki", "Extras\Offgeki\Offgeki.csproj", "{A052743F-24B5-4A39-838E-964091AC7FF1}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x64 = Debug|x64 @@ -158,6 +160,10 @@ Global {0043743F-24B5-4A39-838E-964091AC7FF1}.Debug|x64.Build.0 = Debug|x64 {0043743F-24B5-4A39-838E-964091AC7FF1}.Release|x64.ActiveCfg = Release|x64 {0043743F-24B5-4A39-838E-964091AC7FF1}.Release|x64.Build.0 = Release|x64 + {A052743F-24B5-4A39-838E-964091AC7FF1}.Debug|x64.ActiveCfg = Debug|x64 + {A052743F-24B5-4A39-838E-964091AC7FF1}.Debug|x64.Build.0 = Debug|x64 + {A052743F-24B5-4A39-838E-964091AC7FF1}.Release|x64.ActiveCfg = Release|x64 + {A052743F-24B5-4A39-838E-964091AC7FF1}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE