diff --git a/source/funkin/Alphabet.hx b/source/funkin/Alphabet.hx index 3835ae660..670496727 100644 --- a/source/funkin/Alphabet.hx +++ b/source/funkin/Alphabet.hx @@ -264,8 +264,6 @@ class AlphaCharacter extends FlxSprite animation.play(letter); updateHitbox(); - FlxG.log.add('the row' + row); - y = (110 - height); y += row * 60; } diff --git a/source/funkin/NoteSplash.hx b/source/funkin/NoteSplash.hx index a32a39c08..318ef8f9f 100644 --- a/source/funkin/NoteSplash.hx +++ b/source/funkin/NoteSplash.hx @@ -2,6 +2,7 @@ package funkin; import flixel.FlxSprite; import haxe.io.Path; +import flixel.graphics.frames.FlxAtlasFrames; class NoteSplash extends FlxSprite { @@ -9,15 +10,13 @@ class NoteSplash extends FlxSprite { super(x, y); - frames = Paths.getSparrowAtlas('noteSplashes'); - + animation.addByPrefix('note0-0', 'note impact 1 purple', 24, false); animation.addByPrefix('note1-0', 'note impact 1 blue', 24, false); animation.addByPrefix('note2-0', 'note impact 1 green', 24, false); - animation.addByPrefix('note0-0', 'note impact 1 purple', 24, false); animation.addByPrefix('note3-0', 'note impact 1 red', 24, false); + animation.addByPrefix('note0-1', 'note impact 2 purple', 24, false); animation.addByPrefix('note1-1', 'note impact 2 blue', 24, false); animation.addByPrefix('note2-1', 'note impact 2 green', 24, false); - animation.addByPrefix('note0-1', 'note impact 2 purple', 24, false); animation.addByPrefix('note3-1', 'note impact 2 red', 24, false); setupNoteSplash(x, y, noteData); @@ -25,6 +24,20 @@ class NoteSplash extends FlxSprite // alpha = 0.75; } + public static function buildSplashFrames(force:Bool = false):FlxAtlasFrames + { + // static variables inside functions are a cool of Haxe 4.3.0. + static var splashFrames:FlxAtlasFrames = null; + + if (splashFrames != null && !force) return splashFrames; + + splashFrames = Paths.getSparrowAtlas('noteSplashes'); + + splashFrames.parent.persist = true; + + return splashFrames; + } + public function setupNoteSplash(x:Float, y:Float, noteData:Int = 0) { setPosition(x, y); diff --git a/source/funkin/graphics/rendering/SustainTrail.hx b/source/funkin/graphics/rendering/SustainTrail.hx deleted file mode 100644 index d9f43584e..000000000 --- a/source/funkin/graphics/rendering/SustainTrail.hx +++ /dev/null @@ -1,233 +0,0 @@ -package funkin.graphics.rendering; - -import flixel.FlxSprite; -import flixel.graphics.FlxGraphic; -import flixel.graphics.tile.FlxDrawTrianglesItem; -import flixel.math.FlxMath; - -/** - * This is based heavily on the `FlxStrip` class. It uses `drawTriangles()` to clip a sustain note - * trail at a certain time. - * The whole `FlxGraphic` is used as a texture map. See the `NOTE_hold_assets.fla` file for specifics - * on how it should be constructed. - * - * @author MtH - */ -class SustainTrail extends FlxSprite -{ - /** - * Used to determine which note color/direction to draw for the sustain. - */ - public var noteData:Int = 0; - - /** - * The zoom level to render the sustain at. - * Defaults to 1.0, increased to 6.0 for pixel notes. - */ - public var zoom(default, set):Float = 1; - - /** - * The strumtime of the note, in milliseconds. - */ - public var strumTime:Float = 0; // millis - - /** - * The sustain length of the note, in milliseconds. - */ - public var sustainLength(default, set):Float = 0; // millis - - /** - * The scroll speed of the note, as a multiplier. - */ - public var scrollSpeed(default, set):Float = 1.0; // stand-in for PlayState scroll speed - - /** - * Whether the note was missed. - */ - public var missed:Bool = false; // maybe BlendMode.MULTIPLY if missed somehow, drawTriangles does not support! - - /** - * A `Vector` of floats where each pair of numbers is treated as a coordinate location (an x, y pair). - */ - var vertices:DrawData = new DrawData(); - - /** - * A `Vector` of integers or indexes, where every three indexes define a triangle. - */ - var indices:DrawData = new DrawData(); - - /** - * A `Vector` of normalized coordinates used to apply texture mapping. - */ - var uvtData:DrawData = new DrawData(); - - var processedGraphic:FlxGraphic; - - /** - * What part of the trail's end actually represents the end of the note. - * This can be used to have a little bit sticking out. - */ - public var endOffset:Float = 0.5; // 0.73 is roughly the bottom of the sprite in the normal graphic! - - /** - * At what point the bottom for the trail's end should be clipped off. - * Used in cases where there's an extra bit of the graphic on the bottom to avoid antialiasing issues with overflow. - */ - public var bottomClip:Float = 0.9; - - /** - * Normally you would take strumTime:Float, noteData:Int, sustainLength:Float, parentNote:Note (?) - * @param NoteData - * @param SustainLength - * @param FileName - */ - public function new(NoteData:Int, SustainLength:Float, Path:String, ?Alpha:Float = 0.6, ?Pixel:Bool = false) - { - super(0, 0, Path); - - // BASIC SETUP - this.sustainLength = SustainLength; - this.noteData = NoteData; - - // CALCULATE SIZE - if (Pixel) - { - this.endOffset = bottomClip = 1; - this.antialiasing = false; - this.zoom = 6.0; - } - else - { - this.antialiasing = true; - this.zoom = 1.0; - } - // width = graphic.width / 8 * zoom; // amount of notes * 2 - height = sustainHeight(sustainLength, scrollSpeed); - // instead of scrollSpeed, PlayState.SONG.speed - - alpha = Alpha; // setting alpha calls updateColorTransform(), which initializes processedGraphic! - - updateClipping(); - indices = new DrawData(12, true, [0, 1, 2, 2, 3, 0, 4, 5, 6, 6, 7, 4]); - } - - /** - * Calculates height of a sustain note for a given length (milliseconds) and scroll speed. - * @param susLength The length of the sustain note in milliseconds. - * @param scroll The current scroll speed. - */ - public static inline function sustainHeight(susLength:Float, scroll:Float) - { - return (susLength * 0.45 * scroll); - } - - function set_zoom(z:Float) - { - this.zoom = z; - width = graphic.width / 8 * z; - updateClipping(); - return this.zoom; - } - - function set_sustainLength(s:Float) - { - height = sustainHeight(s, scrollSpeed); - return sustainLength = s; - } - - function set_scrollSpeed(s:Float) - { - height = sustainHeight(sustainLength, s); - return scrollSpeed = s; - } - - /** - * Sets up new vertex and UV data to clip the trail. - * If flipY is true, top and bottom bounds swap places. - * @param songTime The time to clip the note at, in milliseconds. - */ - public function updateClipping(songTime:Float = 0):Void - { - var clipHeight:Float = FlxMath.bound(sustainHeight(sustainLength - (songTime - strumTime), scrollSpeed), 0, height); - if (clipHeight == 0) - { - visible = false; - return; - } - else - visible = true; - var bottomHeight:Float = graphic.height * zoom * endOffset; - var partHeight:Float = clipHeight - bottomHeight; - // == HOLD == // - // left bound - vertices[6] = vertices[0] = 0.0; - // top bound - vertices[3] = vertices[1] = flipY ? clipHeight : height - clipHeight; - // right bound - vertices[4] = vertices[2] = width; - // bottom bound (also top bound for hold ends) - if (partHeight > 0) vertices[7] = vertices[5] = flipY ? 0.0 + bottomHeight : vertices[1] + partHeight; - else - vertices[7] = vertices[5] = vertices[1]; - - // same shit with da bounds, just in relation to the texture - uvtData[6] = uvtData[0] = 1 / 4 * (noteData % 4); - // height overflows past image bounds so wraps around, looping the texture - // flipY bounds are not swapped for UV data, so the graphic is actually flipped - // top bound - uvtData[3] = uvtData[1] = (-partHeight) / graphic.height / zoom; - uvtData[4] = uvtData[2] = uvtData[0] + 1 / 8; // 1 - // bottom bound - uvtData[7] = uvtData[5] = 0.0; - - // == HOLD ENDS == // - // left bound - vertices[14] = vertices[8] = vertices[0]; - // top bound - vertices[11] = vertices[9] = vertices[5]; - // right bound - vertices[12] = vertices[10] = vertices[2]; - // bottom bound, mind the bottomClip because it clips off bottom of graphic!! - vertices[15] = vertices[13] = flipY ? graphic.height * (-bottomClip + endOffset) : height + graphic.height * (bottomClip - endOffset); - - uvtData[14] = uvtData[8] = uvtData[2]; - if (partHeight > 0) uvtData[11] = uvtData[9] = 0.0; - else - uvtData[11] = uvtData[9] = (bottomHeight - clipHeight) / zoom / graphic.height; - uvtData[12] = uvtData[10] = uvtData[8] + 1 / 8; - // again, clips off bottom !! - uvtData[15] = uvtData[13] = bottomClip; - } - - @:access(flixel.FlxCamera) - override public function draw():Void - { - if (alpha == 0 || graphic == null || vertices == null) return; - - for (camera in cameras) - { - if (!camera.visible || !camera.exists || !isOnScreen(camera)) continue; - - getScreenPosition(_point, camera).subtractPoint(offset); - camera.drawTriangles(processedGraphic, vertices, indices, uvtData, null, _point, blend, true, antialiasing); - } - } - - override public function destroy():Void - { - vertices = null; - indices = null; - uvtData = null; - processedGraphic.destroy(); - - super.destroy(); - } - - override function updateColorTransform():Void - { - super.updateColorTransform(); - if (processedGraphic != null) processedGraphic.destroy(); - processedGraphic = FlxGraphic.fromGraphic(graphic, true); - processedGraphic.bitmap.colorTransform(processedGraphic.bitmap.rect, colorTransform); - } -} diff --git a/source/funkin/play/PlayState.hx b/source/funkin/play/PlayState.hx index c76cf24d4..0c4c1abfb 100644 --- a/source/funkin/play/PlayState.hx +++ b/source/funkin/play/PlayState.hx @@ -836,7 +836,7 @@ class PlayState extends MusicBeatState if (isInCutscene && !disableKeys) handleCutsceneKeys(elapsed); // Moving notes into position is now done by Strumline.update(). - processNotes(); + processNotes(elapsed); // Dispatch the onUpdate event to scripted elements. dispatchEvent(new UpdateScriptEvent(elapsed)); @@ -1378,10 +1378,6 @@ class PlayState extends MusicBeatState if (!PlayStatePlaylist.isStoryMode) { playerStrumline.fadeInArrows(); - } - - if (!PlayStatePlaylist.isStoryMode) - { opponentStrumline.fadeInArrows(); } @@ -1629,7 +1625,7 @@ class PlayState extends MusicBeatState /** * Handles opponent note hits and player note misses. */ - function processNotes():Void + function processNotes(elapsed:Float):Void { // Process notes on the opponent's side. for (note in opponentStrumline.notes.members) @@ -1730,6 +1726,15 @@ class PlayState extends MusicBeatState // Process hold notes on the player's side. // This handles scoring so we don't need it on the opponent's side. + for (holdNote in playerStrumline.holdNotes.members) + { + // While the hold note is being hit, and there is length on the hold note... + if (holdNote.hitNote && holdNote.sustainLength > 0) + { + // Grant the player health. + health += Constants.HEALTH_HOLD_BONUS_PER_SECOND * elapsed; + } + } } /** diff --git a/source/funkin/play/notes/Strumline.hx b/source/funkin/play/notes/Strumline.hx index f01031345..77b039712 100644 --- a/source/funkin/play/notes/Strumline.hx +++ b/source/funkin/play/notes/Strumline.hx @@ -588,18 +588,18 @@ class Strumline extends FlxSpriteGroup * @param arrow The arrow to animate. * @param index The index of the arrow in the strumline. */ - function fadeInArrow(arrow:StrumlineNote):Void + function fadeInArrow(index:Int, arrow:StrumlineNote):Void { arrow.y -= 10; - arrow.alpha = 0; - FlxTween.tween(arrow, {y: arrow.y + 10, alpha: 1}, 1, {ease: FlxEase.circOut, startDelay: 0.5 + (0.2 * arrow.ID)}); + arrow.alpha = 0.0; + FlxTween.tween(arrow, {y: arrow.y + 10, alpha: 1}, 1, {ease: FlxEase.circOut, startDelay: 0.5 + (0.2 * index)}); } public function fadeInArrows():Void { - for (arrow in this.strumlineNotes) + for (index => arrow in this.strumlineNotes.members.keyValueIterator()) { - fadeInArrow(arrow); + fadeInArrow(index, arrow); } } diff --git a/source/funkin/play/notes/StrumlineNote.hx b/source/funkin/play/notes/StrumlineNote.hx index 1d24759dc..2f2b41374 100644 --- a/source/funkin/play/notes/StrumlineNote.hx +++ b/source/funkin/play/notes/StrumlineNote.hx @@ -41,6 +41,7 @@ class StrumlineNote extends FlxSprite this.animation.callback = onAnimationFrame; this.animation.finishCallback = onAnimationFinished; + // Must be true for animations to play. this.active = true; } diff --git a/source/funkin/util/Constants.hx b/source/funkin/util/Constants.hx index b014047bc..c6a6d0265 100644 --- a/source/funkin/util/Constants.hx +++ b/source/funkin/util/Constants.hx @@ -147,38 +147,43 @@ class Constants /** * The amount of health the player gains when hitting a note with the KILLER rating. */ - public static final HEALTH_KILLER_BONUS:Float = 2.0 / 100.0 / HEALTH_MAX; // +2.0% + public static final HEALTH_KILLER_BONUS:Float = 2.0 / 100.0 * HEALTH_MAX; // +2.0% /** * The amount of health the player gains when hitting a note with the SICK rating. */ - public static final HEALTH_SICK_BONUS:Float = 1.5 / 100.0 / HEALTH_MAX; // +1.0% + public static final HEALTH_SICK_BONUS:Float = 1.5 / 100.0 * HEALTH_MAX; // +1.0% /** * The amount of health the player gains when hitting a note with the GOOD rating. */ - public static final HEALTH_GOOD_BONUS:Float = 0.75 / 100.0 / HEALTH_MAX; // +0.75% + public static final HEALTH_GOOD_BONUS:Float = 0.75 / 100.0 * HEALTH_MAX; // +0.75% /** * The amount of health the player gains when hitting a note with the BAD rating. */ - public static final HEALTH_BAD_BONUS:Float = 0.0 / 100.0 / HEALTH_MAX; // +0.0% + public static final HEALTH_BAD_BONUS:Float = 0.0 / 100.0 * HEALTH_MAX; // +0.0% /** * The amount of health the player gains when hitting a note with the SHIT rating. * If negative, the player will actually lose health. */ - public static final HEALTH_SHIT_BONUS:Float = -1.0 / 100.0 / HEALTH_MAX; // -1.0% + public static final HEALTH_SHIT_BONUS:Float = -1.0 / 100.0 * HEALTH_MAX; // -1.0% + + /** + * The amount of health the player gains, while holding a hold note, per second. + */ + public static final HEALTH_HOLD_BONUS_PER_SECOND:Float = 7.5 / 100.0 * HEALTH_MAX; // +7.5% / second /** * The amount of health the player loses upon missing a note. */ - public static final HEALTH_MISS_PENALTY:Float = 4.0 / 100.0 / HEALTH_MAX; // 4.0% + public static final HEALTH_MISS_PENALTY:Float = 4.0 / 100.0 * HEALTH_MAX; // 4.0% /** * The amount of health the player loses upon pressing a key when no note is there. */ - public static final HEALTH_GHOST_MISS_PENALTY:Float = 2.0 / 100.0 / HEALTH_MAX; // 2.0% + public static final HEALTH_GHOST_MISS_PENALTY:Float = 2.0 / 100.0 * HEALTH_MAX; // 2.0% /** * The amount of health the player loses upon letting go of a hold note while it is still going. @@ -188,7 +193,7 @@ class Constants /** * The amount of health the player loses upon hitting a mine. */ - public static final HEALTH_MINE_PENALTY:Float = 15.0 / 100.0 / HEALTH_MAX; // 15.0% + public static final HEALTH_MINE_PENALTY:Float = 15.0 / 100.0 * HEALTH_MAX; // 15.0% /** * If true, the player will not receive the ghost miss penalty if there are no notes within the hit window.