mirror of
https://github.com/ninjamuffin99/Funkin.git
synced 2024-11-15 11:22:55 +00:00
Merge branch 'rewrite/master' into feature/results-freeplay-transition
This commit is contained in:
commit
c322e2aeef
12
.github/labeler.yml
vendored
Normal file
12
.github/labeler.yml
vendored
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
# Add Documentation tag to PR's changing markdown files, or anyhting in the docs folder
|
||||||
|
Documentation:
|
||||||
|
- changed-files:
|
||||||
|
- any-glob-to-any-file:
|
||||||
|
- any-glob-to-any-file:
|
||||||
|
- docs/*
|
||||||
|
- '**/*.md'
|
||||||
|
|
||||||
|
# Adds Haxe tag to PR's changing haxe code files
|
||||||
|
Haxe:
|
||||||
|
- changed-files:
|
||||||
|
- any-glob-to-any-file: '**/*.hx'
|
14
.github/workflows/labeler.yml
vendored
Normal file
14
.github/workflows/labeler.yml
vendored
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
name: "Pull Request Labeler"
|
||||||
|
on:
|
||||||
|
- pull_request_target
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
labeler:
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
pull-requests: write
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/labeler@v5
|
||||||
|
with:
|
||||||
|
sync-labels: true
|
4
.gitmodules
vendored
4
.gitmodules
vendored
|
@ -1,6 +1,6 @@
|
||||||
[submodule "assets"]
|
[submodule "assets"]
|
||||||
path = assets
|
path = assets
|
||||||
url = https://github.com/FunkinCrew/Funkin-assets-secret
|
url = https://github.com/FunkinCrew/Funkin-Assets-secret
|
||||||
[submodule "art"]
|
[submodule "art"]
|
||||||
path = art
|
path = art
|
||||||
url = https://github.com/FunkinCrew/Funkin-art-secret
|
url = https://github.com/FunkinCrew/Funkin-Art-secret
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<project>
|
<project xmlns="http://lime.openfl.org/project/1.0.4" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://lime.openfl.org/project/1.0.4 http://lime.openfl.org/xsd/project-1.0.4.xsd">
|
||||||
<!-- _________________________ Application Settings _________________________ -->
|
<!-- _________________________ Application Settings _________________________ -->
|
||||||
<app title="Friday Night Funkin'" file="Funkin" packageName="com.funkin.fnf" package="com.funkin.fnf" main="Main" version="0.3.3" company="ninjamuffin99" />
|
<app title="Friday Night Funkin'" file="Funkin" packageName="com.funkin.fnf" package="com.funkin.fnf" main="Main" version="0.3.3" company="ninjamuffin99" />
|
||||||
<!--Switch Export with Unique ApplicationID and Icon-->
|
<!--Switch Export with Unique ApplicationID and Icon-->
|
||||||
|
@ -28,7 +29,7 @@
|
||||||
<set name="BUILD_DIR" value="export/debug" if="debug" />
|
<set name="BUILD_DIR" value="export/debug" if="debug" />
|
||||||
<set name="BUILD_DIR" value="export/release" unless="debug" />
|
<set name="BUILD_DIR" value="export/release" unless="debug" />
|
||||||
<set name="BUILD_DIR" value="export/32bit" if="32bit" />
|
<set name="BUILD_DIR" value="export/32bit" if="32bit" />
|
||||||
<classpath name="source" />
|
<source path="source" />
|
||||||
<assets path="assets/preload" rename="assets" exclude="*.ogg|*.wav" if="web" />
|
<assets path="assets/preload" rename="assets" exclude="*.ogg|*.wav" if="web" />
|
||||||
<assets path="assets/preload" rename="assets" exclude="*.mp3|*.wav" unless="web" />
|
<assets path="assets/preload" rename="assets" exclude="*.mp3|*.wav" unless="web" />
|
||||||
<define name="PRELOAD_ALL" unless="web" />
|
<define name="PRELOAD_ALL" unless="web" />
|
||||||
|
@ -126,6 +127,7 @@
|
||||||
<haxelib name="hxCodec" if="desktop" unless="hl" /> <!-- Video playback -->
|
<haxelib name="hxCodec" if="desktop" unless="hl" /> <!-- Video playback -->
|
||||||
<haxelib name="funkin.vis"/>
|
<haxelib name="funkin.vis"/>
|
||||||
|
|
||||||
|
<haxelib name="FlxPartialSound" /> <!-- Loading partial sound data -->
|
||||||
|
|
||||||
<haxelib name="json2object" /> <!-- JSON parsing -->
|
<haxelib name="json2object" /> <!-- JSON parsing -->
|
||||||
<haxelib name="thx.core" /> <!-- General utility library, "the lodash of Haxe" -->
|
<haxelib name="thx.core" /> <!-- General utility library, "the lodash of Haxe" -->
|
||||||
|
|
|
@ -79,7 +79,7 @@
|
||||||
{
|
{
|
||||||
"props": {
|
"props": {
|
||||||
"ignoreExtern": true,
|
"ignoreExtern": true,
|
||||||
"format": "^[a-z][A-Z][A-Z0-9]*(_[A-Z0-9_]+)*$",
|
"format": "^[a-zA-Z0-9]+(?:_[a-zA-Z0-9]+)*$",
|
||||||
"tokens": ["INLINE", "NOTINLINE"]
|
"tokens": ["INLINE", "NOTINLINE"]
|
||||||
},
|
},
|
||||||
"type": "ConstantName"
|
"type": "ConstantName"
|
||||||
|
|
7
hmm.json
7
hmm.json
|
@ -1,5 +1,12 @@
|
||||||
{
|
{
|
||||||
"dependencies": [
|
"dependencies": [
|
||||||
|
{
|
||||||
|
"name": "FlxPartialSound",
|
||||||
|
"type": "git",
|
||||||
|
"dir": null,
|
||||||
|
"ref": "44aa7eb",
|
||||||
|
"url": "https://github.com/FunkinCrew/FlxPartialSound.git"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "discord_rpc",
|
"name": "discord_rpc",
|
||||||
"type": "git",
|
"type": "git",
|
||||||
|
|
|
@ -123,9 +123,17 @@ class Paths
|
||||||
return 'songs:assets/songs/${song.toLowerCase()}/Voices$suffix.${Constants.EXT_SOUND}';
|
return 'songs:assets/songs/${song.toLowerCase()}/Voices$suffix.${Constants.EXT_SOUND}';
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function inst(song:String, ?suffix:String = ''):String
|
/**
|
||||||
|
* Gets the path to an `Inst.mp3/ogg` song instrumental from songs:assets/songs/`song`/
|
||||||
|
* @param song name of the song to get instrumental for
|
||||||
|
* @param suffix any suffix to add to end of song name, used for `-erect` variants usually
|
||||||
|
* @param withExtension if it should return with the audio file extension `.mp3` or `.ogg`.
|
||||||
|
* @return String
|
||||||
|
*/
|
||||||
|
public static function inst(song:String, ?suffix:String = '', ?withExtension:Bool = true):String
|
||||||
{
|
{
|
||||||
return 'songs:assets/songs/${song.toLowerCase()}/Inst$suffix.${Constants.EXT_SOUND}';
|
var ext:String = withExtension ? '.${Constants.EXT_SOUND}' : '';
|
||||||
|
return 'songs:assets/songs/${song.toLowerCase()}/Inst$suffix$ext';
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function image(key:String, ?library:String):String
|
public static function image(key:String, ?library:String):String
|
||||||
|
@ -153,3 +161,11 @@ class Paths
|
||||||
return FlxAtlasFrames.fromSpriteSheetPacker(image(key, library), file('images/$key.txt', library));
|
return FlxAtlasFrames.fromSpriteSheetPacker(image(key, library), file('images/$key.txt', library));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum abstract PathsFunction(String)
|
||||||
|
{
|
||||||
|
var MUSIC;
|
||||||
|
var INST;
|
||||||
|
var VOICES;
|
||||||
|
var SOUND;
|
||||||
|
}
|
||||||
|
|
|
@ -11,6 +11,11 @@ import funkin.audio.waveform.WaveformDataParser;
|
||||||
import funkin.data.song.SongData.SongMusicData;
|
import funkin.data.song.SongData.SongMusicData;
|
||||||
import funkin.data.song.SongRegistry;
|
import funkin.data.song.SongRegistry;
|
||||||
import funkin.util.tools.ICloneable;
|
import funkin.util.tools.ICloneable;
|
||||||
|
import funkin.util.flixel.sound.FlxPartialSound;
|
||||||
|
import funkin.Paths.PathsFunction;
|
||||||
|
import openfl.Assets;
|
||||||
|
import lime.app.Future;
|
||||||
|
import lime.app.Promise;
|
||||||
import openfl.media.SoundMixer;
|
import openfl.media.SoundMixer;
|
||||||
|
|
||||||
#if (openfl >= "8.0.0")
|
#if (openfl >= "8.0.0")
|
||||||
|
@ -341,23 +346,68 @@ class FunkinSound extends FlxSound implements ICloneable<FunkinSound>
|
||||||
FlxG.log.warn('Tried and failed to find music metadata for $key');
|
FlxG.log.warn('Tried and failed to find music metadata for $key');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
var pathsFunction = params.pathsFunction ?? MUSIC;
|
||||||
var music = FunkinSound.load(Paths.music('$key/$key'), params?.startingVolume ?? 1.0, params.loop ?? true, false, true);
|
var suffix = params.suffix ?? '';
|
||||||
if (music != null)
|
var pathToUse = switch (pathsFunction)
|
||||||
{
|
{
|
||||||
FlxG.sound.music = music;
|
case MUSIC: Paths.music('$key/$key');
|
||||||
|
case INST: Paths.inst('$key', suffix);
|
||||||
|
default: Paths.music('$key/$key');
|
||||||
|
}
|
||||||
|
|
||||||
// Prevent repeat update() and onFocus() calls.
|
var shouldLoadPartial = params.partialParams?.loadPartial ?? false;
|
||||||
FlxG.sound.list.remove(FlxG.sound.music);
|
|
||||||
|
|
||||||
return true;
|
if (shouldLoadPartial)
|
||||||
|
{
|
||||||
|
var music = FunkinSound.loadPartial(pathToUse, params.partialParams?.start ?? 0, params.partialParams?.end ?? 1, params?.startingVolume ?? 1.0,
|
||||||
|
params.loop ?? true, false, false, params.onComplete);
|
||||||
|
|
||||||
|
if (music != null)
|
||||||
|
{
|
||||||
|
while (partialQueue.length > 0)
|
||||||
|
{
|
||||||
|
@:nullSafety(Off)
|
||||||
|
partialQueue.pop().error("Cancel loading partial sound");
|
||||||
|
}
|
||||||
|
|
||||||
|
partialQueue.push(music);
|
||||||
|
|
||||||
|
@:nullSafety(Off)
|
||||||
|
music.future.onComplete(function(partialMusic:Null<FunkinSound>) {
|
||||||
|
FlxG.sound.music = partialMusic;
|
||||||
|
FlxG.sound.list.remove(FlxG.sound.music);
|
||||||
|
|
||||||
|
if (params.onLoad != null) params.onLoad();
|
||||||
|
});
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return false;
|
var music = FunkinSound.load(pathToUse, params?.startingVolume ?? 1.0, params.loop ?? true, false, true);
|
||||||
|
if (music != null)
|
||||||
|
{
|
||||||
|
FlxG.sound.music = music;
|
||||||
|
|
||||||
|
// Prevent repeat update() and onFocus() calls.
|
||||||
|
FlxG.sound.list.remove(FlxG.sound.music);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static var partialQueue:Array<Promise<Null<FunkinSound>>> = [];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new `FunkinSound` object synchronously.
|
* Creates a new `FunkinSound` object synchronously.
|
||||||
*
|
*
|
||||||
|
@ -414,6 +464,42 @@ class FunkinSound extends FlxSound implements ICloneable<FunkinSound>
|
||||||
return sound;
|
return sound;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Will load a section of a sound file, useful for Freeplay where we don't want to load all the bytes of a song
|
||||||
|
* @param path The path to the sound file
|
||||||
|
* @param start The start time of the sound file
|
||||||
|
* @param end The end time of the sound file
|
||||||
|
* @param volume Volume to start at
|
||||||
|
* @param looped Whether the sound file should loop
|
||||||
|
* @param autoDestroy Whether the sound file should be destroyed after it finishes playing
|
||||||
|
* @param autoPlay Whether the sound file should play immediately
|
||||||
|
* @param onComplete Callback when the sound finishes playing
|
||||||
|
* @param onLoad Callback when the sound finishes loading
|
||||||
|
* @return A FunkinSound object
|
||||||
|
*/
|
||||||
|
public static function loadPartial(path:String, start:Float = 0, end:Float = 1, volume:Float = 1.0, looped:Bool = false, autoDestroy:Bool = false,
|
||||||
|
autoPlay:Bool = true, ?onComplete:Void->Void, ?onLoad:Void->Void):Promise<Null<FunkinSound>>
|
||||||
|
{
|
||||||
|
var promise:lime.app.Promise<Null<FunkinSound>> = new lime.app.Promise<Null<FunkinSound>>();
|
||||||
|
|
||||||
|
// split the path and get only after first :
|
||||||
|
// we are bypassing the openfl/lime asset library fuss
|
||||||
|
path = Paths.stripLibrary(path);
|
||||||
|
|
||||||
|
var soundRequest = FlxPartialSound.partialLoadFromFile(path, start, end);
|
||||||
|
|
||||||
|
promise.future.onError(function(e) {
|
||||||
|
soundRequest.error("Sound loading was errored or cancelled");
|
||||||
|
});
|
||||||
|
|
||||||
|
soundRequest.future.onComplete(function(partialSound) {
|
||||||
|
var snd = FunkinSound.load(partialSound, volume, looped, autoDestroy, autoPlay, onComplete, onLoad);
|
||||||
|
promise.complete(snd);
|
||||||
|
});
|
||||||
|
|
||||||
|
return promise;
|
||||||
|
}
|
||||||
|
|
||||||
@:nullSafety(Off)
|
@:nullSafety(Off)
|
||||||
public override function destroy():Void
|
public override function destroy():Void
|
||||||
{
|
{
|
||||||
|
@ -474,6 +560,12 @@ typedef FunkinSoundPlayMusicParams =
|
||||||
*/
|
*/
|
||||||
var ?startingVolume:Float;
|
var ?startingVolume:Float;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The suffix of the music file to play. Usually for "-erect" tracks when loading an INST file
|
||||||
|
* @default ``
|
||||||
|
*/
|
||||||
|
var ?suffix:String;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether to override music if a different track is already playing.
|
* Whether to override music if a different track is already playing.
|
||||||
* @default `false`
|
* @default `false`
|
||||||
|
@ -497,4 +589,22 @@ typedef FunkinSoundPlayMusicParams =
|
||||||
* @default `true`
|
* @default `true`
|
||||||
*/
|
*/
|
||||||
var ?mapTimeChanges:Bool;
|
var ?mapTimeChanges:Bool;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Which Paths function to use to load a song
|
||||||
|
* @default `MUSIC`
|
||||||
|
*/
|
||||||
|
var ?pathsFunction:PathsFunction;
|
||||||
|
|
||||||
|
var ?partialParams:PartialSoundParams;
|
||||||
|
|
||||||
|
var ?onComplete:Void->Void;
|
||||||
|
var ?onLoad:Void->Void;
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef PartialSoundParams =
|
||||||
|
{
|
||||||
|
var loadPartial:Bool;
|
||||||
|
var start:Float;
|
||||||
|
var end:Float;
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,10 @@ All notable changes to this project will be documented in this file.
|
||||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||||
|
|
||||||
|
## [2.2.3]
|
||||||
|
### Added
|
||||||
|
- Added `charter` field to denote authorship of a chart.
|
||||||
|
|
||||||
## [2.2.2]
|
## [2.2.2]
|
||||||
### Added
|
### Added
|
||||||
- Added `playData.previewStart` and `playData.previewEnd` fields to specify when in the song should the song's audio should be played as a preview in Freeplay.
|
- Added `playData.previewStart` and `playData.previewEnd` fields to specify when in the song should the song's audio should be played as a preview in Freeplay.
|
||||||
|
|
|
@ -30,6 +30,9 @@ class SongMetadata implements ICloneable<SongMetadata>
|
||||||
@:default("Unknown")
|
@:default("Unknown")
|
||||||
public var artist:String;
|
public var artist:String;
|
||||||
|
|
||||||
|
@:optional
|
||||||
|
public var charter:Null<String> = null;
|
||||||
|
|
||||||
@:optional
|
@:optional
|
||||||
@:default(96)
|
@:default(96)
|
||||||
public var divisions:Null<Int>; // Optional field
|
public var divisions:Null<Int>; // Optional field
|
||||||
|
|
|
@ -20,7 +20,7 @@ class SongRegistry extends BaseRegistry<Song, SongMetadata>
|
||||||
* Handle breaking changes by incrementing this value
|
* Handle breaking changes by incrementing this value
|
||||||
* and adding migration to the `migrateStageData()` function.
|
* and adding migration to the `migrateStageData()` function.
|
||||||
*/
|
*/
|
||||||
public static final SONG_METADATA_VERSION:thx.semver.Version = "2.2.2";
|
public static final SONG_METADATA_VERSION:thx.semver.Version = "2.2.3";
|
||||||
|
|
||||||
public static final SONG_METADATA_VERSION_RULE:thx.semver.VersionRule = "2.2.x";
|
public static final SONG_METADATA_VERSION_RULE:thx.semver.VersionRule = "2.2.x";
|
||||||
|
|
||||||
|
|
|
@ -36,7 +36,7 @@ class FNFLegacyImporter
|
||||||
{
|
{
|
||||||
trace('Migrating song metadata from FNF Legacy.');
|
trace('Migrating song metadata from FNF Legacy.');
|
||||||
|
|
||||||
var songMetadata:SongMetadata = new SongMetadata('Import', 'Kawai Sprite', 'default');
|
var songMetadata:SongMetadata = new SongMetadata('Import', Constants.DEFAULT_ARTIST, 'default');
|
||||||
|
|
||||||
var hadError:Bool = false;
|
var hadError:Bool = false;
|
||||||
|
|
||||||
|
|
|
@ -101,6 +101,10 @@ class PauseSubState extends MusicBeatSubState
|
||||||
*/
|
*/
|
||||||
static final MUSIC_FINAL_VOLUME:Float = 0.75;
|
static final MUSIC_FINAL_VOLUME:Float = 0.75;
|
||||||
|
|
||||||
|
static final CHARTER_FADE_DELAY:Float = 15.0;
|
||||||
|
|
||||||
|
static final CHARTER_FADE_DURATION:Float = 0.75;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Defines which pause music to use.
|
* Defines which pause music to use.
|
||||||
*/
|
*/
|
||||||
|
@ -163,6 +167,12 @@ class PauseSubState extends MusicBeatSubState
|
||||||
*/
|
*/
|
||||||
var metadataDeaths:FlxText;
|
var metadataDeaths:FlxText;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A text object which displays the current song's artist.
|
||||||
|
* Fades to the charter after a period before fading back.
|
||||||
|
*/
|
||||||
|
var metadataArtist:FlxText;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The actual text objects for the menu entries.
|
* The actual text objects for the menu entries.
|
||||||
*/
|
*/
|
||||||
|
@ -203,6 +213,8 @@ class PauseSubState extends MusicBeatSubState
|
||||||
regenerateMenu();
|
regenerateMenu();
|
||||||
|
|
||||||
transitionIn();
|
transitionIn();
|
||||||
|
|
||||||
|
startCharterTimer();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -222,6 +234,8 @@ class PauseSubState extends MusicBeatSubState
|
||||||
public override function destroy():Void
|
public override function destroy():Void
|
||||||
{
|
{
|
||||||
super.destroy();
|
super.destroy();
|
||||||
|
charterFadeTween.cancel();
|
||||||
|
charterFadeTween = null;
|
||||||
pauseMusic.stop();
|
pauseMusic.stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -270,16 +284,25 @@ class PauseSubState extends MusicBeatSubState
|
||||||
metadata.scrollFactor.set(0, 0);
|
metadata.scrollFactor.set(0, 0);
|
||||||
add(metadata);
|
add(metadata);
|
||||||
|
|
||||||
var metadataSong:FlxText = new FlxText(20, 15, FlxG.width - 40, 'Song Name - Artist');
|
var metadataSong:FlxText = new FlxText(20, 15, FlxG.width - 40, 'Song Name');
|
||||||
metadataSong.setFormat(Paths.font('vcr.ttf'), 32, FlxColor.WHITE, FlxTextAlign.RIGHT);
|
metadataSong.setFormat(Paths.font('vcr.ttf'), 32, FlxColor.WHITE, FlxTextAlign.RIGHT);
|
||||||
if (PlayState.instance?.currentChart != null)
|
if (PlayState.instance?.currentChart != null)
|
||||||
{
|
{
|
||||||
metadataSong.text = '${PlayState.instance.currentChart.songName} - ${PlayState.instance.currentChart.songArtist}';
|
metadataSong.text = '${PlayState.instance.currentChart.songName}';
|
||||||
}
|
}
|
||||||
metadataSong.scrollFactor.set(0, 0);
|
metadataSong.scrollFactor.set(0, 0);
|
||||||
metadata.add(metadataSong);
|
metadata.add(metadataSong);
|
||||||
|
|
||||||
var metadataDifficulty:FlxText = new FlxText(20, 15 + 32, FlxG.width - 40, 'Difficulty: ');
|
metadataArtist = new FlxText(20, metadataSong.y + 32, FlxG.width - 40, 'Artist: ${Constants.DEFAULT_ARTIST}');
|
||||||
|
metadataArtist.setFormat(Paths.font('vcr.ttf'), 32, FlxColor.WHITE, FlxTextAlign.RIGHT);
|
||||||
|
if (PlayState.instance?.currentChart != null)
|
||||||
|
{
|
||||||
|
metadataArtist.text = 'Artist: ${PlayState.instance.currentChart.songArtist}';
|
||||||
|
}
|
||||||
|
metadataArtist.scrollFactor.set(0, 0);
|
||||||
|
metadata.add(metadataArtist);
|
||||||
|
|
||||||
|
var metadataDifficulty:FlxText = new FlxText(20, metadataArtist.y + 32, FlxG.width - 40, 'Difficulty: ');
|
||||||
metadataDifficulty.setFormat(Paths.font('vcr.ttf'), 32, FlxColor.WHITE, FlxTextAlign.RIGHT);
|
metadataDifficulty.setFormat(Paths.font('vcr.ttf'), 32, FlxColor.WHITE, FlxTextAlign.RIGHT);
|
||||||
if (PlayState.instance?.currentDifficulty != null)
|
if (PlayState.instance?.currentDifficulty != null)
|
||||||
{
|
{
|
||||||
|
@ -288,12 +311,12 @@ class PauseSubState extends MusicBeatSubState
|
||||||
metadataDifficulty.scrollFactor.set(0, 0);
|
metadataDifficulty.scrollFactor.set(0, 0);
|
||||||
metadata.add(metadataDifficulty);
|
metadata.add(metadataDifficulty);
|
||||||
|
|
||||||
metadataDeaths = new FlxText(20, 15 + 64, FlxG.width - 40, '${PlayState.instance?.deathCounter} Blue Balls');
|
metadataDeaths = new FlxText(20, metadataDifficulty.y + 32, FlxG.width - 40, '${PlayState.instance?.deathCounter} Blue Balls');
|
||||||
metadataDeaths.setFormat(Paths.font('vcr.ttf'), 32, FlxColor.WHITE, FlxTextAlign.RIGHT);
|
metadataDeaths.setFormat(Paths.font('vcr.ttf'), 32, FlxColor.WHITE, FlxTextAlign.RIGHT);
|
||||||
metadataDeaths.scrollFactor.set(0, 0);
|
metadataDeaths.scrollFactor.set(0, 0);
|
||||||
metadata.add(metadataDeaths);
|
metadata.add(metadataDeaths);
|
||||||
|
|
||||||
metadataPractice = new FlxText(20, 15 + 96, FlxG.width - 40, 'PRACTICE MODE');
|
metadataPractice = new FlxText(20, metadataDeaths.y + 32, FlxG.width - 40, 'PRACTICE MODE');
|
||||||
metadataPractice.setFormat(Paths.font('vcr.ttf'), 32, FlxColor.WHITE, FlxTextAlign.RIGHT);
|
metadataPractice.setFormat(Paths.font('vcr.ttf'), 32, FlxColor.WHITE, FlxTextAlign.RIGHT);
|
||||||
metadataPractice.visible = PlayState.instance?.isPracticeMode ?? false;
|
metadataPractice.visible = PlayState.instance?.isPracticeMode ?? false;
|
||||||
metadataPractice.scrollFactor.set(0, 0);
|
metadataPractice.scrollFactor.set(0, 0);
|
||||||
|
@ -302,6 +325,62 @@ class PauseSubState extends MusicBeatSubState
|
||||||
updateMetadataText();
|
updateMetadataText();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var charterFadeTween:Null<FlxTween> = null;
|
||||||
|
|
||||||
|
function startCharterTimer():Void
|
||||||
|
{
|
||||||
|
charterFadeTween = FlxTween.tween(metadataArtist, {alpha: 0.0}, CHARTER_FADE_DURATION,
|
||||||
|
{
|
||||||
|
startDelay: CHARTER_FADE_DELAY,
|
||||||
|
ease: FlxEase.quartOut,
|
||||||
|
onComplete: (_) -> {
|
||||||
|
if (PlayState.instance?.currentChart != null)
|
||||||
|
{
|
||||||
|
metadataArtist.text = 'Charter: ${PlayState.instance.currentChart.charter ?? 'Unknown'}';
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
metadataArtist.text = 'Charter: ${Constants.DEFAULT_CHARTER}';
|
||||||
|
}
|
||||||
|
|
||||||
|
FlxTween.tween(metadataArtist, {alpha: 1.0}, CHARTER_FADE_DURATION,
|
||||||
|
{
|
||||||
|
ease: FlxEase.quartOut,
|
||||||
|
onComplete: (_) -> {
|
||||||
|
startArtistTimer();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function startArtistTimer():Void
|
||||||
|
{
|
||||||
|
charterFadeTween = FlxTween.tween(metadataArtist, {alpha: 0.0}, CHARTER_FADE_DURATION,
|
||||||
|
{
|
||||||
|
startDelay: CHARTER_FADE_DELAY,
|
||||||
|
ease: FlxEase.quartOut,
|
||||||
|
onComplete: (_) -> {
|
||||||
|
if (PlayState.instance?.currentChart != null)
|
||||||
|
{
|
||||||
|
metadataArtist.text = 'Artist: ${PlayState.instance.currentChart.songArtist}';
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
metadataArtist.text = 'Artist: ${Constants.DEFAULT_ARTIST}';
|
||||||
|
}
|
||||||
|
|
||||||
|
FlxTween.tween(metadataArtist, {alpha: 1.0}, CHARTER_FADE_DURATION,
|
||||||
|
{
|
||||||
|
ease: FlxEase.quartOut,
|
||||||
|
onComplete: (_) -> {
|
||||||
|
startCharterTimer();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Perform additional animations to transition the pause menu in when it is first displayed.
|
* Perform additional animations to transition the pause menu in when it is first displayed.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -1730,12 +1730,7 @@ class PlayState extends MusicBeatSubState
|
||||||
*/
|
*/
|
||||||
function initStrumlines():Void
|
function initStrumlines():Void
|
||||||
{
|
{
|
||||||
var noteStyleId:String = switch (currentStageId)
|
var noteStyleId:String = currentChart.noteStyle;
|
||||||
{
|
|
||||||
case 'school': 'pixel';
|
|
||||||
case 'schoolEvil': 'pixel';
|
|
||||||
default: Constants.DEFAULT_NOTE_STYLE;
|
|
||||||
}
|
|
||||||
var noteStyle:NoteStyle = NoteStyleRegistry.instance.fetchEntry(noteStyleId);
|
var noteStyle:NoteStyle = NoteStyleRegistry.instance.fetchEntry(noteStyleId);
|
||||||
if (noteStyle == null) noteStyle = NoteStyleRegistry.instance.fetchDefault();
|
if (noteStyle == null) noteStyle = NoteStyleRegistry.instance.fetchDefault();
|
||||||
|
|
||||||
|
@ -2322,8 +2317,6 @@ class PlayState extends MusicBeatSubState
|
||||||
var notesInRange:Array<NoteSprite> = playerStrumline.getNotesMayHit();
|
var notesInRange:Array<NoteSprite> = playerStrumline.getNotesMayHit();
|
||||||
var holdNotesInRange:Array<SustainTrail> = playerStrumline.getHoldNotesHitOrMissed();
|
var holdNotesInRange:Array<SustainTrail> = playerStrumline.getHoldNotesHitOrMissed();
|
||||||
|
|
||||||
// If there are notes in range, pressing a key will cause a ghost miss.
|
|
||||||
|
|
||||||
var notesByDirection:Array<Array<NoteSprite>> = [[], [], [], []];
|
var notesByDirection:Array<Array<NoteSprite>> = [[], [], [], []];
|
||||||
|
|
||||||
for (note in notesInRange)
|
for (note in notesInRange)
|
||||||
|
@ -2345,17 +2338,27 @@ class PlayState extends MusicBeatSubState
|
||||||
|
|
||||||
// Play the strumline animation.
|
// Play the strumline animation.
|
||||||
playerStrumline.playPress(input.noteDirection);
|
playerStrumline.playPress(input.noteDirection);
|
||||||
|
trace('PENALTY Score: ${songScore}');
|
||||||
}
|
}
|
||||||
else if (Constants.GHOST_TAPPING && (holdNotesInRange.length + notesInRange.length > 0) && notesInDirection.length == 0)
|
else if (Constants.GHOST_TAPPING && (!playerStrumline.mayGhostTap()) && notesInDirection.length == 0)
|
||||||
{
|
{
|
||||||
// Pressed a wrong key with no notes nearby AND with notes in a different direction available.
|
// Pressed a wrong key with notes visible on-screen.
|
||||||
// Perform a ghost miss (anti-spam).
|
// Perform a ghost miss (anti-spam).
|
||||||
ghostNoteMiss(input.noteDirection, notesInRange.length > 0);
|
ghostNoteMiss(input.noteDirection, notesInRange.length > 0);
|
||||||
|
|
||||||
// Play the strumline animation.
|
// Play the strumline animation.
|
||||||
playerStrumline.playPress(input.noteDirection);
|
playerStrumline.playPress(input.noteDirection);
|
||||||
|
trace('PENALTY Score: ${songScore}');
|
||||||
}
|
}
|
||||||
else if (notesInDirection.length > 0)
|
else if (notesInDirection.length == 0)
|
||||||
|
{
|
||||||
|
// Press a key with no penalty.
|
||||||
|
|
||||||
|
// Play the strumline animation.
|
||||||
|
playerStrumline.playPress(input.noteDirection);
|
||||||
|
trace('NO PENALTY Score: ${songScore}');
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
// Choose the first note, deprioritizing low priority notes.
|
// Choose the first note, deprioritizing low priority notes.
|
||||||
var targetNote:Null<NoteSprite> = notesInDirection.find((note) -> !note.lowPriority);
|
var targetNote:Null<NoteSprite> = notesInDirection.find((note) -> !note.lowPriority);
|
||||||
|
@ -2365,17 +2368,13 @@ class PlayState extends MusicBeatSubState
|
||||||
// Judge and hit the note.
|
// Judge and hit the note.
|
||||||
trace('Hit note! ${targetNote.noteData}');
|
trace('Hit note! ${targetNote.noteData}');
|
||||||
goodNoteHit(targetNote, input);
|
goodNoteHit(targetNote, input);
|
||||||
|
trace('Score: ${songScore}');
|
||||||
|
|
||||||
notesInDirection.remove(targetNote);
|
notesInDirection.remove(targetNote);
|
||||||
|
|
||||||
// Play the strumline animation.
|
// Play the strumline animation.
|
||||||
playerStrumline.playConfirm(input.noteDirection);
|
playerStrumline.playConfirm(input.noteDirection);
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
// Play the strumline animation.
|
|
||||||
playerStrumline.playPress(input.noteDirection);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
while (inputReleaseQueue.length > 0)
|
while (inputReleaseQueue.length > 0)
|
||||||
|
|
|
@ -373,6 +373,10 @@ class HealthIcon extends FunkinSprite
|
||||||
// Don't flip BF's icon here! That's done later.
|
// Don't flip BF's icon here! That's done later.
|
||||||
this.animation.add(Idle, [0], 0, false, false);
|
this.animation.add(Idle, [0], 0, false, false);
|
||||||
this.animation.add(Losing, [1], 0, false, false);
|
this.animation.add(Losing, [1], 0, false, false);
|
||||||
|
if (animation.numFrames >= 3)
|
||||||
|
{
|
||||||
|
this.animation.add(Winning, [2], 0, false, false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function correctCharacterId(charId:Null<String>):String
|
function correctCharacterId(charId:Null<String>):String
|
||||||
|
|
|
@ -171,6 +171,20 @@ class Strumline extends FlxSpriteGroup
|
||||||
updateNotes();
|
updateNotes();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns `true` if no notes are in range of the strumline and the player can spam without penalty.
|
||||||
|
*/
|
||||||
|
public function mayGhostTap():Bool
|
||||||
|
{
|
||||||
|
// TODO: Refine this. Only querying "can be hit" is too tight but "is being rendered" is too loose.
|
||||||
|
// Also, if you just hit a note, there should be a (short) period where this is off so you can't spam.
|
||||||
|
|
||||||
|
// If there are any notes on screen, we can't ghost tap.
|
||||||
|
return notes.members.filter(function(note:NoteSprite) {
|
||||||
|
return note != null && note.alive && !note.hasBeenHit;
|
||||||
|
}).length == 0;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return notes that are within `Constants.HIT_WINDOW` ms of the strumline.
|
* Return notes that are within `Constants.HIT_WINDOW` ms of the strumline.
|
||||||
* @return An array of `NoteSprite` objects.
|
* @return An array of `NoteSprite` objects.
|
||||||
|
|
|
@ -120,6 +120,18 @@ class Song implements IPlayStateScriptedClass implements IRegistryEntry<SongMeta
|
||||||
return DEFAULT_ARTIST;
|
return DEFAULT_ARTIST;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The artist of the song.
|
||||||
|
*/
|
||||||
|
public var charter(get, never):String;
|
||||||
|
|
||||||
|
function get_charter():String
|
||||||
|
{
|
||||||
|
if (_data != null) return _data?.charter ?? 'Unknown';
|
||||||
|
if (_metadata.size() > 0) return _metadata.get(Constants.DEFAULT_VARIATION)?.charter ?? 'Unknown';
|
||||||
|
return Constants.DEFAULT_CHARTER;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param id The ID of the song to load.
|
* @param id The ID of the song to load.
|
||||||
* @param ignoreErrors If false, an exception will be thrown if the song data could not be loaded.
|
* @param ignoreErrors If false, an exception will be thrown if the song data could not be loaded.
|
||||||
|
@ -270,6 +282,7 @@ class Song implements IPlayStateScriptedClass implements IRegistryEntry<SongMeta
|
||||||
|
|
||||||
difficulty.songName = metadata.songName;
|
difficulty.songName = metadata.songName;
|
||||||
difficulty.songArtist = metadata.artist;
|
difficulty.songArtist = metadata.artist;
|
||||||
|
difficulty.charter = metadata.charter ?? Constants.DEFAULT_CHARTER;
|
||||||
difficulty.timeFormat = metadata.timeFormat;
|
difficulty.timeFormat = metadata.timeFormat;
|
||||||
difficulty.divisions = metadata.divisions;
|
difficulty.divisions = metadata.divisions;
|
||||||
difficulty.timeChanges = metadata.timeChanges;
|
difficulty.timeChanges = metadata.timeChanges;
|
||||||
|
@ -334,6 +347,7 @@ class Song implements IPlayStateScriptedClass implements IRegistryEntry<SongMeta
|
||||||
{
|
{
|
||||||
difficulty.songName = metadata.songName;
|
difficulty.songName = metadata.songName;
|
||||||
difficulty.songArtist = metadata.artist;
|
difficulty.songArtist = metadata.artist;
|
||||||
|
difficulty.charter = metadata.charter ?? Constants.DEFAULT_CHARTER;
|
||||||
difficulty.timeFormat = metadata.timeFormat;
|
difficulty.timeFormat = metadata.timeFormat;
|
||||||
difficulty.divisions = metadata.divisions;
|
difficulty.divisions = metadata.divisions;
|
||||||
difficulty.timeChanges = metadata.timeChanges;
|
difficulty.timeChanges = metadata.timeChanges;
|
||||||
|
@ -590,6 +604,7 @@ class SongDifficulty
|
||||||
|
|
||||||
public var songName:String = Constants.DEFAULT_SONGNAME;
|
public var songName:String = Constants.DEFAULT_SONGNAME;
|
||||||
public var songArtist:String = Constants.DEFAULT_ARTIST;
|
public var songArtist:String = Constants.DEFAULT_ARTIST;
|
||||||
|
public var charter:String = Constants.DEFAULT_CHARTER;
|
||||||
public var timeFormat:SongTimeFormat = Constants.DEFAULT_TIMEFORMAT;
|
public var timeFormat:SongTimeFormat = Constants.DEFAULT_TIMEFORMAT;
|
||||||
public var divisions:Null<Int> = null;
|
public var divisions:Null<Int> = null;
|
||||||
public var looped:Bool = false;
|
public var looped:Bool = false;
|
||||||
|
|
|
@ -852,6 +852,11 @@ class Stage extends FlxSpriteGroup implements IPlayStateScriptedClass implements
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override function toString():String
|
||||||
|
{
|
||||||
|
return 'Stage($id)';
|
||||||
|
}
|
||||||
|
|
||||||
static function _fetchData(id:String):Null<StageData>
|
static function _fetchData(id:String):Null<StageData>
|
||||||
{
|
{
|
||||||
return StageRegistry.instance.parseEntryDataWithMigration(id, StageRegistry.instance.fetchEntryVersion(id));
|
return StageRegistry.instance.parseEntryDataWithMigration(id, StageRegistry.instance.fetchEntryVersion(id));
|
||||||
|
|
|
@ -62,7 +62,6 @@ class DebugMenuSubState extends MusicBeatSubState
|
||||||
#if sys
|
#if sys
|
||||||
createItem("OPEN CRASH LOG FOLDER", openLogFolder);
|
createItem("OPEN CRASH LOG FOLDER", openLogFolder);
|
||||||
#end
|
#end
|
||||||
FlxG.camera.focusOn(new FlxPoint(camFocusPoint.x, camFocusPoint.y));
|
|
||||||
FlxG.camera.focusOn(new FlxPoint(camFocusPoint.x, camFocusPoint.y + 500));
|
FlxG.camera.focusOn(new FlxPoint(camFocusPoint.x, camFocusPoint.y + 500));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1270,7 +1270,7 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
|
||||||
var result:Null<SongMetadata> = songMetadata.get(selectedVariation);
|
var result:Null<SongMetadata> = songMetadata.get(selectedVariation);
|
||||||
if (result == null)
|
if (result == null)
|
||||||
{
|
{
|
||||||
result = new SongMetadata('DadBattle', 'Kawai Sprite', selectedVariation);
|
result = new SongMetadata('Default Song Name', Constants.DEFAULT_ARTIST, selectedVariation);
|
||||||
songMetadata.set(selectedVariation, result);
|
songMetadata.set(selectedVariation, result);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
|
@ -4566,8 +4566,8 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
|
||||||
}
|
}
|
||||||
|
|
||||||
gridGhostHoldNote.visible = true;
|
gridGhostHoldNote.visible = true;
|
||||||
gridGhostHoldNote.noteData = gridGhostNote.noteData;
|
gridGhostHoldNote.noteData = currentPlaceNoteData;
|
||||||
gridGhostHoldNote.noteDirection = gridGhostNote.noteData.getDirection();
|
gridGhostHoldNote.noteDirection = currentPlaceNoteData.getDirection();
|
||||||
gridGhostHoldNote.setHeightDirectly(dragLengthPixels, true);
|
gridGhostHoldNote.setHeightDirectly(dragLengthPixels, true);
|
||||||
|
|
||||||
gridGhostHoldNote.updateHoldNotePosition(renderedHoldNotes);
|
gridGhostHoldNote.updateHoldNotePosition(renderedHoldNotes);
|
||||||
|
|
|
@ -36,6 +36,8 @@ class ChartEditorHoldNoteSprite extends SustainTrail
|
||||||
zoom *= 0.7;
|
zoom *= 0.7;
|
||||||
zoom *= ChartEditorState.GRID_SIZE / Strumline.STRUMLINE_SIZE;
|
zoom *= ChartEditorState.GRID_SIZE / Strumline.STRUMLINE_SIZE;
|
||||||
|
|
||||||
|
flipY = false;
|
||||||
|
|
||||||
setup();
|
setup();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -29,6 +29,7 @@ class ChartEditorMetadataToolbox extends ChartEditorBaseToolbox
|
||||||
{
|
{
|
||||||
var inputSongName:TextField;
|
var inputSongName:TextField;
|
||||||
var inputSongArtist:TextField;
|
var inputSongArtist:TextField;
|
||||||
|
var inputSongCharter:TextField;
|
||||||
var inputStage:DropDown;
|
var inputStage:DropDown;
|
||||||
var inputNoteStyle:DropDown;
|
var inputNoteStyle:DropDown;
|
||||||
var buttonCharacterPlayer:Button;
|
var buttonCharacterPlayer:Button;
|
||||||
|
@ -89,6 +90,20 @@ class ChartEditorMetadataToolbox extends ChartEditorBaseToolbox
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
inputSongCharter.onChange = function(event:UIEvent) {
|
||||||
|
var valid:Bool = event.target.text != null && event.target.text != '';
|
||||||
|
|
||||||
|
if (valid)
|
||||||
|
{
|
||||||
|
inputSongCharter.removeClass('invalid-value');
|
||||||
|
chartEditorState.currentSongMetadata.charter = event.target.text;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
chartEditorState.currentSongMetadata.charter = null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
inputStage.onChange = function(event:UIEvent) {
|
inputStage.onChange = function(event:UIEvent) {
|
||||||
var valid:Bool = event.data != null && event.data.id != null;
|
var valid:Bool = event.data != null && event.data.id != null;
|
||||||
|
|
||||||
|
@ -104,6 +119,8 @@ class ChartEditorMetadataToolbox extends ChartEditorBaseToolbox
|
||||||
if (event.data?.id == null) return;
|
if (event.data?.id == null) return;
|
||||||
chartEditorState.currentSongNoteStyle = event.data.id;
|
chartEditorState.currentSongNoteStyle = event.data.id;
|
||||||
};
|
};
|
||||||
|
var startingValueNoteStyle = ChartEditorDropdowns.populateDropdownWithNoteStyles(inputNoteStyle, chartEditorState.currentSongMetadata.playData.noteStyle);
|
||||||
|
inputNoteStyle.value = startingValueNoteStyle;
|
||||||
|
|
||||||
inputBPM.onChange = function(event:UIEvent) {
|
inputBPM.onChange = function(event:UIEvent) {
|
||||||
if (event.value == null || event.value <= 0) return;
|
if (event.value == null || event.value <= 0) return;
|
||||||
|
@ -176,6 +193,7 @@ class ChartEditorMetadataToolbox extends ChartEditorBaseToolbox
|
||||||
|
|
||||||
inputSongName.value = chartEditorState.currentSongMetadata.songName;
|
inputSongName.value = chartEditorState.currentSongMetadata.songName;
|
||||||
inputSongArtist.value = chartEditorState.currentSongMetadata.artist;
|
inputSongArtist.value = chartEditorState.currentSongMetadata.artist;
|
||||||
|
inputSongCharter.value = chartEditorState.currentSongMetadata.charter;
|
||||||
inputStage.value = chartEditorState.currentSongMetadata.playData.stage;
|
inputStage.value = chartEditorState.currentSongMetadata.playData.stage;
|
||||||
inputNoteStyle.value = chartEditorState.currentSongMetadata.playData.noteStyle;
|
inputNoteStyle.value = chartEditorState.currentSongMetadata.playData.noteStyle;
|
||||||
inputBPM.value = chartEditorState.currentSongMetadata.timeChanges[0].bpm;
|
inputBPM.value = chartEditorState.currentSongMetadata.timeChanges[0].bpm;
|
||||||
|
|
|
@ -31,6 +31,7 @@ import funkin.graphics.shaders.StrokeShader;
|
||||||
import funkin.input.Controls;
|
import funkin.input.Controls;
|
||||||
import funkin.play.PlayStatePlaylist;
|
import funkin.play.PlayStatePlaylist;
|
||||||
import funkin.play.song.Song;
|
import funkin.play.song.Song;
|
||||||
|
import funkin.ui.story.Level;
|
||||||
import funkin.save.Save;
|
import funkin.save.Save;
|
||||||
import funkin.save.Save.SaveScoreData;
|
import funkin.save.Save.SaveScoreData;
|
||||||
import funkin.ui.AtlasText;
|
import funkin.ui.AtlasText;
|
||||||
|
@ -246,10 +247,24 @@ class FreeplayState extends MusicBeatSubState
|
||||||
// programmatically adds the songs via LevelRegistry and SongRegistry
|
// programmatically adds the songs via LevelRegistry and SongRegistry
|
||||||
for (levelId in LevelRegistry.instance.listSortedLevelIds())
|
for (levelId in LevelRegistry.instance.listSortedLevelIds())
|
||||||
{
|
{
|
||||||
for (songId in LevelRegistry.instance.parseEntryData(levelId).songs)
|
var level:Level = LevelRegistry.instance.fetchEntry(levelId);
|
||||||
|
|
||||||
|
if (level == null)
|
||||||
|
{
|
||||||
|
trace('[WARN] Could not find level with id (${levelId})');
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (songId in level.getSongs())
|
||||||
{
|
{
|
||||||
var song:Song = SongRegistry.instance.fetchEntry(songId);
|
var song:Song = SongRegistry.instance.fetchEntry(songId);
|
||||||
|
|
||||||
|
if (song == null)
|
||||||
|
{
|
||||||
|
trace('[WARN] Could not find song with id (${songId})');
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// Only display songs which actually have available difficulties for the current character.
|
// Only display songs which actually have available difficulties for the current character.
|
||||||
var displayedVariations = song.getVariationsByCharId(currentCharacter);
|
var displayedVariations = song.getVariationsByCharId(currentCharacter);
|
||||||
var availableDifficultiesForSong:Array<String> = song.listDifficulties(displayedVariations, false);
|
var availableDifficultiesForSong:Array<String> = song.listDifficulties(displayedVariations, false);
|
||||||
|
@ -1674,23 +1689,25 @@ class FreeplayState extends MusicBeatSubState
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
var potentiallyErect:String = (currentDifficulty == "erect") || (currentDifficulty == "nightmare") ? "-erect" : "";
|
||||||
// TODO: Stream the instrumental of the selected song?
|
// TODO: Stream the instrumental of the selected song?
|
||||||
var didReplace:Bool = FunkinSound.playMusic('freakyMenu',
|
FunkinSound.playMusic(daSongCapsule.songData.songId,
|
||||||
{
|
{
|
||||||
startingVolume: 0.0,
|
startingVolume: 0.0,
|
||||||
overrideExisting: true,
|
overrideExisting: true,
|
||||||
restartTrack: false
|
restartTrack: false,
|
||||||
|
pathsFunction: INST,
|
||||||
|
suffix: potentiallyErect,
|
||||||
|
partialParams:
|
||||||
|
{
|
||||||
|
loadPartial: true,
|
||||||
|
start: 0,
|
||||||
|
end: 0.1
|
||||||
|
},
|
||||||
|
onLoad: function() {
|
||||||
|
FlxG.sound.music.fadeIn(2, 0, 0.4);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
if (didReplace)
|
|
||||||
{
|
|
||||||
FunkinSound.playMusic('freakyMenu',
|
|
||||||
{
|
|
||||||
startingVolume: 0.0,
|
|
||||||
overrideExisting: true,
|
|
||||||
restartTrack: false
|
|
||||||
});
|
|
||||||
FlxG.sound.music.fadeIn(2, 0, 0.8);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
grpCapsules.members[curSelected].selected = true;
|
grpCapsules.members[curSelected].selected = true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,6 +49,8 @@ class MainMenuState extends MusicBeatState
|
||||||
DiscordClient.changePresence("In the Menus", null);
|
DiscordClient.changePresence("In the Menus", null);
|
||||||
#end
|
#end
|
||||||
|
|
||||||
|
FlxG.cameras.reset(new FunkinCamera('mainMenu'));
|
||||||
|
|
||||||
transIn = FlxTransitionableState.defaultTransIn;
|
transIn = FlxTransitionableState.defaultTransIn;
|
||||||
transOut = FlxTransitionableState.defaultTransOut;
|
transOut = FlxTransitionableState.defaultTransOut;
|
||||||
|
|
||||||
|
@ -170,7 +172,6 @@ class MainMenuState extends MusicBeatState
|
||||||
|
|
||||||
function resetCamStuff():Void
|
function resetCamStuff():Void
|
||||||
{
|
{
|
||||||
FlxG.cameras.reset(new FunkinCamera('mainMenu'));
|
|
||||||
FlxG.camera.follow(camFollow, null, 0.06);
|
FlxG.camera.follow(camFollow, null, 0.06);
|
||||||
FlxG.camera.snapToTarget();
|
FlxG.camera.snapToTarget();
|
||||||
}
|
}
|
||||||
|
@ -329,6 +330,8 @@ class MainMenuState extends MusicBeatState
|
||||||
persistentUpdate = false;
|
persistentUpdate = false;
|
||||||
|
|
||||||
FlxG.state.openSubState(new DebugMenuSubState());
|
FlxG.state.openSubState(new DebugMenuSubState());
|
||||||
|
// reset camera when debug menu is closed
|
||||||
|
subStateClosed.addOnce(_ -> resetCamStuff());
|
||||||
}
|
}
|
||||||
#end
|
#end
|
||||||
|
|
||||||
|
|
|
@ -11,12 +11,15 @@ class LevelProp extends Bopper
|
||||||
function set_propData(value:LevelPropData):LevelPropData
|
function set_propData(value:LevelPropData):LevelPropData
|
||||||
{
|
{
|
||||||
// Only reset the prop if the asset path has changed.
|
// Only reset the prop if the asset path has changed.
|
||||||
if (propData == null || value?.assetPath != propData?.assetPath)
|
if (propData == null || !(thx.Dynamics.equals(value, propData)))
|
||||||
{
|
{
|
||||||
|
this.propData = value;
|
||||||
|
|
||||||
|
this.visible = this.propData != null;
|
||||||
|
danceEvery = this.propData?.danceEvery ?? 0;
|
||||||
|
|
||||||
applyData();
|
applyData();
|
||||||
}
|
}
|
||||||
this.visible = (value != null);
|
|
||||||
danceEvery = this.propData?.danceEvery ?? 0;
|
|
||||||
|
|
||||||
return this.propData;
|
return this.propData;
|
||||||
}
|
}
|
||||||
|
|
|
@ -306,7 +306,7 @@ class StoryMenuState extends MusicBeatState
|
||||||
{
|
{
|
||||||
Conductor.instance.update();
|
Conductor.instance.update();
|
||||||
|
|
||||||
highScoreLerp = Std.int(MathUtil.smoothLerp(highScoreLerp, highScore, elapsed, 0.5));
|
highScoreLerp = Std.int(MathUtil.smoothLerp(highScoreLerp, highScore, elapsed, 0.25));
|
||||||
|
|
||||||
scoreText.text = 'LEVEL SCORE: ${Math.round(highScoreLerp)}';
|
scoreText.text = 'LEVEL SCORE: ${Math.round(highScoreLerp)}';
|
||||||
|
|
||||||
|
@ -466,6 +466,9 @@ class StoryMenuState extends MusicBeatState
|
||||||
// Disable the funny music thing for now.
|
// Disable the funny music thing for now.
|
||||||
// funnyMusicThing();
|
// funnyMusicThing();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
updateText();
|
||||||
|
refresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
final FADE_OUT_TIME:Float = 1.5;
|
final FADE_OUT_TIME:Float = 1.5;
|
||||||
|
|
|
@ -67,9 +67,11 @@ class TitleState extends MusicBeatState
|
||||||
// DEBUG BULLSHIT
|
// DEBUG BULLSHIT
|
||||||
|
|
||||||
// netConnection.addEventListener(MouseEvent.MOUSE_DOWN, overlay_onMouseDown);
|
// netConnection.addEventListener(MouseEvent.MOUSE_DOWN, overlay_onMouseDown);
|
||||||
new FlxTimer().start(1, function(tmr:FlxTimer) {
|
if (!initialized) new FlxTimer().start(1, function(tmr:FlxTimer) {
|
||||||
startIntro();
|
startIntro();
|
||||||
});
|
});
|
||||||
|
else
|
||||||
|
startIntro();
|
||||||
}
|
}
|
||||||
|
|
||||||
function client_onMetaData(metaData:Dynamic)
|
function client_onMetaData(metaData:Dynamic)
|
||||||
|
@ -118,7 +120,7 @@ class TitleState extends MusicBeatState
|
||||||
|
|
||||||
function startIntro():Void
|
function startIntro():Void
|
||||||
{
|
{
|
||||||
playMenuMusic();
|
if (!initialized || FlxG.sound.music == null) playMenuMusic();
|
||||||
|
|
||||||
persistentUpdate = true;
|
persistentUpdate = true;
|
||||||
|
|
||||||
|
@ -231,7 +233,7 @@ class TitleState extends MusicBeatState
|
||||||
overrideExisting: true,
|
overrideExisting: true,
|
||||||
restartTrack: true
|
restartTrack: true
|
||||||
});
|
});
|
||||||
// Fade from 0.0 to 0.7 over 4 seconds
|
// Fade from 0.0 to 1 over 4 seconds
|
||||||
if (shouldFadeIn) FlxG.sound.music.fadeIn(4.0, 0.0, 1.0);
|
if (shouldFadeIn) FlxG.sound.music.fadeIn(4.0, 0.0, 1.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -248,6 +248,11 @@ class Constants
|
||||||
*/
|
*/
|
||||||
public static final DEFAULT_ARTIST:String = 'Unknown';
|
public static final DEFAULT_ARTIST:String = 'Unknown';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The default charter for songs.
|
||||||
|
*/
|
||||||
|
public static final DEFAULT_CHARTER:String = 'Unknown';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The default note style for songs.
|
* The default note style for songs.
|
||||||
*/
|
*/
|
||||||
|
|
Loading…
Reference in a new issue