mirror of
https://github.com/ninjamuffin99/Funkin.git
synced 2024-12-12 08:25:13 +00:00
Merge pull request #347 from FunkinCrew/feature/blazin-cutscene
Blazin' Cutscene
This commit is contained in:
commit
b88d0b063b
8
.prettierignore
Normal file
8
.prettierignore
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
# Ignore artifacts
|
||||||
|
export
|
||||||
|
|
||||||
|
# Ignore all asset files (including FlxAnimate JSONs)
|
||||||
|
assets
|
||||||
|
|
||||||
|
# Don't ignore data files
|
||||||
|
!assets/preload/data
|
26
.vscode/settings.json
vendored
26
.vscode/settings.json
vendored
|
@ -93,7 +93,7 @@
|
||||||
{
|
{
|
||||||
"label": "Windows / Debug",
|
"label": "Windows / Debug",
|
||||||
"target": "windows",
|
"target": "windows",
|
||||||
"args": ["-debug"]
|
"args": ["-debug", "-DFORCE_DEBUG_VERSION"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"label": "HashLink / Debug",
|
"label": "HashLink / Debug",
|
||||||
|
@ -103,7 +103,7 @@
|
||||||
{
|
{
|
||||||
"label": "Windows / Debug (FlxAnimate Test)",
|
"label": "Windows / Debug (FlxAnimate Test)",
|
||||||
"target": "windows",
|
"target": "windows",
|
||||||
"args": ["-debug", "-DANIMATE"]
|
"args": ["-debug", "-DANIMATE", "-DFORCE_DEBUG_VERSION"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"label": "HashLink / Debug (FlxAnimate Test)",
|
"label": "HashLink / Debug (FlxAnimate Test)",
|
||||||
|
@ -113,7 +113,7 @@
|
||||||
{
|
{
|
||||||
"label": "Windows / Debug (Straight to Freeplay)",
|
"label": "Windows / Debug (Straight to Freeplay)",
|
||||||
"target": "windows",
|
"target": "windows",
|
||||||
"args": ["-debug", "-DFREEPLAY"]
|
"args": ["-debug", "-DFREEPLAY", "-DFORCE_DEBUG_VERSION"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"label": "HashLink / Debug (Straight to Freeplay)",
|
"label": "HashLink / Debug (Straight to Freeplay)",
|
||||||
|
@ -123,7 +123,11 @@
|
||||||
{
|
{
|
||||||
"label": "Windows / Debug (Straight to Play - Bopeebo Normal)",
|
"label": "Windows / Debug (Straight to Play - Bopeebo Normal)",
|
||||||
"target": "windows",
|
"target": "windows",
|
||||||
"args": ["-debug", "-DSONG=bopeebo -DDIFFICULTY=normal"]
|
"args": [
|
||||||
|
"-debug",
|
||||||
|
"-DSONG=bopeebo -DDIFFICULTY=normal",
|
||||||
|
"-DFORCE_DEBUG_VERSION"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"label": "HashLink / Debug (Straight to Play - Bopeebo Normal)",
|
"label": "HashLink / Debug (Straight to Play - Bopeebo Normal)",
|
||||||
|
@ -133,7 +137,7 @@
|
||||||
{
|
{
|
||||||
"label": "Windows / Debug (Conversation Test)",
|
"label": "Windows / Debug (Conversation Test)",
|
||||||
"target": "windows",
|
"target": "windows",
|
||||||
"args": ["-debug", "-DDIALOGUE"]
|
"args": ["-debug", "-DDIALOGUE", "-DFORCE_DEBUG_VERSION"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"label": "HashLink / Debug (Conversation Test)",
|
"label": "HashLink / Debug (Conversation Test)",
|
||||||
|
@ -143,7 +147,7 @@
|
||||||
{
|
{
|
||||||
"label": "Windows / Debug (Straight to Chart Editor)",
|
"label": "Windows / Debug (Straight to Chart Editor)",
|
||||||
"target": "windows",
|
"target": "windows",
|
||||||
"args": ["-debug", "-DCHARTING"]
|
"args": ["-debug", "-DCHARTING", "-DFORCE_DEBUG_VERSION"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"label": "HashLink / Debug (Straight to Chart Editor)",
|
"label": "HashLink / Debug (Straight to Chart Editor)",
|
||||||
|
@ -153,7 +157,7 @@
|
||||||
{
|
{
|
||||||
"label": "Windows / Debug (Straight to Animation Editor)",
|
"label": "Windows / Debug (Straight to Animation Editor)",
|
||||||
"target": "windows",
|
"target": "windows",
|
||||||
"args": ["-debug", "-DANIMDEBUG"]
|
"args": ["-debug", "-DANIMDEBUG", "-DFORCE_DEBUG_VERSION"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"label": "HashLink / Debug (Straight to Animation Editor)",
|
"label": "HashLink / Debug (Straight to Animation Editor)",
|
||||||
|
@ -163,7 +167,7 @@
|
||||||
{
|
{
|
||||||
"label": "Windows / Debug (Latency Test)",
|
"label": "Windows / Debug (Latency Test)",
|
||||||
"target": "windows",
|
"target": "windows",
|
||||||
"args": ["-debug", "-DLATENCY"]
|
"args": ["-debug", "-DLATENCY", "-DFORCE_DEBUG_VERSION"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"label": "HashLink / Debug (Latency Test)",
|
"label": "HashLink / Debug (Latency Test)",
|
||||||
|
@ -173,7 +177,7 @@
|
||||||
{
|
{
|
||||||
"label": "Windows / Debug (Waveform Test)",
|
"label": "Windows / Debug (Waveform Test)",
|
||||||
"target": "windows",
|
"target": "windows",
|
||||||
"args": ["-debug", "-DWAVEFORM"]
|
"args": ["-debug", "-DWAVEFORM", "-DFORCE_DEBUG_VERSION"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"label": "HashLink / Debug (Waveform Test)",
|
"label": "HashLink / Debug (Waveform Test)",
|
||||||
|
@ -183,12 +187,12 @@
|
||||||
{
|
{
|
||||||
"label": "HTML5 / Debug",
|
"label": "HTML5 / Debug",
|
||||||
"target": "html5",
|
"target": "html5",
|
||||||
"args": ["-debug"]
|
"args": ["-debug", "-DFORCE_DEBUG_VERSION"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"label": "HTML5 / Debug (Watch)",
|
"label": "HTML5 / Debug (Watch)",
|
||||||
"target": "html5",
|
"target": "html5",
|
||||||
"args": ["-debug", "-watch"]
|
"args": ["-debug", "-watch", "-DFORCE_DEBUG_VERSION"]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"cmake.configureOnOpen": false,
|
"cmake.configureOnOpen": false,
|
||||||
|
|
|
@ -108,7 +108,7 @@
|
||||||
<haxelib name="flixel-text-input" /> <!-- Improved text field rendering for HaxeUI -->
|
<haxelib name="flixel-text-input" /> <!-- Improved text field rendering for HaxeUI -->
|
||||||
<haxelib name="polymod" /> <!-- Modding framework -->
|
<haxelib name="polymod" /> <!-- Modding framework -->
|
||||||
<haxelib name="flxanimate" /> <!-- Texture atlas rendering -->
|
<haxelib name="flxanimate" /> <!-- Texture atlas rendering -->
|
||||||
<haxelib name="hxCodec" if="desktop release" /> <!-- Video playback -->
|
<haxelib name="hxCodec" if="desktop" /> <!-- Video playback -->
|
||||||
|
|
||||||
<haxelib name="json2object" /> <!-- JSON parsing -->
|
<haxelib name="json2object" /> <!-- JSON parsing -->
|
||||||
<haxelib name="thx.semver" /> <!-- Version string handling -->
|
<haxelib name="thx.semver" /> <!-- Version string handling -->
|
||||||
|
|
2
assets
2
assets
|
@ -1 +1 @@
|
||||||
Subproject commit cb0fbb56b9667f68a9776a216c16a4e2b29f7096
|
Subproject commit f8c2595844eff9375b522f117bfdadbdc6728c49
|
4
hmm.json
4
hmm.json
|
@ -54,14 +54,14 @@
|
||||||
"name": "haxeui-core",
|
"name": "haxeui-core",
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"dir": null,
|
"dir": null,
|
||||||
"ref": "8a7846b",
|
"ref": "0212d8fdfcafeb5f0d5a41e1ddba8ff21d0e183b",
|
||||||
"url": "https://github.com/haxeui/haxeui-core"
|
"url": "https://github.com/haxeui/haxeui-core"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "haxeui-flixel",
|
"name": "haxeui-flixel",
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"dir": null,
|
"dir": null,
|
||||||
"ref": "e9f880522e27134b29df4067f82df7d7e5237b70",
|
"ref": "63a906a6148958dbfde8c7b48d90b0693767fd95",
|
||||||
"url": "https://github.com/haxeui/haxeui-flixel"
|
"url": "https://github.com/haxeui/haxeui-flixel"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
@ -146,12 +146,11 @@ class InitState extends FlxState
|
||||||
#end
|
#end
|
||||||
|
|
||||||
// Make errors and warnings less annoying.
|
// Make errors and warnings less annoying.
|
||||||
#if FORCE_DEBUG_VERSION
|
// Forcing this always since I have never been happy to have the debugger to pop up
|
||||||
LogStyle.ERROR.openConsole = false;
|
LogStyle.ERROR.openConsole = false;
|
||||||
LogStyle.ERROR.errorSound = null;
|
LogStyle.ERROR.errorSound = null;
|
||||||
LogStyle.WARNING.openConsole = false;
|
LogStyle.WARNING.openConsole = false;
|
||||||
LogStyle.WARNING.errorSound = null;
|
LogStyle.WARNING.errorSound = null;
|
||||||
#end
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// FLIXEL TRANSITIONS
|
// FLIXEL TRANSITIONS
|
||||||
|
|
|
@ -16,6 +16,20 @@ class Paths
|
||||||
currentLevel = name.toLowerCase();
|
currentLevel = name.toLowerCase();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function stripLibrary(path:String):String
|
||||||
|
{
|
||||||
|
var parts = path.split(':');
|
||||||
|
if (parts.length < 2) return path;
|
||||||
|
return parts[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getLibrary(path:String):String
|
||||||
|
{
|
||||||
|
var parts = path.split(':');
|
||||||
|
if (parts.length < 2) return "preload";
|
||||||
|
return parts[0];
|
||||||
|
}
|
||||||
|
|
||||||
static function getPath(file:String, type:AssetType, library:Null<String>)
|
static function getPath(file:String, type:AssetType, library:Null<String>)
|
||||||
{
|
{
|
||||||
if (library != null) return getLibraryPath(file, library);
|
if (library != null) return getLibraryPath(file, library);
|
||||||
|
|
|
@ -23,7 +23,7 @@ import openfl.utils.AssetType;
|
||||||
@:nullSafety
|
@:nullSafety
|
||||||
class FunkinSound extends FlxSound implements ICloneable<FunkinSound>
|
class FunkinSound extends FlxSound implements ICloneable<FunkinSound>
|
||||||
{
|
{
|
||||||
static final MAX_VOLUME:Float = 2.0;
|
static final MAX_VOLUME:Float = 1.0;
|
||||||
|
|
||||||
static var cache(default, null):FlxTypedGroup<FunkinSound> = new FlxTypedGroup<FunkinSound>();
|
static var cache(default, null):FlxTypedGroup<FunkinSound> = new FlxTypedGroup<FunkinSound>();
|
||||||
|
|
||||||
|
@ -40,7 +40,6 @@ class FunkinSound extends FlxSound implements ICloneable<FunkinSound>
|
||||||
override function set_volume(value:Float):Float
|
override function set_volume(value:Float):Float
|
||||||
{
|
{
|
||||||
// Uncap the volume.
|
// Uncap the volume.
|
||||||
fixMaxVolume();
|
|
||||||
_volume = FlxMath.bound(value, 0.0, MAX_VOLUME);
|
_volume = FlxMath.bound(value, 0.0, MAX_VOLUME);
|
||||||
updateTransform();
|
updateTransform();
|
||||||
return _volume;
|
return _volume;
|
||||||
|
@ -126,17 +125,6 @@ class FunkinSound extends FlxSound implements ICloneable<FunkinSound>
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
function fixMaxVolume():Void
|
|
||||||
{
|
|
||||||
#if lime_openal
|
|
||||||
// This code is pretty fragile, it reaches through 5 layers of private access.
|
|
||||||
@:privateAccess
|
|
||||||
var handle = this?._channel?.__source?.__backend?.handle;
|
|
||||||
if (handle == null) return;
|
|
||||||
lime.media.openal.AL.sourcef(handle, lime.media.openal.AL.MAX_GAIN, MAX_VOLUME);
|
|
||||||
#end
|
|
||||||
}
|
|
||||||
|
|
||||||
public override function play(forceRestart:Bool = false, startTime:Float = 0, ?endTime:Float):FunkinSound
|
public override function play(forceRestart:Bool = false, startTime:Float = 0, ?endTime:Float):FunkinSound
|
||||||
{
|
{
|
||||||
if (!exists) return this;
|
if (!exists) return this;
|
||||||
|
|
|
@ -187,6 +187,8 @@ class WaveformData
|
||||||
*/
|
*/
|
||||||
public function merge(that:WaveformData):WaveformData
|
public function merge(that:WaveformData):WaveformData
|
||||||
{
|
{
|
||||||
|
if (that == null) return this.clone();
|
||||||
|
|
||||||
var result = this.clone([]);
|
var result = this.clone([]);
|
||||||
|
|
||||||
for (channelIndex in 0...this.channels)
|
for (channelIndex in 0...this.channels)
|
||||||
|
|
|
@ -61,7 +61,16 @@ abstract class BaseRegistry<T:(IRegistryEntry<J> & Constructible<EntryConstructo
|
||||||
|
|
||||||
for (entryCls in scriptedEntryClassNames)
|
for (entryCls in scriptedEntryClassNames)
|
||||||
{
|
{
|
||||||
var entry:T = createScriptedEntry(entryCls);
|
var entry:Null<T> = null;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
entry = createScriptedEntry(entryCls);
|
||||||
|
}
|
||||||
|
catch (e:Dynamic)
|
||||||
|
{
|
||||||
|
log('Failed to create scripted entry (${entryCls})');
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (entry != null)
|
if (entry != null)
|
||||||
{
|
{
|
||||||
|
@ -196,6 +205,11 @@ abstract class BaseRegistry<T:(IRegistryEntry<J> & Constructible<EntryConstructo
|
||||||
*/
|
*/
|
||||||
public function parseEntryDataWithMigration(id:String, version:thx.semver.Version):Null<J>
|
public function parseEntryDataWithMigration(id:String, version:thx.semver.Version):Null<J>
|
||||||
{
|
{
|
||||||
|
if (version == null)
|
||||||
|
{
|
||||||
|
throw '[${registryId}] Entry ${id} could not be JSON-parsed or does not have a parseable version.';
|
||||||
|
}
|
||||||
|
|
||||||
// If a version rule is not specified, do not check against it.
|
// If a version rule is not specified, do not check against it.
|
||||||
if (versionRule == null || VersionUtil.validateVersion(version, versionRule))
|
if (versionRule == null || VersionUtil.validateVersion(version, versionRule))
|
||||||
{
|
{
|
||||||
|
|
|
@ -108,8 +108,8 @@ class SongEventRegistry
|
||||||
|
|
||||||
public static function handleEvent(data:SongEventData):Void
|
public static function handleEvent(data:SongEventData):Void
|
||||||
{
|
{
|
||||||
var eventType:String = data.event;
|
var eventKind:String = data.eventKind;
|
||||||
var eventHandler:SongEvent = eventCache.get(eventType);
|
var eventHandler:SongEvent = eventCache.get(eventKind);
|
||||||
|
|
||||||
if (eventHandler != null)
|
if (eventHandler != null)
|
||||||
{
|
{
|
||||||
|
@ -117,7 +117,7 @@ class SongEventRegistry
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
trace('WARNING: No event handler for event with id: ${eventType}');
|
trace('WARNING: No event handler for event with kind: ${eventKind}');
|
||||||
}
|
}
|
||||||
|
|
||||||
data.activated = true;
|
data.activated = true;
|
||||||
|
@ -148,6 +148,29 @@ class SongEventRegistry
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The currentTime has jumped far ahead or back.
|
||||||
|
* If we moved back in time, we need to reset all the events in that space.
|
||||||
|
* If we moved forward in time, we need to skip all the events in that space.
|
||||||
|
*/
|
||||||
|
public static function handleSkippedEvents(events:Array<SongEventData>, currentTime:Float):Void
|
||||||
|
{
|
||||||
|
for (event in events)
|
||||||
|
{
|
||||||
|
// Deactivate future events.
|
||||||
|
if (event.time > currentTime)
|
||||||
|
{
|
||||||
|
event.activated = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Skip past events.
|
||||||
|
if (event.time < currentTime)
|
||||||
|
{
|
||||||
|
event.activated = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reset activation of all the provided events.
|
* Reset activation of all the provided events.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -110,7 +110,8 @@ class SongMetadata implements ICloneable<SongMetadata>
|
||||||
*/
|
*/
|
||||||
public function serialize(pretty:Bool = true):String
|
public function serialize(pretty:Bool = true):String
|
||||||
{
|
{
|
||||||
var writer = new json2object.JsonWriter<SongMetadata>();
|
var ignoreNullOptionals = true;
|
||||||
|
var writer = new json2object.JsonWriter<SongMetadata>(ignoreNullOptionals);
|
||||||
// I believe @:jignored should be iggnored by the writer?
|
// I believe @:jignored should be iggnored by the writer?
|
||||||
// var output = this.clone();
|
// var output = this.clone();
|
||||||
// output.variation = null; // Not sure how to make a field optional on the reader and ignored on the writer.
|
// output.variation = null; // Not sure how to make a field optional on the reader and ignored on the writer.
|
||||||
|
@ -597,7 +598,8 @@ class SongChartData implements ICloneable<SongChartData>
|
||||||
*/
|
*/
|
||||||
public function serialize(pretty:Bool = true):String
|
public function serialize(pretty:Bool = true):String
|
||||||
{
|
{
|
||||||
var writer = new json2object.JsonWriter<SongChartData>();
|
var ignoreNullOptionals = true;
|
||||||
|
var writer = new json2object.JsonWriter<SongChartData>(ignoreNullOptionals);
|
||||||
return writer.write(this, pretty ? ' ' : null);
|
return writer.write(this, pretty ? ' ' : null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -648,7 +650,7 @@ class SongEventDataRaw implements ICloneable<SongEventDataRaw>
|
||||||
* Custom events can be added by scripts with the `ScriptedSongEvent` class.
|
* Custom events can be added by scripts with the `ScriptedSongEvent` class.
|
||||||
*/
|
*/
|
||||||
@:alias("e")
|
@:alias("e")
|
||||||
public var event:String;
|
public var eventKind:String;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The data for the event.
|
* The data for the event.
|
||||||
|
@ -668,10 +670,10 @@ class SongEventDataRaw implements ICloneable<SongEventDataRaw>
|
||||||
@:jignored
|
@:jignored
|
||||||
public var activated:Bool = false;
|
public var activated:Bool = false;
|
||||||
|
|
||||||
public function new(time:Float, event:String, value:Dynamic = null)
|
public function new(time:Float, eventKind:String, value:Dynamic = null)
|
||||||
{
|
{
|
||||||
this.time = time;
|
this.time = time;
|
||||||
this.event = event;
|
this.eventKind = eventKind;
|
||||||
this.value = value;
|
this.value = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -687,19 +689,19 @@ class SongEventDataRaw implements ICloneable<SongEventDataRaw>
|
||||||
|
|
||||||
public function clone():SongEventDataRaw
|
public function clone():SongEventDataRaw
|
||||||
{
|
{
|
||||||
return new SongEventDataRaw(this.time, this.event, this.value);
|
return new SongEventDataRaw(this.time, this.eventKind, this.value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Wrap SongEventData in an abstract so we can overload operators.
|
* Wrap SongEventData in an abstract so we can overload operators.
|
||||||
*/
|
*/
|
||||||
@:forward(time, event, value, activated, getStepTime, clone)
|
@:forward(time, eventKind, value, activated, getStepTime, clone)
|
||||||
abstract SongEventData(SongEventDataRaw) from SongEventDataRaw to SongEventDataRaw
|
abstract SongEventData(SongEventDataRaw) from SongEventDataRaw to SongEventDataRaw
|
||||||
{
|
{
|
||||||
public function new(time:Float, event:String, value:Dynamic = null)
|
public function new(time:Float, eventKind:String, value:Dynamic = null)
|
||||||
{
|
{
|
||||||
this = new SongEventDataRaw(time, event, value);
|
this = new SongEventDataRaw(time, eventKind, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public inline function valueAsStruct(?defaultKey:String = "key"):Dynamic
|
public inline function valueAsStruct(?defaultKey:String = "key"):Dynamic
|
||||||
|
@ -726,12 +728,12 @@ abstract SongEventData(SongEventDataRaw) from SongEventDataRaw to SongEventDataR
|
||||||
|
|
||||||
public inline function getHandler():Null<SongEvent>
|
public inline function getHandler():Null<SongEvent>
|
||||||
{
|
{
|
||||||
return SongEventRegistry.getEvent(this.event);
|
return SongEventRegistry.getEvent(this.eventKind);
|
||||||
}
|
}
|
||||||
|
|
||||||
public inline function getSchema():Null<SongEventSchema>
|
public inline function getSchema():Null<SongEventSchema>
|
||||||
{
|
{
|
||||||
return SongEventRegistry.getEventSchema(this.event);
|
return SongEventRegistry.getEventSchema(this.eventKind);
|
||||||
}
|
}
|
||||||
|
|
||||||
public inline function getDynamic(key:String):Null<Dynamic>
|
public inline function getDynamic(key:String):Null<Dynamic>
|
||||||
|
@ -784,7 +786,7 @@ abstract SongEventData(SongEventDataRaw) from SongEventDataRaw to SongEventDataR
|
||||||
var eventHandler = getHandler();
|
var eventHandler = getHandler();
|
||||||
var eventSchema = getSchema();
|
var eventSchema = getSchema();
|
||||||
|
|
||||||
if (eventSchema == null) return 'Unknown Event: ${this.event}';
|
if (eventSchema == null) return 'Unknown Event: ${this.eventKind}';
|
||||||
|
|
||||||
var result = '${eventHandler.getTitle()}';
|
var result = '${eventHandler.getTitle()}';
|
||||||
|
|
||||||
|
@ -809,19 +811,19 @@ abstract SongEventData(SongEventDataRaw) from SongEventDataRaw to SongEventDataR
|
||||||
|
|
||||||
public function clone():SongEventData
|
public function clone():SongEventData
|
||||||
{
|
{
|
||||||
return new SongEventData(this.time, this.event, this.value);
|
return new SongEventData(this.time, this.eventKind, this.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@:op(A == B)
|
@:op(A == B)
|
||||||
public function op_equals(other:SongEventData):Bool
|
public function op_equals(other:SongEventData):Bool
|
||||||
{
|
{
|
||||||
return this.time == other.time && this.event == other.event && this.value == other.value;
|
return this.time == other.time && this.eventKind == other.eventKind && this.value == other.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
@:op(A != B)
|
@:op(A != B)
|
||||||
public function op_notEquals(other:SongEventData):Bool
|
public function op_notEquals(other:SongEventData):Bool
|
||||||
{
|
{
|
||||||
return this.time != other.time || this.event != other.event || this.value != other.value;
|
return this.time != other.time || this.eventKind != other.eventKind || this.value != other.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
@:op(A > B)
|
@:op(A > B)
|
||||||
|
@ -853,7 +855,7 @@ abstract SongEventData(SongEventDataRaw) from SongEventDataRaw to SongEventDataR
|
||||||
*/
|
*/
|
||||||
public function toString():String
|
public function toString():String
|
||||||
{
|
{
|
||||||
return 'SongEventData(${this.time}ms, ${this.event}: ${this.value})';
|
return 'SongEventData(${this.time}ms, ${this.eventKind}: ${this.value})';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1022,6 +1024,12 @@ class SongNoteDataRaw implements ICloneable<SongNoteDataRaw>
|
||||||
{
|
{
|
||||||
return new SongNoteDataRaw(this.time, this.data, this.length, this.kind);
|
return new SongNoteDataRaw(this.time, this.data, this.length, this.kind);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function toString():String
|
||||||
|
{
|
||||||
|
return 'SongNoteData(${this.time}ms, ' + (this.length > 0 ? '[${this.length}ms hold]' : '') + ' ${this.data}'
|
||||||
|
+ (this.kind != '' ? ' [kind: ${this.kind}])' : ')');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -47,7 +47,7 @@ class SongDataUtils
|
||||||
public static function offsetSongEventData(events:Array<SongEventData>, offset:Float):Array<SongEventData>
|
public static function offsetSongEventData(events:Array<SongEventData>, offset:Float):Array<SongEventData>
|
||||||
{
|
{
|
||||||
return events.map(function(event:SongEventData):SongEventData {
|
return events.map(function(event:SongEventData):SongEventData {
|
||||||
return new SongEventData(event.time + offset, event.event, event.value);
|
return new SongEventData(event.time + offset, event.eventKind, event.value);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,9 +6,23 @@ import flixel.graphics.FlxGraphic;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An FlxSprite with additional functionality.
|
* An FlxSprite with additional functionality.
|
||||||
|
* - A more efficient method for creating solid color sprites.
|
||||||
|
* - TODO: Better cache handling for textures.
|
||||||
*/
|
*/
|
||||||
class FunkinSprite extends FlxSprite
|
class FunkinSprite extends FlxSprite
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
* An internal list of all the textures cached with `cacheTexture`.
|
||||||
|
* This excludes any temporary textures like those from `FlxText` or `makeSolidColor`.
|
||||||
|
*/
|
||||||
|
static var currentCachedTextures:Map<String, FlxGraphic> = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An internal list of textures that were cached in the previous state.
|
||||||
|
* We don't know whether we want to keep them cached or not.
|
||||||
|
*/
|
||||||
|
static var previousCachedTextures:Map<String, FlxGraphic> = [];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param x Starting X position
|
* @param x Starting X position
|
||||||
* @param y Starting Y position
|
* @param y Starting Y position
|
||||||
|
@ -18,19 +32,184 @@ class FunkinSprite extends FlxSprite
|
||||||
super(x, y);
|
super(x, y);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new FunkinSprite with a static texture.
|
||||||
|
* @param x The starting X position.
|
||||||
|
* @param y The starting Y position.
|
||||||
|
* @param key The key of the texture to load.
|
||||||
|
* @return The new FunkinSprite.
|
||||||
|
*/
|
||||||
|
public static function create(x:Float = 0.0, y:Float = 0.0, key:String):FunkinSprite
|
||||||
|
{
|
||||||
|
var sprite = new FunkinSprite(x, y);
|
||||||
|
sprite.loadTexture(key);
|
||||||
|
return sprite;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new FunkinSprite with a Sparrow atlas animated texture.
|
||||||
|
* @param x The starting X position.
|
||||||
|
* @param y The starting Y position.
|
||||||
|
* @param key The key of the texture to load.
|
||||||
|
* @return The new FunkinSprite.
|
||||||
|
*/
|
||||||
|
public static function createSparrow(x:Float = 0.0, y:Float = 0.0, key:String):FunkinSprite
|
||||||
|
{
|
||||||
|
var sprite = new FunkinSprite(x, y);
|
||||||
|
sprite.loadSparrow(key);
|
||||||
|
return sprite;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new FunkinSprite with a Packer atlas animated texture.
|
||||||
|
* @param x The starting X position.
|
||||||
|
* @param y The starting Y position.
|
||||||
|
* @param key The key of the texture to load.
|
||||||
|
* @return The new FunkinSprite.
|
||||||
|
*/
|
||||||
|
public static function createPacker(x:Float = 0.0, y:Float = 0.0, key:String):FunkinSprite
|
||||||
|
{
|
||||||
|
var sprite = new FunkinSprite(x, y);
|
||||||
|
sprite.loadPacker(key);
|
||||||
|
return sprite;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load a static image as the sprite's texture.
|
||||||
|
* @param key The key of the texture to load.
|
||||||
|
* @return This sprite, for chaining.
|
||||||
|
*/
|
||||||
|
public function loadTexture(key:String):FunkinSprite
|
||||||
|
{
|
||||||
|
if (!isTextureCached(key)) FlxG.log.warn('Texture not cached, may experience stuttering! $key');
|
||||||
|
|
||||||
|
loadGraphic(key);
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load an animated texture (Sparrow atlas spritesheet) as the sprite's texture.
|
||||||
|
* @param key The key of the texture to load.
|
||||||
|
* @return This sprite, for chaining.
|
||||||
|
*/
|
||||||
|
public function loadSparrow(key:String):FunkinSprite
|
||||||
|
{
|
||||||
|
var graphicKey = Paths.image(key);
|
||||||
|
if (!isTextureCached(graphicKey)) FlxG.log.warn('Texture not cached, may experience stuttering! $graphicKey');
|
||||||
|
|
||||||
|
this.frames = Paths.getSparrowAtlas(key);
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load an animated texture (Packer atlas spritesheet) as the sprite's texture.
|
||||||
|
* @param key The key of the texture to load.
|
||||||
|
* @return This sprite, for chaining.
|
||||||
|
*/
|
||||||
|
public function loadPacker(key:String):FunkinSprite
|
||||||
|
{
|
||||||
|
var graphicKey = Paths.image(key);
|
||||||
|
if (!isTextureCached(graphicKey)) FlxG.log.warn('Texture not cached, may experience stuttering! $graphicKey');
|
||||||
|
|
||||||
|
this.frames = Paths.getPackerAtlas(key);
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function isTextureCached(key:String):Bool
|
||||||
|
{
|
||||||
|
return FlxG.bitmap.get(key) != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function cacheTexture(key:String):Void
|
||||||
|
{
|
||||||
|
// We don't want to cache the same texture twice.
|
||||||
|
if (currentCachedTextures.exists(key)) return;
|
||||||
|
|
||||||
|
if (previousCachedTextures.exists(key))
|
||||||
|
{
|
||||||
|
// Move the graphic from the previous cache to the current cache.
|
||||||
|
var graphic = previousCachedTextures.get(key);
|
||||||
|
previousCachedTextures.remove(key);
|
||||||
|
currentCachedTextures.set(key, graphic);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Else, texture is currently uncached.
|
||||||
|
var graphic = flixel.graphics.FlxGraphic.fromAssetKey(key, false, null, true);
|
||||||
|
if (graphic == null)
|
||||||
|
{
|
||||||
|
FlxG.log.warn('Failed to cache graphic: $key');
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
trace('Successfully cached graphic: $key');
|
||||||
|
graphic.persist = true;
|
||||||
|
currentCachedTextures.set(key, graphic);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function cacheSparrow(key:String):Void
|
||||||
|
{
|
||||||
|
cacheTexture(Paths.image(key));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function cachePacker(key:String):Void
|
||||||
|
{
|
||||||
|
cacheTexture(Paths.image(key));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Call this, then `cacheTexture` to keep the textures we still need, then `purgeCache` to remove the textures that we won't be using anymore.
|
||||||
|
*/
|
||||||
|
public static function preparePurgeCache():Void
|
||||||
|
{
|
||||||
|
previousCachedTextures = currentCachedTextures;
|
||||||
|
currentCachedTextures = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function purgeCache():Void
|
||||||
|
{
|
||||||
|
// Everything that is in previousCachedTextures but not in currentCachedTextures should be destroyed.
|
||||||
|
for (graphicKey in previousCachedTextures.keys())
|
||||||
|
{
|
||||||
|
var graphic = previousCachedTextures.get(graphicKey);
|
||||||
|
FlxG.bitmap.remove(graphic);
|
||||||
|
graphic.destroy();
|
||||||
|
previousCachedTextures.remove(graphicKey);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static function isGraphicCached(graphic:FlxGraphic):Bool
|
||||||
|
{
|
||||||
|
if (graphic == null) return false;
|
||||||
|
var result = FlxG.bitmap.get(graphic.key);
|
||||||
|
if (result == null) return false;
|
||||||
|
if (result != graphic)
|
||||||
|
{
|
||||||
|
FlxG.log.warn('Cached graphic does not match original: ${graphic.key}');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Acts similarly to `makeGraphic`, but with improved memory usage,
|
* Acts similarly to `makeGraphic`, but with improved memory usage,
|
||||||
* at the expense of not being able to paint onto the sprite.
|
* at the expense of not being able to paint onto the resulting sprite.
|
||||||
*
|
*
|
||||||
* @param width The target width of the sprite.
|
* @param width The target width of the sprite.
|
||||||
* @param height The target height of the sprite.
|
* @param height The target height of the sprite.
|
||||||
* @param color The color to fill the sprite with.
|
* @param color The color to fill the sprite with.
|
||||||
|
* @return This sprite, for chaining.
|
||||||
*/
|
*/
|
||||||
public function makeSolidColor(width:Int, height:Int, color:FlxColor = FlxColor.WHITE):FunkinSprite
|
public function makeSolidColor(width:Int, height:Int, color:FlxColor = FlxColor.WHITE):FunkinSprite
|
||||||
{
|
{
|
||||||
|
// Create a tiny solid color graphic and scale it up to the desired size.
|
||||||
var graphic:FlxGraphic = FlxG.bitmap.create(2, 2, color, false, 'solid#${color.toHexString(true, false)}');
|
var graphic:FlxGraphic = FlxG.bitmap.create(2, 2, color, false, 'solid#${color.toHexString(true, false)}');
|
||||||
frames = graphic.imageFrame;
|
frames = graphic.imageFrame;
|
||||||
scale.set(width / 2, height / 2);
|
scale.set(width / 2.0, height / 2.0);
|
||||||
updateHitbox();
|
updateHitbox();
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
|
|
|
@ -18,7 +18,7 @@ class FlxAtlasSprite extends FlxAnimate
|
||||||
// ?OnComplete:Void -> Void,
|
// ?OnComplete:Void -> Void,
|
||||||
ShowPivot: #if debug false #else false #end,
|
ShowPivot: #if debug false #else false #end,
|
||||||
Antialiasing: true,
|
Antialiasing: true,
|
||||||
ScrollFactor: new FlxPoint(1, 1),
|
ScrollFactor: null,
|
||||||
// Offset: new FlxPoint(0, 0), // This is just FlxSprite.offset
|
// Offset: new FlxPoint(0, 0), // This is just FlxSprite.offset
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -55,8 +55,9 @@ class FlxAtlasSprite extends FlxAnimate
|
||||||
*/
|
*/
|
||||||
public function listAnimations():Array<String>
|
public function listAnimations():Array<String>
|
||||||
{
|
{
|
||||||
// return this.anim.getFrameLabels();
|
if (this.anim == null) return [];
|
||||||
return [""];
|
return this.anim.getFrameLabels();
|
||||||
|
// return [""];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -82,8 +83,10 @@ class FlxAtlasSprite extends FlxAnimate
|
||||||
* @param restart Whether to restart the animation if it is already playing.
|
* @param restart Whether to restart the animation if it is already playing.
|
||||||
* @param ignoreOther Whether to ignore all other animation inputs, until this one is done playing
|
* @param ignoreOther Whether to ignore all other animation inputs, until this one is done playing
|
||||||
*/
|
*/
|
||||||
public function playAnimation(id:String, restart:Bool = false, ignoreOther:Bool = false):Void
|
public function playAnimation(id:String, restart:Bool = false, ignoreOther:Bool = false, ?loop:Bool = false):Void
|
||||||
{
|
{
|
||||||
|
if (loop == null) loop = false;
|
||||||
|
|
||||||
// Skip if not allowed to play animations.
|
// Skip if not allowed to play animations.
|
||||||
if ((!canPlayOtherAnims && !ignoreOther)) return;
|
if ((!canPlayOtherAnims && !ignoreOther)) return;
|
||||||
|
|
||||||
|
@ -110,15 +113,14 @@ class FlxAtlasSprite extends FlxAnimate
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stop the current animation if it is playing.
|
anim.callback = function(_, frame:Int) {
|
||||||
// This includes removing existing frame callbacks.
|
if (frame == (anim.getFrameLabel(id).duration - 1) + anim.getFrameLabel(id).index)
|
||||||
if (this.currentAnimation != null) this.stopAnimation();
|
{
|
||||||
|
if (loop) playAnimation(id, true, false, true);
|
||||||
// Add a callback to ensure `onAnimationFinish` is dispatched.
|
else
|
||||||
addFrameCallback(getNextFrameLabel(id), function() {
|
onAnimationFinish.dispatch(id);
|
||||||
trace('Animation finished: ' + id);
|
}
|
||||||
onAnimationFinish.dispatch(id);
|
};
|
||||||
});
|
|
||||||
|
|
||||||
// Prevent other animations from playing if `ignoreOther` is true.
|
// Prevent other animations from playing if `ignoreOther` is true.
|
||||||
if (ignoreOther) canPlayOtherAnims = false;
|
if (ignoreOther) canPlayOtherAnims = false;
|
||||||
|
@ -128,6 +130,11 @@ class FlxAtlasSprite extends FlxAnimate
|
||||||
this.currentAnimation = id;
|
this.currentAnimation = id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override public function update(elapsed:Float)
|
||||||
|
{
|
||||||
|
super.update(elapsed);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stops the current animation.
|
* Stops the current animation.
|
||||||
*/
|
*/
|
||||||
|
@ -146,22 +153,22 @@ class FlxAtlasSprite extends FlxAnimate
|
||||||
frameLabel.add(callback);
|
frameLabel.add(callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline function goToFrameLabel(label:String):Void
|
function goToFrameLabel(label:String):Void
|
||||||
{
|
{
|
||||||
this.anim.goToFrameLabel(label);
|
this.anim.goToFrameLabel(label);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline function getNextFrameLabel(label:String):String
|
function getNextFrameLabel(label:String):String
|
||||||
{
|
{
|
||||||
return listAnimations()[(getLabelIndex(label) + 1) % listAnimations().length];
|
return listAnimations()[(getLabelIndex(label) + 1) % listAnimations().length];
|
||||||
}
|
}
|
||||||
|
|
||||||
inline function getLabelIndex(label:String):Int
|
function getLabelIndex(label:String):Int
|
||||||
{
|
{
|
||||||
return listAnimations().indexOf(label);
|
return listAnimations().indexOf(label);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline function goToFrameIndex(index:Int):Void
|
function goToFrameIndex(index:Int):Void
|
||||||
{
|
{
|
||||||
this.anim.curFrame = index;
|
this.anim.curFrame = index;
|
||||||
}
|
}
|
||||||
|
|
|
@ -106,12 +106,19 @@ class NoteScriptEvent extends ScriptEvent
|
||||||
*/
|
*/
|
||||||
public var playSound(default, default):Bool;
|
public var playSound(default, default):Bool;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A multiplier to the health gained or lost from this note.
|
||||||
|
* This affects both hits and misses. Remember that max health is 2.00.
|
||||||
|
*/
|
||||||
|
public var healthMulti:Float;
|
||||||
|
|
||||||
public function new(type:ScriptEventType, note:NoteSprite, comboCount:Int = 0, cancelable:Bool = false):Void
|
public function new(type:ScriptEventType, note:NoteSprite, comboCount:Int = 0, cancelable:Bool = false):Void
|
||||||
{
|
{
|
||||||
super(type, cancelable);
|
super(type, cancelable);
|
||||||
this.note = note;
|
this.note = note;
|
||||||
this.comboCount = comboCount;
|
this.comboCount = comboCount;
|
||||||
this.playSound = true;
|
this.playSound = true;
|
||||||
|
this.healthMulti = 1.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override function toString():String
|
public override function toString():String
|
||||||
|
@ -182,17 +189,17 @@ class SongEventScriptEvent extends ScriptEvent
|
||||||
* The note associated with this event.
|
* The note associated with this event.
|
||||||
* You cannot replace it, but you can edit it.
|
* You cannot replace it, but you can edit it.
|
||||||
*/
|
*/
|
||||||
public var event(default, null):funkin.data.song.SongData.SongEventData;
|
public var eventData(default, null):funkin.data.song.SongData.SongEventData;
|
||||||
|
|
||||||
public function new(event:funkin.data.song.SongData.SongEventData):Void
|
public function new(eventData:funkin.data.song.SongData.SongEventData):Void
|
||||||
{
|
{
|
||||||
super(SONG_EVENT, true);
|
super(SONG_EVENT, true);
|
||||||
this.event = event;
|
this.eventData = eventData;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override function toString():String
|
public override function toString():String
|
||||||
{
|
{
|
||||||
return 'SongEventScriptEvent(event=' + event + ')';
|
return 'SongEventScriptEvent(event=' + eventData + ')';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,7 @@ package funkin.play;
|
||||||
import flixel.tweens.FlxEase;
|
import flixel.tweens.FlxEase;
|
||||||
import flixel.tweens.FlxTween;
|
import flixel.tweens.FlxTween;
|
||||||
import flixel.FlxSprite;
|
import flixel.FlxSprite;
|
||||||
|
import funkin.graphics.FunkinSprite;
|
||||||
import funkin.modding.events.ScriptEventDispatcher;
|
import funkin.modding.events.ScriptEventDispatcher;
|
||||||
import funkin.modding.module.ModuleHandler;
|
import funkin.modding.module.ModuleHandler;
|
||||||
import funkin.modding.events.ScriptEvent;
|
import funkin.modding.events.ScriptEvent;
|
||||||
|
@ -214,7 +215,7 @@ class Countdown
|
||||||
|
|
||||||
if (spritePath == null) return;
|
if (spritePath == null) return;
|
||||||
|
|
||||||
var countdownSprite:FlxSprite = new FlxSprite(0, 0).loadGraphic(Paths.image(spritePath));
|
var countdownSprite:FunkinSprite = FunkinSprite.create(Paths.image(spritePath));
|
||||||
countdownSprite.scrollFactor.set(0, 0);
|
countdownSprite.scrollFactor.set(0, 0);
|
||||||
|
|
||||||
if (isPixelStyle) countdownSprite.setGraphicSize(Std.int(countdownSprite.width * Constants.PIXEL_ART_SCALE));
|
if (isPixelStyle) countdownSprite.setGraphicSize(Std.int(countdownSprite.width * Constants.PIXEL_ART_SCALE));
|
||||||
|
|
|
@ -4,16 +4,18 @@ import flixel.FlxG;
|
||||||
import flixel.FlxObject;
|
import flixel.FlxObject;
|
||||||
import flixel.FlxSprite;
|
import flixel.FlxSprite;
|
||||||
import flixel.sound.FlxSound;
|
import flixel.sound.FlxSound;
|
||||||
import funkin.ui.story.StoryMenuState;
|
import funkin.audio.FunkinSound;
|
||||||
import flixel.util.FlxColor;
|
import flixel.util.FlxColor;
|
||||||
import flixel.util.FlxTimer;
|
import flixel.util.FlxTimer;
|
||||||
import funkin.graphics.FunkinSprite;
|
import funkin.graphics.FunkinSprite;
|
||||||
import funkin.ui.MusicBeatSubState;
|
|
||||||
import funkin.modding.events.ScriptEvent;
|
import funkin.modding.events.ScriptEvent;
|
||||||
import funkin.modding.events.ScriptEventDispatcher;
|
import funkin.modding.events.ScriptEventDispatcher;
|
||||||
|
import funkin.play.character.BaseCharacter;
|
||||||
import funkin.play.PlayState;
|
import funkin.play.PlayState;
|
||||||
import funkin.ui.freeplay.FreeplayState;
|
import funkin.ui.freeplay.FreeplayState;
|
||||||
import funkin.play.character.BaseCharacter;
|
import funkin.ui.MusicBeatSubState;
|
||||||
|
import funkin.ui.story.StoryMenuState;
|
||||||
|
import openfl.utils.Assets;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A substate which renders over the PlayState when the player dies.
|
* A substate which renders over the PlayState when the player dies.
|
||||||
|
@ -63,7 +65,7 @@ class GameOverSubState extends MusicBeatSubState
|
||||||
/**
|
/**
|
||||||
* The music playing in the background of the state.
|
* The music playing in the background of the state.
|
||||||
*/
|
*/
|
||||||
var gameOverMusic:FlxSound = new FlxSound();
|
var gameOverMusic:Null<FunkinSound> = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether the player has confirmed and prepared to restart the level.
|
* Whether the player has confirmed and prepared to restart the level.
|
||||||
|
@ -71,6 +73,11 @@ class GameOverSubState extends MusicBeatSubState
|
||||||
*/
|
*/
|
||||||
var isEnding:Bool = false;
|
var isEnding:Bool = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether the death music is on its first loop.
|
||||||
|
*/
|
||||||
|
var isStarting:Bool = true;
|
||||||
|
|
||||||
var isChartingMode:Bool = false;
|
var isChartingMode:Bool = false;
|
||||||
|
|
||||||
var transparent:Bool;
|
var transparent:Bool;
|
||||||
|
@ -140,14 +147,16 @@ class GameOverSubState extends MusicBeatSubState
|
||||||
// Set up the audio
|
// Set up the audio
|
||||||
//
|
//
|
||||||
|
|
||||||
// Prepare the game over music.
|
|
||||||
FlxG.sound.list.add(gameOverMusic);
|
|
||||||
gameOverMusic.stop();
|
|
||||||
|
|
||||||
// The conductor now represents the BPM of the game over music.
|
// The conductor now represents the BPM of the game over music.
|
||||||
Conductor.instance.update(0);
|
Conductor.instance.update(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function resetCameraZoom():Void
|
||||||
|
{
|
||||||
|
// Apply camera zoom level from stage data.
|
||||||
|
FlxG.camera.zoom = PlayState?.instance?.currentStage?.camZoom ?? 1.0;
|
||||||
|
}
|
||||||
|
|
||||||
var hasStartedAnimation:Bool = false;
|
var hasStartedAnimation:Bool = false;
|
||||||
|
|
||||||
override function update(elapsed:Float)
|
override function update(elapsed:Float)
|
||||||
|
@ -216,7 +225,7 @@ class GameOverSubState extends MusicBeatSubState
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (gameOverMusic.playing)
|
if (gameOverMusic != null && gameOverMusic.playing)
|
||||||
{
|
{
|
||||||
// Match the conductor to the music.
|
// Match the conductor to the music.
|
||||||
// This enables the stepHit and beatHit events.
|
// This enables the stepHit and beatHit events.
|
||||||
|
@ -291,24 +300,71 @@ class GameOverSubState extends MusicBeatSubState
|
||||||
ScriptEventDispatcher.callEvent(boyfriend, event);
|
ScriptEventDispatcher.callEvent(boyfriend, event);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rather than hardcoding stuff, we look for the presence of a music file
|
||||||
|
* with the given suffix, and strip it down until we find one that's valid.
|
||||||
|
*/
|
||||||
|
function resolveMusicPath(suffix:String, starting:Bool = false, ending:Bool = false):Null<String>
|
||||||
|
{
|
||||||
|
var basePath = 'gameplay/gameover/gameOver';
|
||||||
|
if (starting) basePath += 'Start';
|
||||||
|
else if (ending) basePath += 'End';
|
||||||
|
|
||||||
|
var musicPath = Paths.music(basePath + suffix);
|
||||||
|
while (!Assets.exists(musicPath) && suffix.length > 0)
|
||||||
|
{
|
||||||
|
suffix = suffix.split('-').slice(0, -1).join('-');
|
||||||
|
musicPath = Paths.music(basePath + suffix);
|
||||||
|
}
|
||||||
|
if (!Assets.exists(musicPath)) return null;
|
||||||
|
trace('Resolved music path: ' + musicPath);
|
||||||
|
return musicPath;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Starts the death music at the appropriate volume.
|
* Starts the death music at the appropriate volume.
|
||||||
* @param startingVolume
|
* @param startingVolume
|
||||||
*/
|
*/
|
||||||
function startDeathMusic(?startingVolume:Float = 1, force:Bool = false):Void
|
public function startDeathMusic(startingVolume:Float = 1, force:Bool = false):Void
|
||||||
{
|
{
|
||||||
var musicPath = Paths.music('gameplay/gameover/gameOver' + musicSuffix);
|
var musicPath = resolveMusicPath(musicSuffix, isStarting, isEnding);
|
||||||
if (isEnding)
|
var onComplete = null;
|
||||||
|
if (isStarting)
|
||||||
{
|
{
|
||||||
musicPath = Paths.music('gameplay/gameover/gameOverEnd' + musicSuffix);
|
if (musicPath == null)
|
||||||
|
{
|
||||||
|
isStarting = false;
|
||||||
|
musicPath = resolveMusicPath(musicSuffix, isStarting, isEnding);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
isStarting = false;
|
||||||
|
onComplete = function() {
|
||||||
|
// We need to force to ensure that the non-starting music plays.
|
||||||
|
startDeathMusic(1.0, true);
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (!gameOverMusic.playing || force)
|
|
||||||
|
if (musicPath == null)
|
||||||
{
|
{
|
||||||
gameOverMusic.loadEmbedded(musicPath);
|
trace('Could not find game over music!');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if (gameOverMusic == null || !gameOverMusic.playing || force)
|
||||||
|
{
|
||||||
|
if (gameOverMusic != null) gameOverMusic.stop();
|
||||||
|
gameOverMusic = FunkinSound.load(musicPath);
|
||||||
gameOverMusic.volume = startingVolume;
|
gameOverMusic.volume = startingVolume;
|
||||||
gameOverMusic.looped = !isEnding;
|
gameOverMusic.looped = !(isEnding || isStarting);
|
||||||
|
gameOverMusic.onComplete = onComplete;
|
||||||
gameOverMusic.play();
|
gameOverMusic.play();
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
@:privateAccess
|
||||||
|
trace('Music already playing! ${gameOverMusic?._label}');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static var blueballed:Bool = false;
|
static var blueballed:Bool = false;
|
||||||
|
@ -320,7 +376,14 @@ class GameOverSubState extends MusicBeatSubState
|
||||||
public static function playBlueBalledSFX()
|
public static function playBlueBalledSFX()
|
||||||
{
|
{
|
||||||
blueballed = true;
|
blueballed = true;
|
||||||
FlxG.sound.play(Paths.sound('gameplay/gameover/fnf_loss_sfx' + blueBallSuffix));
|
if (Assets.exists(Paths.sound('gameplay/gameover/fnf_loss_sfx' + blueBallSuffix)))
|
||||||
|
{
|
||||||
|
FlxG.sound.play(Paths.sound('gameplay/gameover/fnf_loss_sfx' + blueBallSuffix));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
FlxG.log.error('Missing blue ball sound effect: ' + Paths.sound('gameplay/gameover/fnf_loss_sfx' + blueBallSuffix));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var playingJeffQuote:Bool = false;
|
var playingJeffQuote:Bool = false;
|
||||||
|
@ -344,6 +407,14 @@ class GameOverSubState extends MusicBeatSubState
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override function destroy()
|
||||||
|
{
|
||||||
|
super.destroy();
|
||||||
|
if (gameOverMusic != null) gameOverMusic.stop();
|
||||||
|
gameOverMusic = null;
|
||||||
|
instance = null;
|
||||||
|
}
|
||||||
|
|
||||||
public override function toString():String
|
public override function toString():String
|
||||||
{
|
{
|
||||||
return "GameOverSubState";
|
return "GameOverSubState";
|
||||||
|
|
|
@ -3,6 +3,7 @@ package funkin.play;
|
||||||
import flixel.FlxSprite;
|
import flixel.FlxSprite;
|
||||||
import flixel.graphics.frames.FlxAtlasFrames;
|
import flixel.graphics.frames.FlxAtlasFrames;
|
||||||
import funkin.play.PlayState;
|
import funkin.play.PlayState;
|
||||||
|
import funkin.graphics.FunkinSprite;
|
||||||
import funkin.ui.MusicBeatState;
|
import funkin.ui.MusicBeatState;
|
||||||
import flixel.addons.transition.FlxTransitionableState;
|
import flixel.addons.transition.FlxTransitionableState;
|
||||||
import funkin.ui.mainmenu.MainMenuState;
|
import funkin.ui.mainmenu.MainMenuState;
|
||||||
|
@ -27,25 +28,22 @@ class GitarooPause extends MusicBeatState
|
||||||
{
|
{
|
||||||
if (FlxG.sound.music != null) FlxG.sound.music.stop();
|
if (FlxG.sound.music != null) FlxG.sound.music.stop();
|
||||||
|
|
||||||
var bg:FlxSprite = new FlxSprite().loadGraphic(Paths.image('pauseAlt/pauseBG'));
|
var bg:FunkinSprite = FunkinSprite.create(Paths.image('pauseAlt/pauseBG'));
|
||||||
add(bg);
|
add(bg);
|
||||||
|
|
||||||
var bf:FlxSprite = new FlxSprite(0, 30);
|
var bf:FunkinSprite = FunkinSprite.createSparrow(0, 30, 'pauseAlt/bfLol');
|
||||||
bf.frames = Paths.getSparrowAtlas('pauseAlt/bfLol');
|
|
||||||
bf.animation.addByPrefix('lol', "funnyThing", 13);
|
bf.animation.addByPrefix('lol', "funnyThing", 13);
|
||||||
bf.animation.play('lol');
|
bf.animation.play('lol');
|
||||||
add(bf);
|
add(bf);
|
||||||
bf.screenCenter(X);
|
bf.screenCenter(X);
|
||||||
|
|
||||||
replayButton = new FlxSprite(FlxG.width * 0.28, FlxG.height * 0.7);
|
replayButton = FunkinSprite.createSparrow(FlxG.width * 0.28, FlxG.height * 0.7, 'pauseAlt/pauseUI');
|
||||||
replayButton.frames = Paths.getSparrowAtlas('pauseAlt/pauseUI');
|
|
||||||
replayButton.animation.addByPrefix('selected', 'bluereplay', 0, false);
|
replayButton.animation.addByPrefix('selected', 'bluereplay', 0, false);
|
||||||
replayButton.animation.appendByPrefix('selected', 'yellowreplay');
|
replayButton.animation.appendByPrefix('selected', 'yellowreplay');
|
||||||
replayButton.animation.play('selected');
|
replayButton.animation.play('selected');
|
||||||
add(replayButton);
|
add(replayButton);
|
||||||
|
|
||||||
cancelButton = new FlxSprite(FlxG.width * 0.58, replayButton.y);
|
cancelButton = FunkinSprite.createSparrow(FlxG.width * 0.58, replayButton.y, 'pauseAlt/pauseUI');
|
||||||
cancelButton.frames = Paths.getSparrowAtlas('pauseAlt/pauseUI');
|
|
||||||
cancelButton.animation.addByPrefix('selected', 'bluecancel', 0, false);
|
cancelButton.animation.addByPrefix('selected', 'bluecancel', 0, false);
|
||||||
cancelButton.animation.appendByPrefix('selected', 'cancelyellow');
|
cancelButton.animation.appendByPrefix('selected', 'cancelyellow');
|
||||||
cancelButton.animation.play('selected');
|
cancelButton.animation.play('selected');
|
||||||
|
|
|
@ -13,6 +13,7 @@ import flixel.util.FlxColor;
|
||||||
import funkin.play.PlayState;
|
import funkin.play.PlayState;
|
||||||
import funkin.data.song.SongRegistry;
|
import funkin.data.song.SongRegistry;
|
||||||
import funkin.ui.Alphabet;
|
import funkin.ui.Alphabet;
|
||||||
|
import funkin.graphics.FunkinSprite;
|
||||||
|
|
||||||
class PauseSubState extends MusicBeatSubState
|
class PauseSubState extends MusicBeatSubState
|
||||||
{
|
{
|
||||||
|
@ -72,7 +73,7 @@ class PauseSubState extends MusicBeatSubState
|
||||||
|
|
||||||
FlxG.sound.list.add(pauseMusic);
|
FlxG.sound.list.add(pauseMusic);
|
||||||
|
|
||||||
bg = new FlxSprite().makeGraphic(FlxG.width, FlxG.height, FlxColor.BLACK);
|
bg = new FunkinSprite().makeSolidColor(FlxG.width, FlxG.height, FlxColor.BLACK);
|
||||||
bg.alpha = 0;
|
bg.alpha = 0;
|
||||||
bg.scrollFactor.set();
|
bg.scrollFactor.set();
|
||||||
add(bg);
|
add(bg);
|
||||||
|
|
|
@ -10,12 +10,14 @@ import flixel.addons.transition.Transition;
|
||||||
import flixel.addons.transition.Transition;
|
import flixel.addons.transition.Transition;
|
||||||
import flixel.FlxCamera;
|
import flixel.FlxCamera;
|
||||||
import flixel.FlxObject;
|
import flixel.FlxObject;
|
||||||
import flixel.FlxSprite;
|
|
||||||
import flixel.FlxState;
|
import flixel.FlxState;
|
||||||
|
import funkin.graphics.FunkinSprite;
|
||||||
import flixel.FlxSubState;
|
import flixel.FlxSubState;
|
||||||
|
import funkin.graphics.FunkinSprite;
|
||||||
import flixel.math.FlxMath;
|
import flixel.math.FlxMath;
|
||||||
import flixel.math.FlxPoint;
|
import flixel.math.FlxPoint;
|
||||||
import flixel.math.FlxRect;
|
import flixel.math.FlxRect;
|
||||||
|
import funkin.graphics.FunkinSprite;
|
||||||
import flixel.text.FlxText;
|
import flixel.text.FlxText;
|
||||||
import flixel.tweens.FlxEase;
|
import flixel.tweens.FlxEase;
|
||||||
import flixel.tweens.FlxTween;
|
import flixel.tweens.FlxTween;
|
||||||
|
@ -213,7 +215,7 @@ class PlayState extends MusicBeatSubState
|
||||||
* The current gameplay camera will always follow this object. Tween its position to move the camera smoothly.
|
* The current gameplay camera will always follow this object. Tween its position to move the camera smoothly.
|
||||||
*
|
*
|
||||||
* It needs to be an object in the scene for the camera to be configured to follow it.
|
* It needs to be an object in the scene for the camera to be configured to follow it.
|
||||||
* We optionally make this an FlxSprite so we can draw a debug graphic with it.
|
* We optionally make this a sprite so we can draw a debug graphic with it.
|
||||||
*/
|
*/
|
||||||
public var cameraFollowPoint:FlxObject;
|
public var cameraFollowPoint:FlxObject;
|
||||||
|
|
||||||
|
@ -400,7 +402,7 @@ class PlayState extends MusicBeatSubState
|
||||||
* The background image used for the health bar.
|
* The background image used for the health bar.
|
||||||
* Emma says the image is slightly skewed so I'm leaving it as an image instead of a `createGraphic`.
|
* Emma says the image is slightly skewed so I'm leaving it as an image instead of a `createGraphic`.
|
||||||
*/
|
*/
|
||||||
public var healthBarBG:FlxSprite;
|
public var healthBarBG:FunkinSprite;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The health icon representing the player.
|
* The health icon representing the player.
|
||||||
|
@ -568,12 +570,15 @@ class PlayState extends MusicBeatSubState
|
||||||
|
|
||||||
if (!assertChartExists()) return;
|
if (!assertChartExists()) return;
|
||||||
|
|
||||||
|
// TODO: Add something to toggle this on!
|
||||||
if (false)
|
if (false)
|
||||||
{
|
{
|
||||||
// Displays the camera follow point as a sprite for debug purposes.
|
// Displays the camera follow point as a sprite for debug purposes.
|
||||||
cameraFollowPoint = new FlxSprite(0, 0).makeGraphic(8, 8, 0xFF00FF00);
|
var cameraFollowPoint = new FunkinSprite(0, 0);
|
||||||
|
cameraFollowPoint.makeSolidColor(8, 8, 0xFF00FF00);
|
||||||
cameraFollowPoint.visible = false;
|
cameraFollowPoint.visible = false;
|
||||||
cameraFollowPoint.zIndex = 1000000;
|
cameraFollowPoint.zIndex = 1000000;
|
||||||
|
this.cameraFollowPoint = cameraFollowPoint;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -918,6 +923,7 @@ class PlayState extends MusicBeatSubState
|
||||||
{
|
{
|
||||||
FlxG.watch.addQuick('bfAnim', currentStage.getBoyfriend().getCurrentAnimation());
|
FlxG.watch.addQuick('bfAnim', currentStage.getBoyfriend().getCurrentAnimation());
|
||||||
}
|
}
|
||||||
|
FlxG.watch.addQuick('health', health);
|
||||||
|
|
||||||
// TODO: Add a song event for Handle GF dance speed.
|
// TODO: Add a song event for Handle GF dance speed.
|
||||||
|
|
||||||
|
@ -981,8 +987,21 @@ class PlayState extends MusicBeatSubState
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
processSongEvents();
|
||||||
|
|
||||||
|
// Handle keybinds.
|
||||||
|
processInputQueue();
|
||||||
|
if (!isInCutscene && !disableKeys) debugKeyShit();
|
||||||
|
if (isInCutscene && !disableKeys) handleCutsceneKeys(elapsed);
|
||||||
|
|
||||||
|
// Moving notes into position is now done by Strumline.update().
|
||||||
|
processNotes(elapsed);
|
||||||
|
}
|
||||||
|
|
||||||
|
function processSongEvents():Void
|
||||||
|
{
|
||||||
// Query and activate song events.
|
// Query and activate song events.
|
||||||
// TODO: Check that these work even when songPosition is less than 0.
|
// TODO: Check that these work appropriately even when songPosition is less than 0, to play events during countdown.
|
||||||
if (songEvents != null && songEvents.length > 0)
|
if (songEvents != null && songEvents.length > 0)
|
||||||
{
|
{
|
||||||
var songEventsToActivate:Array<SongEventData> = SongEventRegistry.queryEvents(songEvents, Conductor.instance.songPosition);
|
var songEventsToActivate:Array<SongEventData> = SongEventRegistry.queryEvents(songEvents, Conductor.instance.songPosition);
|
||||||
|
@ -992,8 +1011,9 @@ class PlayState extends MusicBeatSubState
|
||||||
trace('Found ${songEventsToActivate.length} event(s) to activate.');
|
trace('Found ${songEventsToActivate.length} event(s) to activate.');
|
||||||
for (event in songEventsToActivate)
|
for (event in songEventsToActivate)
|
||||||
{
|
{
|
||||||
// If an event is trying to play, but it's over 5 seconds old, skip it.
|
// If an event is trying to play, but it's over 1 second old, skip it.
|
||||||
if (event.time - Conductor.instance.songPosition < -5000)
|
var eventAge:Float = Conductor.instance.songPosition - event.time;
|
||||||
|
if (eventAge > 1000)
|
||||||
{
|
{
|
||||||
event.activated = true;
|
event.activated = true;
|
||||||
continue;
|
continue;
|
||||||
|
@ -1009,14 +1029,6 @@ class PlayState extends MusicBeatSubState
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle keybinds.
|
|
||||||
processInputQueue();
|
|
||||||
if (!isInCutscene && !disableKeys) debugKeyShit();
|
|
||||||
if (isInCutscene && !disableKeys) handleCutsceneKeys(elapsed);
|
|
||||||
|
|
||||||
// Moving notes into position is now done by Strumline.update().
|
|
||||||
processNotes(elapsed);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override function dispatchEvent(event:ScriptEvent):Void
|
public override function dispatchEvent(event:ScriptEvent):Void
|
||||||
|
@ -1348,7 +1360,7 @@ class PlayState extends MusicBeatSubState
|
||||||
function initHealthBar():Void
|
function initHealthBar():Void
|
||||||
{
|
{
|
||||||
var healthBarYPos:Float = Preferences.downscroll ? FlxG.height * 0.1 : FlxG.height * 0.9;
|
var healthBarYPos:Float = Preferences.downscroll ? FlxG.height * 0.1 : FlxG.height * 0.9;
|
||||||
healthBarBG = new FlxSprite(0, healthBarYPos).loadGraphic(Paths.image('healthBar'));
|
healthBarBG = FunkinSprite.create(0, healthBarYPos, Paths.image('healthBar'));
|
||||||
healthBarBG.screenCenter(X);
|
healthBarBG.screenCenter(X);
|
||||||
healthBarBG.scrollFactor.set(0, 0);
|
healthBarBG.scrollFactor.set(0, 0);
|
||||||
add(healthBarBG);
|
add(healthBarBG);
|
||||||
|
@ -1382,7 +1394,7 @@ class PlayState extends MusicBeatSubState
|
||||||
function initMinimalMode():Void
|
function initMinimalMode():Void
|
||||||
{
|
{
|
||||||
// Create the green background.
|
// Create the green background.
|
||||||
var menuBG = new FlxSprite().loadGraphic(Paths.image('menuDesat'));
|
var menuBG = FunkinSprite.create(Paths.image('menuDesat'));
|
||||||
menuBG.color = 0xFF4CAF50;
|
menuBG.color = 0xFF4CAF50;
|
||||||
menuBG.setGraphicSize(Std.int(menuBG.width * 1.1));
|
menuBG.setGraphicSize(Std.int(menuBG.width * 1.1));
|
||||||
menuBG.updateHitbox();
|
menuBG.updateHitbox();
|
||||||
|
@ -1408,8 +1420,7 @@ class PlayState extends MusicBeatSubState
|
||||||
var event:ScriptEvent = new ScriptEvent(CREATE, false);
|
var event:ScriptEvent = new ScriptEvent(CREATE, false);
|
||||||
ScriptEventDispatcher.callEvent(currentStage, event);
|
ScriptEventDispatcher.callEvent(currentStage, event);
|
||||||
|
|
||||||
// Apply camera zoom level from stage data.
|
resetCameraZoom();
|
||||||
defaultCameraZoom = currentStage.camZoom;
|
|
||||||
|
|
||||||
// Add the stage to the scene.
|
// Add the stage to the scene.
|
||||||
this.add(currentStage);
|
this.add(currentStage);
|
||||||
|
@ -1425,6 +1436,12 @@ class PlayState extends MusicBeatSubState
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function resetCameraZoom():Void
|
||||||
|
{
|
||||||
|
// Apply camera zoom level from stage data.
|
||||||
|
defaultCameraZoom = currentStage.camZoom;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generates the character sprites and adds them to the stage.
|
* Generates the character sprites and adds them to the stage.
|
||||||
*/
|
*/
|
||||||
|
@ -1750,7 +1767,7 @@ class PlayState extends MusicBeatSubState
|
||||||
currentChart.playInst(1.0, false);
|
currentChart.playInst(1.0, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
FlxG.sound.music.onComplete = endSong;
|
FlxG.sound.music.onComplete = endSong.bind(false);
|
||||||
// A negative instrumental offset means the song skips the first few milliseconds of the track.
|
// A negative instrumental offset means the song skips the first few milliseconds of the track.
|
||||||
// This just gets added into the startTimestamp behavior so we don't need to do anything extra.
|
// This just gets added into the startTimestamp behavior so we don't need to do anything extra.
|
||||||
FlxG.sound.music.time = startTimestamp - Conductor.instance.instrumentalOffset;
|
FlxG.sound.music.time = startTimestamp - Conductor.instance.instrumentalOffset;
|
||||||
|
@ -1978,7 +1995,7 @@ class PlayState extends MusicBeatSubState
|
||||||
// Judge the miss.
|
// Judge the miss.
|
||||||
// NOTE: This is what handles the scoring.
|
// NOTE: This is what handles the scoring.
|
||||||
trace('Missed note! ${note.noteData}');
|
trace('Missed note! ${note.noteData}');
|
||||||
onNoteMiss(note);
|
onNoteMiss(note, event.playSound, event.healthMulti);
|
||||||
|
|
||||||
note.handledMiss = true;
|
note.handledMiss = true;
|
||||||
}
|
}
|
||||||
|
@ -2030,6 +2047,7 @@ class PlayState extends MusicBeatSubState
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Respawns notes that were b
|
||||||
playerStrumline.handleSkippedNotes();
|
playerStrumline.handleSkippedNotes();
|
||||||
opponentStrumline.handleSkippedNotes();
|
opponentStrumline.handleSkippedNotes();
|
||||||
}
|
}
|
||||||
|
@ -2129,7 +2147,7 @@ class PlayState extends MusicBeatSubState
|
||||||
// Calling event.cancelEvent() skips all the other logic! Neat!
|
// Calling event.cancelEvent() skips all the other logic! Neat!
|
||||||
if (event.eventCanceled) return;
|
if (event.eventCanceled) return;
|
||||||
|
|
||||||
popUpScore(note, input);
|
popUpScore(note, input, event.healthMulti);
|
||||||
|
|
||||||
if (note.isHoldNote && note.holdNoteSprite != null)
|
if (note.isHoldNote && note.holdNoteSprite != null)
|
||||||
{
|
{
|
||||||
|
@ -2143,15 +2161,11 @@ class PlayState extends MusicBeatSubState
|
||||||
* Called when a note leaves the screen and is considered missed by the player.
|
* Called when a note leaves the screen and is considered missed by the player.
|
||||||
* @param note
|
* @param note
|
||||||
*/
|
*/
|
||||||
function onNoteMiss(note:NoteSprite):Void
|
function onNoteMiss(note:NoteSprite, playSound:Bool = false, healthLossMulti:Float = 1.0):Void
|
||||||
{
|
{
|
||||||
// a MISS is when you let a note scroll past you!!
|
// If we are here, we already CALLED the onNoteMiss script hook!
|
||||||
var event:NoteScriptEvent = new NoteScriptEvent(NOTE_MISS, note, Highscore.tallies.combo, true);
|
|
||||||
dispatchEvent(event);
|
|
||||||
// Calling event.cancelEvent() skips all the other logic! Neat!
|
|
||||||
if (event.eventCanceled) return;
|
|
||||||
|
|
||||||
health -= Constants.HEALTH_MISS_PENALTY;
|
health -= Constants.HEALTH_MISS_PENALTY * healthLossMulti;
|
||||||
songScore -= 10;
|
songScore -= 10;
|
||||||
|
|
||||||
if (!isPracticeMode)
|
if (!isPracticeMode)
|
||||||
|
@ -2201,7 +2215,7 @@ class PlayState extends MusicBeatSubState
|
||||||
Highscore.tallies.combo = comboPopUps.displayCombo(0);
|
Highscore.tallies.combo = comboPopUps.displayCombo(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (event.playSound)
|
if (playSound)
|
||||||
{
|
{
|
||||||
vocals.playerVolume = 0;
|
vocals.playerVolume = 0;
|
||||||
FlxG.sound.play(Paths.soundRandom('missnote', 1, 3), FlxG.random.float(0.1, 0.2));
|
FlxG.sound.play(Paths.soundRandom('missnote', 1, 3), FlxG.random.float(0.1, 0.2));
|
||||||
|
@ -2274,11 +2288,6 @@ class PlayState extends MusicBeatSubState
|
||||||
if (FlxG.keys.justPressed.H) camHUD.visible = !camHUD.visible;
|
if (FlxG.keys.justPressed.H) camHUD.visible = !camHUD.visible;
|
||||||
#end
|
#end
|
||||||
|
|
||||||
// Eject button
|
|
||||||
if (FlxG.keys.justPressed.F4) FlxG.switchState(() -> new MainMenuState());
|
|
||||||
|
|
||||||
if (FlxG.keys.justPressed.F5) debug_refreshModules();
|
|
||||||
|
|
||||||
// Open the stage editor overlaying the current state.
|
// Open the stage editor overlaying the current state.
|
||||||
if (controls.DEBUG_STAGE)
|
if (controls.DEBUG_STAGE)
|
||||||
{
|
{
|
||||||
|
@ -2301,7 +2310,7 @@ class PlayState extends MusicBeatSubState
|
||||||
|
|
||||||
#if (debug || FORCE_DEBUG_VERSION)
|
#if (debug || FORCE_DEBUG_VERSION)
|
||||||
// 1: End the song immediately.
|
// 1: End the song immediately.
|
||||||
if (FlxG.keys.justPressed.ONE) endSong();
|
if (FlxG.keys.justPressed.ONE) endSong(true);
|
||||||
|
|
||||||
// 2: Gain 10% health.
|
// 2: Gain 10% health.
|
||||||
if (FlxG.keys.justPressed.TWO) health += 0.1 * Constants.HEALTH_MAX;
|
if (FlxG.keys.justPressed.TWO) health += 0.1 * Constants.HEALTH_MAX;
|
||||||
|
@ -2328,7 +2337,7 @@ class PlayState extends MusicBeatSubState
|
||||||
/**
|
/**
|
||||||
* Handles health, score, and rating popups when a note is hit.
|
* Handles health, score, and rating popups when a note is hit.
|
||||||
*/
|
*/
|
||||||
function popUpScore(daNote:NoteSprite, input:PreciseInputEvent):Void
|
function popUpScore(daNote:NoteSprite, input:PreciseInputEvent, healthGainMulti:Float = 1.0):Void
|
||||||
{
|
{
|
||||||
vocals.playerVolume = 1;
|
vocals.playerVolume = 1;
|
||||||
|
|
||||||
|
@ -2359,19 +2368,19 @@ class PlayState extends MusicBeatSubState
|
||||||
{
|
{
|
||||||
case 'sick':
|
case 'sick':
|
||||||
Highscore.tallies.sick += 1;
|
Highscore.tallies.sick += 1;
|
||||||
health += Constants.HEALTH_SICK_BONUS;
|
health += Constants.HEALTH_SICK_BONUS * healthGainMulti;
|
||||||
isComboBreak = Constants.JUDGEMENT_SICK_COMBO_BREAK;
|
isComboBreak = Constants.JUDGEMENT_SICK_COMBO_BREAK;
|
||||||
case 'good':
|
case 'good':
|
||||||
Highscore.tallies.good += 1;
|
Highscore.tallies.good += 1;
|
||||||
health += Constants.HEALTH_GOOD_BONUS;
|
health += Constants.HEALTH_GOOD_BONUS * healthGainMulti;
|
||||||
isComboBreak = Constants.JUDGEMENT_GOOD_COMBO_BREAK;
|
isComboBreak = Constants.JUDGEMENT_GOOD_COMBO_BREAK;
|
||||||
case 'bad':
|
case 'bad':
|
||||||
Highscore.tallies.bad += 1;
|
Highscore.tallies.bad += 1;
|
||||||
health += Constants.HEALTH_BAD_BONUS;
|
health += Constants.HEALTH_BAD_BONUS * healthGainMulti;
|
||||||
isComboBreak = Constants.JUDGEMENT_BAD_COMBO_BREAK;
|
isComboBreak = Constants.JUDGEMENT_BAD_COMBO_BREAK;
|
||||||
case 'shit':
|
case 'shit':
|
||||||
Highscore.tallies.shit += 1;
|
Highscore.tallies.shit += 1;
|
||||||
health += Constants.HEALTH_SHIT_BONUS;
|
health += Constants.HEALTH_SHIT_BONUS * healthGainMulti;
|
||||||
isComboBreak = Constants.JUDGEMENT_SHIT_COMBO_BREAK;
|
isComboBreak = Constants.JUDGEMENT_SHIT_COMBO_BREAK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2495,16 +2504,35 @@ class PlayState extends MusicBeatSubState
|
||||||
|
|
||||||
if (skipHeldTimer >= 1.5)
|
if (skipHeldTimer >= 1.5)
|
||||||
{
|
{
|
||||||
VideoCutscene.finishVideo();
|
skipVideoCutscene();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* End the song. Handle saving high scores and transitioning to the results screen.
|
* Handle logic for actually skipping a video cutscene after it has been held.
|
||||||
*/
|
*/
|
||||||
function endSong():Void
|
function skipVideoCutscene():Void
|
||||||
{
|
{
|
||||||
dispatchEvent(new ScriptEvent(SONG_END));
|
VideoCutscene.finishVideo();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* End the song. Handle saving high scores and transitioning to the results screen.
|
||||||
|
*
|
||||||
|
* Broadcasts an `onSongEnd` event, which can be cancelled to prevent the song from ending (for a cutscene or something).
|
||||||
|
* Remember to call `endSong` again when the song should actually end!
|
||||||
|
* @param rightGoddamnNow If true, don't play the fancy animation where you zoom onto Girlfriend. Used after a cutscene.
|
||||||
|
*/
|
||||||
|
public function endSong(rightGoddamnNow:Bool = false):Void
|
||||||
|
{
|
||||||
|
FlxG.sound.music.volume = 0;
|
||||||
|
vocals.volume = 0;
|
||||||
|
mayPauseGame = false;
|
||||||
|
|
||||||
|
// Check if any events want to prevent the song from ending.
|
||||||
|
var event = new ScriptEvent(SONG_END, true);
|
||||||
|
dispatchEvent(event);
|
||||||
|
if (event.eventCanceled) return;
|
||||||
|
|
||||||
#if sys
|
#if sys
|
||||||
// spitter for ravy, teehee!!
|
// spitter for ravy, teehee!!
|
||||||
|
@ -2514,9 +2542,7 @@ class PlayState extends MusicBeatSubState
|
||||||
#end
|
#end
|
||||||
|
|
||||||
deathCounter = 0;
|
deathCounter = 0;
|
||||||
mayPauseGame = false;
|
|
||||||
FlxG.sound.music.volume = 0;
|
|
||||||
vocals.volume = 0;
|
|
||||||
if (currentSong != null && currentSong.validScore)
|
if (currentSong != null && currentSong.validScore)
|
||||||
{
|
{
|
||||||
// crackhead double thingie, sets whether was new highscore, AND saves the song!
|
// crackhead double thingie, sets whether was new highscore, AND saves the song!
|
||||||
|
@ -2603,7 +2629,14 @@ class PlayState extends MusicBeatSubState
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
moveToResultsScreen();
|
if (rightGoddamnNow)
|
||||||
|
{
|
||||||
|
moveToResultsScreen();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
zoomIntoResultsScreen();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -2621,10 +2654,10 @@ class PlayState extends MusicBeatSubState
|
||||||
// TODO: Softcode this cutscene.
|
// TODO: Softcode this cutscene.
|
||||||
if (currentSong.id == 'eggnog')
|
if (currentSong.id == 'eggnog')
|
||||||
{
|
{
|
||||||
var blackShit:FlxSprite = new FlxSprite(-FlxG.width * FlxG.camera.zoom,
|
var blackBG:FunkinSprite = new FunkinSprite(-FlxG.width * FlxG.camera.zoom, -FlxG.height * FlxG.camera.zoom);
|
||||||
-FlxG.height * FlxG.camera.zoom).makeGraphic(FlxG.width * 3, FlxG.height * 3, FlxColor.BLACK);
|
blackBG.makeSolidColor(FlxG.width * 3, FlxG.height * 3, FlxColor.BLACK);
|
||||||
blackShit.scrollFactor.set();
|
blackBG.scrollFactor.set();
|
||||||
add(blackShit);
|
add(blackBG);
|
||||||
camHUD.visible = false;
|
camHUD.visible = false;
|
||||||
isInCutscene = true;
|
isInCutscene = true;
|
||||||
|
|
||||||
|
@ -2661,7 +2694,14 @@ class PlayState extends MusicBeatSubState
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
moveToResultsScreen();
|
if (rightGoddamnNow)
|
||||||
|
{
|
||||||
|
moveToResultsScreen();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
zoomIntoResultsScreen();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2715,9 +2755,9 @@ class PlayState extends MusicBeatSubState
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Play the camera zoom animation and move to the results screen.
|
* Play the camera zoom animation and then move to the results screen once it's done.
|
||||||
*/
|
*/
|
||||||
function moveToResultsScreen():Void
|
function zoomIntoResultsScreen():Void
|
||||||
{
|
{
|
||||||
trace('WENT TO RESULTS SCREEN!');
|
trace('WENT TO RESULTS SCREEN!');
|
||||||
|
|
||||||
|
@ -2771,22 +2811,30 @@ class PlayState extends MusicBeatSubState
|
||||||
{
|
{
|
||||||
ease: FlxEase.expoIn,
|
ease: FlxEase.expoIn,
|
||||||
onComplete: function(_) {
|
onComplete: function(_) {
|
||||||
persistentUpdate = false;
|
moveToResultsScreen();
|
||||||
vocals.stop();
|
|
||||||
camHUD.alpha = 1;
|
|
||||||
var res:ResultState = new ResultState(
|
|
||||||
{
|
|
||||||
storyMode: PlayStatePlaylist.isStoryMode,
|
|
||||||
title: PlayStatePlaylist.isStoryMode ? ('${PlayStatePlaylist.campaignTitle}') : ('${currentChart.songName} by ${currentChart.songArtist}'),
|
|
||||||
tallies: Highscore.tallies,
|
|
||||||
});
|
|
||||||
res.camera = camHUD;
|
|
||||||
openSubState(res);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Move to the results screen right goddamn now.
|
||||||
|
*/
|
||||||
|
function moveToResultsScreen():Void
|
||||||
|
{
|
||||||
|
persistentUpdate = false;
|
||||||
|
vocals.stop();
|
||||||
|
camHUD.alpha = 1;
|
||||||
|
var res:ResultState = new ResultState(
|
||||||
|
{
|
||||||
|
storyMode: PlayStatePlaylist.isStoryMode,
|
||||||
|
title: PlayStatePlaylist.isStoryMode ? ('${PlayStatePlaylist.campaignTitle}') : ('${currentChart.songName} by ${currentChart.songArtist}'),
|
||||||
|
tallies: Highscore.tallies,
|
||||||
|
});
|
||||||
|
res.camera = camHUD;
|
||||||
|
openSubState(res);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Pauses music and vocals easily.
|
* Pauses music and vocals easily.
|
||||||
*/
|
*/
|
||||||
|
@ -2816,14 +2864,18 @@ class PlayState extends MusicBeatSubState
|
||||||
*/
|
*/
|
||||||
function changeSection(sections:Int):Void
|
function changeSection(sections:Int):Void
|
||||||
{
|
{
|
||||||
FlxG.sound.music.pause();
|
// FlxG.sound.music.pause();
|
||||||
|
|
||||||
var targetTimeSteps:Float = Conductor.instance.currentStepTime + (Conductor.instance.timeSignatureNumerator * Constants.STEPS_PER_BEAT * sections);
|
var targetTimeSteps:Float = Conductor.instance.currentStepTime + (Conductor.instance.stepsPerMeasure * sections);
|
||||||
var targetTimeMs:Float = Conductor.instance.getStepTimeInMs(targetTimeSteps);
|
var targetTimeMs:Float = Conductor.instance.getStepTimeInMs(targetTimeSteps);
|
||||||
|
|
||||||
|
// Don't go back in time to before the song started.
|
||||||
|
targetTimeMs = Math.max(0, targetTimeMs);
|
||||||
|
|
||||||
FlxG.sound.music.time = targetTimeMs;
|
FlxG.sound.music.time = targetTimeMs;
|
||||||
|
|
||||||
handleSkippedNotes();
|
handleSkippedNotes();
|
||||||
|
SongEventRegistry.handleSkippedEvents(songEvents, Conductor.instance.songPosition);
|
||||||
// regenNoteData(FlxG.sound.music.time);
|
// regenNoteData(FlxG.sound.music.time);
|
||||||
|
|
||||||
Conductor.instance.update(FlxG.sound.music.time);
|
Conductor.instance.update(FlxG.sound.music.time);
|
||||||
|
|
|
@ -4,6 +4,7 @@ import funkin.ui.story.StoryMenuState;
|
||||||
import funkin.graphics.adobeanimate.FlxAtlasSprite;
|
import funkin.graphics.adobeanimate.FlxAtlasSprite;
|
||||||
import flixel.FlxBasic;
|
import flixel.FlxBasic;
|
||||||
import flixel.FlxSprite;
|
import flixel.FlxSprite;
|
||||||
|
import funkin.graphics.FunkinSprite;
|
||||||
import flixel.graphics.frames.FlxAtlasFrames;
|
import flixel.graphics.frames.FlxAtlasFrames;
|
||||||
import flixel.graphics.frames.FlxBitmapFont;
|
import flixel.graphics.frames.FlxBitmapFont;
|
||||||
import flixel.group.FlxGroup.FlxTypedGroup;
|
import flixel.group.FlxGroup.FlxTypedGroup;
|
||||||
|
@ -96,8 +97,7 @@ class ResultState extends MusicBeatSubState
|
||||||
bfSHIT.anim.play(); // unpauses this anim, since it's on PlayOnce!
|
bfSHIT.anim.play(); // unpauses this anim, since it's on PlayOnce!
|
||||||
};
|
};
|
||||||
|
|
||||||
var gf:FlxSprite = new FlxSprite(500, 300);
|
var gf:FlxSprite = FunkinSprite.createSparrow(500, 300, 'resultScreen/resultGirlfriendGOOD');
|
||||||
gf.frames = Paths.getSparrowAtlas('resultScreen/resultGirlfriendGOOD');
|
|
||||||
gf.animation.addByPrefix("clap", "Girlfriend Good Anim", 24, false);
|
gf.animation.addByPrefix("clap", "Girlfriend Good Anim", 24, false);
|
||||||
gf.visible = false;
|
gf.visible = false;
|
||||||
gf.animation.finishCallback = _ -> {
|
gf.animation.finishCallback = _ -> {
|
||||||
|
@ -105,8 +105,7 @@ class ResultState extends MusicBeatSubState
|
||||||
};
|
};
|
||||||
add(gf);
|
add(gf);
|
||||||
|
|
||||||
var boyfriend:FlxSprite = new FlxSprite(640, -200);
|
var boyfriend:FlxSprite = FunkinSprite.createSparrow(640, -200, 'resultScreen/resultBoyfriendGOOD');
|
||||||
boyfriend.frames = Paths.getSparrowAtlas('resultScreen/resultBoyfriendGOOD');
|
|
||||||
boyfriend.animation.addByPrefix("fall", "Boyfriend Good", 24, false);
|
boyfriend.animation.addByPrefix("fall", "Boyfriend Good", 24, false);
|
||||||
boyfriend.visible = false;
|
boyfriend.visible = false;
|
||||||
boyfriend.animation.finishCallback = function(_) {
|
boyfriend.animation.finishCallback = function(_) {
|
||||||
|
@ -115,8 +114,7 @@ class ResultState extends MusicBeatSubState
|
||||||
|
|
||||||
add(boyfriend);
|
add(boyfriend);
|
||||||
|
|
||||||
var soundSystem:FlxSprite = new FlxSprite(-15, -180);
|
var soundSystem:FlxSprite = FunkinSprite.createSparrow(-15, -180, 'resultScreen/soundSystem');
|
||||||
soundSystem.frames = Paths.getSparrowAtlas("resultScreen/soundSystem");
|
|
||||||
soundSystem.animation.addByPrefix("idle", "sound system", 24, false);
|
soundSystem.animation.addByPrefix("idle", "sound system", 24, false);
|
||||||
soundSystem.visible = false;
|
soundSystem.visible = false;
|
||||||
new FlxTimer().start(0.4, _ -> {
|
new FlxTimer().start(0.4, _ -> {
|
||||||
|
@ -162,20 +160,17 @@ class ResultState extends MusicBeatSubState
|
||||||
FlxTween.tween(blackTopBar, {y: 0}, 0.4, {ease: FlxEase.quartOut, startDelay: 0.5});
|
FlxTween.tween(blackTopBar, {y: 0}, 0.4, {ease: FlxEase.quartOut, startDelay: 0.5});
|
||||||
add(blackTopBar);
|
add(blackTopBar);
|
||||||
|
|
||||||
var resultsAnim:FlxSprite = new FlxSprite(-200, -10);
|
var resultsAnim:FunkinSprite = FunkinSprite.createSparrow(-200, -10, "resultScreen/results");
|
||||||
resultsAnim.frames = Paths.getSparrowAtlas("resultScreen/results");
|
|
||||||
resultsAnim.animation.addByPrefix("result", "results", 24, false);
|
resultsAnim.animation.addByPrefix("result", "results", 24, false);
|
||||||
resultsAnim.animation.play("result");
|
resultsAnim.animation.play("result");
|
||||||
add(resultsAnim);
|
add(resultsAnim);
|
||||||
|
|
||||||
var ratingsPopin:FlxSprite = new FlxSprite(-150, 120);
|
var ratingsPopin:FunkinSprite = FunkinSprite.createSparrow(-150, 120, "resultScreen/ratingsPopin");
|
||||||
ratingsPopin.frames = Paths.getSparrowAtlas("resultScreen/ratingsPopin");
|
|
||||||
ratingsPopin.animation.addByPrefix("idle", "Categories", 24, false);
|
ratingsPopin.animation.addByPrefix("idle", "Categories", 24, false);
|
||||||
ratingsPopin.visible = false;
|
ratingsPopin.visible = false;
|
||||||
add(ratingsPopin);
|
add(ratingsPopin);
|
||||||
|
|
||||||
var scorePopin:FlxSprite = new FlxSprite(-180, 520);
|
var scorePopin:FunkinSprite = FunkinSprite.createSparrow(-180, 520, "resultScreen/scorePopin");
|
||||||
scorePopin.frames = Paths.getSparrowAtlas("resultScreen/scorePopin");
|
|
||||||
scorePopin.animation.addByPrefix("score", "tally score", 24, false);
|
scorePopin.animation.addByPrefix("score", "tally score", 24, false);
|
||||||
scorePopin.visible = false;
|
scorePopin.visible = false;
|
||||||
add(scorePopin);
|
add(scorePopin);
|
||||||
|
|
|
@ -305,9 +305,15 @@ class CharacterDataParser
|
||||||
icon = "darnell";
|
icon = "darnell";
|
||||||
case "senpai-angry":
|
case "senpai-angry":
|
||||||
icon = "senpai";
|
icon = "senpai";
|
||||||
|
case "tankman" | "tankman-atlas":
|
||||||
|
icon = "tankmen";
|
||||||
}
|
}
|
||||||
|
|
||||||
return Paths.image("freeplay/icons/" + icon + "pixel");
|
var path = Paths.image("freeplay/icons/" + icon + "pixel");
|
||||||
|
if (Assets.exists(path)) return path;
|
||||||
|
|
||||||
|
// TODO: Hardcode some additional behavior or a fallback.
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -6,6 +6,7 @@ import flixel.math.FlxMath;
|
||||||
import flixel.math.FlxPoint;
|
import flixel.math.FlxPoint;
|
||||||
import funkin.play.character.CharacterData.CharacterDataParser;
|
import funkin.play.character.CharacterData.CharacterDataParser;
|
||||||
import openfl.utils.Assets;
|
import openfl.utils.Assets;
|
||||||
|
import funkin.graphics.FunkinSprite;
|
||||||
import funkin.util.MathUtil;
|
import funkin.util.MathUtil;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -26,7 +27,7 @@ import funkin.util.MathUtil;
|
||||||
* @author MasterEric
|
* @author MasterEric
|
||||||
*/
|
*/
|
||||||
@:nullSafety
|
@:nullSafety
|
||||||
class HealthIcon extends FlxSprite
|
class HealthIcon extends FunkinSprite
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* The character this icon is representing.
|
* The character this icon is representing.
|
||||||
|
@ -408,7 +409,7 @@ class HealthIcon extends FlxSprite
|
||||||
|
|
||||||
if (!isLegacyStyle)
|
if (!isLegacyStyle)
|
||||||
{
|
{
|
||||||
frames = Paths.getSparrowAtlas('icons/icon-$charId');
|
loadSparrow('icons/icon-$charId');
|
||||||
|
|
||||||
loadAnimationNew();
|
loadAnimationNew();
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@ package funkin.play.components;
|
||||||
import flixel.FlxSprite;
|
import flixel.FlxSprite;
|
||||||
import flixel.group.FlxGroup.FlxTypedGroup;
|
import flixel.group.FlxGroup.FlxTypedGroup;
|
||||||
import flixel.tweens.FlxTween;
|
import flixel.tweens.FlxTween;
|
||||||
|
import funkin.graphics.FunkinSprite;
|
||||||
import funkin.play.PlayState;
|
import funkin.play.PlayState;
|
||||||
|
|
||||||
class PopUpStuff extends FlxTypedGroup<FlxSprite>
|
class PopUpStuff extends FlxTypedGroup<FlxSprite>
|
||||||
|
@ -14,17 +15,20 @@ class PopUpStuff extends FlxTypedGroup<FlxSprite>
|
||||||
|
|
||||||
public function displayRating(daRating:String)
|
public function displayRating(daRating:String)
|
||||||
{
|
{
|
||||||
|
#if sys
|
||||||
|
var perfStart:Float = Sys.time();
|
||||||
|
#end
|
||||||
|
|
||||||
if (daRating == null) daRating = "good";
|
if (daRating == null) daRating = "good";
|
||||||
|
|
||||||
var rating:FlxSprite = new FlxSprite(0, 0);
|
|
||||||
rating.scrollFactor.set(0.2, 0.2);
|
|
||||||
|
|
||||||
rating.zIndex = 1000;
|
|
||||||
var ratingPath:String = daRating;
|
var ratingPath:String = daRating;
|
||||||
|
|
||||||
if (PlayState.instance.currentStageId.startsWith('school')) ratingPath = "weeb/pixelUI/" + ratingPath + "-pixel";
|
if (PlayState.instance.currentStageId.startsWith('school')) ratingPath = "weeb/pixelUI/" + ratingPath + "-pixel";
|
||||||
|
|
||||||
rating.loadGraphic(Paths.image(ratingPath));
|
var rating:FunkinSprite = FunkinSprite.create(0, 0, Paths.image(ratingPath));
|
||||||
|
rating.scrollFactor.set(0.2, 0.2);
|
||||||
|
|
||||||
|
rating.zIndex = 1000;
|
||||||
rating.x = FlxG.width * 0.50;
|
rating.x = FlxG.width * 0.50;
|
||||||
rating.x -= FlxG.camera.scroll.x * 0.2;
|
rating.x -= FlxG.camera.scroll.x * 0.2;
|
||||||
// make sure rating is visible lol!
|
// make sure rating is visible lol!
|
||||||
|
@ -61,10 +65,19 @@ class PopUpStuff extends FlxTypedGroup<FlxSprite>
|
||||||
},
|
},
|
||||||
startDelay: Conductor.instance.beatLengthMs * 0.001
|
startDelay: Conductor.instance.beatLengthMs * 0.001
|
||||||
});
|
});
|
||||||
|
|
||||||
|
#if sys
|
||||||
|
var perfEnd:Float = Sys.time();
|
||||||
|
trace("displayRating took: " + (perfEnd - perfStart));
|
||||||
|
#end
|
||||||
}
|
}
|
||||||
|
|
||||||
public function displayCombo(?combo:Int = 0):Int
|
public function displayCombo(?combo:Int = 0):Int
|
||||||
{
|
{
|
||||||
|
#if sys
|
||||||
|
var perfStart:Float = Sys.time();
|
||||||
|
#end
|
||||||
|
|
||||||
if (combo == null) combo = 0;
|
if (combo == null) combo = 0;
|
||||||
|
|
||||||
var pixelShitPart1:String = "";
|
var pixelShitPart1:String = "";
|
||||||
|
@ -75,7 +88,7 @@ class PopUpStuff extends FlxTypedGroup<FlxSprite>
|
||||||
pixelShitPart1 = 'weeb/pixelUI/';
|
pixelShitPart1 = 'weeb/pixelUI/';
|
||||||
pixelShitPart2 = '-pixel';
|
pixelShitPart2 = '-pixel';
|
||||||
}
|
}
|
||||||
var comboSpr:FlxSprite = new FlxSprite().loadGraphic(Paths.image(pixelShitPart1 + 'combo' + pixelShitPart2));
|
var comboSpr:FunkinSprite = FunkinSprite.create(Paths.image(pixelShitPart1 + 'combo' + pixelShitPart2));
|
||||||
comboSpr.y = FlxG.camera.height * 0.4 + 80;
|
comboSpr.y = FlxG.camera.height * 0.4 + 80;
|
||||||
comboSpr.x = FlxG.width * 0.50;
|
comboSpr.x = FlxG.width * 0.50;
|
||||||
comboSpr.x -= FlxG.camera.scroll.x * 0.2;
|
comboSpr.x -= FlxG.camera.scroll.x * 0.2;
|
||||||
|
@ -129,8 +142,7 @@ class PopUpStuff extends FlxTypedGroup<FlxSprite>
|
||||||
var daLoop:Int = 1;
|
var daLoop:Int = 1;
|
||||||
for (i in seperatedScore)
|
for (i in seperatedScore)
|
||||||
{
|
{
|
||||||
var numScore:FlxSprite = new FlxSprite().loadGraphic(Paths.image(pixelShitPart1 + 'num' + Std.int(i) + pixelShitPart2));
|
var numScore:FunkinSprite = FunkinSprite.create(0, comboSpr.y, Paths.image(pixelShitPart1 + 'num' + Std.int(i) + pixelShitPart2));
|
||||||
numScore.y = comboSpr.y;
|
|
||||||
|
|
||||||
if (PlayState.instance.currentStageId.startsWith('school'))
|
if (PlayState.instance.currentStageId.startsWith('school'))
|
||||||
{
|
{
|
||||||
|
@ -163,6 +175,11 @@ class PopUpStuff extends FlxTypedGroup<FlxSprite>
|
||||||
daLoop++;
|
daLoop++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if sys
|
||||||
|
var perfEnd:Float = Sys.time();
|
||||||
|
trace("displayCombo took: " + (perfEnd - perfStart));
|
||||||
|
#end
|
||||||
|
|
||||||
return combo;
|
return combo;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,13 +19,22 @@ import hxcodec.flixel.FlxVideoSprite;
|
||||||
class VideoCutscene
|
class VideoCutscene
|
||||||
{
|
{
|
||||||
static var blackScreen:FlxSprite;
|
static var blackScreen:FlxSprite;
|
||||||
|
static var cutsceneType:CutsceneType;
|
||||||
|
|
||||||
|
#if html5
|
||||||
|
static var vid:FlxVideo;
|
||||||
|
#end
|
||||||
|
#if hxCodec
|
||||||
|
static var vid:FlxVideoSprite;
|
||||||
|
#end
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Play a video cutscene.
|
* Play a video cutscene.
|
||||||
* TODO: Currently this is hardcoded to start the countdown after the video is done.
|
* TODO: Currently this is hardcoded to start the countdown after the video is done.
|
||||||
* @param path The path to the video file. Use Paths.file(path) to get the correct path.
|
* @param path The path to the video file. Use Paths.file(path) to get the correct path.
|
||||||
|
* @param cutseneType The type of cutscene to play, determines what the game does after. Defaults to `CutsceneType.STARTING`.
|
||||||
*/
|
*/
|
||||||
public static function play(filePath:String):Void
|
public static function play(filePath:String, ?cutsceneType:CutsceneType = STARTING):Void
|
||||||
{
|
{
|
||||||
if (PlayState.instance == null) return;
|
if (PlayState.instance == null) return;
|
||||||
|
|
||||||
|
@ -36,6 +45,8 @@ class VideoCutscene
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var rawFilePath = Paths.stripLibrary(filePath);
|
||||||
|
|
||||||
// Trigger the cutscene. Don't play the song in the background.
|
// Trigger the cutscene. Don't play the song in the background.
|
||||||
PlayState.instance.isInCutscene = true;
|
PlayState.instance.isInCutscene = true;
|
||||||
PlayState.instance.camHUD.visible = false;
|
PlayState.instance.camHUD.visible = false;
|
||||||
|
@ -47,12 +58,14 @@ class VideoCutscene
|
||||||
blackScreen.cameras = [PlayState.instance.camCutscene];
|
blackScreen.cameras = [PlayState.instance.camCutscene];
|
||||||
PlayState.instance.add(blackScreen);
|
PlayState.instance.add(blackScreen);
|
||||||
|
|
||||||
|
VideoCutscene.cutsceneType = cutsceneType;
|
||||||
|
|
||||||
#if html5
|
#if html5
|
||||||
playVideoHTML5(filePath);
|
playVideoHTML5(filePath);
|
||||||
#end
|
#elseif hxCodec
|
||||||
|
playVideoNative(rawFilePath);
|
||||||
#if hxCodec
|
#else
|
||||||
playVideoNative(filePath);
|
throw "No video support for this platform!";
|
||||||
#end
|
#end
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -66,8 +79,6 @@ class VideoCutscene
|
||||||
}
|
}
|
||||||
|
|
||||||
#if html5
|
#if html5
|
||||||
static var vid:FlxVideo;
|
|
||||||
|
|
||||||
static function playVideoHTML5(filePath:String):Void
|
static function playVideoHTML5(filePath:String):Void
|
||||||
{
|
{
|
||||||
// Video displays OVER the FlxState.
|
// Video displays OVER the FlxState.
|
||||||
|
@ -92,8 +103,6 @@ class VideoCutscene
|
||||||
#end
|
#end
|
||||||
|
|
||||||
#if hxCodec
|
#if hxCodec
|
||||||
static var vid:FlxVideoSprite;
|
|
||||||
|
|
||||||
static function playVideoNative(filePath:String):Void
|
static function playVideoNative(filePath:String):Void
|
||||||
{
|
{
|
||||||
// Video displays OVER the FlxState.
|
// Video displays OVER the FlxState.
|
||||||
|
@ -110,6 +119,15 @@ class VideoCutscene
|
||||||
|
|
||||||
PlayState.instance.refresh();
|
PlayState.instance.refresh();
|
||||||
vid.play(filePath, false);
|
vid.play(filePath, false);
|
||||||
|
|
||||||
|
// Resize videos bigger or smaller than the screen.
|
||||||
|
vid.bitmap.onTextureSetup.add(() -> {
|
||||||
|
vid.setGraphicSize(FlxG.width, FlxG.height);
|
||||||
|
vid.updateHitbox();
|
||||||
|
vid.x = 0;
|
||||||
|
vid.y = 0;
|
||||||
|
// vid.scale.set(0.5, 0.5);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -118,10 +136,17 @@ class VideoCutscene
|
||||||
}
|
}
|
||||||
#end
|
#end
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finish the active video cutscene. Done when the video is finished or when the player skips the cutscene.
|
||||||
|
* @param transitionTime The duration of the transition to the next state. Defaults to 0.5 seconds (this time is always used when cancelling the video).
|
||||||
|
* @param finishCutscene The callback to call when the transition is finished.
|
||||||
|
*/
|
||||||
public static function finishVideo(?transitionTime:Float = 0.5):Void
|
public static function finishVideo(?transitionTime:Float = 0.5):Void
|
||||||
{
|
{
|
||||||
trace('ALERT: Finish video cutscene called!');
|
trace('ALERT: Finish video cutscene called!');
|
||||||
|
|
||||||
|
var cutsceneType:CutsceneType = VideoCutscene.cutsceneType;
|
||||||
|
|
||||||
#if html5
|
#if html5
|
||||||
if (vid != null)
|
if (vid != null)
|
||||||
{
|
{
|
||||||
|
@ -157,8 +182,32 @@ class VideoCutscene
|
||||||
{
|
{
|
||||||
ease: FlxEase.quadInOut,
|
ease: FlxEase.quadInOut,
|
||||||
onComplete: function(twn:FlxTween) {
|
onComplete: function(twn:FlxTween) {
|
||||||
PlayState.instance.startCountdown();
|
onCutsceneFinish(cutsceneType);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The default callback used when a cutscene is finished.
|
||||||
|
* You can specify your own callback when calling `VideoCutscene#play()`.
|
||||||
|
*/
|
||||||
|
static function onCutsceneFinish(cutsceneType:CutsceneType):Void
|
||||||
|
{
|
||||||
|
switch (cutsceneType)
|
||||||
|
{
|
||||||
|
case CutsceneType.STARTING:
|
||||||
|
PlayState.instance.startCountdown();
|
||||||
|
case CutsceneType.ENDING:
|
||||||
|
PlayState.instance.endSong(true); // true = right goddamn now
|
||||||
|
case CutsceneType.MIDSONG:
|
||||||
|
throw "Not implemented!";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum CutsceneType
|
||||||
|
{
|
||||||
|
STARTING; // The default cutscene type. Starts the countdown after the video is done.
|
||||||
|
MIDSONG; // TODO: Implement this!
|
||||||
|
ENDING; // Ends the song after the video is done.
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,6 +35,7 @@ class NoteSplash extends FlxSprite
|
||||||
*/
|
*/
|
||||||
function setup():Void
|
function setup():Void
|
||||||
{
|
{
|
||||||
|
if (frameCollection?.parent?.isDestroyed ?? false) frameCollection = null;
|
||||||
if (frameCollection == null) preloadFrames();
|
if (frameCollection == null) preloadFrames();
|
||||||
|
|
||||||
this.frames = frameCollection;
|
this.frames = frameCollection;
|
||||||
|
@ -75,6 +76,8 @@ class NoteSplash extends FlxSprite
|
||||||
this.playAnimation('splash${variant}Right');
|
this.playAnimation('splash${variant}Right');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (animation.curAnim == null) return;
|
||||||
|
|
||||||
// Vary the speed of the animation a bit.
|
// Vary the speed of the animation a bit.
|
||||||
animation.curAnim.frameRate = FRAMERATE_DEFAULT + FlxG.random.int(-FRAMERATE_VARIANCE, FRAMERATE_VARIANCE);
|
animation.curAnim.frameRate = FRAMERATE_DEFAULT + FlxG.random.int(-FRAMERATE_VARIANCE, FRAMERATE_VARIANCE);
|
||||||
|
|
||||||
|
|
|
@ -4,9 +4,10 @@ import funkin.data.song.SongData.SongNoteData;
|
||||||
import funkin.play.notes.notestyle.NoteStyle;
|
import funkin.play.notes.notestyle.NoteStyle;
|
||||||
import flixel.graphics.frames.FlxAtlasFrames;
|
import flixel.graphics.frames.FlxAtlasFrames;
|
||||||
import flixel.FlxSprite;
|
import flixel.FlxSprite;
|
||||||
|
import funkin.graphics.FunkinSprite;
|
||||||
import funkin.graphics.shaders.HSVShader;
|
import funkin.graphics.shaders.HSVShader;
|
||||||
|
|
||||||
class NoteSprite extends FlxSprite
|
class NoteSprite extends FunkinSprite
|
||||||
{
|
{
|
||||||
static final DIRECTION_COLORS:Array<String> = ['purple', 'blue', 'green', 'red'];
|
static final DIRECTION_COLORS:Array<String> = ['purple', 'blue', 'green', 'red'];
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,7 @@ import flixel.graphics.frames.FlxAtlasFrames;
|
||||||
import flixel.graphics.frames.FlxFramesCollection;
|
import flixel.graphics.frames.FlxFramesCollection;
|
||||||
import funkin.data.animation.AnimationData;
|
import funkin.data.animation.AnimationData;
|
||||||
import funkin.data.IRegistryEntry;
|
import funkin.data.IRegistryEntry;
|
||||||
|
import funkin.graphics.FunkinSprite;
|
||||||
import funkin.data.notestyle.NoteStyleData;
|
import funkin.data.notestyle.NoteStyleData;
|
||||||
import funkin.data.notestyle.NoteStyleRegistry;
|
import funkin.data.notestyle.NoteStyleRegistry;
|
||||||
import funkin.data.notestyle.NoteStyleRegistry;
|
import funkin.data.notestyle.NoteStyleRegistry;
|
||||||
|
@ -100,6 +101,14 @@ class NoteStyle implements IRegistryEntry<NoteStyleData>
|
||||||
|
|
||||||
function buildNoteFrames(force:Bool = false):FlxAtlasFrames
|
function buildNoteFrames(force:Bool = false):FlxAtlasFrames
|
||||||
{
|
{
|
||||||
|
if (!FunkinSprite.isTextureCached(Paths.image(getNoteAssetPath())))
|
||||||
|
{
|
||||||
|
FlxG.log.warn('Note texture is not cached: ${getNoteAssetPath()}');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Purge the note frames if the cached atlas is invalid.
|
||||||
|
if (noteFrames?.parent?.isDestroyed ?? false) noteFrames = null;
|
||||||
|
|
||||||
if (noteFrames != null && !force) return noteFrames;
|
if (noteFrames != null && !force) return noteFrames;
|
||||||
|
|
||||||
noteFrames = Paths.getSparrowAtlas(getNoteAssetPath(), getNoteAssetLibrary());
|
noteFrames = Paths.getSparrowAtlas(getNoteAssetPath(), getNoteAssetLibrary());
|
||||||
|
@ -109,8 +118,6 @@ class NoteStyle implements IRegistryEntry<NoteStyleData>
|
||||||
throw 'Could not load note frames for note style: $id';
|
throw 'Could not load note frames for note style: $id';
|
||||||
}
|
}
|
||||||
|
|
||||||
noteFrames.parent.persist = true;
|
|
||||||
|
|
||||||
return noteFrames;
|
return noteFrames;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -185,9 +185,9 @@ class Stage extends FlxSpriteGroup implements IPlayStateScriptedClass implements
|
||||||
switch (dataProp.animType)
|
switch (dataProp.animType)
|
||||||
{
|
{
|
||||||
case 'packer':
|
case 'packer':
|
||||||
propSprite.frames = Paths.getPackerAtlas(dataProp.assetPath);
|
propSprite.loadPacker(dataProp.assetPath);
|
||||||
default: // 'sparrow'
|
default: // 'sparrow'
|
||||||
propSprite.frames = Paths.getSparrowAtlas(dataProp.assetPath);
|
propSprite.loadSparrow(dataProp.assetPath);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (isSolidColor)
|
else if (isSolidColor)
|
||||||
|
@ -209,7 +209,7 @@ class Stage extends FlxSpriteGroup implements IPlayStateScriptedClass implements
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Initalize static sprite.
|
// Initalize static sprite.
|
||||||
propSprite.loadGraphic(Paths.image(dataProp.assetPath));
|
propSprite.loadTexture(Paths.image(dataProp.assetPath));
|
||||||
|
|
||||||
// Disables calls to update() for a performance boost.
|
// Disables calls to update() for a performance boost.
|
||||||
propSprite.active = false;
|
propSprite.active = false;
|
||||||
|
@ -397,15 +397,18 @@ class Stage extends FlxSpriteGroup implements IPlayStateScriptedClass implements
|
||||||
this.characters.set('bf', character);
|
this.characters.set('bf', character);
|
||||||
charData = _data.characters.bf;
|
charData = _data.characters.bf;
|
||||||
character.flipX = !character.getDataFlipX();
|
character.flipX = !character.getDataFlipX();
|
||||||
|
character.name = 'bf';
|
||||||
character.initHealthIcon(false);
|
character.initHealthIcon(false);
|
||||||
case GF:
|
case GF:
|
||||||
this.characters.set('gf', character);
|
this.characters.set('gf', character);
|
||||||
charData = _data.characters.gf;
|
charData = _data.characters.gf;
|
||||||
character.flipX = character.getDataFlipX();
|
character.flipX = character.getDataFlipX();
|
||||||
|
character.name = 'gf';
|
||||||
case DAD:
|
case DAD:
|
||||||
this.characters.set('dad', character);
|
this.characters.set('dad', character);
|
||||||
charData = _data.characters.dad;
|
charData = _data.characters.dad;
|
||||||
character.flipX = character.getDataFlipX();
|
character.flipX = character.getDataFlipX();
|
||||||
|
character.name = 'dad';
|
||||||
character.initHealthIcon(true);
|
character.initHealthIcon(true);
|
||||||
default:
|
default:
|
||||||
this.characters.set(character.characterId, character);
|
this.characters.set(character.characterId, character);
|
||||||
|
|
|
@ -3408,7 +3408,7 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
|
||||||
// Update the event sprite's position.
|
// Update the event sprite's position.
|
||||||
eventSprite.updateEventPosition(renderedEvents);
|
eventSprite.updateEventPosition(renderedEvents);
|
||||||
// Update the sprite's graphic. TODO: Is this inefficient?
|
// Update the sprite's graphic. TODO: Is this inefficient?
|
||||||
eventSprite.playAnimation(eventSprite.eventData.event);
|
eventSprite.playAnimation(eventSprite.eventData.eventKind);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -4669,9 +4669,9 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
|
||||||
|
|
||||||
var eventData:SongEventData = gridGhostEvent.eventData != null ? gridGhostEvent.eventData : new SongEventData(cursorMs, eventKindToPlace, null);
|
var eventData:SongEventData = gridGhostEvent.eventData != null ? gridGhostEvent.eventData : new SongEventData(cursorMs, eventKindToPlace, null);
|
||||||
|
|
||||||
if (eventKindToPlace != eventData.event)
|
if (eventKindToPlace != eventData.eventKind)
|
||||||
{
|
{
|
||||||
eventData.event = eventKindToPlace;
|
eventData.eventKind = eventKindToPlace;
|
||||||
}
|
}
|
||||||
eventData.time = cursorSnappedMs;
|
eventData.time = cursorSnappedMs;
|
||||||
|
|
||||||
|
|
|
@ -34,11 +34,11 @@ class SelectItemsCommand implements ChartEditorCommand
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we just selected one or more events (and no notes), then we should make the event data toolbox display the event data for the selected event.
|
// If we just selected one or more events (and no notes), then we should make the event data toolbox display the event data for the selected event.
|
||||||
if (this.notes.length == 0 && this.events.length >= 1)
|
if (this.notes.length == 0 && this.events.length == 1)
|
||||||
{
|
{
|
||||||
var eventSelected = this.events[0];
|
var eventSelected = this.events[0];
|
||||||
|
|
||||||
state.eventKindToPlace = eventSelected.event;
|
state.eventKindToPlace = eventSelected.eventKind;
|
||||||
|
|
||||||
// This code is here to parse event data that's not built as a struct for some reason.
|
// This code is here to parse event data that's not built as a struct for some reason.
|
||||||
// TODO: Clean this up or get rid of it.
|
// TODO: Clean this up or get rid of it.
|
||||||
|
@ -46,7 +46,7 @@ class SelectItemsCommand implements ChartEditorCommand
|
||||||
var defaultKey = null;
|
var defaultKey = null;
|
||||||
if (eventSchema == null)
|
if (eventSchema == null)
|
||||||
{
|
{
|
||||||
trace('[WARNING] Event schema not found for event ${eventSelected.event}.');
|
trace('[WARNING] Event schema not found for event ${eventSelected.eventKind}.');
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -60,7 +60,7 @@ class SelectItemsCommand implements ChartEditorCommand
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we just selected one or more notes (and no events), then we should make the note data toolbox display the note data for the selected note.
|
// If we just selected one or more notes (and no events), then we should make the note data toolbox display the note data for the selected note.
|
||||||
if (this.events.length == 0 && this.notes.length >= 1)
|
if (this.events.length == 0 && this.notes.length == 1)
|
||||||
{
|
{
|
||||||
var noteSelected = this.notes[0];
|
var noteSelected = this.notes[0];
|
||||||
|
|
||||||
|
|
|
@ -31,11 +31,11 @@ class SetItemSelectionCommand implements ChartEditorCommand
|
||||||
state.currentEventSelection = events;
|
state.currentEventSelection = events;
|
||||||
|
|
||||||
// If we just selected one or more events (and no notes), then we should make the event data toolbox display the event data for the selected event.
|
// If we just selected one or more events (and no notes), then we should make the event data toolbox display the event data for the selected event.
|
||||||
if (this.notes.length == 0 && this.events.length >= 1)
|
if (this.notes.length == 0 && this.events.length == 1)
|
||||||
{
|
{
|
||||||
var eventSelected = this.events[0];
|
var eventSelected = this.events[0];
|
||||||
|
|
||||||
state.eventKindToPlace = eventSelected.event;
|
state.eventKindToPlace = eventSelected.eventKind;
|
||||||
|
|
||||||
// This code is here to parse event data that's not built as a struct for some reason.
|
// This code is here to parse event data that's not built as a struct for some reason.
|
||||||
// TODO: Clean this up or get rid of it.
|
// TODO: Clean this up or get rid of it.
|
||||||
|
@ -43,7 +43,7 @@ class SetItemSelectionCommand implements ChartEditorCommand
|
||||||
var defaultKey = null;
|
var defaultKey = null;
|
||||||
if (eventSchema == null)
|
if (eventSchema == null)
|
||||||
{
|
{
|
||||||
trace('[WARNING] Event schema not found for event ${eventSelected.event}.');
|
trace('[WARNING] Event schema not found for event ${eventSelected.eventKind}.');
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -57,7 +57,7 @@ class SetItemSelectionCommand implements ChartEditorCommand
|
||||||
}
|
}
|
||||||
|
|
||||||
// IF we just selected one or more notes (and no events), then we should make the note data toolbox display the note data for the selected note.
|
// IF we just selected one or more notes (and no events), then we should make the note data toolbox display the note data for the selected note.
|
||||||
if (this.events.length == 0 && this.notes.length >= 1)
|
if (this.events.length == 0 && this.notes.length == 1)
|
||||||
{
|
{
|
||||||
var noteSelected = this.notes[0];
|
var noteSelected = this.notes[0];
|
||||||
|
|
||||||
|
|
|
@ -133,7 +133,7 @@ class ChartEditorEventSprite extends FlxSprite
|
||||||
|
|
||||||
public function playAnimation(?name:String):Void
|
public function playAnimation(?name:String):Void
|
||||||
{
|
{
|
||||||
if (name == null) name = eventData?.event ?? DEFAULT_EVENT;
|
if (name == null) name = eventData?.eventKind ?? DEFAULT_EVENT;
|
||||||
|
|
||||||
var correctedName = correctAnimationName(name);
|
var correctedName = correctAnimationName(name);
|
||||||
this.animation.play(correctedName);
|
this.animation.play(correctedName);
|
||||||
|
@ -160,7 +160,7 @@ class ChartEditorEventSprite extends FlxSprite
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
this.visible = true;
|
this.visible = true;
|
||||||
playAnimation(value.event);
|
playAnimation(value.eventKind);
|
||||||
this.eventData = value;
|
this.eventData = value;
|
||||||
// Update the position to match the note data.
|
// Update the position to match the note data.
|
||||||
updateEventPosition();
|
updateEventPosition();
|
||||||
|
|
|
@ -299,16 +299,14 @@ class ChartEditorAudioHandler
|
||||||
*/
|
*/
|
||||||
public static function playSound(_state:ChartEditorState, path:String, volume:Float = 1.0):Void
|
public static function playSound(_state:ChartEditorState, path:String, volume:Float = 1.0):Void
|
||||||
{
|
{
|
||||||
var snd:FlxSound = FlxG.sound.list.recycle(FlxSound) ?? new FlxSound();
|
|
||||||
var asset:Null<FlxSoundAsset> = FlxG.sound.cache(path);
|
var asset:Null<FlxSoundAsset> = FlxG.sound.cache(path);
|
||||||
if (asset == null)
|
if (asset == null)
|
||||||
{
|
{
|
||||||
trace('WARN: Failed to play sound $path, asset not found.');
|
trace('WARN: Failed to play sound $path, asset not found.');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
snd.loadEmbedded(asset);
|
var snd:FunkinSound = FunkinSound.load(asset);
|
||||||
snd.autoDestroy = true;
|
snd.autoDestroy = true;
|
||||||
FlxG.sound.list.add(snd);
|
|
||||||
snd.play(true);
|
snd.play(true);
|
||||||
snd.volume = volume;
|
snd.volume = volume;
|
||||||
}
|
}
|
||||||
|
|
|
@ -90,7 +90,7 @@ class ChartEditorEventDataToolbox extends ChartEditorBaseToolbox
|
||||||
// Edit the event data of any selected events.
|
// Edit the event data of any selected events.
|
||||||
for (event in chartEditorState.currentEventSelection)
|
for (event in chartEditorState.currentEventSelection)
|
||||||
{
|
{
|
||||||
event.event = chartEditorState.eventKindToPlace;
|
event.eventKind = chartEditorState.eventKindToPlace;
|
||||||
event.value = chartEditorState.eventDataToPlace;
|
event.value = chartEditorState.eventDataToPlace;
|
||||||
}
|
}
|
||||||
chartEditorState.saveDataDirty = true;
|
chartEditorState.saveDataDirty = true;
|
||||||
|
@ -255,7 +255,7 @@ class ChartEditorEventDataToolbox extends ChartEditorBaseToolbox
|
||||||
{
|
{
|
||||||
for (event in chartEditorState.currentEventSelection)
|
for (event in chartEditorState.currentEventSelection)
|
||||||
{
|
{
|
||||||
event.event = chartEditorState.eventKindToPlace;
|
event.eventKind = chartEditorState.eventKindToPlace;
|
||||||
event.value = chartEditorState.eventDataToPlace;
|
event.value = chartEditorState.eventDataToPlace;
|
||||||
}
|
}
|
||||||
chartEditorState.saveDataDirty = true;
|
chartEditorState.saveDataDirty = true;
|
||||||
|
|
|
@ -289,10 +289,10 @@ class ChartEditorFreeplayToolbox extends ChartEditorBaseToolbox
|
||||||
// Build player waveform.
|
// Build player waveform.
|
||||||
// waveformMusic.waveform.forceUpdate = true;
|
// waveformMusic.waveform.forceUpdate = true;
|
||||||
var perfStart = haxe.Timer.stamp();
|
var perfStart = haxe.Timer.stamp();
|
||||||
var waveformData1 = playerVoice.waveformData;
|
var waveformData1 = playerVoice?.waveformData;
|
||||||
var waveformData2 = opponentVoice?.waveformData ?? playerVoice.waveformData; // this null check is for songs that only have 1 vocals file!
|
var waveformData2 = opponentVoice?.waveformData ?? playerVoice?.waveformData; // this null check is for songs that only have 1 vocals file!
|
||||||
var waveformData3 = chartEditorState.audioInstTrack.waveformData;
|
var waveformData3 = chartEditorState.audioInstTrack.waveformData;
|
||||||
var waveformData = waveformData1.merge(waveformData2).merge(waveformData3);
|
var waveformData = waveformData3.merge(waveformData1).merge(waveformData2);
|
||||||
trace('Waveform data merging took: ${haxe.Timer.stamp() - perfStart} seconds');
|
trace('Waveform data merging took: ${haxe.Timer.stamp() - perfStart} seconds');
|
||||||
|
|
||||||
waveformMusic.waveform.waveformData = waveformData;
|
waveformMusic.waveform.waveformData = waveformData;
|
||||||
|
|
|
@ -270,24 +270,21 @@ class ChartEditorOffsetsToolbox extends ChartEditorBaseToolbox
|
||||||
|
|
||||||
// Build player waveform.
|
// Build player waveform.
|
||||||
// waveformPlayer.waveform.forceUpdate = true;
|
// waveformPlayer.waveform.forceUpdate = true;
|
||||||
waveformPlayer.waveform.waveformData = playerVoice.waveformData;
|
waveformPlayer.waveform.waveformData = playerVoice?.waveformData;
|
||||||
// Set the width and duration to render the full waveform, with the clipRect applied we only render a segment of it.
|
// Set the width and duration to render the full waveform, with the clipRect applied we only render a segment of it.
|
||||||
waveformPlayer.waveform.duration = playerVoice.length / Constants.MS_PER_SEC;
|
waveformPlayer.waveform.duration = (playerVoice?.length ?? 1000) / Constants.MS_PER_SEC;
|
||||||
|
|
||||||
// Build opponent waveform.
|
// Build opponent waveform.
|
||||||
// waveformOpponent.waveform.forceUpdate = true;
|
// waveformOpponent.waveform.forceUpdate = true;
|
||||||
// note: if song only has one set of vocals (Vocals.ogg/mp3) then this is null and crashes charting editor
|
// note: if song only has one set of vocals (Vocals.ogg/mp3) then this is null and crashes charting editor
|
||||||
// so we null check
|
// so we null check
|
||||||
if (opponentVoice != null)
|
waveformOpponent.waveform.waveformData = opponentVoice?.waveformData;
|
||||||
{
|
waveformOpponent.waveform.duration = (opponentVoice?.length ?? 1000) / Constants.MS_PER_SEC;
|
||||||
waveformOpponent.waveform.waveformData = opponentVoice.waveformData;
|
|
||||||
waveformOpponent.waveform.duration = opponentVoice.length / Constants.MS_PER_SEC;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Build instrumental waveform.
|
// Build instrumental waveform.
|
||||||
// waveformInstrumental.waveform.forceUpdate = true;
|
// waveformInstrumental.waveform.forceUpdate = true;
|
||||||
waveformInstrumental.waveform.waveformData = chartEditorState.audioInstTrack.waveformData;
|
waveformInstrumental.waveform.waveformData = chartEditorState.audioInstTrack.waveformData;
|
||||||
waveformInstrumental.waveform.duration = instTrack.length / Constants.MS_PER_SEC;
|
waveformInstrumental.waveform.duration = (instTrack?.length ?? 1000) / Constants.MS_PER_SEC;
|
||||||
|
|
||||||
addOffsetsToAudioPreview();
|
addOffsetsToAudioPreview();
|
||||||
}
|
}
|
||||||
|
|
|
@ -147,6 +147,8 @@ class ChartEditorDropdowns
|
||||||
dropDown.dataSource.add(value);
|
dropDown.dataSource.add(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dropDown.dataSource.sort('id', ASCENDING);
|
||||||
|
|
||||||
return returnValue;
|
return returnValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -156,8 +156,6 @@ class DJBoyfriend extends FlxAtlasSprite
|
||||||
|
|
||||||
function setupAnimations():Void
|
function setupAnimations():Void
|
||||||
{
|
{
|
||||||
// frames = FlxAnimationUtil.combineFramesCollections(Paths.getSparrowAtlas('freeplay/bfFreeplay'), Paths.getSparrowAtlas('freeplay/bf-freeplay-afk'));
|
|
||||||
|
|
||||||
// animation.addByPrefix('intro', "boyfriend dj intro", 24, false);
|
// animation.addByPrefix('intro', "boyfriend dj intro", 24, false);
|
||||||
addOffset('boyfriend dj intro', 8, 3);
|
addOffset('boyfriend dj intro', 8, 3);
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,7 @@ class FreeplayFlames extends FlxSpriteGroup
|
||||||
{
|
{
|
||||||
var flame:FlxSprite = new FlxSprite(flameX + (flameSpreadX * i), flameY + (flameSpreadY * i));
|
var flame:FlxSprite = new FlxSprite(flameX + (flameSpreadX * i), flameY + (flameSpreadY * i));
|
||||||
flame.frames = Paths.getSparrowAtlas("freeplay/freeplayFlame");
|
flame.frames = Paths.getSparrowAtlas("freeplay/freeplayFlame");
|
||||||
flame.animation.addByPrefix("flame", "fire loop", FlxG.random.int(23, 25), false);
|
flame.animation.addByPrefix("flame", "fire loop full instance 1", FlxG.random.int(23, 25), false);
|
||||||
flame.animation.play("flame");
|
flame.animation.play("flame");
|
||||||
flame.visible = false;
|
flame.visible = false;
|
||||||
flameCount = 0;
|
flameCount = 0;
|
||||||
|
|
|
@ -111,7 +111,7 @@ class ScoreNum extends FlxSprite
|
||||||
for (i in 0...10)
|
for (i in 0...10)
|
||||||
{
|
{
|
||||||
var stringNum:String = numToString[i];
|
var stringNum:String = numToString[i];
|
||||||
animation.addByPrefix(stringNum, stringNum, 24, false);
|
animation.addByPrefix(stringNum, '$stringNum DIGITAL', 24, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.digit = initDigit;
|
this.digit = initDigit;
|
||||||
|
|
|
@ -7,6 +7,7 @@ import flixel.addons.ui.FlxInputText;
|
||||||
import flixel.FlxCamera;
|
import flixel.FlxCamera;
|
||||||
import flixel.FlxGame;
|
import flixel.FlxGame;
|
||||||
import flixel.FlxSprite;
|
import flixel.FlxSprite;
|
||||||
|
import funkin.graphics.FunkinSprite;
|
||||||
import flixel.FlxState;
|
import flixel.FlxState;
|
||||||
import flixel.group.FlxGroup;
|
import flixel.group.FlxGroup;
|
||||||
import flixel.group.FlxGroup.FlxTypedGroup;
|
import flixel.group.FlxGroup.FlxTypedGroup;
|
||||||
|
@ -226,17 +227,17 @@ class FreeplayState extends MusicBeatSubState
|
||||||
trace(FlxG.camera.initialZoom);
|
trace(FlxG.camera.initialZoom);
|
||||||
trace(FlxCamera.defaultZoom);
|
trace(FlxCamera.defaultZoom);
|
||||||
|
|
||||||
var pinkBack:FlxSprite = new FlxSprite().loadGraphic(Paths.image('freeplay/pinkBack'));
|
var pinkBack:FunkinSprite = FunkinSprite.create(Paths.image('freeplay/pinkBack'));
|
||||||
pinkBack.color = 0xFFffd4e9; // sets it to pink!
|
pinkBack.color = 0xFFffd4e9; // sets it to pink!
|
||||||
pinkBack.x -= pinkBack.width;
|
pinkBack.x -= pinkBack.width;
|
||||||
|
|
||||||
FlxTween.tween(pinkBack, {x: 0}, 0.6, {ease: FlxEase.quartOut});
|
FlxTween.tween(pinkBack, {x: 0}, 0.6, {ease: FlxEase.quartOut});
|
||||||
add(pinkBack);
|
add(pinkBack);
|
||||||
|
|
||||||
var orangeBackShit:FlxSprite = new FlxSprite(84, 440).makeGraphic(Std.int(pinkBack.width), 75, 0xFFfeda00);
|
var orangeBackShit:FunkinSprite = new FunkinSprite(84, 440).makeSolidColor(Std.int(pinkBack.width), 75, 0xFFfeda00);
|
||||||
add(orangeBackShit);
|
add(orangeBackShit);
|
||||||
|
|
||||||
var alsoOrangeLOL:FlxSprite = new FlxSprite(0, orangeBackShit.y).makeGraphic(100, Std.int(orangeBackShit.height), 0xFFffd400);
|
var alsoOrangeLOL:FunkinSprite = new FunkinSprite(0, orangeBackShit.y).makeSolidColor(100, Std.int(orangeBackShit.height), 0xFFffd400);
|
||||||
add(alsoOrangeLOL);
|
add(alsoOrangeLOL);
|
||||||
|
|
||||||
exitMovers.set([pinkBack, orangeBackShit, alsoOrangeLOL],
|
exitMovers.set([pinkBack, orangeBackShit, alsoOrangeLOL],
|
||||||
|
@ -462,7 +463,7 @@ class FreeplayState extends MusicBeatSubState
|
||||||
|
|
||||||
var fnfHighscoreSpr:FlxSprite = new FlxSprite(860, 70);
|
var fnfHighscoreSpr:FlxSprite = new FlxSprite(860, 70);
|
||||||
fnfHighscoreSpr.frames = Paths.getSparrowAtlas('freeplay/highscore');
|
fnfHighscoreSpr.frames = Paths.getSparrowAtlas('freeplay/highscore');
|
||||||
fnfHighscoreSpr.animation.addByPrefix("highscore", "highscore", 24, false);
|
fnfHighscoreSpr.animation.addByPrefix("highscore", "highscore small instance 1", 24, false);
|
||||||
fnfHighscoreSpr.visible = false;
|
fnfHighscoreSpr.visible = false;
|
||||||
fnfHighscoreSpr.setGraphicSize(0, Std.int(fnfHighscoreSpr.height * 1));
|
fnfHighscoreSpr.setGraphicSize(0, Std.int(fnfHighscoreSpr.height * 1));
|
||||||
fnfHighscoreSpr.updateHitbox();
|
fnfHighscoreSpr.updateHitbox();
|
||||||
|
|
|
@ -3,6 +3,7 @@ package funkin.ui.transition;
|
||||||
import flixel.FlxSprite;
|
import flixel.FlxSprite;
|
||||||
import flixel.math.FlxMath;
|
import flixel.math.FlxMath;
|
||||||
import flixel.tweens.FlxEase;
|
import flixel.tweens.FlxEase;
|
||||||
|
import funkin.graphics.FunkinSprite;
|
||||||
import flixel.tweens.FlxTween;
|
import flixel.tweens.FlxTween;
|
||||||
import flixel.util.FlxTimer;
|
import flixel.util.FlxTimer;
|
||||||
import funkin.graphics.shaders.ScreenWipeShader;
|
import funkin.graphics.shaders.ScreenWipeShader;
|
||||||
|
@ -44,11 +45,10 @@ class LoadingState extends MusicBeatState
|
||||||
|
|
||||||
override function create():Void
|
override function create():Void
|
||||||
{
|
{
|
||||||
var bg:FlxSprite = new FunkinSprite().makeSolidColor(FlxG.width, FlxG.height, 0xFFcaff4d);
|
var bg:FunkinSprite = new FunkinSprite().makeSolidColor(FlxG.width, FlxG.height, 0xFFcaff4d);
|
||||||
add(bg);
|
add(bg);
|
||||||
|
|
||||||
funkay = new FlxSprite();
|
funkay = FunkinSprite.create(Paths.image('funkay'));
|
||||||
funkay.loadGraphic(Paths.image('funkay'));
|
|
||||||
funkay.setGraphicSize(0, FlxG.height);
|
funkay.setGraphicSize(0, FlxG.height);
|
||||||
funkay.updateHitbox();
|
funkay.updateHitbox();
|
||||||
add(funkay);
|
add(funkay);
|
||||||
|
@ -209,6 +209,43 @@ class LoadingState extends MusicBeatState
|
||||||
params.targetSong.cacheCharts(true);
|
params.targetSong.cacheCharts(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: This section is a hack! Redo this later when we have a proper asset caching system.
|
||||||
|
FunkinSprite.preparePurgeCache();
|
||||||
|
FunkinSprite.cacheTexture(Paths.image('combo'));
|
||||||
|
FunkinSprite.cacheTexture(Paths.image('healthBar'));
|
||||||
|
FunkinSprite.cacheTexture(Paths.image('menuDesat'));
|
||||||
|
FunkinSprite.cacheTexture(Paths.image('combo'));
|
||||||
|
FunkinSprite.cacheTexture(Paths.image('num0'));
|
||||||
|
FunkinSprite.cacheTexture(Paths.image('num1'));
|
||||||
|
FunkinSprite.cacheTexture(Paths.image('num2'));
|
||||||
|
FunkinSprite.cacheTexture(Paths.image('num3'));
|
||||||
|
FunkinSprite.cacheTexture(Paths.image('num4'));
|
||||||
|
FunkinSprite.cacheTexture(Paths.image('num5'));
|
||||||
|
FunkinSprite.cacheTexture(Paths.image('num6'));
|
||||||
|
FunkinSprite.cacheTexture(Paths.image('num7'));
|
||||||
|
FunkinSprite.cacheTexture(Paths.image('num8'));
|
||||||
|
FunkinSprite.cacheTexture(Paths.image('num9'));
|
||||||
|
FunkinSprite.cacheTexture(Paths.image('notes', 'shared'));
|
||||||
|
FunkinSprite.cacheTexture(Paths.image('noteSplashes', 'shared'));
|
||||||
|
FunkinSprite.cacheTexture(Paths.image('noteStrumline', 'shared'));
|
||||||
|
FunkinSprite.cacheTexture(Paths.image('NOTE_hold_assets'));
|
||||||
|
FunkinSprite.cacheTexture(Paths.image('ready', 'shared'));
|
||||||
|
FunkinSprite.cacheTexture(Paths.image('set', 'shared'));
|
||||||
|
FunkinSprite.cacheTexture(Paths.image('go', 'shared'));
|
||||||
|
FunkinSprite.cacheTexture(Paths.image('sick', 'shared'));
|
||||||
|
FunkinSprite.cacheTexture(Paths.image('good', 'shared'));
|
||||||
|
FunkinSprite.cacheTexture(Paths.image('bad', 'shared'));
|
||||||
|
FunkinSprite.cacheTexture(Paths.image('shit', 'shared'));
|
||||||
|
FunkinSprite.cacheTexture(Paths.image('miss', 'shared')); // TODO: remove this
|
||||||
|
|
||||||
|
// FunkinSprite.cacheAllNoteStyleTextures(noteStyle) // This will replace the stuff above!
|
||||||
|
// FunkinSprite.cacheAllCharacterTextures(player)
|
||||||
|
// FunkinSprite.cacheAllCharacterTextures(girlfriend)
|
||||||
|
// FunkinSprite.cacheAllCharacterTextures(opponent)
|
||||||
|
// FunkinSprite.cacheAllStageTextures(stage)
|
||||||
|
|
||||||
|
FunkinSprite.purgeCache();
|
||||||
|
|
||||||
FlxG.switchState(playStateCtor);
|
FlxG.switchState(playStateCtor);
|
||||||
#end
|
#end
|
||||||
}
|
}
|
||||||
|
@ -354,7 +391,7 @@ class MultiCallback
|
||||||
|
|
||||||
public static function coolSwitchState(state:NextState, transitionTex:String = "shaderTransitionStuff/coolDots", time:Float = 2)
|
public static function coolSwitchState(state:NextState, transitionTex:String = "shaderTransitionStuff/coolDots", time:Float = 2)
|
||||||
{
|
{
|
||||||
var screenShit:FlxSprite = new FlxSprite().loadGraphic(Paths.image("shaderTransitionStuff/coolDots"));
|
var screenShit:FunkinSprite = FunkinSprite.create(Paths.image("shaderTransitionStuff/coolDots"));
|
||||||
var screenWipeShit:ScreenWipeShader = new ScreenWipeShader();
|
var screenWipeShit:ScreenWipeShader = new ScreenWipeShader();
|
||||||
|
|
||||||
screenWipeShit.funnyShit.input = screenShit.pixels;
|
screenWipeShit.funnyShit.input = screenShit.pixels;
|
||||||
|
|
|
@ -3,6 +3,7 @@ package funkin.ui.transition;
|
||||||
import flixel.FlxSprite;
|
import flixel.FlxSprite;
|
||||||
import haxe.Json;
|
import haxe.Json;
|
||||||
import lime.utils.Assets;
|
import lime.utils.Assets;
|
||||||
|
import funkin.graphics.FunkinSprite;
|
||||||
// import flxtyped group
|
// import flxtyped group
|
||||||
import funkin.ui.MusicBeatSubState;
|
import funkin.ui.MusicBeatSubState;
|
||||||
import funkin.ui.story.StoryMenuState;
|
import funkin.ui.story.StoryMenuState;
|
||||||
|
@ -245,6 +246,10 @@ class StickerSubState extends MusicBeatSubState
|
||||||
FlxTransitionableState.skipNextTransIn = true;
|
FlxTransitionableState.skipNextTransIn = true;
|
||||||
FlxTransitionableState.skipNextTransOut = true;
|
FlxTransitionableState.skipNextTransOut = true;
|
||||||
|
|
||||||
|
// TODO: Rework this asset caching stuff
|
||||||
|
FunkinSprite.preparePurgeCache();
|
||||||
|
FunkinSprite.purgeCache();
|
||||||
|
|
||||||
// I think this grabs the screen and puts it under the stickers?
|
// I think this grabs the screen and puts it under the stickers?
|
||||||
// Leaving this commented out rather than stripping it out because it's cool...
|
// Leaving this commented out rather than stripping it out because it's cool...
|
||||||
/*
|
/*
|
||||||
|
@ -301,14 +306,14 @@ class StickerSubState extends MusicBeatSubState
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class StickerSprite extends FlxSprite
|
class StickerSprite extends FunkinSprite
|
||||||
{
|
{
|
||||||
public var timing:Float = 0;
|
public var timing:Float = 0;
|
||||||
|
|
||||||
public function new(x:Float, y:Float, stickerSet:String, stickerName:String):Void
|
public function new(x:Float, y:Float, stickerSet:String, stickerName:String):Void
|
||||||
{
|
{
|
||||||
super(x, y);
|
super(x, y);
|
||||||
loadGraphic(Paths.image('transitionSwag/' + stickerSet + '/' + stickerName));
|
loadTexture(Paths.image('transitionSwag/' + stickerSet + '/' + stickerName));
|
||||||
updateHitbox();
|
updateHitbox();
|
||||||
scrollFactor.set();
|
scrollFactor.set();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue