mirror of
https://github.com/ninjamuffin99/Funkin.git
synced 2025-12-01 16:51:27 +00:00
Tweaks to song events
This commit is contained in:
parent
7b71fc2dff
commit
679ca4aafb
|
|
@ -11,6 +11,7 @@ import funkin.charting.ChartingState;
|
|||
import funkin.modding.module.ModuleHandler;
|
||||
import funkin.play.PlayState;
|
||||
import funkin.play.character.CharacterData.CharacterDataParser;
|
||||
import funkin.play.event.SongEvent.SongEventHandler;
|
||||
import funkin.play.song.SongData.SongDataParser;
|
||||
import funkin.play.stage.StageData;
|
||||
import funkin.ui.PreferencesMenu;
|
||||
|
|
@ -118,6 +119,9 @@ class InitState extends FlxTransitionableState
|
|||
// FlxTransitionableState.skipNextTransOut = true;
|
||||
FlxTransitionableState.skipNextTransIn = true;
|
||||
|
||||
SongEventHandler.registerBaseEventCallbacks();
|
||||
// TODO: Register custom event callbacks here
|
||||
|
||||
SongDataParser.loadSongCache();
|
||||
StageDataParser.loadStageCache();
|
||||
CharacterDataParser.loadCharacterCache();
|
||||
|
|
|
|||
|
|
@ -10,8 +10,6 @@ import flixel.util.FlxColor;
|
|||
import flixel.util.FlxDirectionFlags;
|
||||
import flixel.util.FlxTimer;
|
||||
import funkin.audiovis.SpectogramSprite;
|
||||
import funkin.noteStuff.NoteUtil;
|
||||
import funkin.shaderslmfao.BuildingShaders;
|
||||
import funkin.shaderslmfao.ColorSwap;
|
||||
import funkin.shaderslmfao.TitleOutline;
|
||||
import funkin.ui.AtlasText;
|
||||
|
|
|
|||
|
|
@ -232,6 +232,9 @@ class PolymodHandler
|
|||
|
||||
// Reload everything that is cached.
|
||||
// Currently this freezes the game for a second but I guess that's tolerable?
|
||||
|
||||
// TODO: Reload event callbacks
|
||||
|
||||
SongDataParser.loadSongCache();
|
||||
StageDataParser.loadStageCache();
|
||||
CharacterDataParser.loadCharacterCache();
|
||||
|
|
|
|||
|
|
@ -1,206 +0,0 @@
|
|||
package funkin.play;
|
||||
|
||||
import flixel.FlxSprite;
|
||||
import flixel.addons.effects.FlxTrail;
|
||||
import flixel.group.FlxGroup.FlxTypedGroup;
|
||||
import flixel.math.FlxMath;
|
||||
import flixel.util.FlxColor;
|
||||
import flixel.util.FlxDirectionFlags;
|
||||
import funkin.audiovis.PolygonSpectogram;
|
||||
import funkin.noteStuff.NoteBasic.NoteData;
|
||||
|
||||
class PicoFight extends MusicBeatState
|
||||
{
|
||||
var picoHealth:Float = 1;
|
||||
var darnellHealth:Float = 1;
|
||||
|
||||
var pico:Fighter;
|
||||
var darnell:Fighter;
|
||||
var darnellGhost:Fighter;
|
||||
|
||||
var nextHitTmr:FlxSprite;
|
||||
|
||||
var funnyWave:PolygonSpectogram;
|
||||
|
||||
var noteQueue:Array<NoteData> = [];
|
||||
var noteSpawner:FlxTypedGroup<FlxSprite>;
|
||||
|
||||
override function create()
|
||||
{
|
||||
Paths.setCurrentLevel("weekend1");
|
||||
|
||||
var bg:FlxSprite = new FlxSprite().makeGraphic(FlxG.width, FlxG.height);
|
||||
bg.scrollFactor.set();
|
||||
add(bg);
|
||||
|
||||
FlxG.sound.playMusic(Paths.inst("blazin"));
|
||||
|
||||
SongLoad.loadFromJson('blazin', "blazin");
|
||||
Conductor.forceBPM(SongLoad.songData.bpm);
|
||||
|
||||
for (dumbassSection in SongLoad.songData.noteMap['hard'])
|
||||
{
|
||||
for (noteStuf in dumbassSection.sectionNotes)
|
||||
{
|
||||
noteQueue.push(noteStuf);
|
||||
trace(noteStuf);
|
||||
}
|
||||
}
|
||||
|
||||
funnyWave = new PolygonSpectogram(FlxG.sound.music, FlxColor.RED, FlxG.height);
|
||||
funnyWave.x = (FlxG.width / 2);
|
||||
funnyWave.realtimeVisLenght = 0.6;
|
||||
add(funnyWave);
|
||||
|
||||
noteSpawner = new FlxTypedGroup<FlxSprite>();
|
||||
add(noteSpawner);
|
||||
|
||||
makeNotes();
|
||||
|
||||
nextHitTmr = new FlxSprite((FlxG.width / 2) - 5).makeGraphic(10, FlxG.height, FlxColor.BLACK);
|
||||
add(nextHitTmr);
|
||||
|
||||
var trailShit:FlxTrail = new FlxTrail(nextHitTmr);
|
||||
add(trailShit);
|
||||
|
||||
pico = new Fighter(0, 300, "pico-fighter");
|
||||
add(pico);
|
||||
|
||||
darnell = new Fighter(0, 300, "darnell-fighter");
|
||||
add(darnell);
|
||||
|
||||
darnellGhost = new Fighter(0, 300, "darnell-fighter");
|
||||
darnellGhost.alpha = 0.5;
|
||||
add(darnellGhost);
|
||||
|
||||
mid = (FlxG.width / 2) - (pico.width / 2);
|
||||
resetPositions();
|
||||
|
||||
// fuk u, hardcoded bullshit bitch
|
||||
|
||||
super.create();
|
||||
}
|
||||
|
||||
function makeNotes()
|
||||
{
|
||||
for (notes in noteQueue)
|
||||
{
|
||||
if (notes.strumTime < Conductor.songPosition + (Conductor.crochet * 4))
|
||||
{
|
||||
spawnNote(notes);
|
||||
spawnNote(notes, FlxDirectionFlags.RIGHT);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function spawnNote(note:NoteData, facing:Int = FlxDirectionFlags.LEFT)
|
||||
{
|
||||
var spr:FlxSprite = new FlxSprite(0, (FlxG.height / 2) - 60).makeGraphic(10, 120, Note.codeColors[note.noteData]);
|
||||
spr.ID = Std.int(note.strumTime); // using ID as strum, lol!
|
||||
spr.facing = facing;
|
||||
noteSpawner.add(spr);
|
||||
}
|
||||
|
||||
var mid:Float = (FlxG.width * 0.5) - 200;
|
||||
|
||||
function resetPositions()
|
||||
{
|
||||
resetPicoPos();
|
||||
resetDarnell();
|
||||
}
|
||||
|
||||
function resetPicoPos()
|
||||
{
|
||||
pico.x = mid + pico.width;
|
||||
}
|
||||
|
||||
function resetDarnell()
|
||||
{
|
||||
darnell.x = mid - darnell.width;
|
||||
}
|
||||
|
||||
var prevNoteHit:Float = 0;
|
||||
|
||||
override function update(elapsed:Float)
|
||||
{
|
||||
darnellGhost.x = darnell.x;
|
||||
|
||||
Conductor.songPosition = FlxG.sound.music.time;
|
||||
|
||||
funnyWave.thickness = CoolUtil.coolLerp(funnyWave.thickness, 2, 0.5);
|
||||
funnyWave.waveAmplitude = Std.int(CoolUtil.coolLerp(funnyWave.waveAmplitude, 100, 0.1));
|
||||
funnyWave.realtimeVisLenght = CoolUtil.coolLerp(funnyWave.realtimeVisLenght, 0.6, 0.1);
|
||||
|
||||
noteSpawner.forEachAlive((nt:FlxSprite) ->
|
||||
{
|
||||
// i forget how to make rhythm games
|
||||
nt.x = (nt.ID - Conductor.songPosition) * (nt.ID / (Conductor.songPosition * 0.8));
|
||||
|
||||
if (nt.facing == FlxDirectionFlags.RIGHT)
|
||||
{
|
||||
nt.x = FlxMath.remapToRange(nt.x, 0, FlxG.width, FlxG.width, 0);
|
||||
nt.x -= FlxG.width / 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
nt.x += FlxG.width / 2;
|
||||
}
|
||||
|
||||
nt.scale.x = FlxMath.remapToRange(nt.ID - Conductor.songPosition, 0, Conductor.crochet * 3, 0.2, 2);
|
||||
nt.scale.y = FlxMath.remapToRange((nt.ID - Conductor.songPosition), 0, Conductor.crochet * 2, 6, 0.2);
|
||||
|
||||
if (nt.ID < Conductor.songPosition)
|
||||
nt.kill();
|
||||
});
|
||||
|
||||
if (noteQueue.length > 0)
|
||||
{
|
||||
nextHitTmr.scale.y = FlxMath.remapToRange(Conductor.songPosition, prevNoteHit, noteQueue[0].strumTime, 1, 0);
|
||||
|
||||
darnellGhost.scale.x = darnellGhost.scale.y = FlxMath.remapToRange(Conductor.songPosition, prevNoteHit, noteQueue[0].strumTime, 2, 1);
|
||||
darnellGhost.alpha = FlxMath.remapToRange(Conductor.songPosition, prevNoteHit, noteQueue[0].strumTime, 0.3, 0.1);
|
||||
|
||||
if (Conductor.songPosition >= noteQueue[0].strumTime)
|
||||
{
|
||||
prevNoteHit = noteQueue[0].strumTime;
|
||||
|
||||
noteQueue.shift();
|
||||
|
||||
darnell.doSomething(darnellGhost.curAction);
|
||||
|
||||
darnellGhost.doSomething();
|
||||
darnellGhost.animation.curAnim.frameRate = 12;
|
||||
}
|
||||
}
|
||||
|
||||
if (controls.NOTE_LEFT_P)
|
||||
{
|
||||
pico.punch();
|
||||
}
|
||||
if (controls.NOTE_LEFT_R)
|
||||
pico.playAnimation('idle');
|
||||
|
||||
super.update(elapsed);
|
||||
}
|
||||
|
||||
override function stepHit():Bool
|
||||
{
|
||||
return super.stepHit();
|
||||
}
|
||||
|
||||
override function beatHit():Bool
|
||||
{
|
||||
// super.beatHit() returns false if a module cancelled the event.
|
||||
if (!super.beatHit())
|
||||
return false;
|
||||
|
||||
funnyWave.thickness = 10;
|
||||
funnyWave.waveAmplitude = 300;
|
||||
funnyWave.realtimeVisLenght = 0.1;
|
||||
|
||||
picoHealth += 1;
|
||||
|
||||
makeNotes();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -27,6 +27,7 @@ import funkin.play.Strumline.StrumlineArrow;
|
|||
import funkin.play.Strumline.StrumlineStyle;
|
||||
import funkin.play.character.BaseCharacter;
|
||||
import funkin.play.character.CharacterData;
|
||||
import funkin.play.event.SongEvent;
|
||||
import funkin.play.scoring.Scoring;
|
||||
import funkin.play.song.Song;
|
||||
import funkin.play.song.SongData.SongNoteData;
|
||||
|
|
@ -162,6 +163,8 @@ class PlayState extends MusicBeatState
|
|||
*/
|
||||
private var inactiveNotes:Array<Note>;
|
||||
|
||||
private var songEvents:Array<SongEvent>;
|
||||
|
||||
/**
|
||||
* If true, the player is allowed to pause the game.
|
||||
* Disabled during the ending of a song.
|
||||
|
|
@ -279,7 +282,6 @@ class PlayState extends MusicBeatState
|
|||
var perfectMode:Bool = false;
|
||||
var previousFrameTime:Int = 0;
|
||||
var songTime:Float = 0;
|
||||
var cameraRightSide:Bool = false;
|
||||
|
||||
#if discord_rpc
|
||||
// Discord RPC variables
|
||||
|
|
@ -306,6 +308,12 @@ class PlayState extends MusicBeatState
|
|||
|
||||
instance = this;
|
||||
|
||||
if (currentSong_NEW != null)
|
||||
{
|
||||
// TODO: Do this in the loading state.
|
||||
currentSong_NEW.cacheCharts(true);
|
||||
}
|
||||
|
||||
// Displays the camera follow point as a sprite for debug purposes.
|
||||
// TODO: Put this on a toggle?
|
||||
cameraFollowPoint.makeGraphic(8, 8, 0xFF00FF00);
|
||||
|
|
@ -1172,6 +1180,10 @@ class PlayState extends MusicBeatState
|
|||
|
||||
function regenNoteData_NEW():Void
|
||||
{
|
||||
// Reset song events.
|
||||
songEvents = currentChart.getEvents();
|
||||
SongEventHandler.resetEvents(songEvents);
|
||||
|
||||
// Destroy inactive notes.
|
||||
inactiveNotes = [];
|
||||
|
||||
|
|
@ -1727,6 +1739,16 @@ class PlayState extends MusicBeatState
|
|||
});
|
||||
}
|
||||
|
||||
if (songEvents != null && songEvents.length > 0)
|
||||
{
|
||||
var songEventsToActivate:Array<SongEvent> = SongEventHandler.queryEvents(songEvents, Conductor.songPosition);
|
||||
|
||||
if (songEventsToActivate.length > 0)
|
||||
trace('[EVENTS] Found ${songEventsToActivate.length} event(s) to activate.');
|
||||
|
||||
SongEventHandler.activateEvents(songEventsToActivate);
|
||||
}
|
||||
|
||||
if (!isInCutscene)
|
||||
keyShit(true);
|
||||
}
|
||||
|
|
@ -1915,38 +1937,63 @@ class PlayState extends MusicBeatState
|
|||
comboPopUps.displayCombo(combo);
|
||||
}
|
||||
|
||||
function controlCamera()
|
||||
{
|
||||
if (currentStage == null)
|
||||
return;
|
||||
|
||||
var isFocusedOnDad = cameraFollowPoint.x == currentStage.getDad().cameraFocusPoint.x;
|
||||
var isFocusedOnBF = cameraFollowPoint.x == currentStage.getBoyfriend().cameraFocusPoint.x;
|
||||
|
||||
if (cameraRightSide && !isFocusedOnBF)
|
||||
/*
|
||||
function controlCamera()
|
||||
{
|
||||
// Focus the camera on the player.
|
||||
cameraFollowPoint.setPosition(currentStage.getBoyfriend().cameraFocusPoint.x, currentStage.getBoyfriend().cameraFocusPoint.y);
|
||||
if (currentStage == null)
|
||||
return;
|
||||
|
||||
// TODO: Un-hardcode this.
|
||||
if (currentSong.song.toLowerCase() == 'tutorial')
|
||||
FlxTween.tween(FlxG.camera, {zoom: 1 * FlxCamera.defaultZoom}, (Conductor.stepCrochet * 4 / 1000), {ease: FlxEase.elasticInOut});
|
||||
}
|
||||
else if (!cameraRightSide && !isFocusedOnDad)
|
||||
{
|
||||
// Focus the camera on the opponent.
|
||||
cameraFollowPoint.setPosition(currentStage.getDad().cameraFocusPoint.x, currentStage.getDad().cameraFocusPoint.y);
|
||||
|
||||
// TODO: Un-hardcode this stuff.
|
||||
if (currentStage.getDad().characterId == 'mom')
|
||||
switch (cameraFocusCharacter)
|
||||
{
|
||||
vocals.volume = 1;
|
||||
default: // null = No change
|
||||
break;
|
||||
case 0: // Boyfriend
|
||||
var isFocusedOnBF = cameraFollowPoint.x == currentStage.getBoyfriend().cameraFocusPoint.x;
|
||||
if (!isFocusedOnBF)
|
||||
{
|
||||
// Focus the camera on the player.
|
||||
cameraFollowPoint.setPosition(currentStage.getBoyfriend().cameraFocusPoint.x, currentStage.getBoyfriend().cameraFocusPoint.y);
|
||||
}
|
||||
case 1: // Dad
|
||||
var isFocusedOnDad = cameraFollowPoint.x == currentStage.getDad().cameraFocusPoint.x;
|
||||
if (!isFocusedOnDad)
|
||||
{
|
||||
cameraFollowPoint.setPosition(currentStage.getDad().cameraFocusPoint.x, currentStage.getDad().cameraFocusPoint.y);
|
||||
}
|
||||
case 2: // Girlfriend
|
||||
var isFocusedOnGF = cameraFollowPoint.x == currentStage.getGirlfriend().cameraFocusPoint.x;
|
||||
if (!isFocusedOnGF)
|
||||
{
|
||||
cameraFollowPoint.setPosition(currentStage.getGirlfriend().cameraFocusPoint.x, currentStage.getGirlfriend().cameraFocusPoint.y);
|
||||
}
|
||||
}
|
||||
|
||||
if (currentSong.song.toLowerCase() == 'tutorial')
|
||||
tweenCamIn();
|
||||
}
|
||||
}
|
||||
/*
|
||||
if (cameraRightSide && !isFocusedOnBF)
|
||||
{
|
||||
// Focus the camera on the player.
|
||||
cameraFollowPoint.setPosition(currentStage.getBoyfriend().cameraFocusPoint.x, currentStage.getBoyfriend().cameraFocusPoint.y);
|
||||
|
||||
// TODO: Un-hardcode this.
|
||||
if (currentSong.song.toLowerCase() == 'tutorial')
|
||||
FlxTween.tween(FlxG.camera, {zoom: 1 * FlxCamera.defaultZoom}, (Conductor.stepCrochet * 4 / 1000), {ease: FlxEase.elasticInOut});
|
||||
}
|
||||
else if (!cameraRightSide && !isFocusedOnDad)
|
||||
{
|
||||
// Focus the camera on the opponent.
|
||||
cameraFollowPoint.setPosition(currentStage.getDad().cameraFocusPoint.x, currentStage.getDad().cameraFocusPoint.y);
|
||||
|
||||
// TODO: Un-hardcode this stuff.
|
||||
if (currentStage.getDad().characterId == 'mom')
|
||||
{
|
||||
vocals.volume = 1;
|
||||
}
|
||||
|
||||
if (currentSong.song.toLowerCase() == 'tutorial')
|
||||
tweenCamIn();
|
||||
}
|
||||
*/
|
||||
// }
|
||||
|
||||
public function keyShit(test:Bool):Void
|
||||
{
|
||||
|
|
@ -2193,6 +2240,7 @@ class PlayState extends MusicBeatState
|
|||
|
||||
if (generatedMusic)
|
||||
{
|
||||
// TODO: Sort more efficiently, or less often, to improve performance.
|
||||
activeNotes.sort(SortUtil.byStrumtime, FlxSort.DESCENDING);
|
||||
}
|
||||
|
||||
|
|
@ -2201,8 +2249,7 @@ class PlayState extends MusicBeatState
|
|||
{
|
||||
if (generatedMusic && SongLoad.getSong()[Std.int(Conductor.currentStep / 16)] != null)
|
||||
{
|
||||
cameraRightSide = SongLoad.getSong()[Std.int(Conductor.currentStep / 16)].mustHitSection;
|
||||
controlCamera();
|
||||
// cameraRightSide = SongLoad.getSong()[Std.int(Conductor.currentStep / 16)].mustHitSection;
|
||||
}
|
||||
|
||||
if (SongLoad.getSong()[Math.floor(Conductor.currentStep / 16)] != null)
|
||||
|
|
@ -2215,6 +2262,9 @@ class PlayState extends MusicBeatState
|
|||
}
|
||||
}
|
||||
|
||||
// Manage the camera focus, if necessary.
|
||||
// controlCamera();
|
||||
|
||||
// HARDCODING FOR MILF ZOOMS!
|
||||
|
||||
if (PreferencesMenu.getPref('camera-zoom'))
|
||||
|
|
|
|||
|
|
@ -64,8 +64,8 @@ class VanillaCutscenes
|
|||
FlxTween.tween(FlxG.camera, {zoom: PlayState.defaultCameraZoom}, (Conductor.crochet / 1000) * 5, {ease: FlxEase.quadInOut});
|
||||
@:privateAccess
|
||||
PlayState.instance.startCountdown();
|
||||
@:privateAccess
|
||||
PlayState.instance.controlCamera();
|
||||
// @:privateAccess
|
||||
// PlayState.instance.controlCamera();
|
||||
}
|
||||
|
||||
public static function playHorrorStartCutscene()
|
||||
|
|
|
|||
282
source/funkin/play/event/SongEvent.hx
Normal file
282
source/funkin/play/event/SongEvent.hx
Normal file
|
|
@ -0,0 +1,282 @@
|
|||
package funkin.play.event;
|
||||
|
||||
import flixel.FlxSprite;
|
||||
import funkin.play.PlayState;
|
||||
import funkin.play.song.SongData.RawSongEventData;
|
||||
import haxe.DynamicAccess;
|
||||
|
||||
typedef RawSongEvent =
|
||||
{
|
||||
> RawSongEventData,
|
||||
|
||||
/**
|
||||
* Whether the event has been activated or not.
|
||||
*/
|
||||
var a:Bool;
|
||||
}
|
||||
|
||||
@:forward
|
||||
abstract SongEvent(RawSongEvent)
|
||||
{
|
||||
public function new(time:Float, event:String, value:Dynamic = null)
|
||||
{
|
||||
this = {
|
||||
t: time,
|
||||
e: event,
|
||||
v: value,
|
||||
a: false
|
||||
};
|
||||
}
|
||||
|
||||
public var time(get, set):Float;
|
||||
|
||||
public function get_time():Float
|
||||
{
|
||||
return this.t;
|
||||
}
|
||||
|
||||
public function set_time(value:Float):Float
|
||||
{
|
||||
return this.t = value;
|
||||
}
|
||||
|
||||
public var event(get, set):String;
|
||||
|
||||
public function get_event():String
|
||||
{
|
||||
return this.e;
|
||||
}
|
||||
|
||||
public function set_event(value:String):String
|
||||
{
|
||||
return this.e = value;
|
||||
}
|
||||
|
||||
public var value(get, set):Dynamic;
|
||||
|
||||
public function get_value():Dynamic
|
||||
{
|
||||
return this.v;
|
||||
}
|
||||
|
||||
public function set_value(value:Dynamic):Dynamic
|
||||
{
|
||||
return this.v = value;
|
||||
}
|
||||
|
||||
public inline function getBool():Bool
|
||||
{
|
||||
return cast this.v;
|
||||
}
|
||||
|
||||
public inline function getInt():Int
|
||||
{
|
||||
return cast this.v;
|
||||
}
|
||||
|
||||
public inline function getFloat():Float
|
||||
{
|
||||
return cast this.v;
|
||||
}
|
||||
|
||||
public inline function getString():String
|
||||
{
|
||||
return cast this.v;
|
||||
}
|
||||
|
||||
public inline function getArray():Array<Dynamic>
|
||||
{
|
||||
return cast this.v;
|
||||
}
|
||||
|
||||
public inline function getMap():DynamicAccess<Dynamic>
|
||||
{
|
||||
return cast this.v;
|
||||
}
|
||||
|
||||
public inline function getBoolArray():Array<Bool>
|
||||
{
|
||||
return cast this.v;
|
||||
}
|
||||
}
|
||||
|
||||
typedef SongEventCallback = SongEvent->Void;
|
||||
|
||||
class SongEventHandler
|
||||
{
|
||||
private static final eventCallbacks:Map<String, SongEventCallback> = new Map<String, SongEventCallback>();
|
||||
|
||||
public static function registerCallback(event:String, callback:SongEventCallback):Void
|
||||
{
|
||||
eventCallbacks.set(event, callback);
|
||||
}
|
||||
|
||||
public static function unregisterCallback(event:String):Void
|
||||
{
|
||||
eventCallbacks.remove(event);
|
||||
}
|
||||
|
||||
public static function clearCallbacks():Void
|
||||
{
|
||||
eventCallbacks.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Register each of the event callbacks provided by the base game.
|
||||
*/
|
||||
public static function registerBaseEventCallbacks():Void
|
||||
{
|
||||
// TODO: Add a system for mods to easily add their own event callbacks.
|
||||
// Should be easy as creating character or stage scripts.
|
||||
registerCallback('FocusCamera', VanillaEventCallbacks.focusCamera);
|
||||
registerCallback('PlayAnimation', VanillaEventCallbacks.playAnimation);
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a list of song events and the current timestamp,
|
||||
* return a list of events that should be activated.
|
||||
*/
|
||||
public static function queryEvents(events:Array<SongEvent>, currentTime:Float):Array<SongEvent>
|
||||
{
|
||||
return events.filter(function(event:SongEvent):Bool
|
||||
{
|
||||
// If the event is already activated, don't activate it again.
|
||||
if (event.a)
|
||||
return false;
|
||||
|
||||
// If the event is in the future, don't activate it.
|
||||
if (event.time > currentTime)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
public static function activateEvents(events:Array<SongEvent>):Void
|
||||
{
|
||||
for (event in events)
|
||||
{
|
||||
activateEvent(event);
|
||||
}
|
||||
}
|
||||
|
||||
public static function activateEvent(event:SongEvent):Void
|
||||
{
|
||||
if (event.a)
|
||||
{
|
||||
trace('Event already activated: ' + event);
|
||||
return;
|
||||
}
|
||||
|
||||
// Prevent the event from being activated again.
|
||||
event.a = true;
|
||||
|
||||
// Perform the action.
|
||||
if (eventCallbacks.exists(event.event))
|
||||
{
|
||||
eventCallbacks.get(event.event)(event);
|
||||
}
|
||||
}
|
||||
|
||||
public static function resetEvents(events:Array<SongEvent>):Void
|
||||
{
|
||||
for (event in events)
|
||||
{
|
||||
resetEvent(event);
|
||||
}
|
||||
}
|
||||
|
||||
public static function resetEvent(event:SongEvent):Void
|
||||
{
|
||||
// TODO: Add a system for mods to easily add their reset callbacks.
|
||||
event.a = false;
|
||||
}
|
||||
}
|
||||
|
||||
class VanillaEventCallbacks
|
||||
{
|
||||
/**
|
||||
* Event Name: "FocusCamera"
|
||||
* Event Value: Int
|
||||
* 0: Focus on the player.
|
||||
* 1: Focus on the opponent.
|
||||
* 2: Focus on the girlfriend.
|
||||
*/
|
||||
public static function focusCamera(event:SongEvent):Void
|
||||
{
|
||||
// Does nothing if there is no PlayState camera or stage.
|
||||
if (PlayState.instance == null || PlayState.instance.currentStage == null)
|
||||
return;
|
||||
|
||||
switch (event.getInt())
|
||||
{
|
||||
case 0: // Boyfriend
|
||||
// Focus the camera on the player.
|
||||
trace('[EVENT] Focusing camera on player.');
|
||||
PlayState.instance.cameraFollowPoint.setPosition(PlayState.instance.currentStage.getBoyfriend().cameraFocusPoint.x,
|
||||
PlayState.instance.currentStage.getBoyfriend().cameraFocusPoint.y);
|
||||
case 1: // Dad
|
||||
// Focus the camera on the dad.
|
||||
trace('[EVENT] Focusing camera on dad.');
|
||||
PlayState.instance.cameraFollowPoint.setPosition(PlayState.instance.currentStage.getDad().cameraFocusPoint.x,
|
||||
PlayState.instance.currentStage.getDad().cameraFocusPoint.y);
|
||||
case 2: // Girlfriend
|
||||
// Focus the camera on the girlfriend.
|
||||
trace('[EVENT] Focusing camera on girlfriend.');
|
||||
PlayState.instance.cameraFollowPoint.setPosition(PlayState.instance.currentStage.getGirlfriend().cameraFocusPoint.x,
|
||||
PlayState.instance.currentStage.getGirlfriend().cameraFocusPoint.y);
|
||||
default:
|
||||
trace('[EVENT] Unknown camera focus: ' + event.value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Event Name: "playAnimation"
|
||||
* Event Value: Object
|
||||
* {
|
||||
* target: String, // "player", "dad", "girlfriend", or <stage prop id>
|
||||
* animation: String,
|
||||
* force: Bool // optional
|
||||
* }
|
||||
*/
|
||||
public static function playAnimation(event:SongEvent):Void
|
||||
{
|
||||
// Does nothing if there is no PlayState camera or stage.
|
||||
if (PlayState.instance == null || PlayState.instance.currentStage == null)
|
||||
return;
|
||||
|
||||
var data:Dynamic = event.value;
|
||||
|
||||
var targetName:String = Reflect.field(data, 'target');
|
||||
var anim:String = Reflect.field(data, 'anim');
|
||||
var force:Null<Bool> = Reflect.field(data, 'force');
|
||||
if (force == null)
|
||||
force = false;
|
||||
|
||||
var target:FlxSprite = null;
|
||||
|
||||
switch (targetName)
|
||||
{
|
||||
case 'boyfriend':
|
||||
trace('[EVENT] Playing animation $anim on boyfriend.');
|
||||
target = PlayState.instance.currentStage.getBoyfriend();
|
||||
case 'dad':
|
||||
trace('[EVENT] Playing animation $anim on dad.');
|
||||
target = PlayState.instance.currentStage.getDad();
|
||||
case 'girlfriend':
|
||||
trace('[EVENT] Playing animation $anim on girlfriend.');
|
||||
target = PlayState.instance.currentStage.getGirlfriend();
|
||||
default:
|
||||
target = PlayState.instance.currentStage.getNamedProp(targetName);
|
||||
if (target == null)
|
||||
trace('[EVENT] Unknown animation target: $targetName');
|
||||
else
|
||||
trace('[EVENT] Fetched animation target $targetName from stage.');
|
||||
}
|
||||
|
||||
if (target != null)
|
||||
{
|
||||
target.animation.play(anim, force);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
package funkin.play.song;
|
||||
|
||||
import funkin.VoicesGroup;
|
||||
import funkin.play.event.SongEvent;
|
||||
import funkin.play.song.SongData.SongChartData;
|
||||
import funkin.play.song.SongData.SongDataParser;
|
||||
import funkin.play.song.SongData.SongEventData;
|
||||
|
|
@ -42,9 +43,6 @@ class Song // implements IPlayStateScriptedClass
|
|||
}
|
||||
|
||||
populateFromMetadata();
|
||||
|
||||
// TODO: Disable later.
|
||||
cacheCharts();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -89,8 +87,13 @@ class Song // implements IPlayStateScriptedClass
|
|||
/**
|
||||
* Parse and cache the chart for all difficulties of this song.
|
||||
*/
|
||||
public function cacheCharts():Void
|
||||
public function cacheCharts(?force:Bool = false):Void
|
||||
{
|
||||
if (force)
|
||||
{
|
||||
clearCharts();
|
||||
}
|
||||
|
||||
trace('Caching ${variations.length} chart files for song $songId');
|
||||
for (variation in variations)
|
||||
{
|
||||
|
|
@ -158,6 +161,16 @@ class SongDifficulty
|
|||
*/
|
||||
public final variation:String;
|
||||
|
||||
/**
|
||||
* The note chart for this difficulty.
|
||||
*/
|
||||
public var notes:Array<SongNoteData>;
|
||||
|
||||
/**
|
||||
* The event chart for this difficulty.
|
||||
*/
|
||||
public var events:Array<SongEventData>;
|
||||
|
||||
public var songName:String = SongValidator.DEFAULT_SONGNAME;
|
||||
public var songArtist:String = SongValidator.DEFAULT_ARTIST;
|
||||
public var timeFormat:SongTimeFormat = SongValidator.DEFAULT_TIMEFORMAT;
|
||||
|
|
@ -172,9 +185,6 @@ class SongDifficulty
|
|||
|
||||
public var scrollSpeed:Float = SongValidator.DEFAULT_SCROLLSPEED;
|
||||
|
||||
public var notes:Array<SongNoteData>;
|
||||
public var events:Array<SongEventData>;
|
||||
|
||||
public function new(song:Song, diffId:String, variation:String)
|
||||
{
|
||||
this.song = song;
|
||||
|
|
@ -202,6 +212,11 @@ class SongDifficulty
|
|||
return chars.get(id);
|
||||
}
|
||||
|
||||
public function getEvents():Array<SongEvent>
|
||||
{
|
||||
return cast events;
|
||||
}
|
||||
|
||||
public inline function cacheInst()
|
||||
{
|
||||
FlxG.sound.cache(Paths.inst(this.song.songId));
|
||||
|
|
|
|||
|
|
@ -471,11 +471,6 @@ abstract SongEventData(RawSongEventData)
|
|||
return cast this.v;
|
||||
}
|
||||
|
||||
public inline function getMap():DynamicAccess<Dynamic>
|
||||
{
|
||||
return cast this.v;
|
||||
}
|
||||
|
||||
public inline function getBoolArray():Array<Bool>
|
||||
{
|
||||
return cast this.v;
|
||||
|
|
|
|||
Loading…
Reference in a new issue