1
0
Fork 0
mirror of https://github.com/ninjamuffin99/Funkin.git synced 2025-06-21 18:23:12 +00:00

Merge branch 'develop' into main-to-develop

This commit is contained in:
Abnormal 2025-02-03 23:22:56 +00:00 committed by GitHub
commit 246de95e46
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
23 changed files with 383 additions and 53 deletions

View file

@ -187,6 +187,8 @@ class InitState extends FlxState
ModuleHandler.loadModuleCache(); ModuleHandler.loadModuleCache();
ModuleHandler.callOnCreate(); ModuleHandler.callOnCreate();
funkin.input.Cursor.hide();
trace('Parsing game data took: ${TimerUtil.ms(perfStart)}'); trace('Parsing game data took: ${TimerUtil.ms(perfStart)}');
} }

View file

@ -36,6 +36,13 @@ typedef AlbumData =
*/ */
public var albumTitleAsset:String; public var albumTitleAsset:String;
/**
* Offsets for the album title.
*/
@:optional
@:default([0, 0])
public var albumTitleOffsets:Null<Array<Float>>;
/** /**
* An optional array of animations for the album title. * An optional array of animations for the album title.
*/ */

View file

@ -983,6 +983,7 @@ class Controls extends FlxActionSet
Control.FREEPLAY_FAVORITE => getDefaultGamepadBinds(Control.FREEPLAY_FAVORITE), Control.FREEPLAY_FAVORITE => getDefaultGamepadBinds(Control.FREEPLAY_FAVORITE),
Control.FREEPLAY_LEFT => getDefaultGamepadBinds(Control.FREEPLAY_LEFT), Control.FREEPLAY_LEFT => getDefaultGamepadBinds(Control.FREEPLAY_LEFT),
Control.FREEPLAY_RIGHT => getDefaultGamepadBinds(Control.FREEPLAY_RIGHT), Control.FREEPLAY_RIGHT => getDefaultGamepadBinds(Control.FREEPLAY_RIGHT),
Control.FREEPLAY_CHAR_SELECT => getDefaultGamepadBinds(Control.FREEPLAY_CHAR_SELECT),
Control.VOLUME_UP => getDefaultGamepadBinds(Control.VOLUME_UP), Control.VOLUME_UP => getDefaultGamepadBinds(Control.VOLUME_UP),
Control.VOLUME_DOWN => getDefaultGamepadBinds(Control.VOLUME_DOWN), Control.VOLUME_DOWN => getDefaultGamepadBinds(Control.VOLUME_DOWN),
Control.VOLUME_MUTE => getDefaultGamepadBinds(Control.VOLUME_MUTE), Control.VOLUME_MUTE => getDefaultGamepadBinds(Control.VOLUME_MUTE),
@ -1033,11 +1034,13 @@ class Controls extends FlxActionSet
case Control.CUTSCENE_ADVANCE: case Control.CUTSCENE_ADVANCE:
return [A]; return [A];
case Control.FREEPLAY_FAVORITE: case Control.FREEPLAY_FAVORITE:
[FlxGamepadInputID.BACK]; // Back (i.e. Select) return [Y]; // Back (i.e. Select)
case Control.FREEPLAY_LEFT: case Control.FREEPLAY_LEFT:
[LEFT_SHOULDER]; return [LEFT_SHOULDER];
case Control.FREEPLAY_RIGHT: case Control.FREEPLAY_RIGHT:
[RIGHT_SHOULDER]; return [RIGHT_SHOULDER];
case Control.FREEPLAY_CHAR_SELECT:
return [X];
case Control.VOLUME_UP: case Control.VOLUME_UP:
[]; [];
case Control.VOLUME_DOWN: case Control.VOLUME_DOWN:
@ -1602,10 +1605,10 @@ enum Control
NOTE_UP; NOTE_UP;
NOTE_RIGHT; NOTE_RIGHT;
// UI // UI
UI_UP;
UI_LEFT; UI_LEFT;
UI_RIGHT;
UI_DOWN; UI_DOWN;
UI_UP;
UI_RIGHT;
RESET; RESET;
ACCEPT; ACCEPT;
BACK; BACK;

View file

