mirror of
https://github.com/FunkinCrew/Funkin.git
synced 2024-11-26 17:46:08 -05:00
Merge branch 'rewrite/master' into bugfix/html5-array-clone
This commit is contained in:
commit
25cb73316c
25 changed files with 230 additions and 82 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -7,3 +7,4 @@ export/
|
|||
RECOVER_*.fla
|
||||
shitAudio/
|
||||
.build_time
|
||||
.swp
|
||||
|
|
48
Project.xml
48
Project.xml
|
@ -22,8 +22,8 @@
|
|||
<set name="BUILD_DIR" value="export/release" unless="debug" />
|
||||
<set name="BUILD_DIR" value="export/32bit" if="32bit" />
|
||||
<classpath name="source" />
|
||||
<assets path="assets/preload" rename="assets" exclude="*.ogg" if="web" />
|
||||
<assets path="assets/preload" rename="assets" exclude="*.mp3" unless="web" />
|
||||
<assets path="assets/preload" rename="assets" exclude="*.ogg|*.wav" if="web" />
|
||||
<assets path="assets/preload" rename="assets" exclude="*.mp3|*.wav" unless="web" />
|
||||
<define name="PRELOAD_ALL" unless="web" />
|
||||
<define name="NO_PRELOAD_ALL" unless="PRELOAD_ALL" />
|
||||
<section if="PRELOAD_ALL">
|
||||
|
@ -53,28 +53,28 @@
|
|||
<library name="weekend1" preload="false" />
|
||||
</section>
|
||||
<library name="art" preload="false" />
|
||||
<assets path="assets/songs" library="songs" exclude="*.fla|*.ogg" if="web" />
|
||||
<assets path="assets/songs" library="songs" exclude="*.fla|*.mp3" unless="web" />
|
||||
<assets path="assets/shared" library="shared" exclude="*.fla|*.ogg" if="web" />
|
||||
<assets path="assets/shared" library="shared" exclude="*.fla|*.mp3" unless="web" />
|
||||
<assets path="assets/tutorial" library="tutorial" exclude="*.fla|*.ogg" if="web" />
|
||||
<assets path="assets/tutorial" library="tutorial" exclude="*.fla|*.mp3" unless="web" />
|
||||
<assets path="assets/week1" library="week1" exclude="*.fla|*.ogg" if="web" />
|
||||
<assets path="assets/week1" library="week1" exclude="*.fla|*.mp3" unless="web" />
|
||||
<assets path="assets/week2" library="week2" exclude="*.fla|*.ogg" if="web" />
|
||||
<assets path="assets/week2" library="week2" exclude="*.fla|*.mp3" unless="web" />
|
||||
<assets path="assets/week3" library="week3" exclude="*.fla|*.ogg" if="web" />
|
||||
<assets path="assets/week3" library="week3" exclude="*.fla|*.mp3" unless="web" />
|
||||
<assets path="assets/week4" library="week4" exclude="*.fla|*.ogg" if="web" />
|
||||
<assets path="assets/week4" library="week4" exclude="*.fla|*.mp3" unless="web" />
|
||||
<assets path="assets/week5" library="week5" exclude="*.fla|*.ogg" if="web" />
|
||||
<assets path="assets/week5" library="week5" exclude="*.fla|*.mp3" unless="web" />
|
||||
<assets path="assets/week6" library="week6" exclude="*.fla|*.ogg" if="web" />
|
||||
<assets path="assets/week6" library="week6" exclude="*.fla|*.mp3" unless="web" />
|
||||
<assets path="assets/week7" library="week7" exclude="*.fla|*.ogg" if="web" />
|
||||
<assets path="assets/week7" library="week7" exclude="*.fla|*.mp3" unless="web" />
|
||||
<assets path="assets/weekend1" library="weekend1" exclude="*.fla|*.ogg" if="web" />
|
||||
<assets path="assets/weekend1" library="weekend1" exclude="*.fla|*.mp3" unless="web" />
|
||||
<assets path="assets/songs" library="songs" exclude="*.fla|*.ogg|*.wav" if="web" />
|
||||
<assets path="assets/songs" library="songs" exclude="*.fla|*.mp3|*.wav" unless="web" />
|
||||
<assets path="assets/shared" library="shared" exclude="*.fla|*.ogg|*.wav" if="web" />
|
||||
<assets path="assets/shared" library="shared" exclude="*.fla|*.mp3|*.wav" unless="web" />
|
||||
<assets path="assets/tutorial" library="tutorial" exclude="*.fla|*.ogg|*.wav" if="web" />
|
||||
<assets path="assets/tutorial" library="tutorial" exclude="*.fla|*.mp3|*.wav" unless="web" />
|
||||
<assets path="assets/week1" library="week1" exclude="*.fla|*.ogg|*.wav" if="web" />
|
||||
<assets path="assets/week1" library="week1" exclude="*.fla|*.mp3|*.wav" unless="web" />
|
||||
<assets path="assets/week2" library="week2" exclude="*.fla|*.ogg|*.wav" if="web" />
|
||||
<assets path="assets/week2" library="week2" exclude="*.fla|*.mp3|*.wav" unless="web" />
|
||||
<assets path="assets/week3" library="week3" exclude="*.fla|*.ogg|*.wav" if="web" />
|
||||
<assets path="assets/week3" library="week3" exclude="*.fla|*.mp3|*.wav" unless="web" />
|
||||
<assets path="assets/week4" library="week4" exclude="*.fla|*.ogg|*.wav" if="web" />
|
||||
<assets path="assets/week4" library="week4" exclude="*.fla|*.mp3|*.wav" unless="web" />
|
||||
<assets path="assets/week5" library="week5" exclude="*.fla|*.ogg|*.wav" if="web" />
|
||||
<assets path="assets/week5" library="week5" exclude="*.fla|*.mp3|*.wav" unless="web" />
|
||||
<assets path="assets/week6" library="week6" exclude="*.fla|*.ogg|*.wav" if="web" />
|
||||
<assets path="assets/week6" library="week6" exclude="*.fla|*.mp3|*.wav" unless="web" />
|
||||
<assets path="assets/week7" library="week7" exclude="*.fla|*.ogg|*.wav" if="web" />
|
||||
<assets path="assets/week7" library="week7" exclude="*.fla|*.mp3|*.wav" unless="web" />
|
||||
<assets path="assets/weekend1" library="weekend1" exclude="*.fla|*.ogg|*.wav" if="web" />
|
||||
<assets path="assets/weekend1" library="weekend1" exclude="*.fla|*.mp3|*.wav" unless="web" />
|
||||
<!-- <assets path='example_mods' rename='mods' embed='false'/> -->
|
||||
<!--
|
||||
AUTOMATICALLY MOVING EXAMPLE MODS INTO THE BUILD CAUSES ISSUES
|
||||
|
|
2
assets
2
assets
|
@ -1 +1 @@
|
|||
Subproject commit 69ebdb6a7aa57b6762ce509243679ab959615120
|
||||
Subproject commit 86248e6c9c64f70349fa7d3055f1df8facab894a
|
|
@ -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.
|
||||
*/
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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) {}
|
||||
|
||||
|
|
|
@ -111,6 +111,11 @@ typedef PlayStateParams =
|
|||
* @default `false`
|
||||
*/
|
||||
?practiceMode:Bool,
|
||||
/**
|
||||
* Whether the song should start in Bot Play Mode.
|
||||
* @default `false`
|
||||
*/
|
||||
?botPlayMode:Bool,
|
||||
/**
|
||||
* Whether the song should be in minimal mode.
|
||||
* @default `false`
|
||||
|
@ -282,6 +287,12 @@ class PlayState extends MusicBeatSubState
|
|||
*/
|
||||
public var isPracticeMode:Bool = false;
|
||||
|
||||
/**
|
||||
* Whether the game is currently in Bot Play Mode.
|
||||
* If true, player will not lose gain or lose score from notes.
|
||||
*/
|
||||
public var isBotPlayMode:Bool = false;
|
||||
|
||||
/**
|
||||
* Whether the player has dropped below zero health,
|
||||
* and we are just waiting for an animation to play out before transitioning.
|
||||
|
@ -566,6 +577,7 @@ class PlayState extends MusicBeatSubState
|
|||
if (params.targetDifficulty != null) currentDifficulty = params.targetDifficulty;
|
||||
if (params.targetVariation != null) currentVariation = params.targetVariation;
|
||||
isPracticeMode = params.practiceMode ?? false;
|
||||
isBotPlayMode = params.botPlayMode ?? false;
|
||||
isMinimalMode = params.minimalMode ?? false;
|
||||
startTimestamp = params.startTimestamp ?? 0.0;
|
||||
playbackRate = params.playbackRate ?? 1.0;
|
||||
|
@ -1020,7 +1032,7 @@ class PlayState extends MusicBeatSubState
|
|||
if (isInCutscene && !disableKeys) handleCutsceneKeys(elapsed);
|
||||
|
||||
// Moving notes into position is now done by Strumline.update().
|
||||
processNotes(elapsed);
|
||||
if (!isInCutscene) processNotes(elapsed);
|
||||
|
||||
justUnpaused = false;
|
||||
}
|
||||
|
@ -1614,8 +1626,10 @@ class PlayState extends MusicBeatSubState
|
|||
var noteStyle:NoteStyle = NoteStyleRegistry.instance.fetchEntry(noteStyleId);
|
||||
if (noteStyle == null) noteStyle = NoteStyleRegistry.instance.fetchDefault();
|
||||
|
||||
playerStrumline = new Strumline(noteStyle, true);
|
||||
playerStrumline = new Strumline(noteStyle, !isBotPlayMode);
|
||||
playerStrumline.onNoteIncoming.add(onStrumlineNoteIncoming);
|
||||
opponentStrumline = new Strumline(noteStyle, false);
|
||||
opponentStrumline.onNoteIncoming.add(onStrumlineNoteIncoming);
|
||||
add(playerStrumline);
|
||||
add(opponentStrumline);
|
||||
|
||||
|
@ -1751,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.
|
||||
|
@ -1876,7 +1897,14 @@ class PlayState extends MusicBeatSubState
|
|||
function updateScoreText():Void
|
||||
{
|
||||
// TODO: Add functionality for modules to update the score text.
|
||||
scoreText.text = 'Score:' + songScore;
|
||||
if (isBotPlayMode)
|
||||
{
|
||||
scoreText.text = 'Bot Play Enabled';
|
||||
}
|
||||
else
|
||||
{
|
||||
scoreText.text = 'Score:' + songScore;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1884,7 +1912,14 @@ class PlayState extends MusicBeatSubState
|
|||
*/
|
||||
function updateHealthBar():Void
|
||||
{
|
||||
healthLerp = FlxMath.lerp(healthLerp, health, 0.15);
|
||||
if (isBotPlayMode)
|
||||
{
|
||||
healthLerp = Constants.HEALTH_MAX;
|
||||
}
|
||||
else
|
||||
{
|
||||
healthLerp = FlxMath.lerp(healthLerp, health, 0.15);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1928,13 +1963,16 @@ class PlayState extends MusicBeatSubState
|
|||
|
||||
if (Conductor.instance.songPosition > hitWindowEnd)
|
||||
{
|
||||
if (note.hasMissed) continue;
|
||||
if (note.hasMissed || note.hasBeenHit) continue;
|
||||
|
||||
note.tooEarly = false;
|
||||
note.mayHit = false;
|
||||
note.hasMissed = true;
|
||||
|
||||
if (note.holdNoteSprite != null) note.holdNoteSprite.missedNote = true;
|
||||
if (note.holdNoteSprite != null)
|
||||
{
|
||||
note.holdNoteSprite.missedNote = true;
|
||||
}
|
||||
}
|
||||
else if (Conductor.instance.songPosition > hitWindowCenter)
|
||||
{
|
||||
|
@ -1942,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!
|
||||
|
@ -2021,10 +2059,38 @@ class PlayState extends MusicBeatSubState
|
|||
|
||||
if (Conductor.instance.songPosition > hitWindowEnd)
|
||||
{
|
||||
if (note.hasMissed || note.hasBeenHit) continue;
|
||||
note.tooEarly = false;
|
||||
note.mayHit = false;
|
||||
note.hasMissed = true;
|
||||
if (note.holdNoteSprite != null) note.holdNoteSprite.missedNote = true;
|
||||
if (note.holdNoteSprite != null)
|
||||
{
|
||||
note.holdNoteSprite.missedNote = true;
|
||||
}
|
||||
}
|
||||
else if (isBotPlayMode && Conductor.instance.songPosition > hitWindowCenter)
|
||||
{
|
||||
if (note.hasBeenHit) continue;
|
||||
|
||||
// We call onHitNote to play the proper animations,
|
||||
// but not goodNoteHit! This means zero score and zero notes hit for the results screen!
|
||||
|
||||
// Call an event to allow canceling the note hit.
|
||||
// NOTE: This is what handles the character animations!
|
||||
var event:NoteScriptEvent = new HitNoteScriptEvent(note, 0.0, 0, 'perfect', 0);
|
||||
dispatchEvent(event);
|
||||
|
||||
// Calling event.cancelEvent() skips all the other logic! Neat!
|
||||
if (event.eventCanceled) continue;
|
||||
|
||||
// Command the bot to hit the note on time.
|
||||
// NOTE: This is what handles the strumline and cleaning up the note itself!
|
||||
playerStrumline.hitNote(note);
|
||||
|
||||
if (note.holdNoteSprite != null)
|
||||
{
|
||||
playerStrumline.playNoteHoldCover(note.holdNoteSprite);
|
||||
}
|
||||
}
|
||||
else if (Conductor.instance.songPosition > hitWindowStart)
|
||||
{
|
||||
|
@ -2069,7 +2135,7 @@ class PlayState extends MusicBeatSubState
|
|||
if (holdNote == null || !holdNote.alive) continue;
|
||||
|
||||
// While the hold note is being hit, and there is length on the hold note...
|
||||
if (holdNote.hitNote && !holdNote.missedNote && holdNote.sustainLength > 0)
|
||||
if (!isBotPlayMode && holdNote.hitNote && !holdNote.missedNote && holdNote.sustainLength > 0)
|
||||
{
|
||||
// Grant the player health.
|
||||
health += Constants.HEALTH_HOLD_BONUS_PER_SECOND * elapsed;
|
||||
|
|
|
@ -347,6 +347,10 @@ class ResultState extends MusicBeatSubState
|
|||
|
||||
if (controls.PAUSE)
|
||||
{
|
||||
FlxTween.tween(FlxG.sound.music, {volume: 0}, 0.8);
|
||||
FlxTween.tween(FlxG.sound.music, {pitch: 3}, 0.1, {onComplete: _ -> {
|
||||
FlxTween.tween(FlxG.sound.music, {pitch: 0.5}, 0.4);
|
||||
}});
|
||||
if (params.storyMode)
|
||||
{
|
||||
openSubState(new funkin.ui.transition.StickerSubState(null, (sticker) -> new StoryMenuState(sticker)));
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -378,12 +378,12 @@ class CharacterDataParser
|
|||
}
|
||||
|
||||
/**
|
||||
* The default time the character should sing for, in beats.
|
||||
* The default time the character should sing for, in steps.
|
||||
* Values that are too low will cause the character to stop singing between notes.
|
||||
* Originally, this value was set to 1, but it was changed to 2 because that became
|
||||
* too low after some other code changes.
|
||||
* Values that are too high will cause the character to hold their singing pose for too long after they're done.
|
||||
* @default `8 steps`
|
||||
*/
|
||||
static final DEFAULT_SINGTIME:Float = 2.0;
|
||||
static final DEFAULT_SINGTIME:Float = 8.0;
|
||||
|
||||
static final DEFAULT_DANCEEVERY:Int = 1;
|
||||
static final DEFAULT_FLIPX:Bool = false;
|
||||
|
|
|
@ -61,7 +61,7 @@ class VideoCutscene
|
|||
VideoCutscene.cutsceneType = cutsceneType;
|
||||
|
||||
#if html5
|
||||
playVideoHTML5(filePath);
|
||||
playVideoHTML5(rawFilePath);
|
||||
#elseif hxCodec
|
||||
playVideoNative(rawFilePath);
|
||||
#else
|
||||
|
|
|
@ -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;
|
||||
|
@ -38,6 +39,10 @@ class Strumline extends FlxSpriteGroup
|
|||
return FlxG.height / 0.45;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether this strumline is controlled by the player's inputs.
|
||||
* False means it's controlled by the opponent or Bot Play.
|
||||
*/
|
||||
public var isPlayer:Bool;
|
||||
|
||||
/**
|
||||
|
@ -49,6 +54,8 @@ class Strumline extends FlxSpriteGroup
|
|||
|
||||
public var holdNotes:FlxTypedSpriteGroup<SustainTrail>;
|
||||
|
||||
public var onNoteIncoming:FlxTypedSignal<NoteSprite->Void>;
|
||||
|
||||
var strumlineNotes:FlxTypedSpriteGroup<StrumlineNote>;
|
||||
var noteSplashes:FlxTypedSpriteGroup<NoteSplash>;
|
||||
var noteHoldCovers:FlxTypedSpriteGroup<NoteHoldCover>;
|
||||
|
@ -106,6 +113,8 @@ class Strumline extends FlxSpriteGroup
|
|||
|
||||
this.refresh();
|
||||
|
||||
this.onNoteIncoming = new FlxTypedSignal<NoteSprite->Void>();
|
||||
|
||||
for (i in 0...KEY_COUNT)
|
||||
{
|
||||
var child:StrumlineNote = new StrumlineNote(noteStyle, isPlayer, DIRECTIONS[i]);
|
||||
|
@ -311,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.
|
||||
|
|
|
@ -364,7 +364,9 @@ class Song implements IPlayStateScriptedClass implements IRegistryEntry<SongMeta
|
|||
|
||||
public function onSongRetry(event:ScriptEvent):Void {};
|
||||
|
||||
public function onNoteHit(event:NoteScriptEvent):Void {};
|
||||
public function onNoteIncoming(event:NoteScriptEvent) {}
|
||||
|
||||
public function onNoteHit(event:HitNoteScriptEvent) {}
|
||||
|
||||
public function onNoteMiss(event:NoteScriptEvent):Void {};
|
||||
|
||||
|
|
|
@ -167,10 +167,7 @@ class Bopper extends StageProp implements IPlayStateScriptedClass
|
|||
|
||||
function update_shouldAlternate():Void
|
||||
{
|
||||
if (hasAnimation('danceLeft'))
|
||||
{
|
||||
this.shouldAlternate = true;
|
||||
}
|
||||
this.shouldAlternate = hasAnimation('danceLeft');
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -228,10 +225,11 @@ class Bopper extends StageProp implements IPlayStateScriptedClass
|
|||
|
||||
/**
|
||||
* Ensure that a given animation exists before playing it.
|
||||
* Will gracefully check for name, then name with stripped suffixes, then 'idle', then fail to play.
|
||||
* @param name
|
||||
* Will gracefully check for name, then name with stripped suffixes, then fail to play.
|
||||
* @param name The animation name to attempt to correct.
|
||||
* @param fallback Instead of failing to play, try to play this animation instead.
|
||||
*/
|
||||
function correctAnimationName(name:String):String
|
||||
function correctAnimationName(name:String, ?fallback:String):String
|
||||
{
|
||||
// If the animation exists, we're good.
|
||||
if (hasAnimation(name)) return name;
|
||||
|
@ -247,14 +245,22 @@ class Bopper extends StageProp implements IPlayStateScriptedClass
|
|||
}
|
||||
else
|
||||
{
|
||||
if (name != 'idle')
|
||||
if (fallback != null)
|
||||
{
|
||||
FlxG.log.warn('Bopper tried to play animation "$name" that does not exist, fallback to idle...');
|
||||
return correctAnimationName('idle');
|
||||
if (fallback == name)
|
||||
{
|
||||
FlxG.log.error('Bopper tried to play animation "$name" that does not exist! This is bad!');
|
||||
return null;
|
||||
}
|
||||
else
|
||||
{
|
||||
FlxG.log.warn('Bopper tried to play animation "$name" that does not exist, fallback to idle...');
|
||||
return correctAnimationName('idle');
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
FlxG.log.error('Bopper tried to play animation "idle" that does not exist! This is bad!');
|
||||
FlxG.log.error('Bopper tried to play animation "$name" that does not exist! This is bad!');
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
@ -353,7 +359,9 @@ class Bopper extends StageProp implements IPlayStateScriptedClass
|
|||
|
||||
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) {}
|
||||
|
||||
|
|
|
@ -870,7 +870,9 @@ class Stage extends FlxSpriteGroup implements IPlayStateScriptedClass implements
|
|||
|
||||
public function onCountdownEnd(event:CountdownScriptEvent) {}
|
||||
|
||||
public function onNoteHit(event:NoteScriptEvent) {}
|
||||
public function onNoteIncoming(event:NoteScriptEvent) {}
|
||||
|
||||
public function onNoteHit(event:HitNoteScriptEvent) {}
|
||||
|
||||
public function onNoteMiss(event:NoteScriptEvent) {}
|
||||
|
||||
|
|
|
@ -592,6 +592,11 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
|
|||
*/
|
||||
var playtestPracticeMode:Bool = false;
|
||||
|
||||
/**
|
||||
* If true, playtesting a chart will make the computer do it for you!
|
||||
*/
|
||||
var playtestBotPlayMode:Bool = false;
|
||||
|
||||
/**
|
||||
* Enables or disables the "debugger" popup that appears when you run into a flixel error.
|
||||
*/
|
||||
|
@ -5359,6 +5364,7 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
|
|||
targetDifficulty: selectedDifficulty,
|
||||
targetVariation: selectedVariation,
|
||||
practiceMode: playtestPracticeMode,
|
||||
botPlayMode: playtestBotPlayMode,
|
||||
minimalMode: minimal,
|
||||
startTimestamp: startTimestamp,
|
||||
playbackRate: playbackRate,
|
||||
|
@ -5928,7 +5934,7 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
|
|||
var tempNote:NoteSprite = new NoteSprite(NoteStyleRegistry.instance.fetchDefault());
|
||||
tempNote.noteData = noteData;
|
||||
tempNote.scrollFactor.set(0, 0);
|
||||
var event:NoteScriptEvent = new NoteScriptEvent(NOTE_HIT, tempNote, 1, true);
|
||||
var event:NoteScriptEvent = new HitNoteScriptEvent(tempNote, 0.0, 0, 'perfect', 0);
|
||||
dispatchEvent(event);
|
||||
|
||||
// Calling event.cancelEvent() skips all the other logic! Neat!
|
||||
|
|
|
@ -299,6 +299,15 @@ class ChartEditorToolboxHandler
|
|||
state.playtestStartTime = checkboxStartTime.selected;
|
||||
};
|
||||
|
||||
var checkboxBotPlay:Null<CheckBox> = toolbox.findComponent('playtestBotPlayCheckbox', CheckBox);
|
||||
if (checkboxBotPlay == null) throw 'ChartEditorToolboxHandler.buildToolboxPlaytestPropertiesLayout() - Could not find playtestBotPlayCheckbox component.';
|
||||
|
||||
checkboxBotPlay.selected = state.playtestBotPlayMode;
|
||||
|
||||
checkboxBotPlay.onClick = _ -> {
|
||||
state.playtestBotPlayMode = checkboxBotPlay.selected;
|
||||
};
|
||||
|
||||
var checkboxDebugger:Null<CheckBox> = toolbox.findComponent('playtestDebuggerCheckbox', CheckBox);
|
||||
|
||||
if (checkboxDebugger == null) throw 'ChartEditorToolboxHandler.buildToolboxPlaytestPropertiesLayout() - Could not find playtestDebuggerCheckbox component.';
|
||||
|
|
|
@ -272,19 +272,19 @@ class ChartEditorOffsetsToolbox extends ChartEditorBaseToolbox
|
|||
// waveformPlayer.waveform.forceUpdate = true;
|
||||
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.
|
||||
waveformPlayer.waveform.duration = (playerVoice?.length ?? 1000) / Constants.MS_PER_SEC;
|
||||
waveformPlayer.waveform.duration = (playerVoice?.length ?? 1000.0) / Constants.MS_PER_SEC;
|
||||
|
||||
// Build opponent waveform.
|
||||
// waveformOpponent.waveform.forceUpdate = true;
|
||||
// note: if song only has one set of vocals (Vocals.ogg/mp3) then this is null and crashes charting editor
|
||||
// so we null check
|
||||
waveformOpponent.waveform.waveformData = opponentVoice?.waveformData;
|
||||
waveformOpponent.waveform.duration = (opponentVoice?.length ?? 1000) / Constants.MS_PER_SEC;
|
||||
waveformOpponent.waveform.duration = (opponentVoice?.length ?? 1000.0) / Constants.MS_PER_SEC;
|
||||
|
||||
// Build instrumental waveform.
|
||||
// waveformInstrumental.waveform.forceUpdate = true;
|
||||
waveformInstrumental.waveform.waveformData = chartEditorState.audioInstTrack.waveformData;
|
||||
waveformInstrumental.waveform.duration = (instTrack?.length ?? 1000) / Constants.MS_PER_SEC;
|
||||
waveformInstrumental.waveform.duration = (instTrack?.length ?? 1000.0) / Constants.MS_PER_SEC;
|
||||
|
||||
addOffsetsToAudioPreview();
|
||||
}
|
||||
|
|
|
@ -128,9 +128,9 @@ class ChartEditorDropdowns
|
|||
"weekend-1-picouppercutprep" => "Pico Uppercut (Prep) (Blazin')",
|
||||
"weekend-1-picouppercut" => "Pico Uppercut (Blazin')",
|
||||
"weekend-1-blockhigh" => "Block High (Blazin')",
|
||||
"weekend-1-blocklow" => "Dodge High (Blazin')",
|
||||
"weekend-1-blocklow" => "Block Low (Blazin')",
|
||||
"weekend-1-blockspin" => "Block High (Spin) (Blazin')",
|
||||
"weekend-1-dodgehigh" => "Block Low (Blazin')",
|
||||
"weekend-1-dodgehigh" => "Dodge High (Blazin')",
|
||||
"weekend-1-dodgelow" => "Dodge Low (Blazin')",
|
||||
"weekend-1-dodgespin" => "Dodge High (Spin) (Blazin')",
|
||||
"weekend-1-hithigh" => "Hit High (Blazin')",
|
||||
|
|
|
@ -1143,12 +1143,12 @@ class FreeplayState extends MusicBeatSubState
|
|||
targetSong: targetSong,
|
||||
targetDifficulty: targetDifficulty,
|
||||
targetVariation: targetVariation,
|
||||
// TODO: Make this an option!
|
||||
// startTimestamp: 0.0,
|
||||
// TODO: Make this an option!
|
||||
// playbackRate: 0.5,
|
||||
practiceMode: false,
|
||||
minimalMode: false,
|
||||
// TODO: Make these an option! It's currently only accessible via chart editor.
|
||||
// startTimestamp: 0.0,
|
||||
// playbackRate: 0.5,
|
||||
// botPlayMode: true,
|
||||
}, true);
|
||||
});
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ package funkin.ui.haxeui.components;
|
|||
|
||||
import funkin.modding.events.ScriptEvent.GhostMissNoteScriptEvent;
|
||||
import funkin.modding.events.ScriptEvent.NoteScriptEvent;
|
||||
import funkin.modding.events.ScriptEvent.HitNoteScriptEvent;
|
||||
import funkin.modding.events.ScriptEvent.SongTimeScriptEvent;
|
||||
import funkin.modding.events.ScriptEvent.UpdateScriptEvent;
|
||||
import haxe.ui.core.IDataComponent;
|
||||
|
@ -216,12 +217,17 @@ class CharacterPlayer extends Box
|
|||
if (character != null) character.onStepHit(event);
|
||||
}
|
||||
|
||||
public function onNoteIncoming(event:NoteScriptEvent)
|
||||
{
|
||||
if (character != null) character.onNoteIncoming(event);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when a note is hit in the song
|
||||
* Used to play character animations.
|
||||
* @param event The event.
|
||||
*/
|
||||
public function onNoteHit(event:NoteScriptEvent):Void
|
||||
public function onNoteHit(event:HitNoteScriptEvent):Void
|
||||
{
|
||||
if (character != null) character.onNoteHit(event);
|
||||
}
|
||||
|
|
|
@ -45,6 +45,9 @@ class LevelProp extends Bopper
|
|||
this.visible = true;
|
||||
}
|
||||
|
||||
// Reset animation state.
|
||||
this.shouldAlternate = null;
|
||||
|
||||
var isAnimated:Bool = propData.animations.length > 0;
|
||||
if (isAnimated)
|
||||
{
|
||||
|
|
|
@ -17,7 +17,9 @@ class TrackerUtil
|
|||
*/
|
||||
public static function initTrackers():Void
|
||||
{
|
||||
#if FLX_DEBUG
|
||||
Tracker.addProfile(new TrackerProfile(Highscore, ["tallies"]));
|
||||
FlxG.console.registerClass(Highscore);
|
||||
#end
|
||||
}
|
||||
}
|
||||
|
|
|
@ -52,7 +52,12 @@ class AnsiTrace
|
|||
public static function traceBF()
|
||||
{
|
||||
#if sys
|
||||
if (colorSupported) Sys.println(ansiBF.join("\n"));
|
||||
if (colorSupported)
|
||||
{
|
||||
for (line in ansiBF)
|
||||
Sys.stdout().writeString(line + "\n");
|
||||
Sys.stdout().flush();
|
||||
}
|
||||
#end
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue