mirror of
https://github.com/FunkinCrew/Funkin.git
synced 2024-12-02 04:17:07 -05:00
assets submod
This commit is contained in:
commit
c5c22b245d
55 changed files with 612 additions and 273 deletions
6
.vscode/launch.json
vendored
6
.vscode/launch.json
vendored
|
@ -7,6 +7,12 @@
|
||||||
"type": "lime",
|
"type": "lime",
|
||||||
"request": "launch"
|
"request": "launch"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "Debug",
|
||||||
|
"type": "lime",
|
||||||
|
"request": "launch",
|
||||||
|
"preLaunchTask": null
|
||||||
|
},
|
||||||
{
|
{
|
||||||
// Launch in browser
|
// Launch in browser
|
||||||
"name": "HTML5 Debug",
|
"name": "HTML5 Debug",
|
||||||
|
|
22
.vscode/tasks.json
vendored
22
.vscode/tasks.json
vendored
|
@ -1,13 +1,13 @@
|
||||||
{
|
{
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"tasks": [
|
"tasks": [
|
||||||
{
|
{
|
||||||
"type": "lime",
|
"type": "lime",
|
||||||
"command": "test",
|
"command": "test",
|
||||||
"group": {
|
"group": {
|
||||||
"kind": "build",
|
"kind": "build",
|
||||||
"isDefault": true
|
"isDefault": true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,9 @@ import flixel.util.FlxSignal;
|
||||||
import flixel.math.FlxMath;
|
import flixel.math.FlxMath;
|
||||||
import funkin.data.song.SongData.SongTimeChange;
|
import funkin.data.song.SongData.SongTimeChange;
|
||||||
import funkin.data.song.SongDataUtils;
|
import funkin.data.song.SongDataUtils;
|
||||||
|
import funkin.save.Save;
|
||||||
|
import haxe.Timer;
|
||||||
|
import flixel.sound.FlxSound;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A core class which handles musical timing throughout the game,
|
* A core class which handles musical timing throughout the game,
|
||||||
|
@ -89,6 +92,9 @@ class Conductor
|
||||||
*/
|
*/
|
||||||
public var songPosition(default, null):Float = 0;
|
public var songPosition(default, null):Float = 0;
|
||||||
|
|
||||||
|
var prevTimestamp:Float = 0;
|
||||||
|
var prevTime:Float = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Beats per minute of the current song at the current time.
|
* Beats per minute of the current song at the current time.
|
||||||
*/
|
*/
|
||||||
|
@ -233,8 +239,41 @@ class Conductor
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An offset set by the user to compensate for input lag.
|
* An offset set by the user to compensate for input lag.
|
||||||
|
* No matter if you're using a local conductor or not, this always loads
|
||||||
|
* to/from the save file
|
||||||
*/
|
*/
|
||||||
public var inputOffset:Float = 0;
|
public var inputOffset(get, set):Int;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An offset set by the user to compensate for audio/visual lag
|
||||||
|
* No matter if you're using a local conductor or not, this always loads
|
||||||
|
* to/from the save file
|
||||||
|
*/
|
||||||
|
public var audioVisualOffset(get, set):Int;
|
||||||
|
|
||||||
|
function get_inputOffset():Int
|
||||||
|
{
|
||||||
|
return Save.instance.options.inputOffset;
|
||||||
|
}
|
||||||
|
|
||||||
|
function set_inputOffset(value:Int):Int
|
||||||
|
{
|
||||||
|
Save.instance.options.inputOffset = value;
|
||||||
|
Save.instance.flush();
|
||||||
|
return Save.instance.options.inputOffset;
|
||||||
|
}
|
||||||
|
|
||||||
|
function get_audioVisualOffset():Int
|
||||||
|
{
|
||||||
|
return Save.instance.options.audioVisualOffset;
|
||||||
|
}
|
||||||
|
|
||||||
|
function set_audioVisualOffset(value:Int):Int
|
||||||
|
{
|
||||||
|
Save.instance.options.audioVisualOffset = value;
|
||||||
|
Save.instance.flush();
|
||||||
|
return Save.instance.options.audioVisualOffset;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The number of beats in a measure. May be fractional depending on the time signature.
|
* The number of beats in a measure. May be fractional depending on the time signature.
|
||||||
|
@ -353,16 +392,19 @@ class Conductor
|
||||||
* BPM, current step, etc. will be re-calculated based on the song position.
|
* BPM, current step, etc. will be re-calculated based on the song position.
|
||||||
*
|
*
|
||||||
* @param songPosition The current position in the song in milliseconds.
|
* @param songPosition The current position in the song in milliseconds.
|
||||||
* Leave blank to use the `FlxG.sound.music` position.
|
* Leave blank to use the FlxG.sound.music position.
|
||||||
|
* @param applyOffsets If it should apply the instrumentalOffset + formatOffset + audioVisualOffset
|
||||||
*/
|
*/
|
||||||
public function update(?songPos:Float):Void
|
public function update(?songPos:Float, applyOffsets:Bool = true, forceDispatch:Bool = false)
|
||||||
{
|
{
|
||||||
if (songPos == null)
|
if (songPos == null)
|
||||||
{
|
{
|
||||||
// Take into account instrumental and file format song offsets.
|
songPos = (FlxG.sound.music != null) ? FlxG.sound.music.time : 0.0;
|
||||||
songPos = (FlxG.sound.music != null) ? (FlxG.sound.music.time + instrumentalOffset + formatOffset) : 0.0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Take into account instrumental and file format song offsets.
|
||||||
|
songPos += applyOffsets ? (instrumentalOffset + formatOffset + audioVisualOffset) : 0;
|
||||||
|
|
||||||
var oldMeasure:Float = this.currentMeasure;
|
var oldMeasure:Float = this.currentMeasure;
|
||||||
var oldBeat:Float = this.currentBeat;
|
var oldBeat:Float = this.currentBeat;
|
||||||
var oldStep:Float = this.currentStep;
|
var oldStep:Float = this.currentStep;
|
||||||
|
@ -421,6 +463,35 @@ class Conductor
|
||||||
{
|
{
|
||||||
this.onMeasureHit.dispatch();
|
this.onMeasureHit.dispatch();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// only update the timestamp if songPosition actually changed
|
||||||
|
// which it doesn't do every frame!
|
||||||
|
if (prevTime != this.songPosition)
|
||||||
|
{
|
||||||
|
// Update the timestamp for use in-between frames
|
||||||
|
prevTime = this.songPosition;
|
||||||
|
prevTimestamp = Std.int(Timer.stamp() * 1000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Can be called in-between frames, usually for input related things
|
||||||
|
* that can potentially get processed on exact milliseconds/timestmaps.
|
||||||
|
* If you need song position, use `Conductor.instance.songPosition` instead
|
||||||
|
* for use in update() related functions.
|
||||||
|
* @param soundToCheck Which FlxSound object to check, defaults to FlxG.sound.music if no input
|
||||||
|
* @return Float
|
||||||
|
*/
|
||||||
|
public function getTimeWithDiff(?soundToCheck:FlxSound):Float
|
||||||
|
{
|
||||||
|
if (soundToCheck == null) soundToCheck = FlxG.sound.music;
|
||||||
|
// trace(this.songPosition);
|
||||||
|
|
||||||
|
@:privateAccess
|
||||||
|
this.songPosition = soundToCheck._channel.position;
|
||||||
|
// return this.songPosition + (Std.int(Timer.stamp() * 1000) - prevTimestamp);
|
||||||
|
// trace("\t--> " + this.songPosition);
|
||||||
|
return this.songPosition;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -468,7 +539,7 @@ class Conductor
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update currentStepTime
|
// Update currentStepTime
|
||||||
this.update(Conductor.instance.songPosition);
|
this.update(this.songPosition, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -587,7 +658,8 @@ class Conductor
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add variables of the current Conductor instance to the Flixel debugger.
|
* Adds Conductor fields to the Flixel debugger variable display.
|
||||||
|
* @param conductorToUse The conductor to use. Defaults to `Conductor.instance`.
|
||||||
*/
|
*/
|
||||||
public static function watchQuick(?target:Conductor):Void
|
public static function watchQuick(?target:Conductor):Void
|
||||||
{
|
{
|
||||||
|
|
|
@ -16,14 +16,14 @@ import funkin.util.macro.MacroUtil;
|
||||||
import funkin.util.WindowUtil;
|
import funkin.util.WindowUtil;
|
||||||
import funkin.play.PlayStatePlaylist;
|
import funkin.play.PlayStatePlaylist;
|
||||||
import openfl.display.BitmapData;
|
import openfl.display.BitmapData;
|
||||||
import funkin.data.level.LevelRegistry;
|
import funkin.data.story.level.LevelRegistry;
|
||||||
import funkin.data.notestyle.NoteStyleRegistry;
|
import funkin.data.notestyle.NoteStyleRegistry;
|
||||||
import funkin.data.event.SongEventRegistry;
|
import funkin.data.event.SongEventRegistry;
|
||||||
import funkin.data.stage.StageRegistry;
|
import funkin.data.stage.StageRegistry;
|
||||||
import funkin.data.dialogue.ConversationRegistry;
|
import funkin.data.dialogue.conversation.ConversationRegistry;
|
||||||
import funkin.data.dialogue.DialogueBoxRegistry;
|
import funkin.data.dialogue.dialoguebox.DialogueBoxRegistry;
|
||||||
import funkin.data.dialogue.SpeakerRegistry;
|
import funkin.data.dialogue.speaker.SpeakerRegistry;
|
||||||
import funkin.data.freeplay.AlbumRegistry;
|
import funkin.data.freeplay.album.AlbumRegistry;
|
||||||
import funkin.data.song.SongRegistry;
|
import funkin.data.song.SongRegistry;
|
||||||
import funkin.play.character.CharacterData.CharacterDataParser;
|
import funkin.play.character.CharacterData.CharacterDataParser;
|
||||||
import funkin.modding.module.ModuleHandler;
|
import funkin.modding.module.ModuleHandler;
|
||||||
|
@ -304,7 +304,7 @@ class InitState extends FlxState
|
||||||
*/
|
*/
|
||||||
function startLevel(levelId:String, difficultyId:String = 'normal'):Void
|
function startLevel(levelId:String, difficultyId:String = 'normal'):Void
|
||||||
{
|
{
|
||||||
var currentLevel:funkin.ui.story.Level = funkin.data.level.LevelRegistry.instance.fetchEntry(levelId);
|
var currentLevel:funkin.ui.story.Level = funkin.data.story.level.LevelRegistry.instance.fetchEntry(levelId);
|
||||||
|
|
||||||
if (currentLevel == null)
|
if (currentLevel == null)
|
||||||
{
|
{
|
||||||
|
|
|
@ -120,7 +120,7 @@ class DataParse
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function backdropData(json:Json, name:String):funkin.data.dialogue.ConversationData.BackdropData
|
public static function backdropData(json:Json, name:String):funkin.data.dialogue.conversation.ConversationData.BackdropData
|
||||||
{
|
{
|
||||||
switch (json.value)
|
switch (json.value)
|
||||||
{
|
{
|
||||||
|
@ -152,7 +152,7 @@ class DataParse
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function outroData(json:Json, name:String):Null<funkin.data.dialogue.ConversationData.OutroData>
|
public static function outroData(json:Json, name:String):Null<funkin.data.dialogue.conversation.ConversationData.OutroData>
|
||||||
{
|
{
|
||||||
switch (json.value)
|
switch (json.value)
|
||||||
{
|
{
|
||||||
|
|
9
source/funkin/data/dialogue/conversation/CHANGELOG.md
Normal file
9
source/funkin/data/dialogue/conversation/CHANGELOG.md
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
# Dialogue Conversation Data Schema Changelog
|
||||||
|
|
||||||
|
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/),
|
||||||
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||||
|
|
||||||
|
## [1.0.0]
|
||||||
|
Initial release.
|
|
@ -1,4 +1,4 @@
|
||||||
package funkin.data.dialogue;
|
package funkin.data.dialogue.conversation;
|
||||||
|
|
||||||
import funkin.data.animation.AnimationData;
|
import funkin.data.animation.AnimationData;
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
package funkin.data.dialogue;
|
package funkin.data.dialogue.conversation;
|
||||||
|
|
||||||
import funkin.play.cutscene.dialogue.Conversation;
|
import funkin.play.cutscene.dialogue.Conversation;
|
||||||
import funkin.data.dialogue.ConversationData;
|
import funkin.data.dialogue.conversation.ConversationData;
|
||||||
import funkin.play.cutscene.dialogue.ScriptedConversation;
|
import funkin.play.cutscene.dialogue.ScriptedConversation;
|
||||||
|
|
||||||
class ConversationRegistry extends BaseRegistry<Conversation, ConversationData>
|
class ConversationRegistry extends BaseRegistry<Conversation, ConversationData>
|
13
source/funkin/data/dialogue/dialoguebox/CHANGELOG.md
Normal file
13
source/funkin/data/dialogue/dialoguebox/CHANGELOG.md
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
# Dialogue Box Data Schema Changelog
|
||||||
|
|
||||||
|
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/),
|
||||||
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||||
|
|
||||||
|
## [1.1.0]
|
||||||
|
### Added
|
||||||
|
- Added an option to specify the font used by the dialogue box. Defaults to `Arial` if unspecified.
|
||||||
|
|
||||||
|
## [1.0.0]
|
||||||
|
Initial release.
|
|
@ -1,4 +1,4 @@
|
||||||
package funkin.data.dialogue;
|
package funkin.data.dialogue.dialoguebox;
|
||||||
|
|
||||||
import funkin.data.animation.AnimationData;
|
import funkin.data.animation.AnimationData;
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
package funkin.data.dialogue;
|
package funkin.data.dialogue.dialoguebox;
|
||||||
|
|
||||||
import funkin.play.cutscene.dialogue.DialogueBox;
|
import funkin.play.cutscene.dialogue.DialogueBox;
|
||||||
import funkin.data.dialogue.DialogueBoxData;
|
import funkin.data.dialogue.dialoguebox.DialogueBoxData;
|
||||||
import funkin.play.cutscene.dialogue.ScriptedDialogueBox;
|
import funkin.play.cutscene.dialogue.ScriptedDialogueBox;
|
||||||
|
|
||||||
class DialogueBoxRegistry extends BaseRegistry<DialogueBox, DialogueBoxData>
|
class DialogueBoxRegistry extends BaseRegistry<DialogueBox, DialogueBoxData>
|
9
source/funkin/data/dialogue/speaker/CHANGELOG.md
Normal file
9
source/funkin/data/dialogue/speaker/CHANGELOG.md
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
# Dialogue Speaker Data Schema Changelog
|
||||||
|
|
||||||
|
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/),
|
||||||
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||||
|
|
||||||
|
## [1.0.0]
|
||||||
|
Initial release.
|
|
@ -1,4 +1,4 @@
|
||||||
package funkin.data.dialogue;
|
package funkin.data.dialogue.speaker;
|
||||||
|
|
||||||
import funkin.data.animation.AnimationData;
|
import funkin.data.animation.AnimationData;
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
package funkin.data.dialogue;
|
package funkin.data.dialogue.speaker;
|
||||||
|
|
||||||
import funkin.play.cutscene.dialogue.Speaker;
|
import funkin.play.cutscene.dialogue.Speaker;
|
||||||
import funkin.data.dialogue.SpeakerData;
|
import funkin.data.dialogue.speaker.SpeakerData;
|
||||||
import funkin.play.cutscene.dialogue.ScriptedSpeaker;
|
import funkin.play.cutscene.dialogue.ScriptedSpeaker;
|
||||||
|
|
||||||
class SpeakerRegistry extends BaseRegistry<Speaker, SpeakerData>
|
class SpeakerRegistry extends BaseRegistry<Speaker, SpeakerData>
|
|
@ -1,4 +1,4 @@
|
||||||
package funkin.data.freeplay;
|
package funkin.data.freeplay.album;
|
||||||
|
|
||||||
import funkin.data.animation.AnimationData;
|
import funkin.data.animation.AnimationData;
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
package funkin.data.freeplay;
|
package funkin.data.freeplay.album;
|
||||||
|
|
||||||
import funkin.ui.freeplay.Album;
|
import funkin.ui.freeplay.Album;
|
||||||
import funkin.data.freeplay.AlbumData;
|
import funkin.data.freeplay.album.AlbumData;
|
||||||
import funkin.ui.freeplay.ScriptedAlbum;
|
import funkin.ui.freeplay.ScriptedAlbum;
|
||||||
|
|
||||||
class AlbumRegistry extends BaseRegistry<Album, AlbumData>
|
class AlbumRegistry extends BaseRegistry<Album, AlbumData>
|
9
source/funkin/data/freeplay/album/CHANGELOG.md
Normal file
9
source/funkin/data/freeplay/album/CHANGELOG.md
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
# Freeplay Album Data Schema Changelog
|
||||||
|
|
||||||
|
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/),
|
||||||
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||||
|
|
||||||
|
## [1.0.0]
|
||||||
|
Initial release.
|
36
source/funkin/data/song/CHANGELOG.md
Normal file
36
source/funkin/data/song/CHANGELOG.md
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
# Song Chart Data Schema Changelog
|
||||||
|
|
||||||
|
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/),
|
||||||
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||||
|
|
||||||
|
## [2.2.2]
|
||||||
|
### 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.
|
||||||
|
|
||||||
|
## [2.2.1]
|
||||||
|
### Added
|
||||||
|
- Added `playData.offsets` field to specify instrumental and vocal offsets.
|
||||||
|
|
||||||
|
## [2.2.0]
|
||||||
|
### Added
|
||||||
|
- Added `playData.album` to specify the album art to display in Freeplay.
|
||||||
|
- Added `playData.ratings` for difficulty ratings displayed in Freeplay.
|
||||||
|
### Changed
|
||||||
|
- Renamed `playData.noteSkin` to `playData.noteStyle`.
|
||||||
|
|
||||||
|
## [2.1.0]
|
||||||
|
### Changed
|
||||||
|
- Rearranged the `playData` field.
|
||||||
|
- Refactored the `playableChars`
|
||||||
|
### Removed
|
||||||
|
- Removed the `variation` field.
|
||||||
|
|
||||||
|
## [2.0.0]
|
||||||
|
Full refactor of the chart format for improved structure.
|
||||||
|
### Added
|
||||||
|
- Added a semantic version field for migration tracking.
|
||||||
|
|
||||||
|
## [1.0.0]
|
||||||
|
Initial version from 2020.
|
14
source/funkin/data/stage/CHANGELOG.md
Normal file
14
source/funkin/data/stage/CHANGELOG.md
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
# Story Mode Level Data Schema Changelog
|
||||||
|
|
||||||
|
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/),
|
||||||
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||||
|
|
||||||
|
## [1.0.1]
|
||||||
|
### Added
|
||||||
|
- Added the ability to specify a hexadecimal color in the `assetPath` field instead of a texture key.
|
||||||
|
- In this case, the `scale` property will be used to determine the size of the rectangle in pixels.
|
||||||
|
|
||||||
|
## [1.0.0]
|
||||||
|
Initial release.
|
|
@ -11,7 +11,7 @@ class StageRegistry extends BaseRegistry<Stage, StageData>
|
||||||
* 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 STAGE_DATA_VERSION:thx.semver.Version = "1.0.1";
|
public static final STAGE_DATA_VERSION:thx.semver.Version = "1.0.0";
|
||||||
|
|
||||||
public static final STAGE_DATA_VERSION_RULE:thx.semver.VersionRule = "1.0.x";
|
public static final STAGE_DATA_VERSION_RULE:thx.semver.VersionRule = "1.0.x";
|
||||||
|
|
||||||
|
|
9
source/funkin/data/story/level/CHANGELOG.md
Normal file
9
source/funkin/data/story/level/CHANGELOG.md
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
# Story Mode Level Data Schema Changelog
|
||||||
|
|
||||||
|
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/),
|
||||||
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||||
|
|
||||||
|
## [1.0.0]
|
||||||
|
Initial release.
|
|
@ -1,4 +1,4 @@
|
||||||
package funkin.data.level;
|
package funkin.data.story.level;
|
||||||
|
|
||||||
import funkin.data.animation.AnimationData;
|
import funkin.data.animation.AnimationData;
|
||||||
|
|
||||||
|
@ -13,7 +13,7 @@ typedef LevelData =
|
||||||
* When making changes to the level data format, this should be incremented,
|
* 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.
|
* and a migration function should be added to LevelDataParser to handle old versions.
|
||||||
*/
|
*/
|
||||||
@:default(funkin.data.level.LevelRegistry.LEVEL_DATA_VERSION)
|
@:default(funkin.data.story.level.LevelRegistry.LEVEL_DATA_VERSION)
|
||||||
var version:String;
|
var version:String;
|
||||||
|
|
||||||
/**
|
/**
|
|
@ -1,7 +1,7 @@
|
||||||
package funkin.data.level;
|
package funkin.data.story.level;
|
||||||
|
|
||||||
import funkin.ui.story.Level;
|
import funkin.ui.story.Level;
|
||||||
import funkin.data.level.LevelData;
|
import funkin.data.story.level.LevelData;
|
||||||
import funkin.ui.story.ScriptedLevel;
|
import funkin.ui.story.ScriptedLevel;
|
||||||
|
|
||||||
class LevelRegistry extends BaseRegistry<Level, LevelData>
|
class LevelRegistry extends BaseRegistry<Level, LevelData>
|
|
@ -29,7 +29,7 @@ class HSVShader extends FlxRuntimeShader
|
||||||
|
|
||||||
function set_saturation(value:Float):Float
|
function set_saturation(value:Float):Float
|
||||||
{
|
{
|
||||||
this.setFloat('sat', value);
|
this.setFloat('_sat', value);
|
||||||
this.saturation = value;
|
this.saturation = value;
|
||||||
|
|
||||||
return this.saturation;
|
return this.saturation;
|
||||||
|
@ -37,7 +37,7 @@ class HSVShader extends FlxRuntimeShader
|
||||||
|
|
||||||
function set_value(value:Float):Float
|
function set_value(value:Float):Float
|
||||||
{
|
{
|
||||||
this.setFloat('val', value);
|
this.setFloat('_val', value);
|
||||||
this.value = value;
|
this.value = value;
|
||||||
|
|
||||||
return this.value;
|
return this.value;
|
||||||
|
|
|
@ -293,8 +293,9 @@ class PreciseInputManager extends FlxKeyManager<FlxKey, PreciseInputList>
|
||||||
|
|
||||||
// TODO: Remove this line with SDL3 when timestamps change meaning.
|
// TODO: Remove this line with SDL3 when timestamps change meaning.
|
||||||
// This is because SDL3's timestamps are measured in nanoseconds, not milliseconds.
|
// This is because SDL3's timestamps are measured in nanoseconds, not milliseconds.
|
||||||
timestamp *= Constants.NS_PER_MS;
|
timestamp *= Constants.NS_PER_MS; // 18126000000 38367000000
|
||||||
|
timestamp -= Conductor.instance.inputOffset * Constants.NS_PER_MS;
|
||||||
|
// trace(timestamp);
|
||||||
updateKeyStates(key, true);
|
updateKeyStates(key, true);
|
||||||
|
|
||||||
if (getInputByKey(key)?.justPressed ?? false)
|
if (getInputByKey(key)?.justPressed ?? false)
|
||||||
|
|
|
@ -1,14 +1,14 @@
|
||||||
package funkin.modding;
|
package funkin.modding;
|
||||||
|
|
||||||
import funkin.data.dialogue.ConversationRegistry;
|
import funkin.data.dialogue.conversation.ConversationRegistry;
|
||||||
import funkin.data.dialogue.DialogueBoxRegistry;
|
import funkin.data.dialogue.dialoguebox.DialogueBoxRegistry;
|
||||||
import funkin.data.dialogue.SpeakerRegistry;
|
import funkin.data.dialogue.speaker.SpeakerRegistry;
|
||||||
import funkin.data.event.SongEventRegistry;
|
import funkin.data.event.SongEventRegistry;
|
||||||
import funkin.data.level.LevelRegistry;
|
import funkin.data.story.level.LevelRegistry;
|
||||||
import funkin.data.notestyle.NoteStyleRegistry;
|
import funkin.data.notestyle.NoteStyleRegistry;
|
||||||
import funkin.data.song.SongRegistry;
|
import funkin.data.song.SongRegistry;
|
||||||
import funkin.data.stage.StageRegistry;
|
import funkin.data.stage.StageRegistry;
|
||||||
import funkin.data.freeplay.AlbumRegistry;
|
import funkin.data.freeplay.album.AlbumRegistry;
|
||||||
import funkin.modding.module.ModuleHandler;
|
import funkin.modding.module.ModuleHandler;
|
||||||
import funkin.play.character.CharacterData.CharacterDataParser;
|
import funkin.play.character.CharacterData.CharacterDataParser;
|
||||||
import funkin.save.Save;
|
import funkin.save.Save;
|
||||||
|
|
|
@ -2,14 +2,16 @@ package funkin.play;
|
||||||
|
|
||||||
import flixel.addons.transition.FlxTransitionableState;
|
import flixel.addons.transition.FlxTransitionableState;
|
||||||
import flixel.FlxG;
|
import flixel.FlxG;
|
||||||
import flixel.util.FlxTimer;
|
|
||||||
import flixel.FlxSprite;
|
import flixel.FlxSprite;
|
||||||
|
import flixel.group.FlxGroup.FlxTypedGroup;
|
||||||
import flixel.group.FlxSpriteGroup;
|
import flixel.group.FlxSpriteGroup;
|
||||||
import flixel.math.FlxMath;
|
import flixel.math.FlxMath;
|
||||||
|
import flixel.sound.FlxSound;
|
||||||
import flixel.text.FlxText;
|
import flixel.text.FlxText;
|
||||||
import flixel.tweens.FlxEase;
|
import flixel.tweens.FlxEase;
|
||||||
import flixel.tweens.FlxTween;
|
import flixel.tweens.FlxTween;
|
||||||
import flixel.util.FlxColor;
|
import flixel.util.FlxColor;
|
||||||
|
import flixel.util.FlxTimer;
|
||||||
import funkin.audio.FunkinSound;
|
import funkin.audio.FunkinSound;
|
||||||
import funkin.data.song.SongRegistry;
|
import funkin.data.song.SongRegistry;
|
||||||
import funkin.ui.freeplay.FreeplayState;
|
import funkin.ui.freeplay.FreeplayState;
|
||||||
|
@ -17,6 +19,7 @@ import funkin.graphics.FunkinSprite;
|
||||||
import funkin.play.cutscene.VideoCutscene;
|
import funkin.play.cutscene.VideoCutscene;
|
||||||
import funkin.play.PlayState;
|
import funkin.play.PlayState;
|
||||||
import funkin.ui.AtlasText;
|
import funkin.ui.AtlasText;
|
||||||
|
import funkin.ui.debug.latency.LatencyState;
|
||||||
import funkin.ui.MusicBeatSubState;
|
import funkin.ui.MusicBeatSubState;
|
||||||
import funkin.ui.transition.StickerSubState;
|
import funkin.ui.transition.StickerSubState;
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,7 @@ import flixel.util.FlxTimer;
|
||||||
import funkin.api.newgrounds.NGio;
|
import funkin.api.newgrounds.NGio;
|
||||||
import funkin.audio.FunkinSound;
|
import funkin.audio.FunkinSound;
|
||||||
import funkin.audio.VoicesGroup;
|
import funkin.audio.VoicesGroup;
|
||||||
import funkin.data.dialogue.ConversationRegistry;
|
import funkin.data.dialogue.conversation.ConversationRegistry;
|
||||||
import funkin.data.event.SongEventRegistry;
|
import funkin.data.event.SongEventRegistry;
|
||||||
import funkin.data.notestyle.NoteStyleData;
|
import funkin.data.notestyle.NoteStyleData;
|
||||||
import funkin.data.notestyle.NoteStyleRegistry;
|
import funkin.data.notestyle.NoteStyleRegistry;
|
||||||
|
@ -890,7 +890,8 @@ class PlayState extends MusicBeatSubState
|
||||||
{
|
{
|
||||||
if (isInCountdown)
|
if (isInCountdown)
|
||||||
{
|
{
|
||||||
Conductor.instance.update(Conductor.instance.songPosition + elapsed * 1000);
|
// Do NOT apply offsets at this point, because they already got applied the previous frame!
|
||||||
|
Conductor.instance.update(Conductor.instance.songPosition + elapsed * 1000, false);
|
||||||
if (Conductor.instance.songPosition >= (startTimestamp)) startSong();
|
if (Conductor.instance.songPosition >= (startTimestamp)) startSong();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2049,10 +2050,10 @@ class PlayState extends MusicBeatSubState
|
||||||
{
|
{
|
||||||
if (note == null) continue;
|
if (note == null) continue;
|
||||||
|
|
||||||
// TODO: Does this properly account for offsets?
|
// TODO: Are offsets being accounted for in the correct direction?
|
||||||
var hitWindowStart = note.strumTime - Constants.HIT_WINDOW_MS;
|
var hitWindowStart = note.strumTime + Conductor.instance.inputOffset - Constants.HIT_WINDOW_MS;
|
||||||
var hitWindowCenter = note.strumTime;
|
var hitWindowCenter = note.strumTime + Conductor.instance.inputOffset;
|
||||||
var hitWindowEnd = note.strumTime + Constants.HIT_WINDOW_MS;
|
var hitWindowEnd = note.strumTime + Conductor.instance.inputOffset + Constants.HIT_WINDOW_MS;
|
||||||
|
|
||||||
if (Conductor.instance.songPosition > hitWindowEnd)
|
if (Conductor.instance.songPosition > hitWindowEnd)
|
||||||
{
|
{
|
||||||
|
|
|
@ -42,7 +42,7 @@ class PopUpStuff extends FlxTypedGroup<FlxSprite>
|
||||||
|
|
||||||
if (PlayState.instance.currentStageId.startsWith('school'))
|
if (PlayState.instance.currentStageId.startsWith('school'))
|
||||||
{
|
{
|
||||||
rating.setGraphicSize(Std.int(rating.width * Constants.PIXEL_ART_SCALE * 0.65));
|
rating.setGraphicSize(Std.int(rating.width * Constants.PIXEL_ART_SCALE * 0.7));
|
||||||
rating.antialiasing = false;
|
rating.antialiasing = false;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -133,7 +133,7 @@ class PopUpStuff extends FlxTypedGroup<FlxSprite>
|
||||||
|
|
||||||
if (PlayState.instance.currentStageId.startsWith('school'))
|
if (PlayState.instance.currentStageId.startsWith('school'))
|
||||||
{
|
{
|
||||||
numScore.setGraphicSize(Std.int(numScore.width * Constants.PIXEL_ART_SCALE));
|
numScore.setGraphicSize(Std.int(numScore.width * Constants.PIXEL_ART_SCALE * 0.7));
|
||||||
numScore.antialiasing = false;
|
numScore.antialiasing = false;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
|
@ -8,13 +8,13 @@ import flixel.tweens.FlxTween;
|
||||||
import flixel.util.FlxColor;
|
import flixel.util.FlxColor;
|
||||||
import flixel.util.FlxSort;
|
import flixel.util.FlxSort;
|
||||||
import funkin.audio.FunkinSound;
|
import funkin.audio.FunkinSound;
|
||||||
import funkin.data.dialogue.ConversationData;
|
import funkin.data.dialogue.conversation.ConversationData;
|
||||||
import funkin.data.dialogue.ConversationData.DialogueEntryData;
|
import funkin.data.dialogue.conversation.ConversationData.DialogueEntryData;
|
||||||
import funkin.data.dialogue.ConversationRegistry;
|
import funkin.data.dialogue.conversation.ConversationRegistry;
|
||||||
import funkin.data.dialogue.DialogueBoxData;
|
import funkin.data.dialogue.dialoguebox.DialogueBoxData;
|
||||||
import funkin.data.dialogue.DialogueBoxRegistry;
|
import funkin.data.dialogue.dialoguebox.DialogueBoxRegistry;
|
||||||
import funkin.data.dialogue.SpeakerData;
|
import funkin.data.dialogue.speaker.SpeakerData;
|
||||||
import funkin.data.dialogue.SpeakerRegistry;
|
import funkin.data.dialogue.speaker.SpeakerRegistry;
|
||||||
import funkin.data.IRegistryEntry;
|
import funkin.data.IRegistryEntry;
|
||||||
import funkin.graphics.FunkinSprite;
|
import funkin.graphics.FunkinSprite;
|
||||||
import funkin.modding.events.ScriptEvent;
|
import funkin.modding.events.ScriptEvent;
|
||||||
|
|
|
@ -11,8 +11,8 @@ import funkin.modding.events.ScriptEvent;
|
||||||
import funkin.audio.FunkinSound;
|
import funkin.audio.FunkinSound;
|
||||||
import funkin.modding.IScriptedClass.IDialogueScriptedClass;
|
import funkin.modding.IScriptedClass.IDialogueScriptedClass;
|
||||||
import flixel.util.FlxColor;
|
import flixel.util.FlxColor;
|
||||||
import funkin.data.dialogue.DialogueBoxData;
|
import funkin.data.dialogue.dialoguebox.DialogueBoxData;
|
||||||
import funkin.data.dialogue.DialogueBoxRegistry;
|
import funkin.data.dialogue.dialoguebox.DialogueBoxRegistry;
|
||||||
|
|
||||||
class DialogueBox extends FlxSpriteGroup implements IDialogueScriptedClass implements IRegistryEntry<DialogueBoxData>
|
class DialogueBox extends FlxSpriteGroup implements IDialogueScriptedClass implements IRegistryEntry<DialogueBoxData>
|
||||||
{
|
{
|
||||||
|
|
|
@ -6,8 +6,8 @@ import funkin.modding.events.ScriptEvent;
|
||||||
import flixel.graphics.frames.FlxFramesCollection;
|
import flixel.graphics.frames.FlxFramesCollection;
|
||||||
import funkin.util.assets.FlxAnimationUtil;
|
import funkin.util.assets.FlxAnimationUtil;
|
||||||
import funkin.modding.IScriptedClass.IDialogueScriptedClass;
|
import funkin.modding.IScriptedClass.IDialogueScriptedClass;
|
||||||
import funkin.data.dialogue.SpeakerData;
|
import funkin.data.dialogue.speaker.SpeakerData;
|
||||||
import funkin.data.dialogue.SpeakerRegistry;
|
import funkin.data.dialogue.speaker.SpeakerRegistry;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The character sprite which displays during dialogue.
|
* The character sprite which displays during dialogue.
|
||||||
|
|
|
@ -127,7 +127,7 @@ class FocusCameraSongEvent extends SongEvent
|
||||||
switch (ease)
|
switch (ease)
|
||||||
{
|
{
|
||||||
case 'CLASSIC': // Old-school. No ease. Just set follow point.
|
case 'CLASSIC': // Old-school. No ease. Just set follow point.
|
||||||
PlayState.instance.resetCamera();
|
PlayState.instance.resetCamera(false, true);
|
||||||
PlayState.instance.cameraFollowPoint.setPosition(targetX, targetY);
|
PlayState.instance.cameraFollowPoint.setPosition(targetX, targetY);
|
||||||
case 'INSTANT': // Instant ease. Duration is automatically 0.
|
case 'INSTANT': // Instant ease. Duration is automatically 0.
|
||||||
PlayState.instance.tweenCameraToPosition(targetX, targetY, 0);
|
PlayState.instance.tweenCameraToPosition(targetX, targetY, 0);
|
||||||
|
|
|
@ -15,6 +15,7 @@ import funkin.play.notes.SustainTrail;
|
||||||
import funkin.data.song.SongData.SongNoteData;
|
import funkin.data.song.SongData.SongNoteData;
|
||||||
import funkin.ui.options.PreferencesMenu;
|
import funkin.ui.options.PreferencesMenu;
|
||||||
import funkin.util.SortUtil;
|
import funkin.util.SortUtil;
|
||||||
|
import funkin.modding.events.ScriptEvent;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A group of sprites which handles the receptor, the note splashes, and the notes (with sustains) for a given player.
|
* A group of sprites which handles the receptor, the note splashes, and the notes (with sustains) for a given player.
|
||||||
|
@ -45,6 +46,25 @@ class Strumline extends FlxSpriteGroup
|
||||||
*/
|
*/
|
||||||
public var isPlayer:Bool;
|
public var isPlayer:Bool;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Usually you want to keep this as is, but if you are using a Strumline and
|
||||||
|
* playing a sound that has it's own conductor, set this (LatencyState for example)
|
||||||
|
*/
|
||||||
|
public var conductorInUse(get, set):Conductor;
|
||||||
|
|
||||||
|
var _conductorInUse:Null<Conductor>;
|
||||||
|
|
||||||
|
function get_conductorInUse():Conductor
|
||||||
|
{
|
||||||
|
if (_conductorInUse == null) return Conductor.instance;
|
||||||
|
return _conductorInUse;
|
||||||
|
}
|
||||||
|
|
||||||
|
function set_conductorInUse(value:Conductor):Conductor
|
||||||
|
{
|
||||||
|
return _conductorInUse = value;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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.
|
||||||
|
@ -151,24 +171,10 @@ class Strumline extends FlxSpriteGroup
|
||||||
updateNotes();
|
updateNotes();
|
||||||
}
|
}
|
||||||
|
|
||||||
var frameMax:Int;
|
|
||||||
var animFinishedEver:Bool;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a list of notes within + or - the given strumtime.
|
* Return notes that are within `Constants.HIT_WINDOW` ms of the strumline.
|
||||||
* @param strumTime The current time.
|
* @return An array of `NoteSprite` objects.
|
||||||
* @param hitWindow The hit window to check.
|
|
||||||
*/
|
*/
|
||||||
public function getNotesInRange(strumTime:Float, hitWindow:Float):Array<NoteSprite>
|
|
||||||
{
|
|
||||||
var hitWindowStart:Float = strumTime - hitWindow;
|
|
||||||
var hitWindowEnd:Float = strumTime + hitWindow;
|
|
||||||
|
|
||||||
return notes.members.filter(function(note:NoteSprite) {
|
|
||||||
return note != null && note.alive && !note.hasBeenHit && note.strumTime >= hitWindowStart && note.strumTime <= hitWindowEnd;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getNotesMayHit():Array<NoteSprite>
|
public function getNotesMayHit():Array<NoteSprite>
|
||||||
{
|
{
|
||||||
return notes.members.filter(function(note:NoteSprite) {
|
return notes.members.filter(function(note:NoteSprite) {
|
||||||
|
@ -176,6 +182,10 @@ class Strumline extends FlxSpriteGroup
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return hold notes that are within `Constants.HIT_WINDOW` ms of the strumline.
|
||||||
|
* @return An array of `SustainTrail` objects.
|
||||||
|
*/
|
||||||
public function getHoldNotesHitOrMissed():Array<SustainTrail>
|
public function getHoldNotesHitOrMissed():Array<SustainTrail>
|
||||||
{
|
{
|
||||||
return holdNotes.members.filter(function(holdNote:SustainTrail) {
|
return holdNotes.members.filter(function(holdNote:SustainTrail) {
|
||||||
|
@ -183,19 +193,6 @@ class Strumline extends FlxSpriteGroup
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getHoldNotesInRange(strumTime:Float, hitWindow:Float):Array<SustainTrail>
|
|
||||||
{
|
|
||||||
var hitWindowStart:Float = strumTime - hitWindow;
|
|
||||||
var hitWindowEnd:Float = strumTime + hitWindow;
|
|
||||||
|
|
||||||
return holdNotes.members.filter(function(note:SustainTrail) {
|
|
||||||
return note != null
|
|
||||||
&& note.alive
|
|
||||||
&& note.strumTime >= hitWindowStart
|
|
||||||
&& (note.strumTime + note.fullSustainLength) <= hitWindowEnd;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getNoteSprite(noteData:SongNoteData):NoteSprite
|
public function getNoteSprite(noteData:SongNoteData):NoteSprite
|
||||||
{
|
{
|
||||||
if (noteData == null) return null;
|
if (noteData == null) return null;
|
||||||
|
@ -280,7 +277,7 @@ class Strumline extends FlxSpriteGroup
|
||||||
* @param strumTime
|
* @param strumTime
|
||||||
* @return Float
|
* @return Float
|
||||||
*/
|
*/
|
||||||
static function calculateNoteYPos(strumTime:Float, vwoosh:Bool = true):Float
|
public function calculateNoteYPos(strumTime:Float, vwoosh:Bool = true):Float
|
||||||
{
|
{
|
||||||
// Make the note move faster visually as it moves offscreen.
|
// Make the note move faster visually as it moves offscreen.
|
||||||
// var vwoosh:Float = (strumTime < Conductor.songPosition) && vwoosh ? 2.0 : 1.0;
|
// var vwoosh:Float = (strumTime < Conductor.songPosition) && vwoosh ? 2.0 : 1.0;
|
||||||
|
@ -288,7 +285,8 @@ class Strumline extends FlxSpriteGroup
|
||||||
var vwoosh:Float = 1.0;
|
var vwoosh:Float = 1.0;
|
||||||
var scrollSpeed:Float = PlayState.instance?.currentChart?.scrollSpeed ?? 1.0;
|
var scrollSpeed:Float = PlayState.instance?.currentChart?.scrollSpeed ?? 1.0;
|
||||||
|
|
||||||
return Constants.PIXELS_PER_MS * (Conductor.instance.songPosition - strumTime) * scrollSpeed * vwoosh * (Preferences.downscroll ? 1 : -1);
|
return
|
||||||
|
Constants.PIXELS_PER_MS * (conductorInUse.songPosition - strumTime - Conductor.instance.inputOffset) * scrollSpeed * vwoosh * (Preferences.downscroll ? 1 : -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateNotes():Void
|
function updateNotes():Void
|
||||||
|
@ -301,8 +299,8 @@ class Strumline extends FlxSpriteGroup
|
||||||
// if (conductorInUse.currentStep == 0) nextNoteIndex = 0;
|
// if (conductorInUse.currentStep == 0) nextNoteIndex = 0;
|
||||||
|
|
||||||
var songStart:Float = PlayState.instance?.startTimestamp ?? 0.0;
|
var songStart:Float = PlayState.instance?.startTimestamp ?? 0.0;
|
||||||
var hitWindowStart:Float = Conductor.instance.songPosition - Constants.HIT_WINDOW_MS;
|
var hitWindowStart:Float = conductorInUse.songPosition - Constants.HIT_WINDOW_MS;
|
||||||
var renderWindowStart:Float = Conductor.instance.songPosition + RENDER_DISTANCE_MS;
|
var renderWindowStart:Float = conductorInUse.songPosition + RENDER_DISTANCE_MS;
|
||||||
|
|
||||||
for (noteIndex in nextNoteIndex...noteData.length)
|
for (noteIndex in nextNoteIndex...noteData.length)
|
||||||
{
|
{
|
||||||
|
@ -351,7 +349,7 @@ class Strumline extends FlxSpriteGroup
|
||||||
{
|
{
|
||||||
if (holdNote == null || !holdNote.alive) continue;
|
if (holdNote == null || !holdNote.alive) continue;
|
||||||
|
|
||||||
if (Conductor.instance.songPosition > holdNote.strumTime && holdNote.hitNote && !holdNote.missedNote)
|
if (conductorInUse.songPosition > holdNote.strumTime && holdNote.hitNote && !holdNote.missedNote)
|
||||||
{
|
{
|
||||||
if (isPlayer && !isKeyHeld(holdNote.noteDirection))
|
if (isPlayer && !isKeyHeld(holdNote.noteDirection))
|
||||||
{
|
{
|
||||||
|
@ -365,7 +363,7 @@ class Strumline extends FlxSpriteGroup
|
||||||
|
|
||||||
var renderWindowEnd = holdNote.strumTime + holdNote.fullSustainLength + Constants.HIT_WINDOW_MS + RENDER_DISTANCE_MS / 8;
|
var renderWindowEnd = holdNote.strumTime + holdNote.fullSustainLength + Constants.HIT_WINDOW_MS + RENDER_DISTANCE_MS / 8;
|
||||||
|
|
||||||
if (holdNote.missedNote && Conductor.instance.songPosition >= renderWindowEnd)
|
if (holdNote.missedNote && conductorInUse.songPosition >= renderWindowEnd)
|
||||||
{
|
{
|
||||||
// Hold note is offscreen, kill it.
|
// Hold note is offscreen, kill it.
|
||||||
holdNote.visible = false;
|
holdNote.visible = false;
|
||||||
|
@ -422,13 +420,13 @@ class Strumline extends FlxSpriteGroup
|
||||||
holdNote.cover.kill();
|
holdNote.cover.kill();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (Conductor.instance.songPosition > holdNote.strumTime && holdNote.hitNote)
|
else if (conductorInUse.songPosition > holdNote.strumTime && holdNote.hitNote)
|
||||||
{
|
{
|
||||||
// Hold note is currently being hit, clip it off.
|
// Hold note is currently being hit, clip it off.
|
||||||
holdConfirm(holdNote.noteDirection);
|
holdConfirm(holdNote.noteDirection);
|
||||||
holdNote.visible = true;
|
holdNote.visible = true;
|
||||||
|
|
||||||
holdNote.sustainLength = (holdNote.strumTime + holdNote.fullSustainLength) - Conductor.instance.songPosition;
|
holdNote.sustainLength = (holdNote.strumTime + holdNote.fullSustainLength) - conductorInUse.songPosition;
|
||||||
|
|
||||||
if (holdNote.sustainLength <= 10)
|
if (holdNote.sustainLength <= 10)
|
||||||
{
|
{
|
||||||
|
|
|
@ -87,6 +87,8 @@ class Save
|
||||||
zoomCamera: true,
|
zoomCamera: true,
|
||||||
debugDisplay: false,
|
debugDisplay: false,
|
||||||
autoPause: true,
|
autoPause: true,
|
||||||
|
inputOffset: 0,
|
||||||
|
audioVisualOffset: 0,
|
||||||
|
|
||||||
controls:
|
controls:
|
||||||
{
|
{
|
||||||
|
@ -866,6 +868,18 @@ typedef SaveDataOptions =
|
||||||
*/
|
*/
|
||||||
var autoPause:Bool;
|
var autoPause:Bool;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Offset the users inputs by this many ms.
|
||||||
|
* @default `0`
|
||||||
|
*/
|
||||||
|
var inputOffset:Int;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Affects the delay between the audio and the visuals during gameplay
|
||||||
|
* @default `0`
|
||||||
|
*/
|
||||||
|
var audioVisualOffset:Int;
|
||||||
|
|
||||||
var controls:
|
var controls:
|
||||||
{
|
{
|
||||||
var p1:
|
var p1:
|
||||||
|
|
12
source/funkin/save/changelog.md
Normal file
12
source/funkin/save/changelog.md
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
# Changelog
|
||||||
|
|
||||||
|
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/),
|
||||||
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||||
|
|
||||||
|
|
||||||
|
## [2.0.3] - 2024-01-09
|
||||||
|
### Added
|
||||||
|
- `inputOffset:Float` to `SongDataOptions`
|
||||||
|
- `audioVisualOffset:Float` to `SongDataOptions`
|
|
@ -29,6 +29,21 @@ class MusicBeatState extends FlxTransitionableState implements IEventHandler
|
||||||
public var leftWatermarkText:FlxText = null;
|
public var leftWatermarkText:FlxText = null;
|
||||||
public var rightWatermarkText:FlxText = null;
|
public var rightWatermarkText:FlxText = null;
|
||||||
|
|
||||||
|
public var conductorInUse(get, set):Conductor;
|
||||||
|
|
||||||
|
var _conductorInUse:Null<Conductor>;
|
||||||
|
|
||||||
|
function get_conductorInUse():Conductor
|
||||||
|
{
|
||||||
|
if (_conductorInUse == null) return Conductor.instance;
|
||||||
|
return _conductorInUse;
|
||||||
|
}
|
||||||
|
|
||||||
|
function set_conductorInUse(value:Conductor):Conductor
|
||||||
|
{
|
||||||
|
return _conductorInUse = value;
|
||||||
|
}
|
||||||
|
|
||||||
public function new()
|
public function new()
|
||||||
{
|
{
|
||||||
super();
|
super();
|
||||||
|
@ -111,7 +126,7 @@ class MusicBeatState extends FlxTransitionableState implements IEventHandler
|
||||||
|
|
||||||
public function stepHit():Bool
|
public function stepHit():Bool
|
||||||
{
|
{
|
||||||
var event = new SongTimeScriptEvent(SONG_STEP_HIT, Conductor.instance.currentBeat, Conductor.instance.currentStep);
|
var event = new SongTimeScriptEvent(SONG_STEP_HIT, conductorInUse.currentBeat, conductorInUse.currentStep);
|
||||||
|
|
||||||
dispatchEvent(event);
|
dispatchEvent(event);
|
||||||
|
|
||||||
|
@ -122,7 +137,7 @@ class MusicBeatState extends FlxTransitionableState implements IEventHandler
|
||||||
|
|
||||||
public function beatHit():Bool
|
public function beatHit():Bool
|
||||||
{
|
{
|
||||||
var event = new SongTimeScriptEvent(SONG_BEAT_HIT, Conductor.instance.currentBeat, Conductor.instance.currentStep);
|
var event = new SongTimeScriptEvent(SONG_BEAT_HIT, conductorInUse.currentBeat, conductorInUse.currentStep);
|
||||||
|
|
||||||
dispatchEvent(event);
|
dispatchEvent(event);
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,21 @@ class MusicBeatSubState extends FlxSubState implements IEventHandler
|
||||||
public var leftWatermarkText:FlxText = null;
|
public var leftWatermarkText:FlxText = null;
|
||||||
public var rightWatermarkText:FlxText = null;
|
public var rightWatermarkText:FlxText = null;
|
||||||
|
|
||||||
|
public var conductorInUse(get, set):Conductor;
|
||||||
|
|
||||||
|
var _conductorInUse:Null<Conductor>;
|
||||||
|
|
||||||
|
function get_conductorInUse():Conductor
|
||||||
|
{
|
||||||
|
if (_conductorInUse == null) return Conductor.instance;
|
||||||
|
return _conductorInUse;
|
||||||
|
}
|
||||||
|
|
||||||
|
function set_conductorInUse(value:Conductor):Conductor
|
||||||
|
{
|
||||||
|
return _conductorInUse = value;
|
||||||
|
}
|
||||||
|
|
||||||
public function new(bgColor:FlxColor = FlxColor.TRANSPARENT)
|
public function new(bgColor:FlxColor = FlxColor.TRANSPARENT)
|
||||||
{
|
{
|
||||||
super();
|
super();
|
||||||
|
@ -51,7 +66,6 @@ class MusicBeatSubState extends FlxSubState implements IEventHandler
|
||||||
|
|
||||||
override function update(elapsed:Float):Void
|
override function update(elapsed:Float):Void
|
||||||
{
|
{
|
||||||
// 3.59% CPU Usage (100% is FlxTypedGroup#update() and most of that is updating each member.)
|
|
||||||
super.update(elapsed);
|
super.update(elapsed);
|
||||||
|
|
||||||
// Emergency exit button.
|
// Emergency exit button.
|
||||||
|
@ -62,11 +76,8 @@ class MusicBeatSubState extends FlxSubState implements IEventHandler
|
||||||
|
|
||||||
// Display Conductor info in the watch window.
|
// Display Conductor info in the watch window.
|
||||||
FlxG.watch.addQuick("musicTime", FlxG.sound.music?.time ?? 0.0);
|
FlxG.watch.addQuick("musicTime", FlxG.sound.music?.time ?? 0.0);
|
||||||
|
Conductor.watchQuick(conductorInUse);
|
||||||
|
|
||||||
// 0.09% CPU Usage?
|
|
||||||
Conductor.watchQuick();
|
|
||||||
|
|
||||||
// 4.31% CPU Usage
|
|
||||||
dispatchEvent(new UpdateScriptEvent(elapsed));
|
dispatchEvent(new UpdateScriptEvent(elapsed));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -94,7 +105,7 @@ class MusicBeatSubState extends FlxSubState implements IEventHandler
|
||||||
*/
|
*/
|
||||||
public function stepHit():Bool
|
public function stepHit():Bool
|
||||||
{
|
{
|
||||||
var event:ScriptEvent = new SongTimeScriptEvent(SONG_STEP_HIT, Conductor.instance.currentBeat, Conductor.instance.currentStep);
|
var event:ScriptEvent = new SongTimeScriptEvent(SONG_STEP_HIT, conductorInUse.currentBeat, conductorInUse.currentStep);
|
||||||
|
|
||||||
dispatchEvent(event);
|
dispatchEvent(event);
|
||||||
|
|
||||||
|
@ -110,7 +121,7 @@ class MusicBeatSubState extends FlxSubState implements IEventHandler
|
||||||
*/
|
*/
|
||||||
public function beatHit():Bool
|
public function beatHit():Bool
|
||||||
{
|
{
|
||||||
var event:ScriptEvent = new SongTimeScriptEvent(SONG_BEAT_HIT, Conductor.instance.currentBeat, Conductor.instance.currentStep);
|
var event:ScriptEvent = new SongTimeScriptEvent(SONG_BEAT_HIT, conductorInUse.currentBeat, conductorInUse.currentStep);
|
||||||
|
|
||||||
dispatchEvent(event);
|
dispatchEvent(event);
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,9 @@ class DebugMenuSubState extends MusicBeatSubState
|
||||||
|
|
||||||
override function create():Void
|
override function create():Void
|
||||||
{
|
{
|
||||||
|
FlxTransitionableState.skipNextTransIn = true;
|
||||||
super.create();
|
super.create();
|
||||||
|
|
||||||
bgColor = 0x00000000;
|
bgColor = 0x00000000;
|
||||||
|
|
||||||
// Create an object for the camera to track.
|
// Create an object for the camera to track.
|
||||||
|
@ -48,9 +50,12 @@ class DebugMenuSubState extends MusicBeatSubState
|
||||||
items.onChange.add(onMenuChange);
|
items.onChange.add(onMenuChange);
|
||||||
add(items);
|
add(items);
|
||||||
|
|
||||||
|
FlxTransitionableState.skipNextTransIn = true;
|
||||||
|
|
||||||
// Create each menu item.
|
// Create each menu item.
|
||||||
// Call onMenuChange when the first item is created to move the camera .
|
// Call onMenuChange when the first item is created to move the camera .
|
||||||
onMenuChange(createItem("CHART EDITOR", openChartEditor));
|
onMenuChange(createItem("CHART EDITOR", openChartEditor));
|
||||||
|
createItem("Input Offset Testing", openInputOffsetTesting);
|
||||||
createItem("ANIMATION EDITOR", openAnimationEditor);
|
createItem("ANIMATION EDITOR", openAnimationEditor);
|
||||||
createItem("STAGE EDITOR", openStageEditor);
|
createItem("STAGE EDITOR", openStageEditor);
|
||||||
createItem("TEST STICKERS", testStickers);
|
createItem("TEST STICKERS", testStickers);
|
||||||
|
@ -92,6 +97,12 @@ class DebugMenuSubState extends MusicBeatSubState
|
||||||
FlxG.switchState(() -> new ChartEditorState());
|
FlxG.switchState(() -> new ChartEditorState());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function openInputOffsetTesting()
|
||||||
|
{
|
||||||
|
openSubState(new funkin.ui.debug.latency.LatencyState());
|
||||||
|
trace('Input Offset Testing');
|
||||||
|
}
|
||||||
|
|
||||||
function openAnimationEditor()
|
function openAnimationEditor()
|
||||||
{
|
{
|
||||||
FlxG.switchState(() -> new funkin.ui.debug.anim.DebugBoundingState());
|
FlxG.switchState(() -> new funkin.ui.debug.anim.DebugBoundingState());
|
||||||
|
|
|
@ -5,13 +5,13 @@ import funkin.modding.events.ScriptEventDispatcher;
|
||||||
import funkin.modding.events.ScriptEvent;
|
import funkin.modding.events.ScriptEvent;
|
||||||
import flixel.util.FlxColor;
|
import flixel.util.FlxColor;
|
||||||
import funkin.ui.MusicBeatState;
|
import funkin.ui.MusicBeatState;
|
||||||
import funkin.data.dialogue.ConversationData;
|
import funkin.data.dialogue.conversation.ConversationData;
|
||||||
import funkin.data.dialogue.ConversationRegistry;
|
import funkin.data.dialogue.conversation.ConversationRegistry;
|
||||||
import funkin.data.dialogue.DialogueBoxData;
|
import funkin.data.dialogue.dialoguebox.DialogueBoxData;
|
||||||
import funkin.data.dialogue.DialogueBoxRegistry;
|
import funkin.data.dialogue.dialoguebox.DialogueBoxRegistry;
|
||||||
import funkin.data.dialogue.SpeakerData;
|
import funkin.data.dialogue.speaker.SpeakerData;
|
||||||
import funkin.data.dialogue.SpeakerRegistry;
|
import funkin.data.dialogue.speaker.SpeakerRegistry;
|
||||||
import funkin.data.freeplay.AlbumRegistry;
|
import funkin.data.freeplay.album.AlbumRegistry;
|
||||||
import funkin.play.cutscene.dialogue.Conversation;
|
import funkin.play.cutscene.dialogue.Conversation;
|
||||||
import funkin.play.cutscene.dialogue.DialogueBox;
|
import funkin.play.cutscene.dialogue.DialogueBox;
|
||||||
import funkin.play.cutscene.dialogue.Speaker;
|
import funkin.play.cutscene.dialogue.Speaker;
|
||||||
|
|
|
@ -7,7 +7,6 @@ import flash.text.TextField;
|
||||||
import flash.text.TextFormatAlign;
|
import flash.text.TextFormatAlign;
|
||||||
import flixel.math.FlxMath;
|
import flixel.math.FlxMath;
|
||||||
import flixel.system.debug.DebuggerUtil;
|
import flixel.system.debug.DebuggerUtil;
|
||||||
import flixel.system.debug.stats.Stats;
|
|
||||||
import flixel.util.FlxColor;
|
import flixel.util.FlxColor;
|
||||||
import flixel.util.FlxDestroyUtil;
|
import flixel.util.FlxDestroyUtil;
|
||||||
|
|
||||||
|
@ -16,13 +15,31 @@ import flixel.util.FlxDestroyUtil;
|
||||||
* SHAMELESSLY STOLEN FROM FLIXEL
|
* SHAMELESSLY STOLEN FROM FLIXEL
|
||||||
* https://github.com/HaxeFlixel/flixel/blob/master/flixel/system/debug/stats/StatsGraph.hx
|
* https://github.com/HaxeFlixel/flixel/blob/master/flixel/system/debug/stats/StatsGraph.hx
|
||||||
*/
|
*/
|
||||||
#if FLX_DEBUG
|
|
||||||
class CoolStatsGraph extends Sprite
|
class CoolStatsGraph extends Sprite
|
||||||
{
|
{
|
||||||
static inline var AXIS_COLOR:FlxColor = 0xffffff;
|
static inline var AXIS_COLOR:FlxColor = 0xffffff;
|
||||||
static inline var AXIS_ALPHA:Float = 0.5;
|
static inline var AXIS_ALPHA:Float = 0.5;
|
||||||
static inline var HISTORY_MAX:Int = 500;
|
static inline var HISTORY_MAX:Int = 500;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* How often to update the stats, in ms. The lower, the more performance-intense!
|
||||||
|
*/
|
||||||
|
static inline var UPDATE_DELAY:Int = 250;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The initial width of the stats window.
|
||||||
|
*/
|
||||||
|
static inline var INITIAL_WIDTH:Int = 160;
|
||||||
|
|
||||||
|
static inline var FPS_COLOR:FlxColor = 0xff96ff00;
|
||||||
|
static inline var MEMORY_COLOR:FlxColor = 0xff009cff;
|
||||||
|
static inline var DRAW_TIME_COLOR:FlxColor = 0xffA60004;
|
||||||
|
static inline var UPDATE_TIME_COLOR:FlxColor = 0xffdcd400;
|
||||||
|
|
||||||
|
public static inline var LABEL_COLOR:FlxColor = 0xaaffffff;
|
||||||
|
public static inline var TEXT_SIZE:Int = 11;
|
||||||
|
public static inline var DECIMALS:Int = 1;
|
||||||
|
|
||||||
public var minLabel:TextField;
|
public var minLabel:TextField;
|
||||||
public var curLabel:TextField;
|
public var curLabel:TextField;
|
||||||
public var maxLabel:TextField;
|
public var maxLabel:TextField;
|
||||||
|
@ -45,6 +62,7 @@ class CoolStatsGraph extends Sprite
|
||||||
public function new(X:Int, Y:Int, Width:Int, Height:Int, GraphColor:FlxColor, Unit:String, LabelWidth:Int = 45, ?Label:String)
|
public function new(X:Int, Y:Int, Width:Int, Height:Int, GraphColor:FlxColor, Unit:String, LabelWidth:Int = 45, ?Label:String)
|
||||||
{
|
{
|
||||||
super();
|
super();
|
||||||
|
|
||||||
x = X;
|
x = X;
|
||||||
y = Y;
|
y = Y;
|
||||||
_width = Width - LabelWidth;
|
_width = Width - LabelWidth;
|
||||||
|
@ -57,11 +75,11 @@ class CoolStatsGraph extends Sprite
|
||||||
_axis = new Shape();
|
_axis = new Shape();
|
||||||
_axis.x = _labelWidth + 10;
|
_axis.x = _labelWidth + 10;
|
||||||
|
|
||||||
maxLabel = DebuggerUtil.createTextField(0, 0, Stats.LABEL_COLOR, Stats.TEXT_SIZE);
|
maxLabel = DebuggerUtil.createTextField(0, 0, LABEL_COLOR, TEXT_SIZE);
|
||||||
curLabel = DebuggerUtil.createTextField(0, (_height / 2) - (Stats.TEXT_SIZE / 2), graphColor, Stats.TEXT_SIZE);
|
curLabel = DebuggerUtil.createTextField(0, (_height / 2) - (TEXT_SIZE / 2), graphColor, TEXT_SIZE);
|
||||||
minLabel = DebuggerUtil.createTextField(0, _height - Stats.TEXT_SIZE, Stats.LABEL_COLOR, Stats.TEXT_SIZE);
|
minLabel = DebuggerUtil.createTextField(0, _height - TEXT_SIZE, LABEL_COLOR, TEXT_SIZE);
|
||||||
|
|
||||||
avgLabel = DebuggerUtil.createTextField(_labelWidth + 20, (_height / 2) - (Stats.TEXT_SIZE / 2) - 10, Stats.LABEL_COLOR, Stats.TEXT_SIZE);
|
avgLabel = DebuggerUtil.createTextField(_labelWidth + 20, (_height / 2) - (TEXT_SIZE / 2) - 10, LABEL_COLOR, TEXT_SIZE);
|
||||||
avgLabel.width = _width;
|
avgLabel.width = _width;
|
||||||
avgLabel.defaultTextFormat.align = TextFormatAlign.CENTER;
|
avgLabel.defaultTextFormat.align = TextFormatAlign.CENTER;
|
||||||
avgLabel.alpha = 0.5;
|
avgLabel.alpha = 0.5;
|
||||||
|
@ -136,7 +154,7 @@ class CoolStatsGraph extends Sprite
|
||||||
|
|
||||||
function formatValue(value:Float):String
|
function formatValue(value:Float):String
|
||||||
{
|
{
|
||||||
return FlxMath.roundDecimal(value, Stats.DECIMALS) + " " + _unit;
|
return FlxMath.roundDecimal(value, DECIMALS) + " " + _unit;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function average():Float
|
public function average():Float
|
||||||
|
@ -157,4 +175,3 @@ class CoolStatsGraph extends Sprite
|
||||||
history = null;
|
history = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#end
|
|
||||||
|
|
|
@ -8,20 +8,27 @@ import flixel.group.FlxGroup.FlxTypedGroup;
|
||||||
import flixel.math.FlxMath;
|
import flixel.math.FlxMath;
|
||||||
import funkin.ui.MusicBeatSubState;
|
import funkin.ui.MusicBeatSubState;
|
||||||
import flixel.sound.FlxSound;
|
import flixel.sound.FlxSound;
|
||||||
import flixel.system.debug.stats.StatsGraph;
|
|
||||||
import flixel.text.FlxText;
|
import flixel.text.FlxText;
|
||||||
import flixel.util.FlxColor;
|
import flixel.util.FlxColor;
|
||||||
import funkin.audio.visualize.PolygonSpectogram;
|
import funkin.audio.visualize.PolygonSpectogram;
|
||||||
import funkin.play.notes.NoteSprite;
|
import funkin.play.notes.NoteSprite;
|
||||||
import funkin.ui.debug.latency.CoolStatsGraph;
|
import funkin.ui.debug.latency.CoolStatsGraph;
|
||||||
import haxe.Timer;
|
|
||||||
import openfl.events.KeyboardEvent;
|
import openfl.events.KeyboardEvent;
|
||||||
|
import funkin.input.PreciseInputManager;
|
||||||
|
import funkin.play.notes.Strumline;
|
||||||
|
import funkin.play.notes.notestyle.NoteStyle;
|
||||||
|
import funkin.data.notestyle.NoteStyleData;
|
||||||
|
import funkin.data.notestyle.NoteStyleRegistry;
|
||||||
|
import funkin.data.song.SongData.SongNoteData;
|
||||||
|
import haxe.Timer;
|
||||||
|
import flixel.FlxCamera;
|
||||||
|
|
||||||
class LatencyState extends MusicBeatSubState
|
class LatencyState extends MusicBeatSubState
|
||||||
{
|
{
|
||||||
|
var visualOffsetText:FlxText;
|
||||||
var offsetText:FlxText;
|
var offsetText:FlxText;
|
||||||
var noteGrp:FlxTypedGroup<NoteSprite>;
|
var noteGrp:Array<SongNoteData> = [];
|
||||||
var strumLine:FlxSprite;
|
var strumLine:Strumline;
|
||||||
|
|
||||||
var blocks:FlxTypedGroup<FlxSprite>;
|
var blocks:FlxTypedGroup<FlxSprite>;
|
||||||
|
|
||||||
|
@ -31,76 +38,81 @@ class LatencyState extends MusicBeatSubState
|
||||||
|
|
||||||
var beatTrail:FlxSprite;
|
var beatTrail:FlxSprite;
|
||||||
var diffGrp:FlxTypedGroup<FlxText>;
|
var diffGrp:FlxTypedGroup<FlxText>;
|
||||||
var offsetsPerBeat:Array<Int> = [];
|
var offsetsPerBeat:Array<Null<Int>> = [];
|
||||||
var swagSong:HomemadeMusic;
|
var swagSong:HomemadeMusic;
|
||||||
|
|
||||||
#if FLX_DEBUG
|
var previousVolume:Float;
|
||||||
var funnyStatsGraph:CoolStatsGraph;
|
|
||||||
var realStats:CoolStatsGraph;
|
var stateCamera:FlxCamera;
|
||||||
#end
|
|
||||||
|
/**
|
||||||
|
* A local conductor instance for this testing class, in-case we are in a PlayState
|
||||||
|
* because I'm too lazy to set the old variables for conductor stuff !
|
||||||
|
*/
|
||||||
|
var localConductor:Conductor;
|
||||||
|
|
||||||
|
// stores values of what the previous persistent draw/update stuff was, example if opened
|
||||||
|
// from pause menu, we want to NOT draw persistently, but then resume drawing once closed
|
||||||
|
var prevPersistentDraw:Bool;
|
||||||
|
var prevPersistentUpdate:Bool;
|
||||||
|
|
||||||
override function create()
|
override function create()
|
||||||
{
|
{
|
||||||
|
super.create();
|
||||||
|
|
||||||
|
prevPersistentDraw = FlxG.state.persistentDraw;
|
||||||
|
prevPersistentUpdate = FlxG.state.persistentUpdate;
|
||||||
|
|
||||||
|
FlxG.state.persistentDraw = false;
|
||||||
|
FlxG.state.persistentUpdate = false;
|
||||||
|
|
||||||
|
localConductor = new Conductor();
|
||||||
|
conductorInUse = localConductor;
|
||||||
|
|
||||||
|
stateCamera = new FlxCamera(0, 0, FlxG.width, FlxG.height);
|
||||||
|
stateCamera.bgColor = FlxColor.BLACK;
|
||||||
|
FlxG.cameras.add(stateCamera);
|
||||||
|
|
||||||
|
var bg:FlxSprite = new FlxSprite().makeGraphic(FlxG.width, FlxG.height, FlxColor.BLACK);
|
||||||
|
add(bg);
|
||||||
|
|
||||||
|
if (FlxG.sound.music != null)
|
||||||
|
{
|
||||||
|
previousVolume = FlxG.sound.music.volume;
|
||||||
|
FlxG.sound.music.volume = 0; // only want to mute the volume, incase we are coming from pause menu
|
||||||
|
}
|
||||||
|
else
|
||||||
|
previousVolume = 1; // defaults to 1 if no music is playing 🤔 also fuck it, emoji in code comment
|
||||||
|
|
||||||
swagSong = new HomemadeMusic();
|
swagSong = new HomemadeMusic();
|
||||||
swagSong.loadEmbedded(Paths.sound('soundTest'), true);
|
swagSong.loadEmbedded(Paths.sound('soundTest'), true);
|
||||||
|
swagSong.looped = true;
|
||||||
|
swagSong.play();
|
||||||
|
FlxG.sound.list.add(swagSong);
|
||||||
|
|
||||||
FlxG.sound.music = swagSong;
|
PreciseInputManager.instance.onInputPressed.add(preciseInputPressed);
|
||||||
FlxG.sound.music.play();
|
|
||||||
|
|
||||||
#if FLX_DEBUG
|
PreciseInputManager.instance.onInputReleased.add(preciseInputReleased);
|
||||||
funnyStatsGraph = new CoolStatsGraph(0, Std.int(FlxG.height / 2), FlxG.width, Std.int(FlxG.height / 2), FlxColor.PINK, "time");
|
|
||||||
FlxG.addChildBelowMouse(funnyStatsGraph);
|
|
||||||
|
|
||||||
realStats = new CoolStatsGraph(0, Std.int(FlxG.height / 2), FlxG.width, Std.int(FlxG.height / 2), FlxColor.YELLOW, "REAL");
|
localConductor.forceBPM(60);
|
||||||
FlxG.addChildBelowMouse(realStats);
|
|
||||||
#end
|
|
||||||
|
|
||||||
FlxG.stage.addEventListener(KeyboardEvent.KEY_DOWN, key -> {
|
|
||||||
trace(key.charCode);
|
|
||||||
|
|
||||||
if (key.charCode == 120) generateBeatStuff();
|
|
||||||
|
|
||||||
trace("\tEVENT PRESS: \t" + FlxG.sound.music.time + " " + Timer.stamp());
|
|
||||||
// trace(FlxG.sound.music.prevTimestamp);
|
|
||||||
trace(FlxG.sound.music.time);
|
|
||||||
trace("\tFR FR PRESS: \t" + swagSong.getTimeWithDiff());
|
|
||||||
|
|
||||||
// trace("\tREDDIT: \t" + swagSong.frfrTime + " " + Timer.stamp());
|
|
||||||
@:privateAccess
|
|
||||||
trace("\tREDDIT: \t" + FlxG.sound.music._channel.position + " " + Timer.stamp());
|
|
||||||
// trace("EVENT LISTENER: " + key);
|
|
||||||
});
|
|
||||||
|
|
||||||
// funnyStatsGraph.hi
|
|
||||||
|
|
||||||
Conductor.instance.forceBPM(60);
|
Conductor.instance.forceBPM(60);
|
||||||
|
|
||||||
noteGrp = new FlxTypedGroup<NoteSprite>();
|
|
||||||
add(noteGrp);
|
|
||||||
|
|
||||||
diffGrp = new FlxTypedGroup<FlxText>();
|
diffGrp = new FlxTypedGroup<FlxText>();
|
||||||
add(diffGrp);
|
add(diffGrp);
|
||||||
|
|
||||||
// var musSpec:PolygonSpectogram = new PolygonSpectogram(FlxG.sound.music, FlxColor.RED, FlxG.height, Math.floor(FlxG.height / 2));
|
for (beat in 0...Math.floor(swagSong.length / (localConductor.stepLengthMs * 2)))
|
||||||
// musSpec.x += 170;
|
|
||||||
// musSpec.scrollFactor.set();
|
|
||||||
// musSpec.waveAmplitude = 100;
|
|
||||||
// musSpec.realtimeVisLenght = 0.45;
|
|
||||||
// // musSpec.visType = FREQUENCIES;
|
|
||||||
// add(musSpec);
|
|
||||||
|
|
||||||
for (beat in 0...Math.floor(FlxG.sound.music.length / Conductor.instance.beatLengthMs))
|
|
||||||
{
|
{
|
||||||
var beatTick:FlxSprite = new FlxSprite(songPosToX(beat * Conductor.instance.beatLengthMs), FlxG.height - 15);
|
var beatTick:FlxSprite = new FlxSprite(songPosToX(beat * (localConductor.stepLengthMs * 2)), FlxG.height - 15);
|
||||||
beatTick.makeGraphic(2, 15);
|
beatTick.makeGraphic(2, 15);
|
||||||
beatTick.alpha = 0.3;
|
beatTick.alpha = 0.3;
|
||||||
add(beatTick);
|
add(beatTick);
|
||||||
|
|
||||||
var offsetTxt:FlxText = new FlxText(songPosToX(beat * Conductor.instance.beatLengthMs), FlxG.height - 26, 0, "swag");
|
var offsetTxt:FlxText = new FlxText(songPosToX(beat * (localConductor.stepLengthMs * 2)), FlxG.height - 26, 0, "");
|
||||||
offsetTxt.alpha = 0.5;
|
offsetTxt.alpha = 0.5;
|
||||||
diffGrp.add(offsetTxt);
|
diffGrp.add(offsetTxt);
|
||||||
|
|
||||||
offsetsPerBeat.push(0);
|
offsetsPerBeat.push(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
songVisFollowAudio = new FlxSprite(0, FlxG.height - 20).makeGraphic(2, 20, FlxColor.YELLOW);
|
songVisFollowAudio = new FlxSprite(0, FlxG.height - 20).makeGraphic(2, 20, FlxColor.YELLOW);
|
||||||
|
@ -121,32 +133,92 @@ class LatencyState extends MusicBeatSubState
|
||||||
|
|
||||||
for (i in 0...8)
|
for (i in 0...8)
|
||||||
{
|
{
|
||||||
var block = new FlxSprite(2, 50 * i).makeGraphic(48, 48);
|
var block = new FlxSprite(2, ((FlxG.height / 8) + 2) * i).makeGraphic(Std.int(FlxG.height / 8), Std.int((FlxG.height / 8) - 4));
|
||||||
block.alpha = 0;
|
block.alpha = 0.1;
|
||||||
blocks.add(block);
|
blocks.add(block);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i in 0...32)
|
var strumlineBG:FlxSprite = new FlxSprite();
|
||||||
{
|
add(strumlineBG);
|
||||||
var note:NoteSprite = new NoteSprite(NoteStyleRegistry.instance.fetchDefault());
|
|
||||||
noteGrp.add(note);
|
|
||||||
}
|
|
||||||
|
|
||||||
offsetText = new FlxText();
|
strumLine = new Strumline(NoteStyleRegistry.instance.fetchDefault(), true);
|
||||||
offsetText.screenCenter();
|
strumLine.conductorInUse = localConductor;
|
||||||
add(offsetText);
|
strumLine.screenCenter();
|
||||||
|
|
||||||
strumLine = new FlxSprite(FlxG.width / 2, 100).makeGraphic(FlxG.width, 5);
|
|
||||||
add(strumLine);
|
add(strumLine);
|
||||||
|
|
||||||
super.create();
|
strumlineBG.x = strumLine.x;
|
||||||
|
strumlineBG.makeGraphic(Std.int(strumLine.width), FlxG.height, 0xFFFFFFFF);
|
||||||
|
strumlineBG.alpha = 0.1;
|
||||||
|
|
||||||
|
visualOffsetText = new FlxText();
|
||||||
|
visualOffsetText.setFormat(Paths.font("vcr.ttf"), 20);
|
||||||
|
visualOffsetText.x = (FlxG.height / 8) + 10;
|
||||||
|
visualOffsetText.y = 10;
|
||||||
|
visualOffsetText.fieldWidth = strumLine.x - visualOffsetText.x - 10;
|
||||||
|
add(visualOffsetText);
|
||||||
|
|
||||||
|
offsetText = new FlxText();
|
||||||
|
offsetText.setFormat(Paths.font("vcr.ttf"), 20);
|
||||||
|
offsetText.x = strumLine.x + strumLine.width + 10;
|
||||||
|
offsetText.y = 10;
|
||||||
|
offsetText.fieldWidth = FlxG.width - offsetText.x - 10;
|
||||||
|
add(offsetText);
|
||||||
|
|
||||||
|
var helpText:FlxText = new FlxText();
|
||||||
|
helpText.setFormat(Paths.font("vcr.ttf"), 20);
|
||||||
|
helpText.text = "Press BACK to return to main menu";
|
||||||
|
helpText.x = FlxG.width - helpText.width;
|
||||||
|
helpText.y = FlxG.height - (helpText.height * 2) - 2;
|
||||||
|
add(helpText);
|
||||||
|
|
||||||
|
regenNoteData();
|
||||||
|
}
|
||||||
|
|
||||||
|
function preciseInputPressed(event:PreciseInputEvent)
|
||||||
|
{
|
||||||
|
generateBeatStuff(event);
|
||||||
|
strumLine.pressKey(event.noteDirection);
|
||||||
|
strumLine.playPress(event.noteDirection);
|
||||||
|
}
|
||||||
|
|
||||||
|
function preciseInputReleased(event:PreciseInputEvent)
|
||||||
|
{
|
||||||
|
strumLine.playStatic(event.noteDirection);
|
||||||
|
strumLine.releaseKey(event.noteDirection);
|
||||||
|
}
|
||||||
|
|
||||||
|
override public function close():Void
|
||||||
|
{
|
||||||
|
PreciseInputManager.instance.onInputPressed.remove(preciseInputPressed);
|
||||||
|
PreciseInputManager.instance.onInputReleased.remove(preciseInputReleased);
|
||||||
|
|
||||||
|
FlxG.sound.music.volume = previousVolume;
|
||||||
|
swagSong.stop();
|
||||||
|
FlxG.sound.list.remove(swagSong);
|
||||||
|
|
||||||
|
FlxG.cameras.remove(stateCamera);
|
||||||
|
|
||||||
|
FlxG.state.persistentDraw = prevPersistentDraw;
|
||||||
|
FlxG.state.persistentUpdate = prevPersistentUpdate;
|
||||||
|
super.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
function regenNoteData()
|
||||||
|
{
|
||||||
|
for (i in 0...32)
|
||||||
|
{
|
||||||
|
var note:SongNoteData = new SongNoteData((localConductor.stepLengthMs * 2) * i, 1);
|
||||||
|
noteGrp.push(note);
|
||||||
|
}
|
||||||
|
|
||||||
|
strumLine.applyNoteData(noteGrp);
|
||||||
}
|
}
|
||||||
|
|
||||||
override function stepHit():Bool
|
override function stepHit():Bool
|
||||||
{
|
{
|
||||||
if (Conductor.instance.currentStep % 4 == 2)
|
if (localConductor.currentStep % 4 == 2)
|
||||||
{
|
{
|
||||||
blocks.members[((Conductor.instance.currentBeat % 8) + 1) % 8].alpha = 0.5;
|
blocks.members[((localConductor.currentBeat % 8) + 1) % 8].alpha = 0.5;
|
||||||
}
|
}
|
||||||
|
|
||||||
return super.stepHit();
|
return super.stepHit();
|
||||||
|
@ -154,11 +226,11 @@ class LatencyState extends MusicBeatSubState
|
||||||
|
|
||||||
override function beatHit():Bool
|
override function beatHit():Bool
|
||||||
{
|
{
|
||||||
if (Conductor.instance.currentBeat % 8 == 0) blocks.forEach(blok -> {
|
if (localConductor.currentBeat % 8 == 0) blocks.forEach(blok -> {
|
||||||
blok.alpha = 0;
|
blok.alpha = 0.1;
|
||||||
});
|
});
|
||||||
|
|
||||||
blocks.members[Conductor.instance.currentBeat % 8].alpha = 1;
|
blocks.members[localConductor.currentBeat % 8].alpha = 1;
|
||||||
// block.visible = !block.visible;
|
// block.visible = !block.visible;
|
||||||
|
|
||||||
return super.beatHit();
|
return super.beatHit();
|
||||||
|
@ -171,117 +243,114 @@ class LatencyState extends MusicBeatSubState
|
||||||
trace(FlxG.sound.music._channel.position);
|
trace(FlxG.sound.music._channel.position);
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// localConductor.update(swagSong.time, false);
|
localConductor.update(swagSong.time, false);
|
||||||
|
|
||||||
if (FlxG.keys.justPressed.S)
|
// localConductor.songPosition += (Timer.stamp() * 1000) - FlxG.sound.music.prevTimestamp;
|
||||||
{
|
|
||||||
trace("\tUPDATE PRESS: \t" + FlxG.sound.music.time + " " + Timer.stamp());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (FlxG.keys.justPressed.SPACE)
|
songPosVis.x = songPosToX(localConductor.songPosition);
|
||||||
{
|
songVisFollowAudio.x = songPosToX(localConductor.songPosition - localConductor.audioVisualOffset);
|
||||||
if (FlxG.sound.music.playing) FlxG.sound.music.pause();
|
songVisFollowVideo.x = songPosToX(localConductor.songPosition - localConductor.inputOffset);
|
||||||
else
|
|
||||||
FlxG.sound.music.resume();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (FlxG.keys.pressed.D) FlxG.sound.music.time += 1000 * FlxG.elapsed;
|
visualOffsetText.text = "Visual Offset: " + localConductor.audioVisualOffset + "ms";
|
||||||
|
visualOffsetText.text += "\n\nYou can press SPACE+Left/Right to change this value.";
|
||||||
|
visualOffsetText.text += "\n\nYou can hold SHIFT to step 1ms at a time";
|
||||||
|
|
||||||
Conductor.instance.update(swagSong.getTimeWithDiff() - Conductor.instance.inputOffset);
|
offsetText.text = "INPUT Offset (Left/Right to change): " + localConductor.inputOffset + "ms";
|
||||||
// Conductor.instance.songPosition += (Timer.stamp() * 1000) - FlxG.sound.music.prevTimestamp;
|
offsetText.text += "\n\nYou can hold SHIFT to step 1ms at a time";
|
||||||
|
|
||||||
songPosVis.x = songPosToX(Conductor.instance.songPosition);
|
|
||||||
songVisFollowAudio.x = songPosToX(Conductor.instance.songPosition - Conductor.instance.instrumentalOffset);
|
|
||||||
songVisFollowVideo.x = songPosToX(Conductor.instance.songPosition - Conductor.instance.inputOffset);
|
|
||||||
|
|
||||||
offsetText.text = "INST Offset: " + Conductor.instance.instrumentalOffset + "ms";
|
|
||||||
offsetText.text += "\nINPUT Offset: " + Conductor.instance.inputOffset + "ms";
|
|
||||||
offsetText.text += "\ncurrentStep: " + Conductor.instance.currentStep;
|
|
||||||
offsetText.text += "\ncurrentBeat: " + Conductor.instance.currentBeat;
|
|
||||||
|
|
||||||
var avgOffsetInput:Float = 0;
|
var avgOffsetInput:Float = 0;
|
||||||
|
|
||||||
|
var loopInd:Int = 0;
|
||||||
for (offsetThing in offsetsPerBeat)
|
for (offsetThing in offsetsPerBeat)
|
||||||
|
{
|
||||||
|
if (offsetThing == null) continue;
|
||||||
avgOffsetInput += offsetThing;
|
avgOffsetInput += offsetThing;
|
||||||
|
loopInd++;
|
||||||
|
}
|
||||||
|
|
||||||
avgOffsetInput /= offsetsPerBeat.length;
|
avgOffsetInput /= loopInd;
|
||||||
|
|
||||||
offsetText.text += "\naverage input offset needed: " + avgOffsetInput;
|
offsetText.text += "\n\nEstimated average input offset needed: " + avgOffsetInput;
|
||||||
|
|
||||||
var multiply:Float = 10;
|
var multiply:Int = 10;
|
||||||
|
|
||||||
if (FlxG.keys.pressed.SHIFT) multiply = 1;
|
if (FlxG.keys.pressed.SHIFT) multiply = 1;
|
||||||
|
|
||||||
if (FlxG.keys.pressed.CONTROL)
|
if (FlxG.keys.pressed.CONTROL || FlxG.keys.pressed.SPACE)
|
||||||
{
|
{
|
||||||
if (FlxG.keys.justPressed.RIGHT)
|
if (FlxG.keys.justPressed.RIGHT)
|
||||||
{
|
{
|
||||||
Conductor.instance.instrumentalOffset += 1.0 * multiply;
|
localConductor.audioVisualOffset += 1 * multiply;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (FlxG.keys.justPressed.LEFT)
|
if (FlxG.keys.justPressed.LEFT)
|
||||||
{
|
{
|
||||||
Conductor.instance.instrumentalOffset -= 1.0 * multiply;
|
localConductor.audioVisualOffset -= 1 * multiply;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (FlxG.keys.justPressed.RIGHT)
|
if (FlxG.keys.anyJustPressed([LEFT, RIGHT]))
|
||||||
{
|
{
|
||||||
Conductor.instance.inputOffset += 1.0 * multiply;
|
if (FlxG.keys.justPressed.RIGHT)
|
||||||
}
|
{
|
||||||
|
localConductor.inputOffset += 1 * multiply;
|
||||||
|
}
|
||||||
|
|
||||||
if (FlxG.keys.justPressed.LEFT)
|
if (FlxG.keys.justPressed.LEFT)
|
||||||
{
|
{
|
||||||
Conductor.instance.inputOffset -= 1.0 * multiply;
|
localConductor.inputOffset -= 1 * multiply;
|
||||||
|
}
|
||||||
|
|
||||||
|
// reset the average, so you don't need to wait a full loop to start getting averages
|
||||||
|
// also reset each text member
|
||||||
|
offsetsPerBeat = [];
|
||||||
|
diffGrp.forEach(memb -> memb.text = "");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
noteGrp.forEach(function(daNote:NoteSprite) {
|
if (controls.BACK)
|
||||||
daNote.y = (strumLine.y - ((Conductor.instance.songPosition - Conductor.instance.instrumentalOffset) - daNote.noteData.time) * 0.45);
|
{
|
||||||
daNote.x = strumLine.x + 30;
|
close();
|
||||||
|
}
|
||||||
if (daNote.y < strumLine.y) daNote.alpha = 0.5;
|
|
||||||
|
|
||||||
if (daNote.y < 0 - daNote.height)
|
|
||||||
{
|
|
||||||
daNote.alpha = 1;
|
|
||||||
// daNote.data.strumTime += Conductor.instance.beatLengthMs * 8;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
super.update(elapsed);
|
super.update(elapsed);
|
||||||
}
|
}
|
||||||
|
|
||||||
function generateBeatStuff()
|
function generateBeatStuff(event:PreciseInputEvent)
|
||||||
{
|
{
|
||||||
Conductor.instance.update(swagSong.getTimeWithDiff());
|
// localConductor.update(swagSong.getTimeWithDiff());
|
||||||
|
|
||||||
var closestBeat:Int = Math.round(Conductor.instance.songPosition / Conductor.instance.beatLengthMs) % diffGrp.members.length;
|
var inputLatencyMs:Float = haxe.Int64.toInt(PreciseInputManager.getCurrentTimestamp() - event.timestamp) / 1000.0 / 1000.0;
|
||||||
var getDiff:Float = Conductor.instance.songPosition - (closestBeat * Conductor.instance.beatLengthMs);
|
// trace("input latency: " + inputLatencyMs + "ms");
|
||||||
getDiff -= Conductor.instance.inputOffset;
|
// trace("cur timestamp: " + PreciseInputManager.getCurrentTimestamp() + "ns");
|
||||||
|
// trace("event timestamp: " + event.timestamp + "ns");
|
||||||
|
// trace("songtime: " + localConductor.getTimeWithDiff(swagSong) + "ms");
|
||||||
|
|
||||||
|
var closestBeat:Int = Math.round(localConductor.getTimeWithDiff(swagSong) / (localConductor.stepLengthMs * 2)) % diffGrp.members.length;
|
||||||
|
var getDiff:Float = localConductor.getTimeWithDiff(swagSong) - (closestBeat * (localConductor.stepLengthMs * 2));
|
||||||
|
// getDiff -= localConductor.inputOffset;
|
||||||
|
getDiff -= inputLatencyMs;
|
||||||
|
getDiff -= localConductor.audioVisualOffset;
|
||||||
|
|
||||||
// lil fix for end of song
|
// lil fix for end of song
|
||||||
if (closestBeat == 0 && getDiff >= Conductor.instance.beatLengthMs * 2) getDiff -= FlxG.sound.music.length;
|
if (closestBeat == 0 && getDiff >= localConductor.stepLengthMs * 2) getDiff -= swagSong.length;
|
||||||
|
|
||||||
trace("\tDISTANCE TO CLOSEST BEAT: " + getDiff + "ms");
|
|
||||||
trace("\tCLOSEST BEAT: " + closestBeat);
|
|
||||||
beatTrail.x = songPosVis.x;
|
beatTrail.x = songPosVis.x;
|
||||||
|
|
||||||
diffGrp.members[closestBeat].text = getDiff + "ms";
|
diffGrp.members[closestBeat].text = getDiff + "ms";
|
||||||
offsetsPerBeat[closestBeat] = Std.int(getDiff);
|
offsetsPerBeat[closestBeat] = Math.round(getDiff);
|
||||||
}
|
}
|
||||||
|
|
||||||
function songPosToX(pos:Float):Float
|
function songPosToX(pos:Float):Float
|
||||||
{
|
{
|
||||||
return FlxMath.remapToRange(pos, 0, FlxG.sound.music.length, 0, FlxG.width);
|
return FlxMath.remapToRange(pos, 0, swagSong.length, 0, FlxG.width);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class HomemadeMusic extends FlxSound
|
class HomemadeMusic extends FlxSound
|
||||||
{
|
{
|
||||||
public var prevTimestamp:Int = 0;
|
public var prevTimestamp:Int = 0;
|
||||||
public var timeWithDiff:Float = 0;
|
|
||||||
|
|
||||||
public function new()
|
public function new()
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
package funkin.ui.freeplay;
|
package funkin.ui.freeplay;
|
||||||
|
|
||||||
import funkin.data.freeplay.AlbumData;
|
import funkin.data.freeplay.album.AlbumData;
|
||||||
|
import funkin.data.freeplay.album.AlbumRegistry;
|
||||||
import funkin.data.animation.AnimationData;
|
import funkin.data.animation.AnimationData;
|
||||||
import funkin.data.freeplay.AlbumRegistry;
|
|
||||||
import funkin.data.IRegistryEntry;
|
import funkin.data.IRegistryEntry;
|
||||||
import flixel.graphics.FlxGraphic;
|
import flixel.graphics.FlxGraphic;
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@ import flixel.util.FlxSort;
|
||||||
import flixel.tweens.FlxTween;
|
import flixel.tweens.FlxTween;
|
||||||
import flixel.util.FlxTimer;
|
import flixel.util.FlxTimer;
|
||||||
import flixel.tweens.FlxEase;
|
import flixel.tweens.FlxEase;
|
||||||
import funkin.data.freeplay.AlbumRegistry;
|
import funkin.data.freeplay.album.AlbumRegistry;
|
||||||
import funkin.util.assets.FlxAnimationUtil;
|
import funkin.util.assets.FlxAnimationUtil;
|
||||||
import funkin.graphics.FunkinSprite;
|
import funkin.graphics.FunkinSprite;
|
||||||
import funkin.util.SortUtil;
|
import funkin.util.SortUtil;
|
||||||
|
|
|
@ -18,7 +18,7 @@ import flixel.util.FlxColor;
|
||||||
import flixel.util.FlxSpriteUtil;
|
import flixel.util.FlxSpriteUtil;
|
||||||
import flixel.util.FlxTimer;
|
import flixel.util.FlxTimer;
|
||||||
import funkin.audio.FunkinSound;
|
import funkin.audio.FunkinSound;
|
||||||
import funkin.data.level.LevelRegistry;
|
import funkin.data.story.level.LevelRegistry;
|
||||||
import funkin.data.song.SongRegistry;
|
import funkin.data.song.SongRegistry;
|
||||||
import funkin.graphics.FunkinCamera;
|
import funkin.graphics.FunkinCamera;
|
||||||
import funkin.graphics.FunkinSprite;
|
import funkin.graphics.FunkinSprite;
|
||||||
|
|
|
@ -20,6 +20,7 @@ class FunkinSoundTray extends FlxSoundTray
|
||||||
{
|
{
|
||||||
var graphicScale:Float = 0.30;
|
var graphicScale:Float = 0.30;
|
||||||
var lerpYPos:Float = 0;
|
var lerpYPos:Float = 0;
|
||||||
|
var alphaTarget:Float = 0;
|
||||||
|
|
||||||
var volumeMaxSound:String;
|
var volumeMaxSound:String;
|
||||||
|
|
||||||
|
@ -40,7 +41,7 @@ class FunkinSoundTray extends FlxSoundTray
|
||||||
|
|
||||||
// makes an alpha'd version of all the bars (bar_10.png)
|
// makes an alpha'd version of all the bars (bar_10.png)
|
||||||
var backingBar:Bitmap = new Bitmap(Assets.getBitmapData(Paths.image("soundtray/bars_10")));
|
var backingBar:Bitmap = new Bitmap(Assets.getBitmapData(Paths.image("soundtray/bars_10")));
|
||||||
backingBar.x = 10;
|
backingBar.x = 9;
|
||||||
backingBar.y = 5;
|
backingBar.y = 5;
|
||||||
backingBar.scaleX = graphicScale;
|
backingBar.scaleX = graphicScale;
|
||||||
backingBar.scaleY = graphicScale;
|
backingBar.scaleY = graphicScale;
|
||||||
|
@ -56,7 +57,7 @@ class FunkinSoundTray extends FlxSoundTray
|
||||||
for (i in 1...11)
|
for (i in 1...11)
|
||||||
{
|
{
|
||||||
var bar:Bitmap = new Bitmap(Assets.getBitmapData(Paths.image("soundtray/bars_" + i)));
|
var bar:Bitmap = new Bitmap(Assets.getBitmapData(Paths.image("soundtray/bars_" + i)));
|
||||||
bar.x = 10;
|
bar.x = 9;
|
||||||
bar.y = 5;
|
bar.y = 5;
|
||||||
bar.scaleX = graphicScale;
|
bar.scaleX = graphicScale;
|
||||||
bar.scaleY = graphicScale;
|
bar.scaleY = graphicScale;
|
||||||
|
@ -77,15 +78,18 @@ class FunkinSoundTray extends FlxSoundTray
|
||||||
override public function update(MS:Float):Void
|
override public function update(MS:Float):Void
|
||||||
{
|
{
|
||||||
y = MathUtil.coolLerp(y, lerpYPos, 0.1);
|
y = MathUtil.coolLerp(y, lerpYPos, 0.1);
|
||||||
|
alpha = MathUtil.coolLerp(alpha, alphaTarget, 0.25);
|
||||||
|
|
||||||
// Animate sound tray thing
|
// Animate sound tray thing
|
||||||
if (_timer > 0)
|
if (_timer > 0)
|
||||||
{
|
{
|
||||||
_timer -= (MS / 1000);
|
_timer -= (MS / 1000);
|
||||||
|
alphaTarget = 1;
|
||||||
}
|
}
|
||||||
else if (y > -height)
|
else if (y > -height)
|
||||||
{
|
{
|
||||||
lerpYPos = -height - 10;
|
lerpYPos = -height - 10;
|
||||||
|
alphaTarget = 0;
|
||||||
|
|
||||||
if (y <= -height)
|
if (y <= -height)
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package funkin.ui.options;
|
package funkin.ui.options;
|
||||||
|
|
||||||
|
import funkin.ui.debug.latency.LatencyState;
|
||||||
import flixel.FlxSprite;
|
import flixel.FlxSprite;
|
||||||
import flixel.FlxSubState;
|
import flixel.FlxSubState;
|
||||||
import flixel.addons.transition.FlxTransitionableState;
|
import flixel.addons.transition.FlxTransitionableState;
|
||||||
|
@ -190,6 +191,9 @@ class OptionsMenu extends Page
|
||||||
add(items = new TextMenuList());
|
add(items = new TextMenuList());
|
||||||
createItem("PREFERENCES", function() switchPage(Preferences));
|
createItem("PREFERENCES", function() switchPage(Preferences));
|
||||||
createItem("CONTROLS", function() switchPage(Controls));
|
createItem("CONTROLS", function() switchPage(Controls));
|
||||||
|
createItem("INPUT OFFSETS", function() {
|
||||||
|
FlxG.state.openSubState(new LatencyState());
|
||||||
|
});
|
||||||
|
|
||||||
#if newgrounds
|
#if newgrounds
|
||||||
if (NGio.isLoggedIn) createItem("LOGOUT", selectLogout);
|
if (NGio.isLoggedIn) createItem("LOGOUT", selectLogout);
|
||||||
|
|
|
@ -6,8 +6,8 @@ import flixel.util.FlxColor;
|
||||||
import funkin.play.song.Song;
|
import funkin.play.song.Song;
|
||||||
import funkin.data.IRegistryEntry;
|
import funkin.data.IRegistryEntry;
|
||||||
import funkin.data.song.SongRegistry;
|
import funkin.data.song.SongRegistry;
|
||||||
import funkin.data.level.LevelRegistry;
|
import funkin.data.story.level.LevelRegistry;
|
||||||
import funkin.data.level.LevelData;
|
import funkin.data.story.level.LevelData;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An object used to retrieve data about a story mode level (also known as "weeks").
|
* An object used to retrieve data about a story mode level (also known as "weeks").
|
||||||
|
|
|
@ -2,7 +2,7 @@ package funkin.ui.story;
|
||||||
|
|
||||||
import funkin.play.stage.Bopper;
|
import funkin.play.stage.Bopper;
|
||||||
import funkin.util.assets.FlxAnimationUtil;
|
import funkin.util.assets.FlxAnimationUtil;
|
||||||
import funkin.data.level.LevelData;
|
import funkin.data.story.level.LevelData;
|
||||||
|
|
||||||
class LevelProp extends Bopper
|
class LevelProp extends Bopper
|
||||||
{
|
{
|
||||||
|
|
|
@ -9,7 +9,7 @@ import flixel.tweens.FlxTween;
|
||||||
import flixel.util.FlxColor;
|
import flixel.util.FlxColor;
|
||||||
import flixel.util.FlxTimer;
|
import flixel.util.FlxTimer;
|
||||||
import funkin.audio.FunkinSound;
|
import funkin.audio.FunkinSound;
|
||||||
import funkin.data.level.LevelRegistry;
|
import funkin.data.story.level.LevelRegistry;
|
||||||
import funkin.data.song.SongRegistry;
|
import funkin.data.song.SongRegistry;
|
||||||
import funkin.graphics.FunkinSprite;
|
import funkin.graphics.FunkinSprite;
|
||||||
import funkin.modding.events.ScriptEvent;
|
import funkin.modding.events.ScriptEvent;
|
||||||
|
|
|
@ -295,6 +295,8 @@ class Constants
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constant for the number of seconds in a minute.
|
* Constant for the number of seconds in a minute.
|
||||||
|
*
|
||||||
|
* sex per min
|
||||||
*/
|
*/
|
||||||
public static final SECS_PER_MIN:Int = 60;
|
public static final SECS_PER_MIN:Int = 60;
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
package funkin.data.level;
|
package funkin.data.story.level;
|
||||||
|
|
||||||
import funkin.data.level.LevelRegistry;
|
import funkin.data.story.level.LevelRegistry;
|
||||||
import funkin.ui.story.Level;
|
import funkin.ui.story.Level;
|
||||||
import massive.munit.Assert;
|
import massive.munit.Assert;
|
||||||
import massive.munit.async.AsyncFactory;
|
import massive.munit.async.AsyncFactory;
|
||||||
|
@ -8,7 +8,7 @@ import massive.munit.util.Timer;
|
||||||
|
|
||||||
@:nullSafety
|
@:nullSafety
|
||||||
@:access(funkin.ui.story.Level)
|
@:access(funkin.ui.story.Level)
|
||||||
@:access(funkin.data.level.LevelRegistry)
|
@:access(funkin.data.story.level.LevelRegistry)
|
||||||
class LevelRegistryTest extends FunkinTest
|
class LevelRegistryTest extends FunkinTest
|
||||||
{
|
{
|
||||||
public function new()
|
public function new()
|
||||||
|
|
Loading…
Reference in a new issue