@ -37,6 +37,9 @@ interface IStateChangingScriptedClass extends IScriptedClass
public function onSubStateOpenEnd(event:SubStateScriptEvent):Void; public function onSubStateOpenEnd(event:SubStateScriptEvent):Void;
public function onSubStateCloseBegin(event:SubStateScriptEvent):Void; public function onSubStateCloseBegin(event:SubStateScriptEvent):Void;
public function onSubStateCloseEnd(event:SubStateScriptEvent):Void; public function onSubStateCloseEnd(event:SubStateScriptEvent):Void;
public function onFocusLost(event:FocusScriptEvent):Void;
public function onFocusGained(event:FocusScriptEvent):Void;
} }
/** /**
@ -140,7 +143,7 @@ interface IPlayStateScriptedClass extends INoteScriptedClass extends IBPMSyncedS
/** /**
* Called when the player restarts the song, either via pause menu or restarting after a game over. * Called when the player restarts the song, either via pause menu or restarting after a game over.
*/ */
public function onSongRetry(event:ScriptEvent):Void; public function onSongRetry(event:SongRetryEvent):Void;
/** /**
* Called when the player presses a key when no note is on the strumline. * Called when the player presses a key when no note is on the strumline.

View file

@ -414,6 +414,28 @@ class SongLoadScriptEvent extends ScriptEvent
} }
} }
/**
* AAn event that is fired when the player retries the song.
*/
class SongRetryEvent extends ScriptEvent
{
/**
* The new difficulty of the song.
*/
public var difficulty(default, null):String;
public function new(difficulty:String):Void
{
super(SONG_RETRY, false);
this.difficulty = difficulty;
}
public override function toString():String
{
return 'SongRetryEvent(difficulty=$difficulty)';
}
}
/** /**
* An event that is fired when moving out of or into an FlxState. * An event that is fired when moving out of or into an FlxState.
*/ */
@ -436,6 +458,22 @@ class StateChangeScriptEvent extends ScriptEvent
} }
} }
/**
* An event that is fired when the game loses or gains focus.
*/
class FocusScriptEvent extends ScriptEvent
{
public function new(type:ScriptEventType):Void
{
super(type, false);
}
public override function toString():String
{
return 'FocusScriptEvent(type=' + type + ')';
}
}
/** /**
* An event that is fired when moving out of or into an FlxSubState. * An event that is fired when moving out of or into an FlxSubState.
*/ */

View file

@ -124,7 +124,7 @@ class ScriptEventDispatcher
t.onSongEnd(event); t.onSongEnd(event);
return; return;
case SONG_RETRY: case SONG_RETRY:
t.onSongRetry(event); t.onSongRetry(cast event);
return; return;
case GAME_OVER: case GAME_OVER:
t.onGameOver(event); t.onGameOver(event);
@ -177,6 +177,12 @@ class ScriptEventDispatcher
case SUBSTATE_CLOSE_END: case SUBSTATE_CLOSE_END:
t.onSubStateCloseEnd(cast event); t.onSubStateCloseEnd(cast event);
return; return;
case FOCUS_LOST:
t.onFocusLost(cast event);
return;
case FOCUS_GAINED:
t.onFocusGained(cast event);
return;
default: // Continue; default: // Continue;
} }
} }

View file

