Add multiple new callbacks for Freeplay and Character Select

This commit is contained in:
AbnormalPoof
2025-10-07 20:08:51 -05:00
committed by Abnormal
parent 71b4a58cab
commit cdb3acc691
10 changed files with 405 additions and 5 deletions
+57
View File
@@ -176,6 +176,63 @@ interface IPlayStateScriptedClass extends INoteScriptedClass extends IBPMSyncedS
public function onCountdownEnd(event:CountdownScriptEvent):Void;
}
/**
* Defines a set of callbacks activated in Freeplay.
*/
interface IFreeplayScriptedClass extends IScriptedClass
{
/**
* Called when a capsule is selected.
*/
public function onCapsuleSelected(event:CapsuleScriptEvent):Void;
/**
* Called when the current difficulty is changed.
*/
public function onDifficultySwitch(event:CapsuleScriptEvent):Void;
/**
* Called when a song is selected.
*/
public function onSongSelected(event:CapsuleScriptEvent):Void;
/**
* Called when the intro for Freeplay finishes.
*/
public function onFreeplayIntroDone(event:FreeplayScriptEvent):Void;
/**
* Called when the Freeplay outro begins.
*/
public function onFreeplayOutro(event:FreeplayScriptEvent):Void;
/**
* Called when Freeplay is closed.
*/
public function onFreeplayClose(event:FreeplayScriptEvent):Void;
}
/**
* Defines a set of callbacks activated in Character Select.
*/
interface ICharacterSelectScriptedClass extends IScriptedClass
{
/**
* Called when a character is selected.
*/
public function onCharacterSelect(event:CharacterSelectScriptEvent):Void;
/**
* Called when the user presses BACK after confirming a character.
*/
public function onCharacterDeselect(event:CharacterSelectScriptEvent):Void;
/**
* Called when a character has been confirmed.
*/
public function onCharacterConfirm(event:CharacterSelectScriptEvent):Void;
}
/**
* Defines a set of callbacks activated during a dialogue conversation.
*/
@@ -9,6 +9,7 @@ import funkin.play.notes.SustainTrail;
import funkin.play.cutscene.dialogue.Conversation;
import funkin.play.Countdown.CountdownStep;
import funkin.play.notes.NoteDirection;
import funkin.ui.freeplay.SongMenuItem;
import openfl.events.KeyboardEvent;
/**
@@ -518,6 +519,78 @@ class FocusScriptEvent extends ScriptEvent
}
}
/**
* An event that is fired when a capsule is selected.
*/
class CapsuleScriptEvent extends ScriptEvent
{
/**
* The capsule that was selected.
*/
public var capsule(default, null):SongMenuItem;
/**
* The difficulty ID of the selected song.
*/
public var difficultyId(default, null):String;
/**
* The variation ID of the selected song.
*/
public var variationId(default, null):String;
public function new(type:ScriptEventType, capsule:SongMenuItem, difficultyId:String, variationId:String):Void
{
super(type, false);
this.capsule = capsule;
this.difficultyId = difficultyId;
this.variationId = variationId;
}
public override function toString():String
{
return 'CapsuleScriptEvent(type=' + type + ')';
}
}
/**
* An event that is fired when Freeplay is entered or exited.
*/
class FreeplayScriptEvent extends ScriptEvent
{
public function new(type:ScriptEventType):Void
{
super(type, false);
}
public override function toString():String
{
return 'FreeplayScriptEvent(type=' + type + ')';
}
}
/**
* An event that is fired when a character is selected or deselected.
*/
class CharacterSelectScriptEvent extends ScriptEvent
{
/**
* The character ID of the selected character.
*/
public var characterId(default, null):String;
public function new(type:ScriptEventType, characterId:String):Void
{
super(type, false);
this.characterId = characterId;
}
public override function toString():String
{
return 'CharacterSelectScriptEvent(type=' + type + ')';
}
}
/**
* An event that is fired when moving out of or into an FlxSubState.
*/
@@ -204,6 +204,51 @@ class ScriptEventDispatcher
return;
}
if (Std.isOfType(target, IFreeplayScriptedClass))
{
var t:IFreeplayScriptedClass = cast target;
switch (event.type)
{
case CAPSULE_SELECTED:
t.onCapsuleSelected(cast event);
return;
case DIFFICULTY_SWITCH:
t.onDifficultySwitch(cast event);
return;
case SONG_SELECTED:
t.onSongSelected(cast event);
return;
case FREEPLAY_INTRO:
t.onFreeplayIntroDone(cast event);
return;
case FREEPLAY_OUTRO:
t.onFreeplayOutro(cast event);
return;
case FREEPLAY_CLOSE:
t.onFreeplayClose(cast event);
return;
default: // Continue;
}
}
if (Std.isOfType(target, ICharacterSelectScriptedClass))
{
var t:ICharacterSelectScriptedClass = cast target;
switch (event.type)
{
case CHARACTER_SELECTED:
t.onCharacterSelect(cast event);
return;
case CHARACTER_DESELECTED:
t.onCharacterDeselect(cast event);
return;
case CHARACTER_CONFIRMED:
t.onCharacterConfirm(cast event);
return;
default: // Continue;
}
}
// If you get a crash on this line, that means ERIC FUCKED UP!
// throw 'No function called for event type: ${event.type}';
}
@@ -254,6 +254,69 @@ enum abstract ScriptEventType(String) from String to String
*/
var FOCUS_LOST = 'FOCUS_LOST';
/**
* Called when a freeplay capsule is selected.
*
* This event is not cancelable.
*/
var CAPSULE_SELECTED = 'CAPSULE_SELECTED';
/**
* Called when the current difficulty in Freeplay is changed.
*
* This event is not cancelable.
*/
var DIFFICULTY_SWITCH = 'DIFFICULTY_SWITCH';
/**
* Called when a song is selected in Freeplay.
*
* This event is not cancelable.
*/
var SONG_SELECTED = 'SONG_SELECTED';
/**
* Called when the intro for Freeplay finishes.
*
* This event is not cancelable.
*/
var FREEPLAY_INTRO = 'FREEPLAY_INTRO';
/**
* Called when the outro for Freeplay starts.
*
* This event is not cancelable.
*/
var FREEPLAY_OUTRO = 'FREEPLAY_OUTRO';
/**
* Called when Freeplay is closed.
*
* This event is not cancelable.
*/
var FREEPLAY_CLOSE = 'FREEPLAY_CLOSE';
/**
* Called when a character is selected, but not confirmed, in Character Select.
*
* This event is not cancelable.
*/
var CHARACTER_SELECTED = 'CHARACTER_SELECTED';
/**
* Called when a character is deselected in Character Select.
*
* This event is not cancelable.
*/
var CHARACTER_DESELECTED = 'CHARACTER_DESELECTED';
/**
* Called when a character is confirmed in Character Select.
*
* This event is not cancelable.
*/
var CHARACTER_CONFIRMED = 'CHARACTER_CONFIRMED';
/**
* Called when the game starts a conversation.
*
+51 -2
View File
@@ -2,6 +2,8 @@ package funkin.modding.module;
import funkin.modding.IScriptedClass.IPlayStateScriptedClass;
import funkin.modding.IScriptedClass.IStateChangingScriptedClass;
import funkin.modding.IScriptedClass.IFreeplayScriptedClass;
import funkin.modding.IScriptedClass.ICharacterSelectScriptedClass;
import funkin.modding.events.ScriptEvent;
/**
@@ -21,7 +23,8 @@ typedef ModuleParams =
* You may have the module active at all times, or only when another script enables it.
*/
@:nullSafety
class Module implements IPlayStateScriptedClass implements IStateChangingScriptedClass
class Module implements IPlayStateScriptedClass implements IStateChangingScriptedClass implements IFreeplayScriptedClass
implements ICharacterSelectScriptedClass
{
/**
* Whether the module is currently active.
@@ -74,7 +77,7 @@ class Module implements IPlayStateScriptedClass implements IStateChangingScripte
}
}
public function toString()
public function toString():String
{
return 'Module(' + this.moduleId + ')';
}
@@ -234,8 +237,54 @@ class Module implements IPlayStateScriptedClass implements IStateChangingScripte
* Called when the song has been restarted.
*/
public function onSongRetry(event:SongRetryEvent) {}
/**
* Called when any state is created.
*/
public function onStateCreate(event:ScriptEvent) {}
/**
* Called when a capsule is selected.
*/
public function onCapsuleSelected(event:CapsuleScriptEvent):Void {}
/**
* Called when the current difficulty is changed.
*/
public function onDifficultySwitch(event:CapsuleScriptEvent):Void {}
/**
* Called when a song is selected.
*/
public function onSongSelected(event:CapsuleScriptEvent):Void {}
/**
* Called when the intro for Freeplay finishes.
*/
public function onFreeplayIntroDone(event:FreeplayScriptEvent):Void {}
/**
* Called when the Freeplay outro begins.
*/
public function onFreeplayOutro(event:FreeplayScriptEvent):Void {}
/**
* Called when Freeplay is closed.
*/
public function onFreeplayClose(event:FreeplayScriptEvent):Void {}
/**
* Called when a character is selected.
*/
public function onCharacterSelect(event:CharacterSelectScriptEvent):Void {}
/**
* Called when the user presses BACK after confirming a character.
*/
public function onCharacterDeselect(event:CharacterSelectScriptEvent):Void {}
/**
* Called when a character has been confirmed.
*/
public function onCharacterConfirm(event:CharacterSelectScriptEvent):Void {}
}
+4 -1
View File
@@ -1200,7 +1200,10 @@ class PlayState extends MusicBeatSubState
Events.logFailSong(currentSong.id, currentVariation);
#end
dispatchEvent(new ScriptEvent(GAME_OVER));
var event:ScriptEvent = new ScriptEvent(GAME_OVER);
dispatchEvent(event);
if (event.eventCanceled) return;
// Disable updates, preventing animations in the background from playing.
persistentUpdate = false;
@@ -932,6 +932,8 @@ class CharSelectSubState extends MusicBeatSubState
cursorConfirmed.visible = false;
grpCursors.visible = true;
dispatchEvent(new CharacterSelectScriptEvent(CHARACTER_DESELECTED, curChar));
FlxTween.globalManager.cancelTweensOf(FlxG.sound.music);
FlxTween.tween(FlxG.sound.music, {pitch: 1.0, volume: 1.0}, 1, {ease: FlxEase.quartInOut});
playerChill.playAnimation("deselect");
@@ -966,6 +968,8 @@ class CharSelectSubState extends MusicBeatSubState
FlxG.sound.play(Paths.sound('CS_confirm'));
dispatchEvent(new CharacterSelectScriptEvent(CHARACTER_CONFIRMED, curChar));
FlxTween.tween(FlxG.sound.music, {pitch: 0.1}, 1, {ease: FlxEase.quadInOut});
FlxTween.tween(FlxG.sound.music, {volume: 0.0}, 1.5, {ease: FlxEase.quadInOut});
playerChill.playAnimation("select");
@@ -1227,6 +1231,8 @@ class CharSelectSubState extends MusicBeatSubState
else
staticSound.stop();
dispatchEvent(new CharacterSelectScriptEvent(CHARACTER_SELECTED, value));
nametag.switchChar(value);
gfChill.visible = false;
playerChill.visible = false;
@@ -712,6 +712,8 @@ class FreeplayState extends MusicBeatSubState
var onDJIntroDone:Void->Void = () -> {
controls.active = true;
dispatchEvent(new FreeplayScriptEvent(FREEPLAY_INTRO));
// when boyfriend hits dat shiii
albumRoll.playIntro();
@@ -863,6 +865,7 @@ class FreeplayState extends MusicBeatSubState
{
super.dispatchEvent(event);
if (backingCard != null) ScriptEventDispatcher.callEvent(backingCard, event);
if (dj != null) ScriptEventDispatcher.callEvent(dj, event);
}
/**
@@ -999,6 +1002,8 @@ class FreeplayState extends MusicBeatSubState
rememberSelection();
changeSelection();
refreshCapsuleDisplays();
dispatchEvent(new CapsuleScriptEvent(DIFFICULTY_SWITCH, currentCapsule, currentDifficulty, currentVariation));
}
/**
@@ -2135,6 +2140,8 @@ class FreeplayState extends MusicBeatSubState
FlxTimer.globalManager.clear();
dj?.onIntroDone.removeAll();
dispatchEvent(new FreeplayScriptEvent(FREEPLAY_OUTRO));
FunkinSound.playOnce(Paths.sound('cancelMenu'));
var longestTimer:Float = 0;
@@ -2195,6 +2202,7 @@ class FreeplayState extends MusicBeatSubState
persist: true
});
FlxG.sound.music.fadeIn(4.0, 0.0, 1.0);
dispatchEvent(new FreeplayScriptEvent(FREEPLAY_CLOSE));
close();
}
else
@@ -2651,6 +2659,8 @@ class FreeplayState extends MusicBeatSubState
letterSort.inputEnabled = false;
#end
dispatchEvent(new CapsuleScriptEvent(SONG_SELECTED, currentCapsule, currentDifficulty, currentVariation));
PlayStatePlaylist.isStoryMode = false;
var targetVariation:Null<String> = currentVariation;
@@ -2877,6 +2887,8 @@ class FreeplayState extends MusicBeatSubState
// Small vibrations every selection change.
if (change != 0) HapticUtil.vibrate(0, 0.01, 0.5);
dispatchEvent(new CapsuleScriptEvent(CAPSULE_SELECTED, currentCapsule, currentDifficulty, currentVariation));
}
public function playCurSongPreview(?daSongCapsule:SongMenuItem):Void
@@ -10,9 +10,11 @@ import funkin.graphics.adobeanimate.FlxAtlasSprite;
import funkin.graphics.FunkinSprite;
import funkin.ui.freeplay.charselect.PlayableCharacter;
import openfl.display.BlendMode;
import funkin.modding.events.ScriptEvent;
import flixel.group.FlxSpriteGroup;
import funkin.modding.IScriptedClass.IBPMSyncedScriptedClass;
import funkin.modding.IScriptedClass.IStateChangingScriptedClass;
import funkin.modding.IScriptedClass.IFreeplayScriptedClass;
import funkin.modding.events.ScriptEvent;
import funkin.ui.FullScreenScaleMode;
import funkin.util.BitmapUtil;
@@ -20,7 +22,7 @@ import funkin.util.BitmapUtil;
/**
* A class for the backing cards so they dont have to be part of freeplayState......
*/
class BackingCard extends FlxSpriteGroup implements IBPMSyncedScriptedClass implements IStateChangingScriptedClass
class BackingCard extends FlxSpriteGroup implements IBPMSyncedScriptedClass implements IStateChangingScriptedClass implements IFreeplayScriptedClass
{
public var backingTextYeah:FlxAtlasSprite;
public var orangeBackShit:FunkinSprite;
@@ -275,6 +277,36 @@ class BackingCard extends FlxSpriteGroup implements IBPMSyncedScriptedClass impl
public function onFocusGained(event:FocusScriptEvent):Void {}
/**
* Called when a capsule is selected.
*/
public function onCapsuleSelected(event:CapsuleScriptEvent):Void {}
/**
* Called when the current difficulty is changed.
*/
public function onDifficultySwitch(event:CapsuleScriptEvent):Void {}
/**
* Called when a song is selected.
*/
public function onSongSelected(event:CapsuleScriptEvent):Void {}
/**
* Called when the intro for Freeplay finishes.
*/
public function onFreeplayIntroDone(event:FreeplayScriptEvent):Void {}
/**
* Called when the Freeplay outro begins.
*/
public function onFreeplayOutro(event:FreeplayScriptEvent):Void {}
/**
* Called when Freeplay is closed.
*/
public function onFreeplayClose(event:FreeplayScriptEvent):Void {}
public function centerObjectOnCard(object:flixel.FlxObject)
{
if (pinkBack != null) object.x = (x + ((pinkBack.width - object.width) / 2)) * 0.74;
+61 -1
View File
@@ -9,6 +9,8 @@ import funkin.audio.FunkinSound;
import funkin.data.freeplay.player.PlayerRegistry;
import funkin.data.freeplay.player.PlayerData.PlayerFreeplayDJData;
import funkin.util.assets.FlxAnimationUtil;
import funkin.modding.events.ScriptEvent;
import funkin.modding.IScriptedClass.IFreeplayScriptedClass;
enum FreeplayDJState
{
@@ -62,7 +64,7 @@ enum FreeplayDJState
}
@:nullSafety
class BaseFreeplayDJ extends FlxAtlasSprite
class BaseFreeplayDJ extends FlxAtlasSprite implements IFreeplayScriptedClass
{
public var IDLE_EGG_PERIOD:Float = 60.0;
public var IDLE_CARTOON_PERIOD:Float = 120.0;
@@ -238,6 +240,64 @@ class BaseFreeplayDJ extends FlxAtlasSprite
else
offset.set(0, 0);
}
public function onScriptEvent(event:ScriptEvent) {}
public function onCreate(event:ScriptEvent) {}
public function onDestroy(event:ScriptEvent):Void {}
public function onUpdate(event:UpdateScriptEvent):Void {}
public function onStepHit(event:SongTimeScriptEvent):Void {}
public function onBeatHit(event:SongTimeScriptEvent):Void {}
public function onStateChangeBegin(event:StateChangeScriptEvent):Void {}
public function onStateChangeEnd(event:StateChangeScriptEvent):Void {}
public function onSubStateOpenBegin(event:SubStateScriptEvent):Void {}
public function onSubStateOpenEnd(event:SubStateScriptEvent):Void {}
public function onSubStateCloseBegin(event:SubStateScriptEvent):Void {}
public function onSubStateCloseEnd(event:SubStateScriptEvent):Void {}
public function onFocusLost(event:FocusScriptEvent):Void {}
public function onFocusGained(event:FocusScriptEvent):Void {}
/**
* Called when a capsule is selected.
*/
public function onCapsuleSelected(event:CapsuleScriptEvent):Void {}
/**
* Called when the current difficulty is changed.
*/
public function onDifficultySwitch(event:CapsuleScriptEvent):Void {}
/**
* Called when a song is selected.
*/
public function onSongSelected(event:CapsuleScriptEvent):Void {}
/**
* Called when the intro for Freeplay finishes.
*/
public function onFreeplayIntroDone(event:FreeplayScriptEvent):Void {}
/**
* Called when the Freeplay outro begins.
*/
public function onFreeplayOutro(event:FreeplayScriptEvent):Void {}
/**
* Called when Freeplay is closed.
*/
public function onFreeplayClose(event:FreeplayScriptEvent):Void {}
}
// Class for all non-atalas DJ's