Merge remote-tracking branch 'upstream/main'

This commit is contained in:
Ne_Eo
2025-04-10 02:24:58 +02:00
254 changed files with 243 additions and 73 deletions
+1 -1
View File
@@ -18,7 +18,7 @@ class Socket implements IFlxDestroyable {
public function read():String {
try {
return this.socket.input.readUntil(('\n').charCodeAt(0)).replace("\\n", "\n");
return this.socket.input.readUntil('\n'.code).replace("\\n", "\n");
} catch(e) {
}
+118
View File
@@ -980,6 +980,124 @@ class CoolUtil
}
return result;
}
public inline static function parsePropertyString(fieldPath:String):Array<OneOfTwo<String, Int>> {
return FlxTween.parseFieldString(fieldPath);
}
public static function stringifyFieldsPath(fields:Array<OneOfTwo<String, Int>>):String {
var str = new StringBuf();
var first = true;
for (field in fields) {
if (Type.typeof(field) == TInt) {
str.add('[${field}]');
} else {
if (!first)
str.add('.');
str.add(field);
}
first = false;
}
return str.toString();
}
public static function parseProperty(target:Dynamic, fields:OneOfTwo<String, Array<OneOfTwo<String, Int>>>):Dynamic {
var fields:Array<OneOfTwo<String, Int>> = {
if((fields is String)) CoolUtil.parsePropertyString(fields);
else fields;
}
var field = CoolUtil.last(fields);
for (i in 0...fields.length - 1) {
var component = fields[i];
if (Type.typeof(component) == TInt) {
if ((target is Array)) {
var index:Int = cast component;
var arr:Array<Dynamic> = cast target;
target = arr[index];
}
} else { // TClass(String)
target = Reflect.getProperty(target, component);
}
if (!Reflect.isObject(target) && !(target is Array))
throw 'The object does not have the property "$component" in "${stringifyFieldsPath(fields)}"';
}
return new PropertyInfo(target, field);
}
public static function cloneProperty(toTarget:Dynamic, fields:OneOfTwo<String, Array<OneOfTwo<String, Int>>>, fromTarget:Dynamic):Dynamic {
var fields:Array<OneOfTwo<String, Int>> = {
if((fields is String)) CoolUtil.parsePropertyString(fields);
else fields;
}
var toProperty = CoolUtil.parseProperty(toTarget, fields);
var fromProperty = CoolUtil.parseProperty(fromTarget, fields);
return toProperty.setValue(fromProperty.getValue());
}
}
class PropertyInfo {
public var object:Dynamic;
public var field:OneOfTwo<String, Int>;
public var typeOfField:Type.ValueType;
#if hscript_improved
public var isCustom:Bool = false;
public var custom:hscript.IHScriptCustomBehaviour;
#end
public function new(object:Dynamic, field:OneOfTwo<String, Int>) {
this.object = object;
this.field = field;
#if hscript_improved
if (object is hscript.IHScriptCustomBehaviour)
{
isCustom = true;
custom = cast object;
}
#end
typeOfField = Type.typeof(field);
}
public function getValue():Dynamic
{
if (typeOfField == TInt)
{
var index:Int = cast field;
var arr:Array<Dynamic> = cast object;
return arr[index];
}
else
{
#if hscript_improved
if (isCustom)
return custom.hget(field);
else
#end
return Reflect.getProperty(object, field);
}
}
public function setValue(value:Dynamic):Void
{
if (typeOfField == TInt)
{
var index:Int = cast field;
var arr:Array<Dynamic> = cast object;
arr[index] = value;
}
else
{
#if hscript_improved
if (isCustom)
custom.hset(field, value);
else
#end
Reflect.setProperty(object, field, value);
}
}
}
/**
+4 -4
View File
@@ -135,12 +135,12 @@ class ZipUtil {
if (prog == null) prog = new ZipProgress();
try {
var curPath:Array<String> = ['$path'];
var curPath:Array<String> = [path];
var destPath:Array<String> = [];
if (prefix != "") {
prefix = prefix.replace("\\", "/");
while(prefix.charAt(0) == "/") prefix = prefix.substr(1);
while(prefix.charAt(prefix.length-1) == "/") prefix = prefix.substr(0, prefix.length-1);
while(prefix.charCodeAt(0) == "/".code) prefix = prefix.substr(1);
while(prefix.charCodeAt(prefix.length-1) == "/".code) prefix = prefix.substr(0, prefix.length-1);
destPath.push(prefix);
}
@@ -160,7 +160,7 @@ class ZipUtil {
} else {
// is file, put it in the list
var zipPath = '$zipPath/$e';
while(zipPath.charAt(0) == "/") zipPath = zipPath.substr(1);
while(zipPath.charCodeAt(0) == "/".code) zipPath = zipPath.substr(1);
files.push(new StrNameLabel('$path/$e', zipPath));
}
}
+21 -23
View File
@@ -101,29 +101,8 @@ class GameOverSubstate extends MusicBeatSubstate
if (__cancelDefault)
return;
if (controls.ACCEPT)
{
endBullshit();
}
if (controls.BACK)
{
if (PlayState.chartingMode && Charter.undos.unsaved)
game.saveWarn(false);
else {
if (Charter.instance != null) Charter.instance.__clearStatics();
if (FlxG.sound.music != null)
FlxG.sound.music.stop();
FlxG.sound.music = null;
if (PlayState.isStoryMode)
FlxG.switchState(new StoryMenuState());
else
FlxG.switchState(new FreeplayState());
}
}
if (controls.ACCEPT) endBullshit();
if (controls.BACK) exit();
if (!isEnding && ((!lossSFX.playing) || (character.getAnimName() == "firstDeath" && character.isAnimFinished())) && (FlxG.sound.music == null || !FlxG.sound.music.playing))
{
@@ -192,6 +171,25 @@ class GameOverSubstate extends MusicBeatSubstate
});
}
function exit()
{
var event = new CancellableEvent();
gameoverScript.call('onReturnToMenu', [event]);
if (event.cancelled)
return;
if (PlayState.chartingMode && Charter.undos.unsaved) game.saveWarn(false);
else {
if (Charter.instance != null) Charter.instance.__clearStatics();
if (FlxG.sound.music != null) FlxG.sound.music.stop();
FlxG.sound.music = null;
FlxG.switchState(PlayState.isStoryMode ? new StoryMenuState() : new FreeplayState());
}
}
override function destroy()
{
gameoverScript.call("destroy");
+6 -1
View File
@@ -75,6 +75,11 @@ class Note extends FlxSprite
public var scrollSpeed:Null<Float> = null;
public var noteAngle:Null<Float> = null;
public var copyStrumAngle:Bool = true;
public var updateNotesPosX:Bool = true;
public var updateNotesPosY:Bool = true;
public var updateFlipY:Bool = true;
public var noteType(get, never):String;
@:dox(hide) public var __strumCameras:Array<FlxCamera> = null;
@@ -211,7 +216,7 @@ class Note extends FlxSprite
override function drawComplex(camera:FlxCamera) {
var downscrollCam = (camera is HudCamera ? ({var _:HudCamera=cast camera;_;}).downscroll : false);
flipY = (isSustainNote && flipSustain) && (downscrollCam != (__strum != null && __strum.getScrollSpeed(this) < 0));
if (updateFlipY) flipY = (isSustainNote && flipSustain) && (downscrollCam != (__strum != null && __strum.getScrollSpeed(this) < 0));
if (downscrollCam) {
frameOffset.y += __notePosFrameOffset.y * 2;
super.drawComplex(camera);
+25 -5
View File
@@ -710,7 +710,7 @@ class PlayState extends MusicBeatState
case 2: "girlfriend";
}) : strumLine.position;
if (strumLine.characters != null) for(k=>charName in strumLine.characters) {
var char = new Character(0, 0, charName, stage.isCharFlipped(charPosName, strumLine.type == 1));
var char = new Character(0, 0, charName, stage.isCharFlipped(stage.characterPoses[charName] != null ? charName : charPosName, strumLine.type == 1));
stage.applyCharStuff(char, charPosName, k);
chars.push(char);
}
@@ -1312,9 +1312,6 @@ class PlayState extends MusicBeatState
updateRatingStuff();
if (controls.PAUSE && startedCountdown && canPause)
pauseGame();
if (canAccessDebugMenus) {
if (chartingMode && FlxG.keys.justPressed.SEVEN) {
FlxG.switchState(new funkin.editors.charter.Charter(SONG.meta.name, difficulty, false));
@@ -1357,6 +1354,9 @@ class PlayState extends MusicBeatState
while(events.length > 0 && events.last().time <= Conductor.songPosition)
executeEvent(events.pop());
if (controls.PAUSE && startedCountdown && canPause)
pauseGame();
if (generatedMusic)
moveCamera();
@@ -1442,7 +1442,27 @@ class PlayState extends MusicBeatState
switch(event.name) {
case "HScript Call":
scripts.call(event.params[0], event.params[1].split(','));
var scriptPacks:Array<ScriptPack> = [scripts, stateScripts];
for (strLine in strumLines.members) for (char in strLine.characters) scriptPacks.push(char.scripts);
var args:Array<String> = event.params[1].split(',');
for (pack in scriptPacks) {
pack.call(event.params[0], args);
//public functions
if (pack.publicVariables.exists(event.params[0])) {
var func = pack.publicVariables.get(event.params[0]);
if (func != null && Reflect.isFunction(func))
Reflect.callMethod(null, func, args);
}
}
//static functions
if (Script.staticVariables.exists(event.params[0])) {
var func = Script.staticVariables.get(event.params[0]);
if (func != null && Reflect.isFunction(func))
Reflect.callMethod(null, func, args);
}
case "Camera Movement":
var tween = eventsTween.get("cameraMovement");
if (tween != null) tween.cancel();
+58 -32
View File
@@ -42,6 +42,18 @@ class Strum extends FlxSprite {
public var lastDrawCameras(default, null):Array<FlxCamera> = [];
// Copy fields
public var copyStrumCamera:Bool = true;
public var copyStrumScrollX:Bool = true;
public var copyStrumScrollY:Bool = true;
public var copyStrumAngle:Bool = true;
public var updateNotesPosX:Bool = true;
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;
/**
* Whenever the strum is pressed.
**/
@@ -130,47 +142,61 @@ class Strum extends FlxSprite {
public function updateNotePosition(daNote:Note) {
if (!daNote.exists) return;
daNote.__strumCameras = lastDrawCameras;
daNote.__strum = this;
daNote.scrollFactor.set(scrollFactor.x, scrollFactor.y);
daNote.__noteAngle = getNotesAngle(daNote);
daNote.angle = daNote.isSustainNote ? daNote.__noteAngle : angle;
if (copyStrumCamera) daNote.__strumCameras = lastDrawCameras;
if (copyStrumScrollX) daNote.scrollFactor.x = scrollFactor.x;
if (copyStrumScrollY) daNote.scrollFactor.y = scrollFactor.y;
if (copyStrumAngle && daNote.copyStrumAngle) {
daNote.__noteAngle = getNotesAngle(daNote);
daNote.angle = daNote.isSustainNote ? daNote.__noteAngle : angle;
}
updateNotePos(daNote);
for (field in extraCopyFields)
CoolUtil.cloneProperty(daNote, field, this); // TODO: make this cached to reduce the reflection calls - Neo
}
private inline function updateNotePos(daNote:Note) {
if (daNote.strumRelativePos) {
daNote.setPosition((this.width - daNote.width) / 2, (daNote.strumTime - Conductor.songPosition) * (0.45 * CoolUtil.quantize(getScrollSpeed(daNote), 100)));
if (daNote.isSustainNote) daNote.y += N_WIDTHDIV2;
} else {
var offset = FlxPoint.get(0, (Conductor.songPosition - daNote.strumTime) * (0.45 * CoolUtil.quantize(getScrollSpeed(daNote), 100)));
var realOffset = FlxPoint.get(0, 0);
var shouldX = updateNotesPosX && daNote.updateNotesPosX;
var shouldY = updateNotesPosY && daNote.updateNotesPosY;
if (daNote.isSustainNote) offset.y -= N_WIDTHDIV2;
if (Std.int(daNote.__noteAngle % 360) != 0) {
var noteAngleCos = FlxMath.fastCos(daNote.__noteAngle / PIX180);
var noteAngleSin = FlxMath.fastSin(daNote.__noteAngle / PIX180);
var aOffset:FlxPoint = FlxPoint.get(
(daNote.origin.x / daNote.scale.x) - daNote.offset.x,
(daNote.origin.y / daNote.scale.y) - daNote.offset.y
);
realOffset.x = -aOffset.x + (noteAngleCos * (offset.x + aOffset.x)) + (noteAngleSin * (offset.y + aOffset.y));
realOffset.y = -aOffset.y + (noteAngleSin * (offset.x + aOffset.x)) + (noteAngleCos * (offset.y + aOffset.y));
aOffset.put();
if (shouldX || shouldY) {
if (daNote.strumRelativePos) {
if (shouldX) daNote.x = (this.width - daNote.width) / 2;
if (shouldY) {
daNote.y = (daNote.strumTime - Conductor.songPosition) * (0.45 * CoolUtil.quantize(getScrollSpeed(daNote), 100));
if (daNote.isSustainNote) daNote.y += N_WIDTHDIV2;
}
} else {
realOffset.x = offset.x;
realOffset.y = offset.y;
var offset = FlxPoint.get(0, (Conductor.songPosition - daNote.strumTime) * (0.45 * CoolUtil.quantize(getScrollSpeed(daNote), 100)));
var realOffset = FlxPoint.get(0, 0);
if (daNote.isSustainNote) offset.y -= N_WIDTHDIV2;
if (Std.int(daNote.__noteAngle % 360) != 0) {
var noteAngleCos = FlxMath.fastCos(daNote.__noteAngle / PIX180);
var noteAngleSin = FlxMath.fastSin(daNote.__noteAngle / PIX180);
var aOffset:FlxPoint = FlxPoint.get(
(daNote.origin.x / daNote.scale.x) - daNote.offset.x,
(daNote.origin.y / daNote.scale.y) - daNote.offset.y
);
realOffset.x = -aOffset.x + (noteAngleCos * (offset.x + aOffset.x)) + (noteAngleSin * (offset.y + aOffset.y));
realOffset.y = -aOffset.y + (noteAngleSin * (offset.x + aOffset.x)) + (noteAngleCos * (offset.y + aOffset.y));
aOffset.put();
} else {
realOffset.x = offset.x;
realOffset.y = offset.y;
}
realOffset.y *= -1;
if (shouldX) daNote.x = x + realOffset.x;
if (shouldY) daNote.y = y + realOffset.y;
offset.put();
realOffset.put();
}
realOffset.y *= -1;
daNote.setPosition(x + realOffset.x, y + realOffset.y);
offset.put();
realOffset.put();
}
}
+5 -2
View File
@@ -347,8 +347,10 @@ class StrumLine extends FlxTypedGroup<Strum> {
* Creates a strum and returns the created strum (needs to be added manually).
* @param i Index of the strum
* @param animPrefix (Optional) Animation prefix (`left` = `arrowLEFT`, `left press`, `left confirm`).
* @param spritePath (Optional) The sprite's graphic path if you don't want the default one.
* @param playIntroAnimation (Optional) Whenever the intro animation should be played, by default might be `true` under certain conditions.
*/
public function createStrum(i:Int, ?animPrefix:String) {
public function createStrum(i:Int, ?animPrefix:String, ?spritePath:String, ?playIntroAnimation:Bool) {
if (animPrefix == null)
animPrefix = strumAnimPrefix[i % strumAnimPrefix.length];
var babyArrow:Strum = new Strum(startingPos.x + ((Note.swagWidth * strumScale) * i), startingPos.y);
@@ -359,7 +361,8 @@ class StrumLine extends FlxTypedGroup<Strum> {
babyArrow.scrollSpeed = data.scrollSpeed;
var event = EventManager.get(StrumCreationEvent).recycle(babyArrow, PlayState.instance.strumLines.members.indexOf(this), i, animPrefix);
event.__doAnimation = !MusicBeatState.skipTransIn && (PlayState.instance != null ? PlayState.instance.introLength > 0 : true);
event.__doAnimation = playIntroAnimation == null ? (!MusicBeatState.skipTransIn && (PlayState.instance != null ? PlayState.instance.introLength > 0 : true)) : playIntroAnimation;
if (spritePath != null) event.sprite = spritePath;
if (PlayState.instance != null) event = PlayState.instance.gameAndCharsEvent("onStrumCreation", event);
if (!event.cancelled) {
@@ -92,7 +92,7 @@ class DialogueCutscene extends ScriptedCutscene {
callback: node.getAtt('callback'),
changeDefAnim: node.getAtt('changeDefAnim'),
speed: Std.parseFloat(node.getAtt("speed")).getDefault(0.05),
musicVolume: node.has.musicVolume ? (volume = Std.parseFloat(node.att.speed).getDefault(0.8)) : null,
musicVolume: node.has.musicVolume ? (volume = Std.parseFloat(node.att.musicVolume).getDefault(0.8)) : null,
changeMusic: node.has.changeMusic ? FlxG.sound.load(Paths.music(node.att.changeMusic), volume, true) : null,
playSound: node.has.playSound ? FlxG.sound.load(Paths.sound(node.att.playSound)) : null,
nextSound: node.has.nextSound ? FlxG.sound.load(Paths.sound(node.att.nextSound)) : null,