note splashes

This commit is contained in:
Yoshman29
2023-01-12 18:57:52 +01:00
parent d78b8c4c20
commit 1dd8003559
227 changed files with 506 additions and 256 deletions
+5
View File
@@ -45,6 +45,11 @@ class Note extends FlxSprite
*/
public var nextSustain:Note;
/**
* Name of the splash.
*/
public var splash:String = "default";
public var strumID(get, never):Int;
private function get_strumID() {
var id = noteData % 4;
+48 -39
View File
@@ -1,5 +1,6 @@
package funkin.game;
import funkin.game.SplashHandler;
import funkin.editors.CharacterEditor;
import funkin.scripting.DummyScript;
import funkin.menus.StoryMenuState.WeekData;
@@ -190,6 +191,11 @@ class PlayState extends MusicBeatState
*/
public var cpuStrums:FlxTypedGroup<Strum>;
/**
* Note splashes container
*/
public var splashHandler:SplashHandler;
/**
* Whenever the vocals should be muted when a note is missed.
*/
@@ -581,6 +587,9 @@ class PlayState extends MusicBeatState
cpuStrums = new FlxTypedGroup<Strum>();
add(strumLineNotes);
splashHandler = new SplashHandler();
add(splashHandler);
generateSong(SONG);
if (prevCamFollow != null)
@@ -868,6 +877,8 @@ class PlayState extends MusicBeatState
swagNote.stepLength = stepCrochet;
notes.add(swagNote);
}
splashHandler.getSplashGroup(swagNote.splash);
}
daBeats += 1;
}
@@ -1450,43 +1461,40 @@ class PlayState extends MusicBeatState
function noteMiss(note:Note):Void
{
if (!boyfriend.stunned)
var event:NoteHitEvent = scripts.event("onPlayerMiss", EventManager.get(NoteHitEvent).recycle(true, false, false, note, [boyfriend], true, note.noteType, "", "", "", note.strumID, -10, 0, -0.04, "shit"));
if (event.cancelled) return;
health += event.healthGain;
if (gf != null && combo > 5 && gf.animOffsets.exists('sad'))
{
var event:NoteHitEvent = scripts.event("onPlayerMiss", EventManager.get(NoteHitEvent).recycle(true, false, false, note, [boyfriend], true, note.noteType, "", "", "", note.strumID, -10, 0, -0.04, "shit"));
if (event.cancelled) return;
health += event.healthGain;
if (gf != null && combo > 5 && gf.animOffsets.exists('sad'))
{
gf.playAnim('sad', true, MISS);
}
combo = 0;
songScore -= 10;
misses++;
FlxG.sound.play(Paths.soundRandom('missnote', 1, 3), FlxG.random.float(0.1, 0.2));
if (muteVocalsOnMiss) vocals.volume = 0;
if (event.accuracy != null) {
accuracyPressedNotes++;
totalAccuracyAmount += event.accuracy;
updateRating();
}
for(char in event.characters) {
if (char == null) continue;
char.stunned = true;
char.playSingAnim(note.strumID, "miss", MISS);
}
// boyfriend.stunned = true;
deleteNote(note);
gf.playAnim('sad', true, MISS);
}
combo = 0;
songScore -= 10;
misses++;
FlxG.sound.play(Paths.soundRandom('missnote', 1, 3), FlxG.random.float(0.1, 0.2));
if (muteVocalsOnMiss) vocals.volume = 0;
if (event.accuracy != null) {
accuracyPressedNotes++;
totalAccuracyAmount += event.accuracy;
updateRating();
}
for(char in event.characters) {
if (char == null) continue;
char.stunned = true;
char.playSingAnim(note.strumID, "miss", MISS);
}
// boyfriend.stunned = true;
deleteNote(note);
}
public function getNoteType(id:Int):String {
@@ -1529,9 +1537,9 @@ class PlayState extends MusicBeatState
var event:NoteHitEvent;
if (note.mustPress)
// event = scripts.event("onPlayerHit", EventManager.get(NoteHitEvent).recycle(note, [boyfriend], true, note.noteType, note.strumID, note.noteData > 0 ? 0.023 : 0.004, score, note.animSuffix, daRating, note.isSustainNote ? null : accuracy, "game/score/", ''));
event = scripts.event("onPlayerHit", EventManager.get(NoteHitEvent).recycle(false, !note.isSustainNote, !note.isSustainNote, note, [boyfriend], true, note.noteType, "", "game/score/", "", note.strumID, score, note.isSustainNote ? null : accuracy, note.noteData > 0 ? 0.023 : 0.004, daRating));
event = scripts.event("onPlayerHit", EventManager.get(NoteHitEvent).recycle(false, !note.isSustainNote, !note.isSustainNote, note, [boyfriend], true, note.noteType, "", "game/score/", "", note.strumID, score, note.isSustainNote ? null : accuracy, note.noteData > 0 ? 0.023 : 0.004, daRating, daRating == "sick"));
else
event = scripts.event("onDadHit", EventManager.get(NoteHitEvent).recycle(false, false, false, note, [dad], false, note.noteType, "", "game/score/", "", note.strumID, 0, null, 0, daRating));
event = scripts.event("onDadHit", EventManager.get(NoteHitEvent).recycle(false, false, false, note, [dad], false, note.noteType, "", "game/score/", "", note.strumID, 0, null, 0, daRating, false));
if (!event.cancelled) {
if (event.accuracy != null) {
@@ -1625,9 +1633,10 @@ class PlayState extends MusicBeatState
if (char != null)
char.playSingAnim(event.direction, event.animSuffix);
if (!event.strumGlowCancelled) (event.player ? playerStrums : cpuStrums).forEach(function(str:Strum) {
(event.player ? playerStrums : cpuStrums).forEach(function(str:Strum) {
if (str.ID == Math.abs(note.strumID)) {
str.press(note.strumTime);
if (!event.strumGlowCancelled) str.press(note.strumTime);
if (event.showSplash) splashHandler.showSplash(note.splash, str);
}
});
}
+117
View File
@@ -0,0 +1,117 @@
package funkin.game;
import flixel.FlxG;
import openfl.utils.Assets;
import haxe.xml.Access;
import flixel.group.FlxGroup.FlxTypedGroup;
class SplashGroup extends FlxTypedGroup<FunkinSprite> {
/**
* Whenever the splash group has successfully loaded or not.
*/
public var valid:Bool = true;
/**
* XML data for the note splashes.
*/
public var xml:Access;
/**
* Animation names sorted by strum IDs.
* Use `getSplashAnim` to get one.
*/
public var animationNames:Array<Array<String>> = [];
/**
* Creates a new Splash group
* @param path Path to the splash data (xml)
*/
public function new(path) {
super();
try {
xml = new Access(Xml.parse(Assets.getText(path)).firstElement());
if (!xml.has.sprite) throw "The <splash> element requires a sprite attribute.";
var splashSprite = new FunkinSprite();
splashSprite.antialiasing = true;
splashSprite.active = splashSprite.visible = false;
splashSprite.loadSprite(Paths.image(xml.att.sprite));
/**
* ANIMATIONS
*/
for(strum in xml.nodes.strum) {
var id:Null<Int> = Std.parseInt(strum.att.id);
if (id != null) {
animationNames[id] = [];
for(anim in strum.nodes.anim) {
if (!anim.has.name) continue;
XMLUtil.addXMLAnimation(splashSprite, anim, false);
animationNames[id].push(anim.att.name);
}
}
}
if (animationNames.length <= 0)
animationNames.push([]);
for(anim in xml.nodes.anim) {
if (!anim.has.name) continue;
XMLUtil.addXMLAnimation(splashSprite, anim, false);
for(a in animationNames) {
if (a == null) continue;
a.push(anim.att.name);
}
}
/**
* END OF ANIMATIONS
*/
splashSprite.animation.finishCallback = function(name) {
splashSprite.active = splashSprite.visible = false;
};
if (xml.has.scale) splashSprite.scale.scale(Std.parseFloat(xml.att.scale).getDefault(1));
if (xml.has.alpha) splashSprite.alpha = Std.parseFloat(xml.att.alpha).getDefault(1);
if (xml.has.antialiasing) splashSprite.antialiasing = xml.att.antialiasing == "true";
add(splashSprite);
for (i in 0...7) {
// make 7 additional splashes
var spr = FunkinSprite.copyFrom(splashSprite);
spr.animation.finishCallback = function(name) {
spr.active = spr.visible = false;
};
add(spr);
}
// immediatly draw once and put image in GPU to prevent freezes
splashSprite.draw();
} catch(e) {
Logs.trace('Couldn\'t parse splash data for "${path}": ${e.toString()}', ERROR);
valid = false;
}
maxSize = 8;
}
public function getSplashAnim(id:Int):String {
if (animationNames.length <= 0) return null;
id %= animationNames.length;
if (animationNames[id] == null) return null;
if (animationNames[id].length <= 0) return null;
return animationNames[id][FlxG.random.int(0, animationNames[id].length-1)];
}
public function showOnStrum(strum:Strum) {
if (!valid) return null;
var splash = recycle();
splash.cameras = strum.lastDrawCameras;
splash.setPosition(strum.x + ((strum.width - splash.width) / 2), strum.y + ((strum.height - splash.height) / 2));
splash.active = splash.visible = true;
splash.playAnim(getSplashAnim(strum.ID), true);
return splash;
}
}
+42
View File
@@ -0,0 +1,42 @@
package funkin.game;
import flixel.group.FlxGroup.FlxTypedGroup;
class SplashHandler extends FlxTypedGroup<FunkinSprite> {
/**
* Map containing all of the splashes group.
*/
public var grpMap:Map<String, SplashGroup> = [];
public function new() {
super();
}
/**
* Returns a group of splashes, and creates it if it doesn't exist.
* @param path Path to the splashes XML (`Paths.xml('splashes/splash')`)
*/
public function getSplashGroup(name:String) {
if (!grpMap.exists(name)) {
var grp = new SplashGroup(Paths.xml('splashes/$name'));
grpMap.set(name, grp);
}
return grpMap.get(name);
}
public override function destroy() {
super.destroy();
for(grp in grpMap)
grp.destroy();
grpMap = null;
}
public function showSplash(name:String, strum:Strum) {
var grp = getSplashGroup(name);
add(grp.showOnStrum(strum));
// max 8 rendered splashes
while(members.length > 8)
remove(members[0]);
}
}
@@ -75,6 +75,10 @@ class NoteHitEvent extends CancellableEvent {
* Rating name. Defaults to "sick", "good", "bad" and "shit". Customisable.
*/
public var rating:String = "sick";
/**
* Whenever a splash should be shown when the note is hit.
*/
public var showSplash:Bool = false;
/**
* Scale of combo numbers.
*/
+12
View File
@@ -41,6 +41,18 @@ class FunkinSprite extends FlxSprite implements IBeatReceiver implements IOffset
@:noCompletion public var atlasPlayingAnim:String;
@:noCompletion public var atlasPath:String;
public static function copyFrom(source:FunkinSprite) {
var spr = new FunkinSprite();
spr.setPosition(source.x, source.y);
spr.frames = source.frames;
if (source.animateAtlas != null && source.atlasPath != null)
spr.loadSprite(source.atlasPath);
spr.animation.copyFrom(source.animation);
spr.visible = source.visible;
spr.alpha = source.alpha;
return spr;
}
public override function update(elapsed:Float) {
super.update(elapsed);
if (animateAtlas != null)