using MonoMod; using MU3.Battle; using MU3.Game; using MU3.Notes; using MU3.Util; using System; using System.Collections; using System.Reflection; using UnityEngine; namespace MU3.Sequence; class patch_PlayMusic: PlayMusic { private static readonly TimeSpan HOLD_DURATION = TimeSpan.FromSeconds(0.67f); public double TargetFrame { get; set; } = 0f; [MonoModIgnore] private patch_NotesManager ntMgr => null; private GameEngine _gameEngine; private SessionInfo _sessionInfo; private bool _isForceEndBattle; private bool _isRolling; private bool _isHoldingAck; private DateTime _holdingStartTime; [MonoModIgnore] private extern bool isPartyPlay(); private extern void orig_Execute_Play(); private void Execute_Play() { if(isPartyPlay() || _sessionInfo.isTutorial) { orig_Execute_Play(); return; } if(_isRolling) { return; } if(Singleton.instance.getTriggerOn(UIInput.Key.MenuLeft) || Singleton.instance.getTriggerOn(UIInput.Key.MenuRight)) { _holdingStartTime = CustomDateTime.Now; _isHoldingAck = true; } if(_isHoldingAck && (Singleton.instance.getStateOn(UIInput.Key.MenuLeft) || Singleton.instance.getStateOn(UIInput.Key.MenuRight))) { if(CustomDateTime.Now - _holdingStartTime > HOLD_DURATION) { if(Singleton.instance.getStateOn(UIInput.Key.MenuRight)) { restartPlay(shouldRoll: true); } else { skipPlay(); } } } else { _isHoldingAck = false; } orig_Execute_Play(); } private extern void orig_Execute_DispCombo(); private void Execute_DispCombo() { orig_Execute_DispCombo(); if(Singleton.instance.getStateOn(UIInput.Key.MenuRight) && ntMgr.retireResult != RetireResult.None && !isPartyPlay()) { restartPlay(shouldRoll: false); _gameEngine.battleUI.skipDispRetireResult(); setNextState(EState.Play); } } private extern void orig_Execute_DispFinish(); private void Execute_DispFinish() { orig_Execute_DispFinish(); if(Singleton.instance.getStateOn(UIInput.Key.MenuRight) && ntMgr.retireResult != RetireResult.None && !isPartyPlay()) { ntMgr.stopPlay(); ntMgr.setPause(false); _gameEngine.reset(); Singleton.instance.gameBGM.stop(); setNextState(EState.Init); } } private void restartPlay(bool shouldRoll) { _isHoldingAck = false; _gameEngine.destroyAllies(); ntMgr.forceRecover(recover: 100); Singleton.instance.gameBGM.stop(); if(shouldRoll) { _isRolling = true; _gameEngine.StartCoroutine(roll()); } else { finishRestart(); } } private void finishRestart() { _isForceEndBattle = false; ntMgr.stopPlay(); ntMgr.setPause(false); ntMgr.reset(); // This has to go first or otherwise enemies will shrink _gameEngine.createPlayers(); _gameEngine.counters.reset(); _gameEngine.enemyManager.destroy(); ntMgr.reloadScore(_gameEngine.IsStageDazzling); _gameEngine.battleReward.initialize(_sessionInfo); _gameEngine.enemyManager.initialize(); _gameEngine.reset(); double targetMs = TargetFrame * 16.6666667; ntMgr.startPlay((float)targetMs); ntMgr.led.setGameColor(true); Singleton.instance.gameBGM.playMusic(_sessionInfo.musicData, (int)Math.Round(targetMs)); } private IEnumerator roll() { static float fadeOut(float progress, float min, float max) => min + (max - min) * (1f - Mathf.Pow(1f - progress, 2f)); static float fadeIn(float progress, float min, float max) => min + (max - min) * Mathf.Pow(progress, 2f); FieldInfo fi = typeof(Player).GetField("_object", BindingFlags.Instance | BindingFlags.NonPublic); var po = (PlayerObject)fi.GetValue(_gameEngine.player); var control = (patch_PlayerControl)po.control; po.leaveField(); var enemyPos = ntMgr.getEnemyPos(); var playerPos = control._playPosition; var rollingStartFrame = ntMgr.getCurrentFrame(); var rollingStartTime = CustomDateTime.Now; var rollDuration = TimeSpan.FromSeconds( Math.Max(0.5, Math.Sqrt(Math.Abs(rollingStartFrame - TargetFrame) * 16.6666667) / 300.0) ); while(_isRolling) { TimeSpan timeSpan = CustomDateTime.Now - rollingStartTime; if(timeSpan <= rollDuration) { float frame = (float)(timeSpan.TotalMilliseconds / rollDuration.TotalMilliseconds); float num1 = fadeOut(frame, 0f, 1f); float num2 = fadeIn(frame, 0f, 1f); ntMgr.setFrameForce(rollingStartFrame + ((float)TargetFrame - rollingStartFrame) * num1); ntMgr.EnemyPositionForce = new Vector3(enemyPos.x, enemyPos.y + num2 * 215f, enemyPos.z + num2 * 1600f); control._playPosition = new Vector3(playerPos.x, playerPos.y, playerPos.z - num2 * 10f); } else { _isRolling = false; ntMgr.EnemyPositionForce = null; finishRestart(); yield break; } yield return new WaitForEndOfFrame(); } } private void skipPlay() { Singleton.instance.SkipPlay = true; setNextState(EState.End); destroy(); ntMgr.stopPlay(); _gameEngine.destroyAllies(); _gameEngine.finishGame(); _gameEngine.playFinish(); } }