@ -223,6 +223,20 @@ enum abstract ScriptEventType(String) from String to String
*/ */
var SUBSTATE_CLOSE_END = 'SUBSTATE_CLOSE_END'; var SUBSTATE_CLOSE_END = 'SUBSTATE_CLOSE_END';
/**
* Called when the game regains focus.
*
* This event is not cancelable.
*/
var FOCUS_GAINED = 'FOCUS_GAINED';
/**
* Called when the game loses focus.
*
* This event is not cancelable.
*/
var FOCUS_LOST = 'FOCUS_LOST';
/** /**
* Called when the game starts a conversation. * Called when the game starts a conversation.
* *

View file

@ -109,6 +109,10 @@ class Module implements IPlayStateScriptedClass implements IStateChangingScripte
public function onStateChangeEnd(event:StateChangeScriptEvent) {} public function onStateChangeEnd(event:StateChangeScriptEvent) {}
public function onFocusGained(event:FocusScriptEvent) {}
public function onFocusLost(event:FocusScriptEvent) {}
public function onSubStateOpenBegin(event:SubStateScriptEvent) {} public function onSubStateOpenBegin(event:SubStateScriptEvent) {}
public function onSubStateOpenEnd(event:SubStateScriptEvent) {} public function onSubStateOpenEnd(event:SubStateScriptEvent) {}
@ -117,5 +121,5 @@ class Module implements IPlayStateScriptedClass implements IStateChangingScripte
public function onSubStateCloseEnd(event:SubStateScriptEvent) {} public function onSubStateCloseEnd(event:SubStateScriptEvent) {}
public function onSongRetry(event:ScriptEvent) {} public function onSongRetry(event:SongRetryEvent) {}
} }

View file

@ -649,6 +649,7 @@ class PauseSubState extends MusicBeatSubState
// So if you switch difficulty on the last song of a week you get a really low overall score. // So if you switch difficulty on the last song of a week you get a really low overall score.
PlayStatePlaylist.campaignScore = 0; PlayStatePlaylist.campaignScore = 0;
PlayStatePlaylist.campaignDifficulty = difficulty; PlayStatePlaylist.campaignDifficulty = difficulty;
PlayState.instance.previousDifficulty = PlayState.instance.currentDifficulty;
PlayState.instance.currentDifficulty = PlayStatePlaylist.campaignDifficulty; PlayState.instance.currentDifficulty = PlayStatePlaylist.campaignDifficulty;
FreeplayState.rememberedDifficulty = difficulty; FreeplayState.rememberedDifficulty = difficulty;

View file

@ -332,6 +332,11 @@ class PlayState extends MusicBeatSubState
*/ */
public var disableKeys:Bool = false; public var disableKeys:Bool = false;
/**
* The previous difficulty the player was playing on.
*/
public var previousDifficulty:String = Constants.DEFAULT_DIFFICULTY;
public var isSubState(get, never):Bool; public var isSubState(get, never):Bool;
function get_isSubState():Bool function get_isSubState():Bool
@ -603,6 +608,7 @@ class PlayState extends MusicBeatSubState
// Apply parameters. // Apply parameters.
currentSong = params.targetSong; currentSong = params.targetSong;
if (params.targetDifficulty != null) currentDifficulty = params.targetDifficulty; if (params.targetDifficulty != null) currentDifficulty = params.targetDifficulty;
previousDifficulty = currentDifficulty;
if (params.targetVariation != null) currentVariation = params.targetVariation; if (params.targetVariation != null) currentVariation = params.targetVariation;
if (params.targetInstrumental != null) currentInstrumental = params.targetInstrumental; if (params.targetInstrumental != null) currentInstrumental = params.targetInstrumental;
isPracticeMode = params.practiceMode ?? false; isPracticeMode = params.practiceMode ?? false;
@ -813,7 +819,11 @@ class PlayState extends MusicBeatSubState
prevScrollTargets = []; prevScrollTargets = [];
dispatchEvent(new ScriptEvent(SONG_RETRY)); var retryEvent = new SongRetryEvent(currentDifficulty);
previousDifficulty = currentDifficulty;
dispatchEvent(retryEvent);
resetCamera(); resetCamera();
@ -906,7 +916,7 @@ class PlayState extends MusicBeatSubState
Conductor.instance.formatOffset = 0.0; Conductor.instance.formatOffset = 0.0;
} }
Conductor.instance.update(); // Normal conductor update. Conductor.instance.update(Conductor.instance.songPosition + elapsed * 1000, false); // Normal conductor update.
} }
var androidPause:Bool = false; var androidPause:Bool = false;
@ -1447,7 +1457,9 @@ class PlayState extends MusicBeatSubState
} }
if (!startingSong if (!startingSong
&& (Math.abs(FlxG.sound.music.time - correctSync) > 5 || Math.abs(playerVoicesError) > 5 || Math.abs(opponentVoicesError) > 5)) && (Math.abs(FlxG.sound.music.time - correctSync) > 100
|| Math.abs(playerVoicesError) > 100
|| Math.abs(opponentVoicesError) > 100))
{ {
trace("VOCALS NEED RESYNC"); trace("VOCALS NEED RESYNC");
if (vocals != null) if (vocals != null)

View file

@ -36,11 +36,31 @@ class Strumline extends FlxSpriteGroup
static var RENDER_DISTANCE_MS(get, never):Float; static var RENDER_DISTANCE_MS(get, never):Float;
/**
* The custom render distance for the strumline.
* This should be in miliseconds only! Not pixels.
*/
public static var CUSTOM_RENDER_DISTANCE_MS:Float = 0.0;
/**
* Whether to use the custom render distance.
* If false, the render distance will be calculated based on the screen height.
*/
public static var USE_CUSTOM_RENDER_DISTANCE:Bool = false;
static function get_RENDER_DISTANCE_MS():Float static function get_RENDER_DISTANCE_MS():Float
{ {
if (USE_CUSTOM_RENDER_DISTANCE) return CUSTOM_RENDER_DISTANCE_MS;
return FlxG.height / Constants.PIXELS_PER_MS; return FlxG.height / Constants.PIXELS_PER_MS;
} }
/**
* Whether to play note splashes or not
* TODO: Make this a setting!
* IE: Settings.noSplash
*/
public var showNotesplash:Bool = true;
/** /**
* Whether this strumline is controlled by the player's inputs. * Whether this strumline is controlled by the player's inputs.
* False means it's controlled by the opponent or Bot Play. * False means it's controlled by the opponent or Bot Play.
@ -74,6 +94,11 @@ class Strumline extends FlxSpriteGroup
return _conductorInUse = value; return _conductorInUse = value;
} }
/**
* Whether the game should auto position notes.
*/
public var customPositionData:Bool = false;
/** /**
* The notes currently being rendered on the strumline. * The notes currently being rendered on the strumline.
* This group iterates over this every frame to update note positions. * This group iterates over this every frame to update note positions.
@ -376,7 +401,7 @@ class Strumline extends FlxSpriteGroup
var vwoosh:Bool = note.holdNoteSprite == null; var vwoosh:Bool = note.holdNoteSprite == null;
// Set the note's position. // Set the note's position.
note.y = this.y - INITIAL_OFFSET + calculateNoteYPos(note.strumTime, vwoosh); if (!customPositionData) note.y = this.y - INITIAL_OFFSET + calculateNoteYPos(note.strumTime, vwoosh);
// If the note is miss // If the note is miss
var isOffscreen = Preferences.downscroll ? note.y > FlxG.height : note.y < -note.height; var isOffscreen = Preferences.downscroll ? note.y > FlxG.height : note.y < -note.height;
@ -446,13 +471,16 @@ class Strumline extends FlxSpriteGroup
var vwoosh:Bool = false; var vwoosh:Bool = false;
if (Preferences.downscroll) if (!customPositionData)
{ {
holdNote.y = this.y - INITIAL_OFFSET + calculateNoteYPos(holdNote.strumTime, vwoosh) - holdNote.height + STRUMLINE_SIZE / 2; if (Preferences.downscroll)
} {
else holdNote.y = this.y - INITIAL_OFFSET + calculateNoteYPos(holdNote.strumTime, vwoosh) - holdNote.height + STRUMLINE_SIZE / 2;
{ }
holdNote.y = this.y - INITIAL_OFFSET + calculateNoteYPos(holdNote.strumTime, vwoosh) + yOffset + STRUMLINE_SIZE / 2; else
{
holdNote.y = this.y - INITIAL_OFFSET + calculateNoteYPos(holdNote.strumTime, vwoosh) + yOffset + STRUMLINE_SIZE / 2;
}
} }
// Clean up the cover. // Clean up the cover.
@ -475,13 +503,16 @@ class Strumline extends FlxSpriteGroup
holdNote.visible = false; holdNote.visible = false;
} }
if (Preferences.downscroll) if (!customPositionData)
{ {
holdNote.y = this.y - INITIAL_OFFSET - holdNote.height + STRUMLINE_SIZE / 2; if (Preferences.downscroll)
} {
else holdNote.y = this.y - INITIAL_OFFSET - holdNote.height + STRUMLINE_SIZE / 2;
{ }
holdNote.y = this.y - INITIAL_OFFSET + STRUMLINE_SIZE / 2; else
{
holdNote.y = this.y - INITIAL_OFFSET + STRUMLINE_SIZE / 2;
}
} }
} }
else else
@ -490,13 +521,16 @@ class Strumline extends FlxSpriteGroup
holdNote.visible = true; holdNote.visible = true;
var vwoosh:Bool = false; var vwoosh:Bool = false;
if (Preferences.downscroll) if (!customPositionData)
{ {
holdNote.y = this.y - INITIAL_OFFSET + calculateNoteYPos(holdNote.strumTime, vwoosh) - holdNote.height + STRUMLINE_SIZE / 2; if (Preferences.downscroll)
} {
else holdNote.y = this.y - INITIAL_OFFSET + calculateNoteYPos(holdNote.strumTime, vwoosh) - holdNote.height + STRUMLINE_SIZE / 2;
{ }
holdNote.y = this.y - INITIAL_OFFSET + calculateNoteYPos(holdNote.strumTime, vwoosh) + STRUMLINE_SIZE / 2; else
{
holdNote.y = this.y - INITIAL_OFFSET + calculateNoteYPos(holdNote.strumTime, vwoosh) + STRUMLINE_SIZE / 2;
}
} }
} }
} }
@ -708,8 +742,7 @@ class Strumline extends FlxSpriteGroup
public function playNoteSplash(direction:NoteDirection):Void public function playNoteSplash(direction:NoteDirection):Void
{ {
// TODO: Add a setting to disable note splashes. if (!showNotesplash) return;
// if (Settings.noSplash) return;
if (!noteStyle.isNoteSplashEnabled()) return; if (!noteStyle.isNoteSplashEnabled()) return;
var splash:NoteSplash = this.constructNoteSplash(); var splash:NoteSplash = this.constructNoteSplash();
@ -729,8 +762,7 @@ class Strumline extends FlxSpriteGroup
public function playNoteHoldCover(holdNote:SustainTrail):Void public function playNoteHoldCover(holdNote:SustainTrail):Void
{ {
// TODO: Add a setting to disable note splashes. if (!showNotesplash) return;
// if (Settings.noSplash) return;
if (!noteStyle.isHoldNoteCoverEnabled()) return; if (!noteStyle.isHoldNoteCoverEnabled()) return;
var cover:NoteHoldCover = this.constructNoteHoldCover(); var cover:NoteHoldCover = this.constructNoteHoldCover();

View file

@ -86,6 +86,11 @@ class SustainTrail extends FlxSprite
*/ */
public var bottomClip:Float = 0.9; public var bottomClip:Float = 0.9;
/**
* Whether the note will recieve custom vertex data
*/
public var customVertexData:Bool = false;
public var isPixel:Bool; public var isPixel:Bool;
public var noteStyleOffsets:Array<Float>; public var noteStyleOffsets:Array<Float>;
@ -110,11 +115,68 @@ class SustainTrail extends FlxSprite
setupHoldNoteGraphic(noteStyle); setupHoldNoteGraphic(noteStyle);
noteStyleOffsets = noteStyle.getHoldNoteOffsets(); noteStyleOffsets = noteStyle.getHoldNoteOffsets();
indices = new DrawData<Int>(12, true, TRIANGLE_VERTEX_INDICES); setIndices(TRIANGLE_VERTEX_INDICES);
this.active = true; // This NEEDS to be true for the note to be drawn! this.active = true; // This NEEDS to be true for the note to be drawn!
} }
/**
* Sets the indices for the triangles.
* @param indices The indices to set.
*/
public function setIndices(indices:Array<Int>):Void
{
if (this.indices.length == indices.length)
{
for (i in 0...indices.length)
{
this.indices[i] = indices[i];
}
}
else
{
this.indices = new DrawData<Int>(indices.length, false, indices);
}
}
/**
* Sets the vertices for the triangles.
* @param vertices The vertices to set.
*/
public function setVertices(vertices:Array<Float>):Void
{
if (this.vertices.length == vertices.length)
{
for (i in 0...vertices.length)
{
this.vertices[i] = vertices[i];
}
}
else
{
this.vertices = new DrawData<Float>(vertices.length, false, vertices);
}
}
/**
* Sets the UV data for the triangles.
* @param uvtData The UV data to set.
*/
public function setUVTData(uvtData:Array<Float>):Void
{
if (this.uvtData.length == uvtData.length)
{
for (i in 0...uvtData.length)
{
this.uvtData[i] = uvtData[i];
}
}
else
{
this.uvtData = new DrawData<Float>(uvtData.length, false, uvtData);
}
}
/** /**
* Creates hold note graphic and applies correct zooming * Creates hold note graphic and applies correct zooming
* @param noteStyle The note style * @param noteStyle The note style
@ -214,7 +276,7 @@ class SustainTrail extends FlxSprite
*/ */
public function updateClipping(songTime:Float = 0):Void public function updateClipping(songTime:Float = 0):Void
{ {
if (graphic == null) if (graphic == null || customVertexData)
{ {
return; return;
} }

View file

@ -643,11 +643,11 @@ class Song implements IPlayStateScriptedClass implements IRegistryEntry<SongMeta
public function onGameOver(event:ScriptEvent):Void {}; public function onGameOver(event:ScriptEvent):Void {};
public function onSongRetry(event:ScriptEvent):Void {}; public function onSongRetry(event:SongRetryEvent):Void {};
public function onNoteIncoming(event:NoteScriptEvent) {} public function onNoteIncoming(event:NoteScriptEvent) {};
public function onNoteHit(event:HitNoteScriptEvent) {} public function onNoteHit(event:HitNoteScriptEvent) {};
public function onNoteMiss(event:NoteScriptEvent):Void {}; public function onNoteMiss(event:NoteScriptEvent):Void {};
@ -955,12 +955,14 @@ class SongDifficulty
// Add player vocals. // Add player vocals.
for (playerVoice in playerVoiceList) for (playerVoice in playerVoiceList)
{ {
if (!Assets.exists(playerVoice)) continue;
result.addPlayerVoice(FunkinSound.load(playerVoice)); result.addPlayerVoice(FunkinSound.load(playerVoice));
} }
// Add opponent vocals. // Add opponent vocals.
for (opponentVoice in opponentVoiceList) for (opponentVoice in opponentVoiceList)
{ {
if (!Assets.exists(opponentVoice)) continue;
result.addOpponentVoice(FunkinSound.load(opponentVoice)); result.addOpponentVoice(FunkinSound.load(opponentVoice));
} }

View file

@ -389,5 +389,5 @@ class Bopper extends StageProp implements IPlayStateScriptedClass
public function onSongLoaded(event:SongLoadScriptEvent) {} public function onSongLoaded(event:SongLoadScriptEvent) {}
public function onSongRetry(event:ScriptEvent) {} public function onSongRetry(event:SongRetryEvent) {}
} }

