Skip to content

Commit ff07e25

Browse files
committed
Merge branch 'AP-CustomEx' of https://github.com/Z11Coding/Mixtape-Engine-Rework into AP-CustomEx
2 parents dd76016 + a54d501 commit ff07e25

20 files changed

+887
-288
lines changed

source/archipelago/APInfo.hx

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,8 @@ typedef APSlotDataType = {
2424
songData: Map<String, SongDetailData>,
2525
?custom_weeks: Dynamic, // Custom weeks data from HScript processing
2626
?song_modifications: Dynamic, // Song additions/exclusions data
27-
?unoColorsUsed:Array<{name:String, color_code:String}> // Uno mod colors used in the slot
27+
?unoColorsUsed:Array<{name:String, color_code:String}>, // Uno mod colors used in the slot
28+
?highQualityExpected: Bool // Whether high quality trap content is expected to be available
2829
}
2930

3031
abstract APSlotData(APSlotDataType) from APSlotDataType to APSlotDataType {
@@ -42,7 +43,8 @@ abstract APSlotData(APSlotDataType) from APSlotDataType to APSlotDataType {
4243
selectedSongs: [],
4344
songData: new Map<String, SongDetailData>(),
4445
custom_weeks: null,
45-
song_modifications: null
46+
song_modifications: null,
47+
highQualityExpected: false
4648
};
4749
}
4850

