Files
blockout/BlockOutReplica/Assets/Scripts/Gameplay/BlockOutFullLoopReview.cs
T
2026-10-20 13:21:04 +08:00

121 lines
8.2 KiB
C#

#if UNITY_EDITOR
using System;
using System.Collections;
using BlockOutReplica.Infrastructure;
using UnityEngine;
namespace BlockOutReplica.Gameplay
{
public sealed partial class BlockOutGameController
{
private BlockOutProgress savedLoopProgress;
private BlockOutPlayerState savedLoopPlayer;
private BlockOutJourney savedLoopJourney;
private BlockOutEconomy savedLoopEconomy;
private bool savedLoopHome;
private bool savedLoopJourneyTab;
private string savedLoopJourneyNotice;
private int savedLoopCelebrationLevel;
private float savedLoopCelebrationTime;
public bool IsManualLoopSandbox { get; private set; }
public bool IsFullLoopSandbox => savedLoopProgress!=null;
public void BeginFullLoopSandbox(bool manual=false)
{
if(IsFullLoopSandbox) return;
savedLoopProgress=progress;savedLoopPlayer=Player;savedLoopJourney=Journey;savedLoopEconomy=economy;
savedLoopHome=ScreenState==BlockOutScreenState.Home;
savedLoopJourneyTab=JourneyTab;savedLoopJourneyNotice=JourneyNotice;
savedLoopCelebrationLevel=JourneyCelebrationLevel;savedLoopCelebrationTime=JourneyCelebrationStartedAt;
IsManualLoopSandbox=manual;
economy=BlockOutEconomy.Load(); economy.InitialUfoAmount=30;economy.InitialRocketAmount=30;
player=new BlockOutPlayerState(economy,"",_=>{});
journey=new BlockOutJourney(BlockOutJourneyConfig.Load(),"",_=>{});
// Controlled Home fixture at 9 exercises the exact win-9 -> current10
// native boundary; it does not claim original early Home accessibility.
progress=new BlockOutProgress(OriginalFlowRepository.Load(),false,9);
InitializeInteractions();LoadCurrentLevel();GoHome();
Debug.Log("BLOCKOUT_FULL_LOOP_SANDBOX: started, level=9, isolatedSaves=True");
}
public void RestoreFullLoopSandbox()
{
if(!IsFullLoopSandbox)return;
progress=savedLoopProgress;player=savedLoopPlayer;journey=savedLoopJourney;economy=savedLoopEconomy;
savedLoopProgress=null;savedLoopPlayer=null;savedLoopJourney=null;savedLoopEconomy=null;
IsManualLoopSandbox=false;
IsFirstTwentyPreview=false;
InitializeInteractions();LoadCurrentLevel();if(savedLoopHome)GoHome(false);
JourneyTab=savedLoopJourneyTab;JourneyNotice=savedLoopJourneyNotice;
JourneyCelebrationLevel=savedLoopCelebrationLevel;JourneyCelebrationStartedAt=savedLoopCelebrationTime;
JourneyRevision++;
Debug.Log("BLOCKOUT_FULL_LOOP_SANDBOX: restored, persistentPlayerDataUntouched=True");
}
public IEnumerator ReviewFullLoop()
{
if(IsFullLoopSandbox)throw new InvalidOperationException("Restore manual sandbox before running automated review.");
int checks=0; Action<bool,string> check=(ok,name)=>{if(!ok)throw new InvalidOperationException(name);checks++;};
BeginFullLoopSandbox();
try
{
check(ScreenState==BlockOutScreenState.Home&&LevelNumber==9,"controlled Home fixture at level 9");
RequestEnterLevel(); check(Modal==GameModal.PreLevel,"pre-level");
EnterPreparedLevel();IsInputReviewRunning=true;yield return null;
check(pieces.Count>0&&LevelNumber==9,"real level 9 loaded");
ClickBooster(BoosterType.Freeze);check(Player.Amount(BoosterType.Freeze)==2&&FreezeRemaining==10,"freeze activated");
yield return WaitReviewCondition(()=>FreezeAnimationTime>=.42f,"freeze pose");
CaptureLoop("freeze");yield return null;
yield return WaitReviewCondition(()=>FreezeAnimationTime>=2.3f,"ice clock pose");
check(HasNativeFreezeScreen&&ActiveFreezeParticleCount>0,"native freeze screen and ice particles visible");
CaptureLoop("freeze-clock");yield return null;
RequestPause();float frozenAnimation=FreezeAnimationTime;int frozenParticles=ActiveFreezeParticleCount;
yield return WaitReviewTime(.25f);
check(FreezeAnimationTime==frozenAnimation&&ActiveFreezeParticleCount==frozenParticles,"native freeze particles pause");CloseModal();
yield return WaitReviewCondition(()=>FreezeRemaining<=0&&!HasNativeFreezeScreen,"freeze end cleanup");
check(ActiveFreezeParticleCount==0,"ice effect expires and cleans up");
ClickBooster(BoosterType.Rocket);
var target=pieces[0];BeginDrag(gameCamera.WorldToScreenPoint(target.transform.position),gameCamera);
yield return WaitReviewCondition(()=>BoosterPlaybackTime>=.2f,"rocket entry pose");CaptureLoop("rocket-entry");yield return null;
RequestPause();float time=TimeLeft;yield return WaitReviewTime(.25f);
check(TimeLeft==time&&InputLocked,"effect and timer paused");CloseModal();
yield return WaitReviewCondition(()=>BoosterPlaybackTime>=1.45f,"rocket impact pose");
check(ActiveBoosterParticleCount>0,"native rocket impact particles emitted");CaptureLoop("rocket-impact");yield return null;
while(InputLocked&&ScreenState==BlockOutScreenState.Playing)yield return null;
check(target==null&&activeExits==0,"rocket impact retired target");
int guard=0;
while(ScreenState==BlockOutScreenState.Playing&&pieces.Count>0&&guard++<12)
{
ClickBooster(BoosterType.Ufo);target=pieces[0];
BeginDrag(gameCamera.WorldToScreenPoint(target.transform.position),gameCamera);
yield return WaitReviewCondition(()=>BoosterPlaybackTime>=1.55f,"ufo absorption pose");CaptureLoop("ufo-absorb");yield return null;
yield return WaitReviewCondition(()=>BoosterPlaybackTime>=1.85f,"ufo beam pose");
check(ActiveBoosterParticleCount>0,"native UFO beam particles emitted");CaptureLoop("ufo-beam");yield return null;
while(InputLocked&&ScreenState==BlockOutScreenState.Playing)yield return null;
}
check(ScreenState==BlockOutScreenState.LevelComplete,"actual board clear, no debug win");
check(LevelNumber==10&&Player.Coins==1020&&Journey.IsQueued(10)&&!Journey.IsClaimed(10),"win 9 pays ordinary20 and queues Journey50");
CaptureLoop("win");yield return null;ContinueAfterWin();
check(ScreenState==BlockOutScreenState.Home&&LevelNumber==10,"returned Home at current level 10");
check(Journey.IsClaimed(10)&&!Journey.IsQueued(10)&&Player.Coins==1070,"source level 10 reward automatically received");
ClaimJourneyReward(10);ClaimJourneyReward(10);
check(Player.Coins==1070&&Journey.IsClaimed(10),"repeated settlement cannot duplicate 50 coins");
OpenHomeTab(true);
CaptureLoop("journey-claimed");yield return null;
OpenHomeTab(false);CaptureLoop("home");yield return null;
RequestEnterLevel();EnterPreparedLevel();IsInputReviewRunning=true;yield return null;
check(ScreenState==BlockOutScreenState.Playing&&LevelNumber==10,"current level 10 enters from Home");
Debug.Log($"BLOCKOUT_FULL_LOOP_REVIEW: passed=True, checks={checks}, realBoardClear=True, debugWin=False, persistentPlayerDataUntouched=True");
}
finally{RestoreFullLoopSandbox();}
}
private IEnumerator WaitReviewTime(float seconds)
{float end=Time.realtimeSinceStartup+seconds;while(Time.realtimeSinceStartup<end)yield return null;}
private IEnumerator WaitReviewCondition(Func<bool> condition,string name)
{
float end=Time.realtimeSinceStartup+45;
while(!condition()) {if(Time.realtimeSinceStartup>end)throw new InvalidOperationException("Timed out: "+name);yield return null;}
}
private static void CaptureLoop(string suffix)
{System.IO.Directory.CreateDirectory("Docs/iterations");ScreenCapture.CaptureScreenshot("Docs/iterations/2026-10-19-full-loop-"+suffix+".png");}
}
}
#endif