diff --git a/assets b/assets index 51b02f0d4..095e91fb3 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit 51b02f0d47e5b34bf8589065c092953c10c5040d +Subproject commit 095e91fb33dad70a5b51e37542e335cedd025d09 diff --git a/source/funkin/modding/IScriptedClass.hx b/source/funkin/modding/IScriptedClass.hx index b009aea41..5f2ff2b9e 100644 --- a/source/funkin/modding/IScriptedClass.hx +++ b/source/funkin/modding/IScriptedClass.hx @@ -56,7 +56,20 @@ interface IStateStageProp extends IScriptedClass */ interface INoteScriptedClass extends IScriptedClass { - public function onNoteHit(event:NoteScriptEvent):Void; + /** + * Called when a note enters the field of view and approaches the strumline. + */ + public function onNoteIncoming(event:NoteScriptEvent):Void; + + /** + * Called when EITHER player hits a note. + * Query the note attached to the event to determine if it was hit by the player or CPU. + */ + public function onNoteHit(event:HitNoteScriptEvent):Void; + + /** + * Called when EITHER player (usually the player) misses a note. + */ public function onNoteMiss(event:NoteScriptEvent):Void; } @@ -73,7 +86,7 @@ interface INoteScriptedClass extends IScriptedClass /** * Defines a set of callbacks available to scripted classes that involve the lifecycle of the Play State. */ -interface IPlayStateScriptedClass extends IScriptedClass +interface IPlayStateScriptedClass extends INoteScriptedClass { /** * Called when the game is paused. @@ -113,17 +126,6 @@ interface IPlayStateScriptedClass extends IScriptedClass */ public function onSongRetry(event:ScriptEvent):Void; - /** - * Called when EITHER player hits a note. - * Query the note attached to the event to determine if it was hit by the player or CPU. - */ - public function onNoteHit(event:NoteScriptEvent):Void; - - /** - * Called when EITHER player (usually the player) misses a note. - */ - public function onNoteMiss(event:NoteScriptEvent):Void; - /** * Called when the player presses a key when no note is on the strumline. */ diff --git a/source/funkin/modding/events/ScriptEventDispatcher.hx b/source/funkin/modding/events/ScriptEventDispatcher.hx index f5d797ea4..fd58d0fad 100644 --- a/source/funkin/modding/events/ScriptEventDispatcher.hx +++ b/source/funkin/modding/events/ScriptEventDispatcher.hx @@ -71,17 +71,29 @@ class ScriptEventDispatcher } } - if (Std.isOfType(target, IPlayStateScriptedClass)) + if (Std.isOfType(target, INoteScriptedClass)) { - var t:IPlayStateScriptedClass = cast(target, IPlayStateScriptedClass); + var t:INoteScriptedClass = cast(target, INoteScriptedClass); switch (event.type) { + case NOTE_INCOMING: + t.onNoteIncoming(cast event); + return; case NOTE_HIT: t.onNoteHit(cast event); return; case NOTE_MISS: t.onNoteMiss(cast event); return; + default: // Continue; + } + } + + if (Std.isOfType(target, IPlayStateScriptedClass)) + { + var t:IPlayStateScriptedClass = cast(target, IPlayStateScriptedClass); + switch (event.type) + { case NOTE_GHOST_MISS: t.onNoteGhostMiss(cast event); return; diff --git a/source/funkin/modding/events/ScriptEventType.hx b/source/funkin/modding/events/ScriptEventType.hx index e06b5ad24..eeeb8ef29 100644 --- a/source/funkin/modding/events/ScriptEventType.hx +++ b/source/funkin/modding/events/ScriptEventType.hx @@ -63,6 +63,13 @@ enum abstract ScriptEventType(String) from String to String */ var SONG_STEP_HIT = 'STEP_HIT'; + /** + * Called when a note comes on screen and starts approaching the strumline. + * + * This event is not cancelable. + */ + var NOTE_INCOMING = 'NOTE_INCOMING'; + /** * Called when a character hits a note. * Important information such as judgement/timing, note data, player/opponent, etc. are all provided. diff --git a/source/funkin/modding/module/Module.hx b/source/funkin/modding/module/Module.hx index f50c9936a..be9b7146b 100644 --- a/source/funkin/modding/module/Module.hx +++ b/source/funkin/modding/module/Module.hx @@ -83,7 +83,9 @@ class Module implements IPlayStateScriptedClass implements IStateChangingScripte public function onGameOver(event:ScriptEvent) {} - public function onNoteHit(event:NoteScriptEvent) {} + public function onNoteIncoming(event:NoteScriptEvent) {} + + public function onNoteHit(event:HitNoteScriptEvent) {} public function onNoteMiss(event:NoteScriptEvent) {} diff --git a/source/funkin/play/PlayState.hx b/source/funkin/play/PlayState.hx index 46c09090d..ab693ef46 100644 --- a/source/funkin/play/PlayState.hx +++ b/source/funkin/play/PlayState.hx @@ -1627,7 +1627,9 @@ class PlayState extends MusicBeatSubState if (noteStyle == null) noteStyle = NoteStyleRegistry.instance.fetchDefault(); playerStrumline = new Strumline(noteStyle, !isBotPlayMode); + playerStrumline.onNoteIncoming.add(onStrumlineNoteIncoming); opponentStrumline = new Strumline(noteStyle, false); + opponentStrumline.onNoteIncoming.add(onStrumlineNoteIncoming); add(playerStrumline); add(opponentStrumline); @@ -1763,6 +1765,13 @@ class PlayState extends MusicBeatSubState opponentStrumline.applyNoteData(opponentNoteData); } + function onStrumlineNoteIncoming(noteSprite:NoteSprite):Void + { + var event:NoteScriptEvent = new NoteScriptEvent(NOTE_INCOMING, noteSprite, 0, false); + + dispatchEvent(event); + } + /** * Prepares to start the countdown. * Ends any running cutscenes, creates the strumlines, and starts the countdown. @@ -1971,7 +1980,7 @@ class PlayState extends MusicBeatSubState // Call an event to allow canceling the note hit. // NOTE: This is what handles the character animations! - var event:NoteScriptEvent = new NoteScriptEvent(NOTE_HIT, note, 0, true); + var event:NoteScriptEvent = new HitNoteScriptEvent(note, 0.0, 0, 'perfect', 0); dispatchEvent(event); // Calling event.cancelEvent() skips all the other logic! Neat! diff --git a/source/funkin/play/character/BaseCharacter.hx b/source/funkin/play/character/BaseCharacter.hx index cf5311bdc..d39f19b76 100644 --- a/source/funkin/play/character/BaseCharacter.hx +++ b/source/funkin/play/character/BaseCharacter.hx @@ -485,7 +485,7 @@ class BaseCharacter extends Bopper * Every time a note is hit, check if the note is from the same strumline. * If it is, then play the sing animation. */ - public override function onNoteHit(event:NoteScriptEvent) + public override function onNoteHit(event:HitNoteScriptEvent) { super.onNoteHit(event); diff --git a/source/funkin/play/notes/Strumline.hx b/source/funkin/play/notes/Strumline.hx index efe1c707a..9a6699c43 100644 --- a/source/funkin/play/notes/Strumline.hx +++ b/source/funkin/play/notes/Strumline.hx @@ -1,5 +1,6 @@ package funkin.play.notes; +import flixel.util.FlxSignal.FlxTypedSignal; import flixel.FlxG; import funkin.play.notes.notestyle.NoteStyle; import flixel.group.FlxSpriteGroup; @@ -53,6 +54,8 @@ class Strumline extends FlxSpriteGroup public var holdNotes:FlxTypedSpriteGroup; + public var onNoteIncoming:FlxTypedSignalVoid>; + var strumlineNotes:FlxTypedSpriteGroup; var noteSplashes:FlxTypedSpriteGroup; var noteHoldCovers:FlxTypedSpriteGroup; @@ -110,6 +113,8 @@ class Strumline extends FlxSpriteGroup this.refresh(); + this.onNoteIncoming = new FlxTypedSignalVoid>(); + for (i in 0...KEY_COUNT) { var child:StrumlineNote = new StrumlineNote(noteStyle, isPlayer, DIRECTIONS[i]); @@ -315,6 +320,8 @@ class Strumline extends FlxSpriteGroup } nextNoteIndex = noteIndex + 1; // Increment the nextNoteIndex rather than splicing the array, because splicing is slow. + + onNoteIncoming.dispatch(noteSprite); } // Update rendering of notes. diff --git a/source/funkin/play/song/Song.hx b/source/funkin/play/song/Song.hx index 61f83d1ed..3997692c2 100644 --- a/source/funkin/play/song/Song.hx +++ b/source/funkin/play/song/Song.hx @@ -364,7 +364,9 @@ class Song implements IPlayStateScriptedClass implements IRegistryEntry