@@ -4,7 +4,9 @@ import backend.Song;
44import flixel .FlxObject ;
55import flixel .input .keyboard .FlxKey ;
66import flixel .tweens .misc .NumTween ;
7+ import flixel .util .FlxColor ;
78import flixel .util .FlxDestroyUtil ;
9+ import managers .FreeplayManager ;
810import objects .* ;
911import objects .Character ;
1012import objects .Note ;
@@ -14,6 +16,9 @@ import openfl.filters.BlurFilter;
1416import openfl .filters .ColorMatrixFilter ;
1517import shaders .MosaicEffect ;
1618import stages .StageData ;
19+ import states .PlayState ;
20+ import states .freeplay .FreeplayState ;
21+ import states .freeplay .OsuFreeplayState ;
1722import streamervschat .* ;
1823
1924using yutautil .Table ;
@@ -52,6 +57,9 @@ class APPlayState extends PlayState {
5257 private var lastDifficultyName : String = ' ' ;
5358 private var invulnCount : Int = 0 ;
5459 private var debugKeysDodge : Array <FlxKey >;
60+
61+ // Song unlock system
62+ private var songNotUnlocked : Bool = false ;
5563 // private var unBlurShaderRestore:Map<Dynamic, Dynamic> = new Map<Dynamic, Dynamic>();
5664 var curDifficulty : Int = - 1 ;
5765 var effectsActive : Map <String , Int > = new Map <String , Int >();
@@ -152,6 +160,64 @@ class APPlayState extends PlayState {
152160 allowDebugKeys = false ;
153161 lives = livecount ;
154162
163+ // Check if the current song/mod is unlocked; if not, set flag and show info panel
164+ if (APEntryState .inArchipelagoMode )
165+ {
166+ var found = false ;
167+ for (entry in APFreeplayManager .curUnlocked )
168+ {
169+ if (entry .song == currentSong && entry .mod == currentMod )
170+ {
171+ found = true ;
172+ break ;
173+ }
174+ }
175+ if (! found ) {
176+ songNotUnlocked = true ;
177+ // Show info panel immediately
178+ showUnlockInfoPanel ();
179+ return ;
180+ }
181+ }
182+
183+ if (FlxG .save .data .manualOverride != null && FlxG .save .data .manualOverride )
184+ {
185+ // When manual override is active, ensure we're playing the correct saved song
186+ trace (' Manual Override detected - verifying song consistency' );
187+
188+ var savedSong = FlxG .save .data .SONG ;
189+ var currentSong = PlayState .SONG ;
190+
191+ // Check if the current song matches the saved song
192+ if (savedSong != null && currentSong != null ) {
193+ var songMismatch = (savedSong .song != currentSong .song ||
194+ FlxG .save .data .storyWeek != PlayState .storyWeek ||
195+ FlxG .save .data .currentModDirectory != Mods .currentModDirectory ||
196+ FlxG .save .data .storyDifficulty != PlayState .storyDifficulty );
197+
198+ if (songMismatch ) {
199+ trace (' Song mismatch detected during manual override' );
200+ trace (' Expected: ' + savedSong .song + ' (Week: ' + FlxG .save .data .storyWeek + ' , Mod: ' + FlxG .save .data .currentModDirectory + ' )' );
201+ trace (' Current: ' + currentSong .song + ' (Week: ' + PlayState .storyWeek + ' , Mod: ' + Mods .currentModDirectory + ' )' );
202+
203+ // Restore the correct song state and force a reset
204+ PlayState .storyWeek = FlxG .save .data .storyWeek ;
205+ Mods .currentModDirectory = FlxG .save .data .currentModDirectory ;
206+ Difficulty .list = FlxG .save .data .difficulties ;
207+ curDifficulty = FlxG .save .data .curDifficulty ;
208+ PlayState .SONG = FlxG .save .data .SONG ;
209+ PlayState .storyDifficulty = FlxG .save .data .storyDifficulty ;
210+
211+
212+
213+ trace (' Song state corrected - resetting APPlayState' );
214+ StageData .loadDirectory (PlayState .SONG );
215+ MusicBeatState .resetState ();
216+ return ;
217+ }
218+ }
219+ }
220+
155221 instance = this ; // For traps and items
156222 if (APEntryState .inArchipelagoMode )
157223 {
@@ -187,18 +253,7 @@ class APPlayState extends PlayState {
187253 return ;
188254 }
189255
190- if (archipelago. APInfo .inMinigame != None )
191- {
192- switch (archipelago. APInfo .inMinigame ) {
193- case Uno :
194- FlxG .switchState (new archipelago.traps.games. APUnoTrapState ());
195- return ;
196- case Pong :
197- FlxG .switchState (new archipelago.traps.games. APPongTrapState ());
198- return ;
199- case None :
200- }
201- }
256+
202257 {
203258
204259 }
@@ -1458,6 +1513,12 @@ class APPlayState extends PlayState {
14581513
14591514 override public function startCountdown (): Bool
14601515 {
1516+ // Prevent countdown if song is not unlocked
1517+ if (songNotUnlocked ) {
1518+ // trace("Countdown blocked: Song not unlocked");
1519+ return false ;
1520+ }
1521+
14611522 if (PlayState .SONG .player1 .toLowerCase ().contains (' zenetta' ) || PlayState .SONG .player2 .toLowerCase ().contains (' zenetta' ) || PlayState .SONG .gfVersion .toLowerCase ().contains (' zenetta' ))
14621523 {
14631524 itemAmount = 69 ;
@@ -1570,6 +1631,27 @@ class APPlayState extends PlayState {
15701631 }
15711632 }
15721633
1634+ function showUnlockInfoPanel () {
1635+ var songDisplayName = currentSong != null && currentSong != " " ? currentSong : " this song" ;
1636+ var modDisplayName = currentMod != null && currentMod != " " ? " from " + currentMod : " " ;
1637+
1638+ var content = " You haven't unlocked " + songDisplayName + modDisplayName + " yet.\\ n\\ n" +
1639+ " Complete more checks in the Archipelago\\ nmultiworld to unlock new songs!\\ n\\ n" +
1640+ " Press ESC or ENTER to return to Freeplay." ;
1641+
1642+ archipelago.substates. InfoPanelSubstate .show (
1643+ " SONG LOCKED" ,
1644+ content ,
1645+ FlxColor .RED ,
1646+ returnToFreeplay
1647+ );
1648+ }
1649+
1650+ function returnToFreeplay () {
1651+ // Use FreeplayManager's built-in method to return to freeplay
1652+ FreeplayManager .openFreeplay ();
1653+ }
1654+
15731655 override function destroy ()
15741656 {
15751657 if (drunkTween != null && drunkTween .active )
@@ -1950,24 +2032,42 @@ class APPlayState extends PlayState {
19502032 var doRandomize : Bool = false ;
19512033 override public function update (elapsed : Float )
19522034 {
2035+
2036+ if (archipelago. APInfo .inMinigame != None )
2037+ {
2038+ // Save current state before switching to minigame
2039+ if (APEntryState .apGame != null ) {
2040+ APEntryState .apGame .updateSaveData ();
2041+ }
2042+
2043+ switch (archipelago. APInfo .inMinigame ) {
2044+ case Uno :
2045+ FlxG .switchState (new archipelago.traps.games. APUnoTrapState ());
2046+ return ;
2047+ case Pong :
2048+ FlxG .switchState (new archipelago.traps.games. APPongTrapState ());
2049+ return ;
2050+ case None :
2051+ }
2052+ }
19532053 // If Legacy Lua settings are being edited, don't allow AP PlayState during gameplay
19542054 // This prevents conflicts but doesn't interrupt mid-song
19552055 if (options.legacylua. LegacyLuaSettingsState .inLegacyLuaSettingsMode && ! startedCountdown ) {
19562056 // Only switch if we haven't started the song yet to avoid interrupting gameplay
1957- FlxG .switchState (new states. PlayState ());
2057+ FlxG .switchState (new PlayState ());
19582058 return ;
19592059 }
19602060
19612061 // If we're in Legacy Lua testing mode, switch to regular PlayState
1962- if (states. PlayState .isLegacyLuaTest && ! startedCountdown ) {
1963- FlxG .switchState (new states. PlayState ());
2062+ if (PlayState .isLegacyLuaTest && ! startedCountdown ) {
2063+ FlxG .switchState (new PlayState ());
19642064 return ;
19652065 }
19662066
1967- if (zenetta .holdTimer > Conductor .stepCrochet * 0.001 * zenetta .singDuration
1968- && zenetta .animation .curAnim .name .startsWith (' sing' )
1969- && ! zenetta .animation .curAnim .name .endsWith (' miss' ))
1970- zenetta .dance ();
2067+ if (zenetta ? .holdTimer > Conductor .stepCrochet * 0.001 * zenetta ? .singDuration
2068+ && zenetta ? .animation .curAnim .name .startsWith (' sing' )
2069+ && ! zenetta ? .animation .curAnim .name .endsWith (' miss' ))
2070+ zenetta ? .dance ();
19712071
19722072 // if (archipelago.APItem.activeItem is archipelago.APItem.APChartModifier && cast(archipealgo.APItem.activeItem:archipelago.APItem.APChartModifier).chartModifier != chartModifier)
19732073 //
@@ -2614,11 +2714,12 @@ class APPlayState extends PlayState {
26142714 if (note .isSustainNote )
26152715 {
26162716 var holdAnim : String = animToPlay + ' -hold' ;
2617- if (zenetta .animation .exists (holdAnim )) animToPlay = holdAnim ;
2717+ if (zenetta ? .animation .exists (holdAnim )) animToPlay = holdAnim ;
26182718 }
26192719
2620- zenetta .playAnim (animToPlay , true );
2720+ zenetta ? .playAnim (animToPlay , true );
26212721 zenetta .holdTimer = 0 ;
2722+ " e" .GoToTag ();
26222723 }
26232724 }
26242725
@@ -2770,8 +2871,8 @@ class APPlayState extends PlayState {
27702871 if (releasethebeast ) {
27712872 if (resistanceAmount < 1 ) resistanceAmount + = 0.005 ;
27722873
2773- if (curBeat % zenetta .danceEveryNumBeats == 0 && ! zenetta .getAnimationName ().endsWith (' -alt' )) {
2774- zenetta .dance ();
2874+ if (curBeat % zenetta ? .danceEveryNumBeats == 0 && ! zenetta ? .getAnimationName ().endsWith (' -alt' )) {
2875+ zenetta ? .dance ();
27752876 }
27762877 }
27772878 super .beatHit ();
0 commit comments