View file

@ -901,5 +901,5 @@ class Stage extends FlxSpriteGroup implements IPlayStateScriptedClass implements
public function onSongLoaded(event:SongLoadScriptEvent) {} public function onSongLoaded(event:SongLoadScriptEvent) {}
public function onSongRetry(event:ScriptEvent) {} public function onSongRetry(event:SongRetryEvent) {}
} }

View file

@ -623,7 +623,7 @@ class Save
else else
{ {
// Level has score data, but the score is 0. // Level has score data, but the score is 0.
return false; continue;
} }
} }
} }
@ -818,7 +818,7 @@ class Save
else else
{ {
// Level has score data, but the score is 0. // Level has score data, but the score is 0.
return false; continue;
} }
} }
} }

View file

@ -87,6 +87,20 @@ class MusicBeatState extends FlxTransitionableState implements IEventHandler
dispatchEvent(new UpdateScriptEvent(elapsed)); dispatchEvent(new UpdateScriptEvent(elapsed));
} }
override function onFocus():Void
{
super.onFocus();
dispatchEvent(new FocusScriptEvent(FOCUS_GAINED));
}
override function onFocusLost():Void
{
super.onFocusLost();
dispatchEvent(new FocusScriptEvent(FOCUS_LOST));
}
function createWatermarkText() function createWatermarkText()
{ {
// Both have an xPos of 0, but a width equal to the full screen. // Both have an xPos of 0, but a width equal to the full screen.

View file

@ -89,6 +89,20 @@ class MusicBeatSubState extends FlxSubState implements IEventHandler
dispatchEvent(new UpdateScriptEvent(elapsed)); dispatchEvent(new UpdateScriptEvent(elapsed));
} }
override function onFocus():Void
{
super.onFocus();
dispatchEvent(new FocusScriptEvent(FOCUS_GAINED));
}
override function onFocusLost():Void
{
super.onFocusLost();
dispatchEvent(new FocusScriptEvent(FOCUS_LOST));
}
public function initConsoleHelpers():Void {} public function initConsoleHelpers():Void {}
function reloadAssets() function reloadAssets()

