Merge branch 'main' into internal-merge

# Conflicts:
#	.github/workflows/linux.yml
#	.github/workflows/macos.yml
#	.github/workflows/release.yml
#	.github/workflows/windows.yml
#	source/funkin/menus/FreeplayState.hx
#	source/openfl/utils/Assets.hx
This commit is contained in:
Ralty
2026-04-07 10:42:35 +07:00
14 changed files with 180 additions and 70 deletions
+2
View File
@@ -12,6 +12,8 @@ jobs:
steps:
- name: Pulling the new commit
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setting up Haxe
uses: krdlab/setup-haxe@v2
with:
+2
View File
@@ -12,6 +12,8 @@ jobs:
steps:
- name: Pulling the new commit
uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Setting up Haxe
uses: krdlab/setup-haxe@v2
with:
+2
View File
@@ -12,6 +12,8 @@ jobs:
steps:
- name: Pulling the new commit
uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Setting up Haxe
uses: krdlab/setup-haxe@v2
with:
+2
View File
@@ -22,6 +22,8 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Download Windows Full Build
uses: dawidd6/action-download-artifact@v8
+2
View File
@@ -12,6 +12,8 @@ jobs:
steps:
- name: Pulling the new commit
uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Setting up Haxe
uses: krdlab/setup-haxe@v2
with:
+2
View File
@@ -165,6 +165,8 @@ class Flags {
// Font configuration
public static var DEFAULT_FONT:String = "vcr.ttf";
public static var DEFAULT_FONT_SIZE:Int = 16;
public static var DEFAULT_ALT_ANIM_SUFFIX:String = "-alt";
// to translate these you need to convert them into ids
// Resume -> pause.resume
+2 -4
View File
@@ -440,11 +440,9 @@ final class CoolUtil
* @param fadeIn
*/
@:noUsing public static function playMenuSong(fadeIn:Bool = false) {
if (FlxG.sound.music == null || !FlxG.sound.music.playing)
{
if (FlxG.sound.music == null || !FlxG.sound.music.playing) {
playMusic(Paths.music(Flags.DEFAULT_MENU_MUSIC), true, fadeIn ? 0 : 1, true, 102);
if (fadeIn)
FlxG.sound.music.fadeIn(4, 0, 0.7);
if (fadeIn) FlxG.sound.music.fadeIn(4, 0, 1);
}
}
@@ -146,11 +146,10 @@ class CharterSelectionScreen extends EditorTreeMenuScreen {
var screen = parent.tree.last();
var idx = 0;
while (!(screen.members[idx] is Separator)) idx++;
while (!(screen.members[idx] is Separator || idx >= screen.members.length)) idx++;
screen.insert(idx, makeChartOption(name, curSong.variant != null && curSong.variant != "" ? curSong.variant : null, curSong.name));
// Add to Meta
var metaPath = '$songFolder/meta${curSong.variant != null && curSong.variant == "" ? "-" + curSong.variant : ""}.json';
var metaPath = '$songFolder/meta${curSong.variant != null && curSong.variant != "" ? "-" + curSong.variant : ""}.json';
CoolUtil.safeSaveFile(metaPath, Chart.makeMetaSaveable(curSong));
}
#end
+80 -37
View File
@@ -126,8 +126,7 @@ class Note extends FlxSprite
static var DEFAULT_FIELDS:Array<String> = ["time", "id", "type", "sLen"];
public function new(strumLine:StrumLine, noteData:ChartNote, sustain:Bool = false, sustainLength:Float = 0, sustainOffset:Float = 0, ?prev:Note)
{
public function new(strumLine:StrumLine, noteData:ChartNote, sustain:Bool = false, sustainLength:Float = 0, sustainOffset:Float = 0, ?prev:Note) {
super();
moves = false;
@@ -241,23 +240,13 @@ class Note extends FlxSprite
*/
public var strumRelativePos:Bool = true;
override function drawComplex(camera:FlxCamera) {
var downscrollCam = (camera is HudCamera ? ({var _:HudCamera=cast camera;_;}).downscroll : false);
if (updateFlipY) flipY = (isSustainNote && flipSustain) && (downscrollCam != (__strum != null && __strum.getScrollSpeed(this) < 0));
if (downscrollCam && __strum != null) {
final xx = x;
x += origin.x - offset.x;
x -= __strum.x; x *= -1; x += __strum.x;
x -= origin.x - offset.x;
x += __strum.width; // ??? maybe this isnt good
super.drawComplex(camera);
x = xx;
} else
super.drawComplex(camera);
}
static var __notePosFrameOffset:FlxPoint = new FlxPoint();
static var __posPoint:FlxPoint = new FlxPoint();
@:dox(hide) static var __lastAngle:Float = Math.NaN;
@:dox(hide) static var __lastAngleSin:Float = 0;
@:dox(hide) static var __lastAngleCos:Float = 0;
@:dox(hide) static var __lastStrumW:Float = Math.NaN;
@:dox(hide) static var __lastStrumH:Float = Math.NaN;
@:dox(hide) static var __lastStrumHalfW:Float = 0;
@:dox(hide) static var __lastStrumHalfH:Float = 0;
override function draw() {
@:privateAccess var oldDefaultCameras = FlxCamera._defaultCameras;
@@ -266,16 +255,28 @@ class Note extends FlxSprite
var negativeScroll = isSustainNote && strumRelativePos && lastScrollSpeed < 0;
if (negativeScroll) y -= height;
if (__strum != null && strumRelativePos) {
final pos = __posPoint.set(x, y);
// distance = pos.y , we can use it safely like this
final xx = -origin.x + offset.x + (pos.y * Math.cos((__noteAngle + 90) * FlxAngle.TO_RAD));
final yy = -origin.y + offset.y + (pos.y * Math.sin((__noteAngle + 90) * FlxAngle.TO_RAD));
setPosition(
xx + __strum.x + (__strum.width * 0.5),
yy + __strum.y + (__strum.height * 0.5)
);
final originalX = x;
final originalY = y;
if (__noteAngle != __lastAngle) {
__lastAngle = __noteAngle;
final result = FlxMath.fastSinCos((__noteAngle + 90) * FlxAngle.TO_RAD);
__lastAngleSin = result.sin;
__lastAngleCos = result.cos;
}
if (__strum.width != __lastStrumW || __strum.height != __lastStrumH) {
__lastStrumW = __strum.width;
__lastStrumH = __strum.height;
__lastStrumHalfW = __strum.width * 0.5;
__lastStrumHalfH = __strum.height * 0.5;
}
x = -origin.x + offset.x + (originalY * __lastAngleCos) + __strum.x + __lastStrumHalfW;
y = -origin.y + offset.y + (originalY * __lastAngleSin) + __strum.y + __lastStrumHalfH;
super.draw();
setPosition(pos.x, pos.y);
x = originalX;
y = originalY;
} else {
super.draw();
}
@@ -284,6 +285,38 @@ class Note extends FlxSprite
@:privateAccess FlxCamera._defaultCameras = oldDefaultCameras;
}
var __lastDownscrollCam:Bool = false;
var __lastX:Float = 0;
@:noCompletion @:dox(hide) override function isOnScreen(?camera:FlxCamera):Bool {
var downscrollCam = (Std.isOfType(camera, HudCamera) ? cast(camera, HudCamera).downscroll : false);
if (downscrollCam == __lastDownscrollCam)
return super.isOnScreen(camera);
else
__lastX = x;
if (updateFlipY) flipY = (isSustainNote && flipSustain) && (downscrollCam != (__strum != null && __strum.getScrollSpeed(this) < 0));
if (downscrollCam && __strum != null) {
x = -x + 2 * (__strum.x - origin.x + offset.x) + __strum.width;
}
final isOnScreen = super.isOnScreen(camera);
return isOnScreen;
}
override function drawComplex(camera:FlxCamera):Void {
super.drawComplex(camera);
if (__lastDownscrollCam) {
__lastDownscrollCam = false;
x = __lastX;
}
}
public function isOnScreenOriginal(?camera:FlxCamera):Bool {
return super.isOnScreen(camera);
}
// The * 0.5 is so that it's easier to hit them too late, instead of too early
public var earlyPressWindow:Float = 0.5;
public var latePressWindow:Float = 1;
@@ -294,7 +327,7 @@ class Note extends FlxSprite
if (lastScrollSpeed != scrollSpeed) {
lastScrollSpeed = scrollSpeed;
if (nextSustain != null) {
scale.y = (sustainLength * 0.45 * Math.abs(scrollSpeed)) / frameHeight;
scale.y = (sustainLength * 0.45 * scrollSpeed) / frameHeight;
updateHitbox();
scale.y += gapFix / frameHeight;
}
@@ -304,18 +337,28 @@ class Note extends FlxSprite
}
public function updateSustainClip() if (wasGoodHit && !noSustainClip) {
var t = CoolUtil.bound((Conductor.songPosition - strumTime) / height * 0.45 * Math.abs(lastScrollSpeed), 0, 1);
var rect = clipRect == null ? FlxRect.get() : clipRect;
clipRect = rect.set(0, frameHeight * t, frameWidth, frameHeight * (1 - t));
var t = CoolUtil.bound((Conductor.songPosition - strumTime) / height * 0.45 * lastScrollSpeed, 0, 1);
@:bypassAccessor {
if (clipRect == null) clipRect = FlxRect.get();
clipRect.set(0, frameHeight * t, frameWidth, frameHeight * (1 - t));
}
@:privateAccess {
if (frame != null && _frame != null)
_frame = frame.clipTo(clipRect, _frame);
}
}
@:noCompletion
override function set_clipRect(rect:FlxRect):FlxRect
{
clipRect = rect;
override function set_clipRect(rect:FlxRect):FlxRect {
@:bypassAccessor clipRect = rect;
if (frames != null)
frame = frames.frames[animation.frameIndex];
@:privateAccess if (frame != null) {
if (rect != null && _frame != null)
_frame = frame.clipTo(rect, _frame);
else if (_frame != null)
_frame = frame.copyTo(_frame);
dirty = true;
}
return rect;
}
+1 -1
View File
@@ -1657,7 +1657,7 @@ class PlayState extends MusicBeatState
if (strLine.characters != null) // Alt anim Idle
for (character in strLine.characters) {
if (character == null) continue;
character.idleSuffix = event.params[1] ? "-alt" : "";
character.idleSuffix = event.params[1] ? strLine.defaultAnimSuffix : "";
}
}
case "Play Animation":
+66 -19
View File
@@ -2,6 +2,7 @@ package funkin.game;
import flixel.math.FlxPoint;
import flixel.math.FlxAngle;
import flixel.util.typeLimit.OneOfTwo;
import funkin.backend.system.Conductor;
class Strum extends FlxSprite {
@@ -52,8 +53,27 @@ class Strum extends FlxSprite {
public var updateNotesPosY:Bool = true;
public var extraCopyFields(default, set):Array<String> = [];
private inline function set_extraCopyFields(val:Array<String>)
return extraCopyFields = val == null ? [] : val;
@:noCompletion public var __cachedCopyFields:Array<Array<OneOfTwo<String, Int>>> = null;
private function set_extraCopyFields(val:Array<String>) {
extraCopyFields = val == null ? [] : val;
__cachedCopyFields = null;
return extraCopyFields;
}
private inline function __initCachedCopyFields() {
if (__cachedCopyFields != null) return;
__cachedCopyFields = [for (field in extraCopyFields) CoolUtil.parsePropertyString(field)];
}
private inline function __applyCopyFields(daNote:Note) {
for (i in 0...extraCopyFields.length) {
final parsed = __cachedCopyFields[i];
final fromProp = CoolUtil.parseProperty(this, parsed);
final toProp = CoolUtil.parseProperty(daNote, parsed);
toProp.setValue(fromProp.getValue());
}
}
/**
* Whenever the strum is pressed.
@@ -129,13 +149,28 @@ class Strum extends FlxSprite {
}
public override function draw() {
lastDrawCameras = cameras.copy();
if (cameras.length == 1) {
if (lastDrawCameras.length != 1 || lastDrawCameras[0] != cameras[0]) {
lastDrawCameras = [cameras[0]];
}
} else {
lastDrawCameras = cameras.copy();
}
super.draw();
}
@:noCompletion public static inline final PIX180:Float = 565.4866776461628; // 180 * Math.PI
@:noCompletion public static final N_WIDTHDIV2:Float = Note.swagWidth / 2; // DEPRECATED
static var __lastStrumW:Float = Math.NaN;
static var __lastStrumH:Float = Math.NaN;
static var __lastStrumHalfW:Float = 0;
static var __lastStrumHalfH:Float = 0;
static var __noteOffset:FlxPoint = FlxPoint.get();
static var __lastNoteAngle:Float = Math.NaN;
static var __lastAngleCos:Float = 0;
static var __lastAngleSin:Float = 0;
/**
* Updates the position of a note.
* @param daNote The note
@@ -153,8 +188,10 @@ class Strum extends FlxSprite {
}
updateNotePos(daNote);
for (field in extraCopyFields)
CoolUtil.cloneProperty(daNote, field, this); // TODO: make this cached to reduce the reflection calls - Neo
if (extraCopyFields.length > 0) {
__initCachedCopyFields();
__applyCopyFields(daNote);
}
}
private inline function updateNotePos(daNote:Note) {
@@ -169,24 +206,34 @@ class Strum extends FlxSprite {
if (daNote.isSustainNote) daNote.y += daNote.height * 0.5;
}
} else {
if (width != __lastStrumW || height != __lastStrumH) {
__lastStrumW = width;
__lastStrumH = height;
__lastStrumHalfW = width * 0.5;
__lastStrumHalfH = height * 0.5;
}
if (daNote.__noteAngle != __lastNoteAngle) {
__lastNoteAngle = daNote.__noteAngle;
final result = FlxMath.fastSinCos((__lastNoteAngle + 90) * FlxAngle.TO_RAD);
__lastAngleCos = result.cos;
__lastAngleSin = result.sin;
}
final speed = getScrollSpeed(daNote);
final distance = (daNote.strumTime - Conductor.songPosition) * 0.45 * speed;
final __noteAngle = FlxMath.fastSinCos((daNote.__noteAngle + 90) * FlxAngle.TO_RAD);
final angleX = __noteAngle.cos;
final angleY = __noteAngle.sin;
final _noteOffset = FlxPoint.get(angleX * distance, angleY * distance);
_noteOffset.x += -daNote.origin.x + daNote.offset.x;
_noteOffset.y += -daNote.origin.y + daNote.offset.y;
__noteOffset.set(__lastAngleCos * distance, __lastAngleSin * distance);
__noteOffset.x += -daNote.origin.x + daNote.offset.x;
__noteOffset.y += -daNote.origin.y + daNote.offset.y;
if (daNote.isSustainNote) {
final m = (daNote.height * 0.5 * (speed < 0 ? -1 : 1)); // daNote.height works better than this.height in this case ???
_noteOffset.x += angleX * m;
_noteOffset.y += angleY * m;
final m = (daNote.height * 0.5 * (speed < 0 ? -1 : 1));
__noteOffset.x += __lastAngleCos * m;
__noteOffset.y += __lastAngleSin * m;
}
_noteOffset.x += x + (width * 0.5);
_noteOffset.y += y + (height * 0.5);
if (shouldX) daNote.x = _noteOffset.x;
if (shouldY) daNote.y = _noteOffset.y;
_noteOffset.put();
__noteOffset.x += x + __lastStrumHalfW;
__noteOffset.y += y + __lastStrumHalfH;
if (shouldX) daNote.x = __noteOffset.x;
if (shouldY) daNote.y = __noteOffset.y;
}
}
}
+6 -2
View File
@@ -74,6 +74,10 @@ class StrumLine extends FlxTypedGroup<Strum> {
* Which animation suffix on characters that should be used when hitting notes.
*/
public var animSuffix(default, set):String = "";
/**
* The current animation suffix the strumline should use. Note that setting this will only take effect upon the alt. animation being reset.
*/
public var defaultAnimSuffix:String = Flags.DEFAULT_ALT_ANIM_SUFFIX;
/**
* TODO: Write documentation about this being a variable that can help when making multi key
*/
@@ -468,11 +472,11 @@ class StrumLine extends FlxTypedGroup<Strum> {
return animSuffix = str;
}
private inline function set_altAnim(b:Bool):Bool {
animSuffix = b ? "-alt" : "";
animSuffix = b ? defaultAnimSuffix : "";
return b;
}
private inline function get_altAnim():Bool {
return animSuffix == "-alt";
return animSuffix == defaultAnimSuffix;
}
#end
}
+2 -2
View File
@@ -43,8 +43,8 @@ class Options
public static var framerate:Int = 120;
public static var gpuOnlyBitmaps:Bool = #if (mac || web) false #else true #end; // causes issues on mac and web
public static var language = "en"; // default to english, Flags.DEFAULT_LANGUAGE should not modify this
public static var streamedMusic:Bool = true;
public static var streamedVocals:Bool = true;
public static var streamedMusic:Bool = false;
public static var streamedVocals:Bool = false;
public static var quality:Int = 1;
public static var allowConfigWarning:Bool = true;
#if MODCHARTING_FEATURES
@@ -67,7 +67,14 @@ class AdvancedGameplayOptions extends TreeMenuScreen {
public function new() {
super('optionsMenu.advanced', 'optionsTree.gameplay.advanced-desc', 'GameplayOptions.Advanced.');
add(new Checkbox(getNameID('streamedMusic'), getDescID('streamedMusic'), 'streamedMusic'));
add(new Checkbox(getNameID('streamedVocals'), getDescID('streamedVocals'), 'streamedVocals'));
// Remove locked whenever this PR from FunkinCrew is merged.
// https://github.com/FunkinCrew/lime/pull/57
for (checkbox in [
new Checkbox(getNameID('streamedMusic'), getDescID('streamedMusic'), 'streamedMusic'),
new Checkbox(getNameID('streamedVocals'), getDescID('streamedVocals'), 'streamedVocals')
]) {
checkbox.locked = true;
add(checkbox);
}
}
}