@@ -60,6 +62,7 @@ abstract APSlotData(APSlotDataType) from APSlotDataType to APSlotDataType {
6062
public var custom_weeks(get, never):Dynamic;
6163
public var song_modifications(get, never):Dynamic;
6264
public var unoColorsUsed(get, never):Array<{name:String, color_code:String}>;
65+
public var highQualityExpected(get, never):Bool;
6366

6467
private function get_deathLink():Bool return this.deathLink;
6568
private function get_fullSongCount():Int return this.fullSongCount;
@@ -75,6 +78,7 @@ abstract APSlotData(APSlotDataType) from APSlotDataType to APSlotDataType {
7578
private function get_custom_weeks():Dynamic return this.custom_weeks;
7679
private function get_song_modifications():Dynamic return this.song_modifications;
7780
private function get_unoColorsUsed():Array<{name:String, color_code:String}> return this.unoColorsUsed;
81+
private function get_highQualityExpected():Bool return this.highQualityExpected != null ? this.highQualityExpected : false;
7882

7983
public function get(key:String):Dynamic {
8084
return Reflect.field(this, key);

source/archipelago/APItem.hx

Lines changed: 64 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,7 @@ class APItem {
146146
public static var unoColorsUnlocked:Array<{name:String, color_code:String}> = [];
147147

148148
public static var unknownSongs:Bool = false; // If true, songs are unknown.
149+
public static var queuedTrap:APItem = null; // Trap queued for execution when conditions are met
149150

150151
private var toSync:Bool = true;
151152
public var triggered:Bool = false;
@@ -240,7 +241,68 @@ class APItem {
240241
t.isTrap = true;
241242
});
242243
case "High Quality Trap":
243-
return new APTrap(name, ConditionHelper.Everywhere(), function() {
244+
return new APTrap(name, ConditionHelper.Special().funcAndReturn(function(c) {
245+
c.extraConditions = [];
246+
c.extraConditions.push(function(e) {
247+
// Check if trap is already being used to prevent duplicate activation
248+
if (archipelago.HighQualityTrapManager.isTrapAlreadyInUse()) {
249+
return false;
250+
}
251+
252+
// If we're in PlayState, check if we're in a compatible song
253+
if (Std.is(FlxG.state, states.PlayState)) {
254+
var playState = states.PlayState.instance;
255+
if (playState != null && playState.startedSong) {
256+
// Check if current song is compatible with High Quality trap
257+
return archipelago.HighQualityTrapManager.isCurrentSongCompatible();
258+
}
259+
return false;
260+
}
261+
// If we're in Freeplay, we can always trigger (it will wait)
262+
if (Std.is(FlxG.state, FreeplayManager.getFreeplay())) {
263+
return true;
264+
}
265+
return false;
266+
});
267+
}), function() {
268+
// Check if we need to download repository content first
269+
if (APInfo.slotData != null && APInfo.slotData.highQualityExpected) {
270+
// If expected but not available, go to existing high quality waiting state
271+
if (APInfo.apGame != null && APInfo.ap != null) {
272+
FlxG.switchState(new archipelago.states.HighQualityWaitingState(APInfo.apGame, APInfo.ap));
273+
} else {
274+
// Fallback: use the non-AP waiting state if not in AP context
275+
FlxG.switchState(new states.HighQualityTrapWaitingState());
276+
}
277+
return;
278+
}
279+
280+
// Start using the trap (activates song replacements)
281+
archipelago.HighQualityTrapManager.startUsingTrap();
282+
283+
// If we're in PlayState and in a compatible song, reset the state
284+
if (Std.is(FlxG.state, states.PlayState)) {
285+
var playState = states.PlayState.instance;
286+
if (playState != null && playState.startedSong) {
287+
TrapLinkFunctions.doHighQualityTrap();
288+
// Reset the state to apply High Quality changes
289+
MusicBeatState.resetState();
290+
return;
291+
}
292+
}
293+
294+
// If we're not in PlayState, wait until we're in Freeplay to do anything
295+
if (!Std.is(FlxG.state, FreeplayManager.getFreeplay())) {
296+
// Create a queued trap that will execute the High Quality trap logic later
297+
APItem.queuedTrap = new APTrap("High Quality Trap - Queued", ConditionHelper.Everywhere(), function() {
298+
archipelago.HighQualityTrapManager.startUsingTrap();
299+
TrapLinkFunctions.doHighQualityTrap();
300+
}, false, false);
301+
// No popup - trap is silent and hidden
302+
return;
303+
}
304+
305+
// We're in Freeplay, execute the trap
244306
TrapLinkFunctions.doHighQualityTrap();
245307
}, false, false).funcAndReturn(function(t:APItem) {
246308
// Set it as a trap.
@@ -670,7 +732,7 @@ class APItem {
670732
});
671733

672734
case "Lonely Friday Night":
673-
popup('Looks like you\'re spending this Friday Night alone...', "APItem: Lonely Friday Night");
735+
popup('Alone on a friday night? How pathetic...', "Lonely Friday Night", true);
674736
return null;
675737

676738
case "PowerPoint Trap":

source/archipelago/APPlayState.hx

Lines changed: 55 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -188,35 +188,33 @@ class APPlayState extends PlayState {
188188

189189
if (FlxG.save.data.manualOverride != null && FlxG.save.data.manualOverride)
190190
{
191-
// When manual override is active, ensure we're playing the correct saved song
192-
trace('Manual Override detected - verifying song consistency');
191+
// When manual override is active, ensure we're playing the correct trap song
192+
trace('Manual Override detected - verifying trap song consistency');
193193

194-
var savedSong = FlxG.save.data.SONG;
194+
var intendedTrapSong = FlxG.save.data.trapSONG; // The song the trap wanted to play
195195
var currentSong = PlayState.SONG;
196196

197-
// Check if the current song matches the saved song
198-
if (savedSong != null && currentSong != null) {
199-
var songMismatch = (savedSong.song != currentSong.song ||
200-
FlxG.save.data.storyWeek != PlayState.storyWeek ||
201-
FlxG.save.data.currentModDirectory != Mods.currentModDirectory ||
202-
FlxG.save.data.storyDifficulty != PlayState.storyDifficulty);
197+
// Check if the current song matches the intended trap song
198+
if (intendedTrapSong != null && currentSong != null) {
199+
var songMismatch = (intendedTrapSong.song != currentSong.song ||
200+
FlxG.save.data.trapStoryWeek != PlayState.storyWeek ||
201+
FlxG.save.data.trapCurrentModDirectory != Mods.currentModDirectory ||
202+
FlxG.save.data.trapStoryDifficulty != PlayState.storyDifficulty);
203203

204204
if (songMismatch) {
205-
trace('Song mismatch detected during manual override');
206-
trace('Expected: ' + savedSong.song + ' (Week: ' + FlxG.save.data.storyWeek + ', Mod: ' + FlxG.save.data.currentModDirectory + ')');
205+
trace('Trap song mismatch detected during manual override');
206+
trace('Expected trap song: ' + intendedTrapSong.song + ' (Week: ' + FlxG.save.data.trapStoryWeek + ', Mod: ' + FlxG.save.data.trapCurrentModDirectory + ')');
207207
trace('Current: ' + currentSong.song + ' (Week: ' + PlayState.storyWeek + ', Mod: ' + Mods.currentModDirectory + ')');
208208

209-
// Restore the correct song state and force a reset
210-
PlayState.storyWeek = FlxG.save.data.storyWeek;
211-
Mods.currentModDirectory = FlxG.save.data.currentModDirectory;
212-
Difficulty.list = FlxG.save.data.difficulties;
213-
curDifficulty = FlxG.save.data.curDifficulty;
214-
PlayState.SONG = FlxG.save.data.SONG;
215-
PlayState.storyDifficulty = FlxG.save.data.storyDifficulty;
209+
// Restore the correct trap song state and force a reset
210+
PlayState.storyWeek = FlxG.save.data.trapStoryWeek;
211+
Mods.currentModDirectory = FlxG.save.data.trapCurrentModDirectory;
212+
Difficulty.list = FlxG.save.data.trapDifficulties;
213+
curDifficulty = FlxG.save.data.trapCurDifficulty;
214+
PlayState.SONG = FlxG.save.data.trapSONG;
215+
PlayState.storyDifficulty = FlxG.save.data.trapStoryDifficulty;
216216

217-
218-
219-
trace('Song state corrected - resetting APPlayState');
217+
trace('Trap song state corrected - resetting APPlayState');
220218
StageData.loadDirectory(PlayState.SONG);
221219
MusicBeatState.resetState();
222220
return;
@@ -1232,6 +1230,7 @@ class APPlayState extends PlayState {
12321230
trace('MANUAL OVERRIDE: ' + FlxG.save.data.manualOverride);
12331231
if (!FlxG.save.data.manualOverride) {
12341232
FlxG.save.data.manualOverride = true;
1233+
// Save original song data for restoration later
12351234
FlxG.save.data.storyWeek = PlayState.storyWeek;
12361235
FlxG.save.data.currentModDirectory = Mods.currentModDirectory;
12371236
FlxG.save.data.difficulties = Difficulty.list; // just in case
@@ -1243,13 +1242,22 @@ class APPlayState extends PlayState {
12431242
FlxG.save.data.rating = comboManager.ratingPercent;
12441243
FlxG.save.data.misses = comboManager.songMisses;
12451244
FlxG.save.data.health = health;
1246-
FlxG.save.flush();
12471245

1246+
// Set up trap song
12481247
Difficulty.list = Difficulty.defaultList.copy();
12491248
PlayState.storyWeek = 0;
12501249
Mods.currentModDirectory = 'week1';
12511250
PlayState.SONG = Song.loadFromJson(backend.Highscore.formatSong('tutorial', Difficulty.list.length-1), Paths.formatToSongPath('tutorial'));
12521251
PlayState.storyDifficulty = Difficulty.list.length-1;
1252+
1253+
// Save trap song data for consistency checking
1254+
FlxG.save.data.trapStoryWeek = PlayState.storyWeek;
1255+
FlxG.save.data.trapCurrentModDirectory = Mods.currentModDirectory;
1256+
FlxG.save.data.trapDifficulties = Difficulty.list;
1257+
FlxG.save.data.trapCurDifficulty = curDifficulty;
1258+
FlxG.save.data.trapSONG = PlayState.SONG;
1259+
FlxG.save.data.trapStoryDifficulty = PlayState.storyDifficulty;
1260+
12531261
FlxG.save.flush();
12541262

12551263
if (Std.is(FlxG.state, APPlayState)) {
@@ -1272,22 +1280,33 @@ class APPlayState extends PlayState {
12721280
trace('MANUAL OVERRIDE: ' + FlxG.save.data.manualOverride);
12731281
if (!FlxG.save.data.manualOverride) {
12741282
FlxG.save.data.manualOverride = true;
1283+
// Save original song data for restoration later
12751284
FlxG.save.data.storyWeek = PlayState.storyWeek;
12761285
FlxG.save.data.currentModDirectory = Mods.currentModDirectory;
12771286
FlxG.save.data.difficulties = Difficulty.list; // just in case
12781287
FlxG.save.data.curDifficulty = curDifficulty; // just in case
12791288
FlxG.save.data.SONG = PlayState.SONG;
12801289
FlxG.save.data.storyDifficulty = PlayState.storyDifficulty;
12811290
FlxG.save.data.songPos = FlxG.sound.music.time;
1282-
FlxG.save.flush();
12831291

12841292
var specialSongList = ['Rise', 'Zeventeen', 'Pack-A-Punch', 'Driller', 'Test Field', 'Rawr', 'Fightback', 'Funky Fanta', 'Tag And Seek', 'Testimony', 'Fangirl Frenzy', 'Slowdown'];
12851293
var curSong = FlxG.random.int(0, specialSongList.length-1);
1294+
1295+
// Set up trap song
12861296
Difficulty.list = Difficulty.defaultList.copy();
12871297
PlayState.storyWeek = -1;
12881298
Mods.currentModDirectory = '';
12891299
PlayState.SONG = Song.loadFromJson(backend.Highscore.formatSong(specialSongList[curSong], Difficulty.list.length-1), Paths.formatToSongPath(specialSongList[curSong]));
12901300
PlayState.storyDifficulty = Difficulty.list.length-1;
1301+
1302+
// Save trap song data for consistency checking
1303+
FlxG.save.data.trapStoryWeek = PlayState.storyWeek;
1304+
FlxG.save.data.trapCurrentModDirectory = Mods.currentModDirectory;
1305+
FlxG.save.data.trapDifficulties = Difficulty.list;
1306+
FlxG.save.data.trapCurDifficulty = curDifficulty;
1307+
FlxG.save.data.trapSONG = PlayState.SONG;
1308+
FlxG.save.data.trapStoryDifficulty = PlayState.storyDifficulty;
1309+
12911310
FlxG.save.flush();
12921311

12931312
if (Std.is(FlxG.state, APPlayState)) {
@@ -1790,7 +1809,7 @@ class APPlayState extends PlayState {
17901809
{
17911810
super.generateSong();
17921811
if (PlayState.SONG == null || archipelago.APItem.activeItem?.name=="Tutorial Trap") return;
1793-
apNotes = archipelago.APNote.replaceInQueue(playerField.noteQueue, apGame.excludeCheckedLocations(apGame.noteData(PlayState.SONG.song, currentMod)));
1812+
apNotes = archipelago.APNote.replaceInQueue(playerField.noteQueue, apGame.excludeCheckedLocations(apGame.noteData(currentSong, currentMod)));
17941813

17951814
for (field in playfields.members)
17961815
field.clearStackedNotes();
@@ -2580,13 +2599,24 @@ class APPlayState extends PlayState {
25802599
if (ClientPrefs.getGameplaySetting('chartModifier', 'Normal') != "Normal" || ClientPrefs.getGameplaySetting('chartModifier', 'Normal') == null)
25812600
ClientPrefs.data.gameplaySettings.set('chartModifier', 'Normal');
25822601

2602+
if (archipelago.HighQualityTrapManager.isTrapInUse()) {
2603+
// Don't stop the trap here - let APVictorySubstate handle it
2604+
// Remove the stopHighQualityTrap call
2605+
}
2606+
25832607
ghostChat = false;
25842608
super.endSong();
25852609

25862610

25872611
paused = true;
25882612
APFreeplayManager.callVictory = APFreeplayManager.isVictorySong(PlayState.SONG.song, currentMod);
2589-
openSubState(new substates.RankingSubstate());
2613+
2614+
// Use APVictorySubstate instead of RankingSubstate when High Quality Trap is active
2615+
if (archipelago.HighQualityTrapManager.isTrapInUse()) {
2616+
openSubState(new archipelago.APVictorySubstate(boyfriend));
2617+
} else {
2618+
openSubState(new substates.RankingSubstate());
2619+
}
25902620

25912621
return true; //why does endsong need this?????
25922622
}

source/archipelago/APStyledEntryState.hx

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -896,7 +896,15 @@ class APStyledEntryState extends MusicBeatState {
896896

897897
APEntryState.apGame = apGame;
898898

899-
FlxG.switchState(new archipelago.APCategoryState(apGame, ap));
899+
// Check if high quality content is expected and should be downloaded
900+
if (slotData != null && slotData.highQualityExpected == true) {
901+
// Go to existing high quality waiting state first
902+
FlxG.switchState(new archipelago.states.HighQualityWaitingState(apGame, ap));
903+
} else {
904+
// Normal flow - go directly to AP category state
905+
FlxG.switchState(new archipelago.APCategoryState(apGame, ap));
906+
}
907+
900908
backend.ClientPrefs.data.gameplaySettings.set("chartModifier", "Normal");
901909
backend.ClientPrefs.data.gameplaySettings.set("convertMania", 3);
902910
}

0 commit comments

Comments
 (0)