View file

@ -76,6 +76,14 @@ class Album implements IRegistryEntry<AlbumData>
return _data.albumTitleAsset; return _data.albumTitleAsset;
} }
/**
* Get the offsets for the album title.
*/
public function getAlbumTitleOffsets():Null<Array<Float>>
{
return _data.albumTitleOffsets;
}
public function hasAlbumTitleAnimations() public function hasAlbumTitleAnimations()
{ {
return _data.albumTitleAnimations.length > 0; return _data.albumTitleAnimations.length > 0;

View file

@ -112,7 +112,7 @@ class AlbumRoll extends FlxSpriteGroup
var albumGraphic = Paths.image(albumData.getAlbumArtAssetKey()); var albumGraphic = Paths.image(albumData.getAlbumArtAssetKey());
newAlbumArt.replaceFrameGraphic(0, albumGraphic); newAlbumArt.replaceFrameGraphic(0, albumGraphic);
buildAlbumTitle(albumData.getAlbumTitleAssetKey()); buildAlbumTitle(albumData.getAlbumTitleAssetKey(), albumData.getAlbumTitleOffsets());
applyExitMovers(); applyExitMovers();
@ -198,7 +198,7 @@ class AlbumRoll extends FlxSpriteGroup
albumTitle.visible = true; albumTitle.visible = true;
} }
public function buildAlbumTitle(assetKey:String):Void public function buildAlbumTitle(assetKey:String, ?titleOffsets:Null<Array<Float>>):Void
{ {
if (albumTitle != null) if (albumTitle != null)
{ {
@ -206,6 +206,11 @@ class AlbumRoll extends FlxSpriteGroup
albumTitle = null; albumTitle = null;
} }
if (titleOffsets == null)
{
titleOffsets = [0, 0];
}
albumTitle = FunkinSprite.createSparrow(925, 500, assetKey); albumTitle = FunkinSprite.createSparrow(925, 500, assetKey);
albumTitle.visible = albumTitle.frames != null && newAlbumArt.visible; albumTitle.visible = albumTitle.frames != null && newAlbumArt.visible;
albumTitle.animation.addByPrefix('idle', 'idle0', 24, true); albumTitle.animation.addByPrefix('idle', 'idle0', 24, true);
@ -219,6 +224,9 @@ class AlbumRoll extends FlxSpriteGroup
albumTitle.zIndex = 1000; albumTitle.zIndex = 1000;
albumTitle.x += titleOffsets[0];
albumTitle.y += titleOffsets[1];
if (_exitMovers != null) _exitMovers.set([albumTitle], if (_exitMovers != null) _exitMovers.set([albumTitle],
{ {
x: FlxG.width, x: FlxG.width,

View file

@ -3,10 +3,13 @@ package funkin.ui.options;
import flixel.FlxCamera; import flixel.FlxCamera;
import flixel.FlxObject; import flixel.FlxObject;
import flixel.FlxSprite; import flixel.FlxSprite;
import flixel.text.FlxText;
import flixel.util.FlxColor;
import flixel.group.FlxSpriteGroup.FlxTypedSpriteGroup; import flixel.group.FlxSpriteGroup.FlxTypedSpriteGroup;
import funkin.ui.AtlasText.AtlasFont; import funkin.ui.AtlasText.AtlasFont;
import funkin.ui.options.OptionsState.Page; import funkin.ui.options.OptionsState.Page;
import funkin.graphics.FunkinCamera; import funkin.graphics.FunkinCamera;
import funkin.graphics.FunkinSprite;
import funkin.ui.TextMenuList.TextMenuItem; import funkin.ui.TextMenuList.TextMenuItem;
import funkin.audio.FunkinSound; import funkin.audio.FunkinSound;
import funkin.ui.options.MenuItemEnums; import funkin.ui.options.MenuItemEnums;
@ -18,8 +21,12 @@ class PreferencesMenu extends Page
{ {
var items:TextMenuList; var items:TextMenuList;
var preferenceItems:FlxTypedSpriteGroup<FlxSprite>; var preferenceItems:FlxTypedSpriteGroup<FlxSprite>;
var preferenceDesc:Array<String> = [];
var itemDesc:FlxText;
var itemDescBox:FunkinSprite;
var menuCamera:FlxCamera; var menuCamera:FlxCamera;
var hudCamera:FlxCamera;
var camFollow:FlxObject; var camFollow:FlxObject;
public function new() public function new()
@ -29,47 +36,81 @@ class PreferencesMenu extends Page
menuCamera = new FunkinCamera('prefMenu'); menuCamera = new FunkinCamera('prefMenu');
FlxG.cameras.add(menuCamera, false); FlxG.cameras.add(menuCamera, false);
menuCamera.bgColor = 0x0; menuCamera.bgColor = 0x0;
hudCamera = new FlxCamera();
FlxG.cameras.add(hudCamera, false);
hudCamera.bgColor = 0x0;
camera = menuCamera; camera = menuCamera;
add(items = new TextMenuList()); add(items = new TextMenuList());
add(preferenceItems = new FlxTypedSpriteGroup<FlxSprite>()); add(preferenceItems = new FlxTypedSpriteGroup<FlxSprite>());
add(itemDescBox = new FunkinSprite());
itemDescBox.cameras = [hudCamera];
add(itemDesc = new FlxText(0, 0, 1180, null, 32));
itemDesc.cameras = [hudCamera];
createPrefItems(); createPrefItems();
createPrefDescription();
camFollow = new FlxObject(FlxG.width / 2, 0, 140, 70); camFollow = new FlxObject(FlxG.width / 2, 0, 140, 70);
if (items != null) camFollow.y = items.selectedItem.y; if (items != null) camFollow.y = items.selectedItem.y;
menuCamera.follow(camFollow, null, 0.06); menuCamera.follow(camFollow, null, 0.085);
var margin = 160; var margin = 160;
menuCamera.deadzone.set(0, margin, menuCamera.width, 40); menuCamera.deadzone.set(0, margin, menuCamera.width, menuCamera.height - margin * 2);
menuCamera.minScrollY = 0; menuCamera.minScrollY = 0;
items.onChange.add(function(selected) { items.onChange.add(function(selected) {
camFollow.y = selected.y; camFollow.y = selected.y;
itemDesc.text = preferenceDesc[items.selectedIndex];
}); });
} }
/**
* Create the description for preferences.
*/
function createPrefDescription():Void
{
itemDescBox.makeSolidColor(1, 1, FlxColor.BLACK);
itemDescBox.alpha = 0.6;
itemDesc.setFormat(Paths.font('vcr.ttf'), 32, FlxColor.WHITE, FlxTextAlign.CENTER, FlxTextBorderStyle.OUTLINE, FlxColor.BLACK);
itemDesc.borderSize = 3;
// Update the text.
itemDesc.text = preferenceDesc[items.selectedIndex];
itemDesc.screenCenter();
itemDesc.y += 270;
// Create the box around the text.
itemDescBox.setPosition(itemDesc.x - 10, itemDesc.y - 10);
itemDescBox.setGraphicSize(Std.int(itemDesc.width + 20), Std.int(itemDesc.height + 25));
itemDescBox.updateHitbox();
}
/** /**
* Create the menu items for each of the preferences. * Create the menu items for each of the preferences.
*/ */
function createPrefItems():Void function createPrefItems():Void
{ {
createPrefItemCheckbox('Naughtyness', 'Toggle displaying raunchy content', function(value:Bool):Void { createPrefItemCheckbox('Naughtyness', 'If enabled, raunchy content (such as swearing, etc.) will be displayed.', function(value:Bool):Void {
Preferences.naughtyness = value; Preferences.naughtyness = value;
}, Preferences.naughtyness); }, Preferences.naughtyness);
createPrefItemCheckbox('Downscroll', 'Enable to make notes move downwards', function(value:Bool):Void { createPrefItemCheckbox('Downscroll', 'If enabled, this will make the notes move downwards.', function(value:Bool):Void {
Preferences.downscroll = value; Preferences.downscroll = value;
}, Preferences.downscroll); }, Preferences.downscroll);
createPrefItemCheckbox('Flashing Lights', 'Disable to dampen flashing effects', function(value:Bool):Void { createPrefItemCheckbox('Flashing Lights', 'If disabled, it will dampen flashing effects. Useful for people with photosensitive epilepsy.', function(value:Bool):Void {
Preferences.flashingLights = value; Preferences.flashingLights = value;
}, Preferences.flashingLights); }, Preferences.flashingLights);
createPrefItemCheckbox('Camera Zooming on Beat', 'Disable to stop the camera bouncing to the song', function(value:Bool):Void { createPrefItemCheckbox('Camera Zooms', 'If disabled, camera stops bouncing to the song.', function(value:Bool):Void {
Preferences.zoomCamera = value; Preferences.zoomCamera = value;
}, Preferences.zoomCamera); }, Preferences.zoomCamera);
createPrefItemCheckbox('Debug Display', 'Enable to show FPS and other debug stats', function(value:Bool):Void { createPrefItemCheckbox('Debug Display', 'If enabled, FPS and other debug stats will be displayed.', function(value:Bool):Void {
Preferences.debugDisplay = value; Preferences.debugDisplay = value;
}, Preferences.debugDisplay); }, Preferences.debugDisplay);
createPrefItemCheckbox('Auto Pause', 'Automatically pause the game when it loses focus', function(value:Bool):Void { createPrefItemCheckbox('Auto Pause', 'If enabled, game automatically pauses when it loses focus.', function(value:Bool):Void {
Preferences.autoPause = value; Preferences.autoPause = value;
}, Preferences.autoPause); }, Preferences.autoPause);
@ -134,6 +175,7 @@ class PreferencesMenu extends Page
}); });
preferenceItems.add(checkbox); preferenceItems.add(checkbox);
preferenceDesc.push(prefDesc);
} }
/** /**
@ -152,6 +194,7 @@ class PreferencesMenu extends Page
var item = new NumberPreferenceItem(0, (120 * items.length) + 30, prefName, defaultValue, min, max, step, precision, onChange, valueFormatter); var item = new NumberPreferenceItem(0, (120 * items.length) + 30, prefName, defaultValue, min, max, step, precision, onChange, valueFormatter);
items.addItem(prefName, item); items.addItem(prefName, item);
preferenceItems.add(item.lefthandText); preferenceItems.add(item.lefthandText);
preferenceDesc.push(prefDesc);
} }
/** /**
@ -172,6 +215,7 @@ class PreferencesMenu extends Page
var item = new NumberPreferenceItem(0, (120 * items.length) + 30, prefName, defaultValue, min, max, 10, 0, newCallback, formatter); var item = new NumberPreferenceItem(0, (120 * items.length) + 30, prefName, defaultValue, min, max, 10, 0, newCallback, formatter);
items.addItem(prefName, item); items.addItem(prefName, item);
preferenceItems.add(item.lefthandText); preferenceItems.add(item.lefthandText);
preferenceDesc.push(prefDesc);
} }
/** /**
@ -185,5 +229,6 @@ class PreferencesMenu extends Page
var item = new EnumPreferenceItem(0, (120 * items.length) + 30, prefName, values, defaultValue, onChange); var item = new EnumPreferenceItem(0, (120 * items.length) + 30, prefName, values, defaultValue, onChange);
items.addItem(prefName, item); items.addItem(prefName, item);
preferenceItems.add(item.lefthandText); preferenceItems.add(item.lefthandText);
preferenceDesc.push(prefDesc);
} }
} }

View file

@ -55,6 +55,11 @@ class Constants
} }
#end #end
/**
* Whether or not the game is a debug build.
*/
public static final DEBUG_BUILD:Bool = #if FEATURE_DEBUG_FUNCTIONS true #else false #end;
/** /**
* URL DATA * URL DATA
*/ */

View file

@ -44,8 +44,58 @@ class ReflectUtil
return Reflect.field(obj, name); return Reflect.field(obj, name);
} }
public static function setAnonymousField(obj:Dynamic, name:String, value:Dynamic):Void
{
return Reflect.setField(obj, name, value);
}
public static function hasAnonymousField(obj:Dynamic, name:String):Bool public static function hasAnonymousField(obj:Dynamic, name:String):Bool
{ {
return Reflect.hasField(obj, name); return Reflect.hasField(obj, name);
} }
public static function copyAnonymousFieldsOf(obj:Dynamic):Dynamic
{
return Reflect.copy(obj);
}
public static function deleteAnonymousField(obj:Dynamic, name:String):Bool
{
return Reflect.deleteField(obj, name);
}
public static function compareValues(valueA:Dynamic, valueB:Dynamic):Int
{
return Reflect.compare(valueA, valueB);
}
public static function isObject(value:Dynamic):Bool
{
return Reflect.isObject(value);
}
public static function isFunction(value:Dynamic):Bool
{
return Reflect.isFunction(value);
}
public static function isEnumValue(value:Dynamic):Bool
{
return Reflect.isEnumValue(value);
}
public static function getProperty(obj:Dynamic, name:String):Dynamic
{
return Reflect.getProperty(obj, name);
}
public static function setProperty(obj:Dynamic, name:String, value:Dynamic):Void
{
return Reflect.setProperty(obj, name, value);
}
public static function compareMethods(functionA:Dynamic, functionB:Dynamic):Bool
{
return Reflect.compareMethods(functionA, functionB);
}
} }