mirror of
https://github.com/FunkinCrew/Funkin.git
synced 2024-11-14 19:25:16 -05:00
Reworked Story Menu (data driven)
This commit is contained in:
parent
021f7a0a1c
commit
a599dbea11
18 changed files with 416 additions and 80 deletions
|
@ -130,6 +130,7 @@
|
|||
<haxelib name="polymod" /> <!-- Modding framework -->
|
||||
<haxelib name="flxanimate" /> <!-- Texture atlas rendering -->
|
||||
<!-- <haxelib name="hxcodec" /> Video playback -->
|
||||
<haxelib name="json2object" /> <!-- JSON parsing -->
|
||||
|
||||
<haxelib name="thx.semver" />
|
||||
|
||||
|
@ -144,6 +145,9 @@
|
|||
<!--Enable this for Nape release builds for a serious peformance improvement-->
|
||||
<haxedef name="NAPE_RELEASE_BUILD" unless="debug" />
|
||||
|
||||
<!-- TODO: REMOVE THIS!!!! -->
|
||||
<haxeflag name="-w" value="-WDeprecated" />
|
||||
|
||||
<!-- _________________________________ Custom _______________________________ -->
|
||||
|
||||
<!-- Disable trace() calls in release builds to bump up performance. -->
|
||||
|
|
|
@ -207,9 +207,15 @@ class Conductor
|
|||
}
|
||||
|
||||
// FlxSignals are really cool.
|
||||
if (currentStep != oldStep) stepHit.dispatch();
|
||||
if (currentStep != oldStep)
|
||||
{
|
||||
stepHit.dispatch();
|
||||
}
|
||||
|
||||
if (currentBeat != oldBeat) beatHit.dispatch();
|
||||
if (currentBeat != oldBeat)
|
||||
{
|
||||
beatHit.dispatch();
|
||||
}
|
||||
}
|
||||
|
||||
@:deprecated // Switch to TimeChanges instead.
|
||||
|
|
|
@ -153,6 +153,7 @@ class InitState extends FlxTransitionableState
|
|||
|
||||
// TODO: Register custom event callbacks here
|
||||
|
||||
funkin.data.level.LevelRegistry.instance.loadEntries();
|
||||
SongEventParser.loadEventCache();
|
||||
SongDataParser.loadSongCache();
|
||||
StageDataParser.loadStageCache();
|
||||
|
|
|
@ -21,6 +21,7 @@ import funkin.shaderslmfao.ScreenWipeShader;
|
|||
import funkin.ui.AtlasMenuList;
|
||||
import funkin.ui.MenuList.MenuItem;
|
||||
import funkin.ui.MenuList;
|
||||
import funkin.ui.story.StoryMenuState;
|
||||
import funkin.ui.OptionsState;
|
||||
import funkin.ui.PreferencesMenu;
|
||||
import funkin.ui.Prompt;
|
||||
|
|
|
@ -66,7 +66,7 @@ abstract class BaseRegistry<T:(IRegistryEntry<J> & Constructible<EntryConstructo
|
|||
//
|
||||
// UNSCRIPTED ENTRIES
|
||||
//
|
||||
var entryIdList:Array<String> = DataAssets.listDataFilesInPath(dataFilePath);
|
||||
var entryIdList:Array<String> = DataAssets.listDataFilesInPath('${dataFilePath}/');
|
||||
var unscriptedEntryIds:Array<String> = entryIdList.filter(function(entryId:String):Bool {
|
||||
return !entries.exists(entryId);
|
||||
});
|
||||
|
@ -101,6 +101,11 @@ abstract class BaseRegistry<T:(IRegistryEntry<J> & Constructible<EntryConstructo
|
|||
return entries.size();
|
||||
}
|
||||
|
||||
public function fetchEntry(id:String):Null<T>
|
||||
{
|
||||
return entries.get(id);
|
||||
}
|
||||
|
||||
public function toString():String
|
||||
{
|
||||
return 'Registry(' + registryId + ', ${countEntries()} entries)';
|
||||
|
|
|
@ -13,7 +13,7 @@ typedef LevelData =
|
|||
* When making changes to the level data format, this should be incremented,
|
||||
* and a migration function should be added to LevelDataParser to handle old versions.
|
||||
*/
|
||||
@:default(LevelRegistry.LEVEL_DATA_VERSION)
|
||||
@:default(funkin.data.level.LevelRegistry.LEVEL_DATA_VERSION)
|
||||
var version:String;
|
||||
|
||||
/**
|
||||
|
@ -50,6 +50,14 @@ typedef LevelPropData =
|
|||
@:optional
|
||||
var scale:Float;
|
||||
|
||||
/**
|
||||
* The opacity to render the prop at.
|
||||
* @default 1.0
|
||||
*/
|
||||
@:default(1.0)
|
||||
@:optional
|
||||
var alpha:Float;
|
||||
|
||||
/**
|
||||
* If true, the prop is a pixel sprite, and will be rendered without smoothing.
|
||||
*/
|
||||
|
@ -59,11 +67,11 @@ typedef LevelPropData =
|
|||
|
||||
/**
|
||||
* The frequency to bop at, in beats.
|
||||
* @default 1.0 = every beat
|
||||
* @default 1 = every beat, 2 = every other beat, etc.
|
||||
*/
|
||||
@:default(1.0)
|
||||
@:default(1)
|
||||
@:optional
|
||||
var danceEvery:Float;
|
||||
var danceEvery:Int;
|
||||
|
||||
/**
|
||||
* The offset on the position to render the prop at.
|
||||
|
@ -71,7 +79,7 @@ typedef LevelPropData =
|
|||
*/
|
||||
@:default([0, 0])
|
||||
@:optional
|
||||
var offset:Array<Float>;
|
||||
var offsets:Array<Float>;
|
||||
|
||||
/**
|
||||
* A set of animations to play on the prop.
|
||||
|
|
|
@ -55,10 +55,10 @@ class LevelRegistry extends BaseRegistry<Level, LevelData>
|
|||
}
|
||||
|
||||
/**
|
||||
* A list of all the story weeks, in order.
|
||||
* A list of all the story weeks from the base game, in order.
|
||||
* TODO: Should this be hardcoded?
|
||||
*/
|
||||
public function listDefaultLevelIds():String
|
||||
public function listBaseGameLevelIds():Array<String>
|
||||
{
|
||||
return [
|
||||
"tutorial",
|
||||
|
@ -70,6 +70,16 @@ class LevelRegistry extends BaseRegistry<Level, LevelData>
|
|||
"week6",
|
||||
"week7",
|
||||
"weekend1"
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* A list of all installed story weeks that are not from the base game.
|
||||
*/
|
||||
public function listModdedLevelIds():Array<String>
|
||||
{
|
||||
return listEntryIds().filter(function(id:String):Bool {
|
||||
return listBaseGameLevelIds().indexOf(id) == -1;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -277,6 +277,7 @@ class PolymodHandler
|
|||
|
||||
// TODO: Reload event callbacks
|
||||
|
||||
funkin.data.level.LevelRegistry.instance.loadEntries();
|
||||
SongDataParser.loadSongCache();
|
||||
StageDataParser.loadStageCache();
|
||||
CharacterDataParser.loadCharacterCache();
|
||||
|
|
|
@ -21,36 +21,48 @@ typedef AnimationData =
|
|||
* ONLY for use by MultiSparrow characters.
|
||||
* @default The assetPath of the parent sprite
|
||||
*/
|
||||
@:default(null)
|
||||
@:optional
|
||||
var assetPath:Null<String>;
|
||||
|
||||
/**
|
||||
* Offset the character's position by this amount when playing this animation.
|
||||
* @default [0, 0]
|
||||
*/
|
||||
@:default([0, 0])
|
||||
@:optional
|
||||
var offsets:Null<Array<Float>>;
|
||||
|
||||
/**
|
||||
* Whether the animation should loop when it finishes.
|
||||
* @default false
|
||||
*/
|
||||
@:default(false)
|
||||
@:optional
|
||||
var looped:Null<Bool>;
|
||||
|
||||
/**
|
||||
* Whether the animation's sprites should be flipped horizontally.
|
||||
* @default false
|
||||
*/
|
||||
@:default(false)
|
||||
@:optional
|
||||
var flipX:Null<Bool>;
|
||||
|
||||
/**
|
||||
* Whether the animation's sprites should be flipped vertically.
|
||||
* @default false
|
||||
*/
|
||||
@:default(false)
|
||||
@:optional
|
||||
var flipY:Null<Bool>;
|
||||
|
||||
/**
|
||||
* The frame rate of the animation.
|
||||
* @default 24
|
||||
*/
|
||||
@:default(24)
|
||||
@:optional
|
||||
var frameRate:Null<Int>;
|
||||
|
||||
/**
|
||||
|
@ -59,5 +71,7 @@ typedef AnimationData =
|
|||
* @example [0, 1, 2, 3] (use only the first four frames)
|
||||
* @default [] (all frames)
|
||||
*/
|
||||
@:default([])
|
||||
@:optional
|
||||
var frameIndices:Null<Array<Int>>;
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ package funkin.play;
|
|||
import flixel.FlxObject;
|
||||
import flixel.FlxSprite;
|
||||
import flixel.system.FlxSound;
|
||||
import funkin.ui.story.StoryMenuState;
|
||||
import flixel.util.FlxColor;
|
||||
import flixel.util.FlxTimer;
|
||||
import funkin.modding.events.ScriptEvent;
|
||||
|
@ -208,11 +209,9 @@ class GameOverSubstate extends MusicBeatSubstate
|
|||
boyfriend.playAnimation('deathConfirm' + animationSuffix, true);
|
||||
|
||||
// After the animation finishes...
|
||||
new FlxTimer().start(0.7, function(tmr:FlxTimer)
|
||||
{
|
||||
new FlxTimer().start(0.7, function(tmr:FlxTimer) {
|
||||
// ...fade out the graphics. Then after that happens...
|
||||
FlxG.camera.fade(FlxColor.BLACK, 2, false, function()
|
||||
{
|
||||
FlxG.camera.fade(FlxColor.BLACK, 2, false, function() {
|
||||
// ...close the GameOverSubstate.
|
||||
FlxG.camera.fade(FlxColor.BLACK, 1, true, null, true);
|
||||
PlayState.needsReset = true;
|
||||
|
@ -276,8 +275,7 @@ class GameOverSubstate extends MusicBeatSubstate
|
|||
|
||||
if (PreferencesMenu.getPref('censor-naughty')) randomCensor = [1, 3, 8, 13, 17, 21];
|
||||
|
||||
FlxG.sound.play(Paths.sound('jeffGameover/jeffGameover-' + FlxG.random.int(1, 25, randomCensor)), 1, false, null, true, function()
|
||||
{
|
||||
FlxG.sound.play(Paths.sound('jeffGameover/jeffGameover-' + FlxG.random.int(1, 25, randomCensor)), 1, false, null, true, function() {
|
||||
// Once the quote ends, fade in the game over music.
|
||||
if (!isEnding && gameOverMusic != null)
|
||||
{
|
||||
|
|
|
@ -2,6 +2,7 @@ package funkin.play;
|
|||
|
||||
import flixel.FlxCamera;
|
||||
import flixel.FlxObject;
|
||||
import funkin.ui.story.StoryMenuState;
|
||||
import flixel.FlxSprite;
|
||||
import flixel.FlxState;
|
||||
import flixel.FlxSubState;
|
||||
|
|
|
@ -29,11 +29,14 @@ class Song // implements IPlayStateScriptedClass
|
|||
final variations:Array<String>;
|
||||
final difficulties:Map<String, SongDifficulty>;
|
||||
|
||||
var difficultyIds:Array<String>;
|
||||
|
||||
public function new(id:String)
|
||||
{
|
||||
this.songId = id;
|
||||
|
||||
variations = [];
|
||||
difficultyIds = [];
|
||||
difficulties = new Map<String, SongDifficulty>();
|
||||
|
||||
_metadata = SongDataParser.parseSongMetadata(songId);
|
||||
|
@ -61,6 +64,8 @@ class Song // implements IPlayStateScriptedClass
|
|||
{
|
||||
for (diffId in metadata.playData.difficulties)
|
||||
{
|
||||
difficultyIds.push(diffId);
|
||||
|
||||
var difficulty:SongDifficulty = new SongDifficulty(this, diffId, metadata.variation);
|
||||
|
||||
variations.push(metadata.variation);
|
||||
|
@ -138,7 +143,12 @@ class Song // implements IPlayStateScriptedClass
|
|||
|
||||
public function listDifficulties():Array<String>
|
||||
{
|
||||
return difficulties.keys().array();
|
||||
return difficultyIds;
|
||||
}
|
||||
|
||||
public function hasDifficulty(diffId:String):Bool
|
||||
{
|
||||
return difficulties.exists(diffId);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -256,6 +256,7 @@ class Bopper extends StageProp implements IPlayStateScriptedClass
|
|||
var correctName = correctAnimationName(name);
|
||||
if (correctName == null) return;
|
||||
|
||||
this.animation.paused = false;
|
||||
this.animation.play(correctName, restart, false, 0);
|
||||
|
||||
if (ignoreOther)
|
||||
|
|
|
@ -4,6 +4,7 @@ import flixel.FlxSprite;
|
|||
import haxe.Json;
|
||||
import lime.utils.Assets;
|
||||
// import flxtyped group
|
||||
import funkin.ui.story.StoryMenuState;
|
||||
import flixel.group.FlxGroup.FlxTypedGroup;
|
||||
import flixel.util.FlxTimer;
|
||||
import flixel.FlxG;
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
package funkin.ui.story;
|
||||
|
||||
import flixel.FlxSprite;
|
||||
import flixel.util.FlxColor;
|
||||
import funkin.play.song.Song;
|
||||
import funkin.data.IRegistryEntry;
|
||||
import funkin.data.level.LevelRegistry;
|
||||
import funkin.data.level.LevelData;
|
||||
|
@ -66,9 +68,11 @@ class Level implements IRegistryEntry<LevelData>
|
|||
*/
|
||||
public function getSongDisplayNames(difficulty:String):Array<String>
|
||||
{
|
||||
return getSongs().map(function(songId) {
|
||||
return funkin.play.song.SongData.SongDataParser.fetchSong(songId).getDifficulty(difficulty).songName;
|
||||
var songList:Array<String> = getSongs() ?? [];
|
||||
var songNameList:Array<String> = songList.map(function(songId) {
|
||||
return funkin.play.song.SongData.SongDataParser.fetchSong(songId) ?.getDifficulty(difficulty) ?.songName ?? 'Unknown';
|
||||
});
|
||||
return songNameList;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -112,14 +116,15 @@ class Level implements IRegistryEntry<LevelData>
|
|||
var firstSongId:String = songList[0];
|
||||
var firstSong:Song = funkin.play.song.SongData.SongDataParser.fetchSong(firstSongId);
|
||||
|
||||
for (difficulty in firstSong.getDifficulties())
|
||||
for (difficulty in firstSong.listDifficulties())
|
||||
{
|
||||
difficulties.push(difficulty);
|
||||
}
|
||||
|
||||
// Filter to only include difficulties that are present in all songs
|
||||
for (songId in 1...songList.length)
|
||||
for (songIndex in 1...songList.length)
|
||||
{
|
||||
var songId:String = songList[songIndex];
|
||||
var song:Song = funkin.play.song.SongData.SongDataParser.fetchSong(songId);
|
||||
|
||||
for (difficulty in difficulties)
|
||||
|
@ -145,7 +150,10 @@ class Level implements IRegistryEntry<LevelData>
|
|||
var propData = _data.props[propIndex];
|
||||
var propSprite:LevelProp = LevelProp.build(propData);
|
||||
propSprite.x += FlxG.width * 0.25 * propIndex;
|
||||
props.push(propSprite);
|
||||
}
|
||||
|
||||
return props;
|
||||
}
|
||||
|
||||
public function destroy():Void {}
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
package funkin.ui.story;
|
||||
|
||||
import funkin.play.stage.Bopper;
|
||||
import funkin.util.assets.FlxAnimationUtil;
|
||||
import funkin.data.level.LevelData;
|
||||
|
||||
class LevelProp extends Bopper
|
||||
{
|
||||
public function new(danceEvery:Int)
|
||||
|
@ -7,6 +11,11 @@ class LevelProp extends Bopper
|
|||
super(danceEvery);
|
||||
}
|
||||
|
||||
public function playConfirm():Void
|
||||
{
|
||||
playAnimation('confirm', true, true);
|
||||
}
|
||||
|
||||
public static function build(propData:LevelPropData):Null<LevelProp>
|
||||
{
|
||||
var isAnimated:Bool = propData.animations.length > 0;
|
||||
|
@ -33,8 +42,8 @@ class LevelProp extends Bopper
|
|||
return null;
|
||||
}
|
||||
|
||||
prop.scale.set(propData.scale * (propData.isPixel ? 6 : 1));
|
||||
prop.updateHitbox();
|
||||
var scale:Float = propData.scale * (propData.isPixel ? 6 : 1);
|
||||
prop.scale.set(scale, scale);
|
||||
prop.antialiasing = !propData.isPixel;
|
||||
prop.alpha = propData.alpha;
|
||||
prop.x = propData.offsets[0];
|
||||
|
@ -46,6 +55,9 @@ class LevelProp extends Bopper
|
|||
prop.setAnimationOffsets(propAnim.name, propAnim.offsets[0], propAnim.offsets[1]);
|
||||
}
|
||||
|
||||
prop.dance();
|
||||
prop.animation.paused = true;
|
||||
|
||||
return prop;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
package funkin.ui.story;
|
||||
|
||||
import funkin.CoolUtil;
|
||||
import flixel.FlxSprite;
|
||||
import flixel.graphics.frames.FlxAtlasFrames;
|
||||
import flixel.group.FlxSpriteGroup;
|
||||
import flixel.util.FlxColor;
|
||||
import funkin.CoolUtil;
|
||||
|
||||
class LevelTitle extends FlxSpriteGroup
|
||||
{
|
||||
|
@ -24,16 +25,27 @@ class LevelTitle extends FlxSpriteGroup
|
|||
super(x, y);
|
||||
|
||||
this.level = level;
|
||||
}
|
||||
|
||||
public override function create():Void
|
||||
{
|
||||
super.create();
|
||||
if (this.level == null) throw "Level cannot be null!";
|
||||
|
||||
buildLevelTitle();
|
||||
buildLevelLock();
|
||||
}
|
||||
|
||||
override function get_width():Float
|
||||
{
|
||||
if (length == 0) return 0;
|
||||
|
||||
if (lock.visible)
|
||||
{
|
||||
return title.width + lock.width + LOCK_PAD;
|
||||
}
|
||||
else
|
||||
{
|
||||
return title.width;
|
||||
}
|
||||
}
|
||||
|
||||
// if it runs at 60fps, fake framerate will be 6
|
||||
// if it runs at 144 fps, fake framerate will be like 14, and will update the graphic every 0.016666 * 3 seconds still???
|
||||
// so it runs basically every so many seconds, not dependant on framerate??
|
||||
|
@ -42,12 +54,12 @@ class LevelTitle extends FlxSpriteGroup
|
|||
|
||||
public override function update(elapsed:Float):Void
|
||||
{
|
||||
this.y = CoolUtil.coolLerp(y, (targetY * 120) + 480, 0.17);
|
||||
this.y = CoolUtil.coolLerp(y, targetY, 0.17);
|
||||
|
||||
if (isFlashing) flashingInt += 1;
|
||||
if (flashingInt % fakeFramerate >= Math.floor(fakeFramerate / 2)) week.color = 0xFF33ffff;
|
||||
if (flashingInt % fakeFramerate >= Math.floor(fakeFramerate / 2)) title.color = 0xFF33ffff;
|
||||
else
|
||||
week.color = FlxColor.WHITE;
|
||||
title.color = FlxColor.WHITE;
|
||||
}
|
||||
|
||||
public function showLock():Void
|
||||
|
|
|
@ -1,5 +1,20 @@
|
|||
package funkin.ui.story;
|
||||
|
||||
import flixel.addons.transition.FlxTransitionableState;
|
||||
import flixel.FlxSprite;
|
||||
import flixel.group.FlxGroup.FlxTypedGroup;
|
||||
import flixel.text.FlxText;
|
||||
import flixel.tweens.FlxEase;
|
||||
import flixel.tweens.FlxTween;
|
||||
import flixel.util.FlxColor;
|
||||
import flixel.util.FlxTimer;
|
||||
import funkin.data.level.LevelRegistry;
|
||||
import funkin.modding.events.ScriptEvent;
|
||||
import funkin.modding.events.ScriptEventDispatcher;
|
||||
import funkin.play.PlayState;
|
||||
import funkin.play.song.SongData.SongDataParser;
|
||||
import funkin.util.Constants;
|
||||
|
||||
class StoryMenuState extends MusicBeatState
|
||||
{
|
||||
static final DEFAULT_BACKGROUND_COLOR:FlxColor = FlxColor.fromString("#F9CF51");
|
||||
|
@ -10,12 +25,15 @@ class StoryMenuState extends MusicBeatState
|
|||
var currentLevelId:String = 'tutorial';
|
||||
var currentLevel:Level;
|
||||
var isLevelUnlocked:Bool;
|
||||
var currentLevelTitle:LevelTitle;
|
||||
|
||||
var highScore:Int = 42069420;
|
||||
var highScoreLerp:Int = 12345678;
|
||||
|
||||
var exitingMenu:Bool = false;
|
||||
var selectedWeek:Bool = false;
|
||||
var selectedLevel:Bool = false;
|
||||
|
||||
var displayingModdedLevels:Bool = false;
|
||||
|
||||
//
|
||||
// RENDER OBJECTS
|
||||
|
@ -37,7 +55,7 @@ class StoryMenuState extends MusicBeatState
|
|||
var tracklistText:FlxText;
|
||||
|
||||
/**
|
||||
* The title of the week in the middle.
|
||||
* The titles of the levels in the middle.
|
||||
*/
|
||||
var levelTitles:FlxTypedGroup<LevelTitle>;
|
||||
|
||||
|
@ -66,18 +84,26 @@ class StoryMenuState extends MusicBeatState
|
|||
*/
|
||||
var difficultySprite:FlxSprite;
|
||||
|
||||
var difficultySprites:Map<String, FlxSprite>;
|
||||
|
||||
var stickerSubState:StickerSubState;
|
||||
|
||||
public function new(?stickers:StickerSubState = null)
|
||||
{
|
||||
super();
|
||||
|
||||
if (stickers != null)
|
||||
{
|
||||
stickerSubState = stickers;
|
||||
}
|
||||
|
||||
super();
|
||||
}
|
||||
|
||||
override function create():Void
|
||||
{
|
||||
super.create();
|
||||
|
||||
difficultySprites = new Map<String, FlxSprite>();
|
||||
|
||||
transIn = FlxTransitionableState.defaultTransIn;
|
||||
transOut = FlxTransitionableState.defaultTransOut;
|
||||
|
||||
|
@ -101,92 +127,131 @@ class StoryMenuState extends MusicBeatState
|
|||
|
||||
persistentUpdate = persistentDraw = true;
|
||||
|
||||
updateData();
|
||||
|
||||
// Explicitly define the background color.
|
||||
this.bgColor = FlxColor.BLACK;
|
||||
|
||||
levelTitles = new FlxTypedGroup<LevelTitle>();
|
||||
add(levelTitles);
|
||||
|
||||
levelBackground = new FlxSprite(0, 56).makeGraphic(FlxG.width, BACKGROUND_HEIGHT, DEFAULT_BACKGROUND_COLOR);
|
||||
add(levelBackground);
|
||||
updateBackground();
|
||||
|
||||
levelProps = new FlxTypedGroup<LevelProp>();
|
||||
levelProps.zIndex = 1000;
|
||||
add(levelProps);
|
||||
|
||||
updateProps();
|
||||
|
||||
scoreText = new FlxText(10, 10, 0, 'HIGH SCORE: 42069420');
|
||||
scoreText.setFormat("VCR OSD Mono", 32);
|
||||
add(scoreText);
|
||||
|
||||
tracklistText = new FlxText(FlxG.width * 0.05, yellowBG.x + yellowBG.height + 100, 0, "Tracks", 32);
|
||||
tracklistText = new FlxText(FlxG.width * 0.05, levelBackground.x + levelBackground.height + 100, 0, "Tracks", 32);
|
||||
tracklistText.setFormat("VCR OSD Mono", 32);
|
||||
tracklistText.alignment = CENTER;
|
||||
tracklistText.font = rankText.font;
|
||||
tracklistText.color = 0xFFe55777;
|
||||
add(tracklistText);
|
||||
|
||||
levelTitleText = new FlxText(FlxG.width * 0.7, 10, 0, 'WEEK 1');
|
||||
levelTitleText = new FlxText(FlxG.width * 0.7, 10, 0, 'LEVEL 1');
|
||||
levelTitleText.setFormat("VCR OSD Mono", 32, FlxColor.WHITE, RIGHT);
|
||||
levelTitleText.alpha = 0.7;
|
||||
add(levelTitleText);
|
||||
|
||||
buildLevelTitles(false);
|
||||
buildLevelTitles();
|
||||
|
||||
leftArrow = new FlxSprite(grpWeekText.members[0].x + grpWeekText.members[0].width + 10, grpWeekText.members[0].y + 10);
|
||||
leftArrow.frames = Paths.getSparrowAtlas('storymenu/ui/arrows');
|
||||
leftArrow.animation.addByPrefix('idle', 'leftIdle0');
|
||||
leftArrow.animation.addByPrefix('press', 'leftConfirm0');
|
||||
leftArrow.animation.play('idle');
|
||||
add(leftArrow);
|
||||
leftDifficultyArrow = new FlxSprite(levelTitles.members[0].x + levelTitles.members[0].width + 10, levelTitles.members[0].y + 10);
|
||||
leftDifficultyArrow.frames = Paths.getSparrowAtlas('storymenu/ui/arrows');
|
||||
leftDifficultyArrow.animation.addByPrefix('idle', 'leftIdle0');
|
||||
leftDifficultyArrow.animation.addByPrefix('press', 'leftConfirm0');
|
||||
leftDifficultyArrow.animation.play('idle');
|
||||
add(leftDifficultyArrow);
|
||||
|
||||
rightArrow = new FlxSprite(sprDifficulty.x + sprDifficulty.width + 50, leftArrow.y);
|
||||
rightArrow.frames = leftArrow.frames;
|
||||
rightArrow.animation.addByPrefix('idle', 'rightIdle0');
|
||||
rightArrow.animation.addByPrefix('press', 'rightConfirm0');
|
||||
rightArrow.animation.play('idle');
|
||||
add(rightArrow);
|
||||
buildDifficultySprite();
|
||||
|
||||
rightDifficultyArrow = new FlxSprite(difficultySprite.x + difficultySprite.width + 10, leftDifficultyArrow.y);
|
||||
rightDifficultyArrow.frames = leftDifficultyArrow.frames;
|
||||
rightDifficultyArrow.animation.addByPrefix('idle', 'rightIdle0');
|
||||
rightDifficultyArrow.animation.addByPrefix('press', 'rightConfirm0');
|
||||
rightDifficultyArrow.animation.play('idle');
|
||||
add(rightDifficultyArrow);
|
||||
|
||||
difficultySprite = buildDifficultySprite();
|
||||
changeDifficulty();
|
||||
add(difficultySprite);
|
||||
|
||||
updateText();
|
||||
changeDifficulty();
|
||||
changeLevel();
|
||||
refresh();
|
||||
|
||||
#if discord_rpc
|
||||
// Updating Discord Rich Presence
|
||||
DiscordClient.changePresence("In the Menus", null);
|
||||
#end
|
||||
}
|
||||
|
||||
function buildDifficultySprite():Void
|
||||
function updateData():Void
|
||||
{
|
||||
difficultySprite = new FlxSprite(leftArrow.x + 130, leftArrow.y);
|
||||
difficultySprite.frames = ui_tex;
|
||||
difficultySprite.animation.addByPrefix('easy', 'EASY');
|
||||
difficultySprite.animation.addByPrefix('normal', 'NORMAL');
|
||||
difficultySprite.animation.addByPrefix('hard', 'HARD');
|
||||
difficultySprite.animation.play('easy');
|
||||
currentLevel = LevelRegistry.instance.fetchEntry(currentLevelId);
|
||||
isLevelUnlocked = currentLevel == null ? false : currentLevel.isUnlocked();
|
||||
}
|
||||
|
||||
function buildLevelTitles(moddedLevels:Bool):Void
|
||||
function buildDifficultySprite():Void
|
||||
{
|
||||
remove(difficultySprite);
|
||||
difficultySprite = difficultySprites.get(currentDifficultyId);
|
||||
if (difficultySprite == null)
|
||||
{
|
||||
difficultySprite = new FlxSprite(leftDifficultyArrow.x + leftDifficultyArrow.width + 10, leftDifficultyArrow.y);
|
||||
difficultySprite.loadGraphic(Paths.image('storymenu/difficulties/${currentDifficultyId}'));
|
||||
difficultySprites.set(currentDifficultyId, difficultySprite);
|
||||
|
||||
difficultySprite.x += (difficultySprites.get('normal').width - difficultySprite.width) / 2;
|
||||
}
|
||||
difficultySprite.alpha = 0;
|
||||
difficultySprite.y = leftDifficultyArrow.y - 15;
|
||||
FlxTween.tween(difficultySprite, {y: leftDifficultyArrow.y + 15, alpha: 1}, 0.07);
|
||||
add(difficultySprite);
|
||||
}
|
||||
|
||||
function buildLevelTitles():Void
|
||||
{
|
||||
levelTitles.clear();
|
||||
|
||||
var levelIds:Array<String> = LevelRegistry.instance.getLevelIds();
|
||||
var levelIds:Array<String> = displayingModdedLevels ? LevelRegistry.instance.listModdedLevelIds() : LevelRegistry.instance.listBaseGameLevelIds();
|
||||
if (levelIds.length == 0) levelIds = ['tutorial'];
|
||||
|
||||
for (levelIndex in 0...levelIds.length)
|
||||
{
|
||||
var levelId:String = levelIds[levelIndex];
|
||||
var level:Level = LevelRegistry.instance.fetchEntry(levelId);
|
||||
var levelTitleItem:LevelTitle = new LevelTitle(0, yellowBG.y + yellowBG.height + 10, level);
|
||||
levelTitleItem.targetY = ((weekThing.height + 20) * levelIndex);
|
||||
if (level == null) continue;
|
||||
|
||||
var levelTitleItem:LevelTitle = new LevelTitle(0, Std.int(levelBackground.y + levelBackground.height + 10), level);
|
||||
levelTitleItem.targetY = ((levelTitleItem.height + 20) * levelIndex);
|
||||
levelTitleItem.screenCenter(X);
|
||||
levelTitles.add(levelTitleItem);
|
||||
}
|
||||
}
|
||||
|
||||
function switchMode(moddedLevels:Bool):Void
|
||||
{
|
||||
displayingModdedLevels = moddedLevels;
|
||||
buildLevelTitles();
|
||||
|
||||
changeLevel(0);
|
||||
changeDifficulty(0);
|
||||
}
|
||||
|
||||
override function update(elapsed:Float)
|
||||
{
|
||||
highScoreLerp = CoolUtil.coolLerp(highScoreLerp, highScore, 0.5);
|
||||
Conductor.update();
|
||||
|
||||
scoreText.text = 'WEEK SCORE: ${Math.round(highScoreLerp)}';
|
||||
highScoreLerp = Std.int(CoolUtil.coolLerp(highScoreLerp, highScore, 0.5));
|
||||
|
||||
txtWeekTitle.text = weekNames[curWeek].toUpperCase();
|
||||
txtWeekTitle.x = FlxG.width - (txtWeekTitle.width + 10);
|
||||
scoreText.text = 'LEVEL SCORE: ${Math.round(highScoreLerp)}';
|
||||
|
||||
levelTitleText.text = currentLevel.getTitle();
|
||||
levelTitleText.x = FlxG.width - (levelTitleText.width + 10); // Right align.
|
||||
|
||||
handleKeyPresses();
|
||||
|
||||
|
@ -197,7 +262,7 @@ class StoryMenuState extends MusicBeatState
|
|||
{
|
||||
if (!exitingMenu)
|
||||
{
|
||||
if (!selectedWeek)
|
||||
if (!selectedLevel)
|
||||
{
|
||||
if (controls.UI_UP_P)
|
||||
{
|
||||
|
@ -211,20 +276,20 @@ class StoryMenuState extends MusicBeatState
|
|||
|
||||
if (controls.UI_RIGHT)
|
||||
{
|
||||
rightArrow.animation.play('press')
|
||||
rightDifficultyArrow.animation.play('press');
|
||||
}
|
||||
else
|
||||
{
|
||||
rightArrow.animation.play('idle');
|
||||
rightDifficultyArrow.animation.play('idle');
|
||||
}
|
||||
|
||||
if (controls.UI_LEFT)
|
||||
{
|
||||
leftArrow.animation.play('press');
|
||||
leftDifficultyArrow.animation.play('press');
|
||||
}
|
||||
else
|
||||
{
|
||||
leftArrow.animation.play('idle');
|
||||
leftDifficultyArrow.animation.play('idle');
|
||||
}
|
||||
|
||||
if (controls.UI_RIGHT_P)
|
||||
|
@ -236,15 +301,20 @@ class StoryMenuState extends MusicBeatState
|
|||
{
|
||||
changeDifficulty(-1);
|
||||
}
|
||||
|
||||
if (FlxG.keys.justPressed.TAB)
|
||||
{
|
||||
switchMode(!displayingModdedLevels);
|
||||
}
|
||||
}
|
||||
|
||||
if (controls.ACCEPT)
|
||||
{
|
||||
selectWeek();
|
||||
selectLevel();
|
||||
}
|
||||
}
|
||||
|
||||
if (controls.BACK && !exitingMenu && !selectedWeek)
|
||||
if (controls.BACK && !exitingMenu && !selectedLevel)
|
||||
{
|
||||
FlxG.sound.play(Paths.sound('cancelMenu'));
|
||||
exitingMenu = true;
|
||||
|
@ -252,7 +322,180 @@ class StoryMenuState extends MusicBeatState
|
|||
}
|
||||
}
|
||||
|
||||
function changeLevel(change:Int = 0):Void {}
|
||||
/**
|
||||
* Changes the selected level.
|
||||
* @param change +1 (down), -1 (up)
|
||||
*/
|
||||
function changeLevel(change:Int = 0):Void
|
||||
{
|
||||
var levelList:Array<String> = displayingModdedLevels ? LevelRegistry.instance.listModdedLevelIds() : LevelRegistry.instance.listBaseGameLevelIds();
|
||||
if (levelList.length == 0) levelList = ['tutorial'];
|
||||
|
||||
function changeDifficulty(change:Int = 0):Void {}
|
||||
var currentIndex:Int = levelList.indexOf(currentLevelId);
|
||||
|
||||
currentIndex += change;
|
||||
|
||||
// Wrap around
|
||||
if (currentIndex < 0) currentIndex = levelList.length - 1;
|
||||
if (currentIndex >= levelList.length) currentIndex = 0;
|
||||
|
||||
currentLevelId = levelList[currentIndex];
|
||||
|
||||
updateData();
|
||||
|
||||
for (index in 0...levelTitles.members.length)
|
||||
{
|
||||
var item:LevelTitle = levelTitles.members[index];
|
||||
|
||||
item.targetY = (index - currentIndex) * 120 + 480;
|
||||
|
||||
if (index == currentIndex)
|
||||
{
|
||||
currentLevelTitle = item;
|
||||
item.alpha = 1.0;
|
||||
}
|
||||
else if (index > currentIndex)
|
||||
{
|
||||
item.alpha = 0.6;
|
||||
}
|
||||
else
|
||||
{
|
||||
item.alpha = 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
updateText();
|
||||
updateBackground();
|
||||
updateProps();
|
||||
refresh();
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes the selected difficulty.
|
||||
* @param change +1 (right) to increase difficulty, -1 (left) to decrease difficulty
|
||||
*/
|
||||
function changeDifficulty(change:Int = 0):Void
|
||||
{
|
||||
var difficultyList:Array<String> = currentLevel.getDifficulties();
|
||||
var currentIndex:Int = difficultyList.indexOf(currentDifficultyId);
|
||||
|
||||
currentIndex += change;
|
||||
|
||||
// Wrap around
|
||||
if (currentIndex < 0) currentIndex = difficultyList.length - 1;
|
||||
if (currentIndex >= difficultyList.length) currentIndex = 0;
|
||||
|
||||
currentDifficultyId = difficultyList[currentIndex];
|
||||
|
||||
buildDifficultySprite();
|
||||
}
|
||||
|
||||
override function dispatchEvent(event:ScriptEvent):Void
|
||||
{
|
||||
// super.dispatchEvent(event) dispatches event to module scripts.
|
||||
super.dispatchEvent(event);
|
||||
|
||||
if ((levelProps?.length ?? 0) > 0)
|
||||
{
|
||||
// Dispatch event to props.
|
||||
for (prop in levelProps)
|
||||
{
|
||||
ScriptEventDispatcher.callEvent(prop, event);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function selectLevel()
|
||||
{
|
||||
if (!currentLevel.isUnlocked())
|
||||
{
|
||||
FlxG.sound.play(Paths.sound('cancelMenu'));
|
||||
return;
|
||||
}
|
||||
|
||||
if (selectedLevel) return;
|
||||
|
||||
selectedLevel = true;
|
||||
|
||||
FlxG.sound.play(Paths.sound('confirmMenu'));
|
||||
|
||||
currentLevelTitle.isFlashing = true;
|
||||
|
||||
for (prop in levelProps.members)
|
||||
{
|
||||
prop.playConfirm();
|
||||
}
|
||||
|
||||
PlayState.storyPlaylist = currentLevel.getSongs();
|
||||
PlayState.isStoryMode = true;
|
||||
|
||||
PlayState.currentSong = SongLoad.loadFromJson(PlayState.storyPlaylist[0].toLowerCase(), PlayState.storyPlaylist[0].toLowerCase());
|
||||
PlayState.currentSong_NEW = SongDataParser.fetchSong(PlayState.storyPlaylist[0].toLowerCase());
|
||||
|
||||
// TODO: Fix this.
|
||||
PlayState.storyWeek = 0;
|
||||
PlayState.campaignScore = 0;
|
||||
|
||||
// TODO: Fix this.
|
||||
PlayState.storyDifficulty = 0;
|
||||
PlayState.storyDifficulty_NEW = currentDifficultyId;
|
||||
|
||||
SongLoad.curDiff = PlayState.storyDifficulty_NEW;
|
||||
|
||||
new FlxTimer().start(1, function(tmr:FlxTimer) {
|
||||
LoadingState.loadAndSwitchState(new PlayState(), true);
|
||||
});
|
||||
}
|
||||
|
||||
function updateBackground():Void
|
||||
{
|
||||
if (levelBackground != null)
|
||||
{
|
||||
var oldBackground:FlxSprite = levelBackground;
|
||||
|
||||
FlxTween.tween(oldBackground, {alpha: 0.0}, 0.6,
|
||||
{
|
||||
ease: FlxEase.linear,
|
||||
onComplete: function(_) {
|
||||
remove(oldBackground);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
levelBackground = currentLevel.buildBackground();
|
||||
levelBackground.x = 0;
|
||||
levelBackground.y = 56;
|
||||
levelBackground.alpha = 0.0;
|
||||
levelBackground.zIndex = 100;
|
||||
add(levelBackground);
|
||||
|
||||
FlxTween.tween(levelBackground, {alpha: 1.0}, 0.6,
|
||||
{
|
||||
ease: FlxEase.linear
|
||||
});
|
||||
}
|
||||
|
||||
function updateProps():Void
|
||||
{
|
||||
levelProps.clear();
|
||||
for (prop in currentLevel.buildProps())
|
||||
{
|
||||
prop.zIndex = 1000;
|
||||
levelProps.add(prop);
|
||||
}
|
||||
|
||||
refresh();
|
||||
}
|
||||
|
||||
function updateText():Void
|
||||
{
|
||||
tracklistText.text = 'TRACKS\n\n';
|
||||
tracklistText.text += currentLevel.getSongDisplayNames(currentDifficultyId).join('\n');
|
||||
|
||||
tracklistText.screenCenter(X);
|
||||
tracklistText.x -= FlxG.width * 0.35;
|
||||
|
||||
// TODO: Fix this.
|
||||
highScore = Highscore.getWeekScore(0, 0);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue