1
0
Fork 0
mirror of https://github.com/ninjamuffin99/Funkin.git synced 2024-11-15 11:22:55 +00:00

Merge branch 'rewrite/master' into lemz1/fps-setting

This commit is contained in:
Cameron Taylor 2024-09-19 23:34:51 -04:00 committed by GitHub
commit 76bf5df57f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
29 changed files with 321 additions and 118 deletions

44
.github/label-actions.yml vendored Normal file
View file

@ -0,0 +1,44 @@
# Configuration for Label Actions - https://github.com/dessant/label-actions
# Automatically close issues and pull requests when the `status: duplicate` label is applied
'status: duplicate':
issues:
# Post a comment
comment: >
This issue is a duplicate. Please direct all discussion to the original issue.
# Close the issue
close: true
# Remove other status labels
unlabel:
- 'status: pending triage'
# Set a close reason
close-reason: 'not planned'
prs:
# Post a comment
comment: >
This pull request is a duplicate. Please direct all discussion to the original pull request.
# Remove other status labels
unlabel:
- 'status: pending triage'
# Close the pull request
close: true
# Set a close reason
close-reason: 'not planned'
'status: rejected':
issues:
# Close the issue
close: true
# Remove other status labels
unlabel:
- 'status: pending triage'
# Set a close reason
close-reason: 'not planned'
prs:
# Close the pull request
close: true
# Remove other status labels
unlabel:
- 'status: pending triage'
# Set a close reason
close-reason: 'not planned'

29
.github/workflows/label-actions.yml vendored Normal file
View file

@ -0,0 +1,29 @@
# Perform actions when labels are applied to issues, discussions, or pull requests
# See .github/label-actions.yml
name: 'Label Actions'
on:
issues:
types:
- labeled
- unlabeled
pull_request_target:
types:
- labeled
- unlabeled
discussion:
types:
- labeled
- unlabeled
permissions:
contents: read
issues: write
pull-requests: write
discussions: write
jobs:
action:
runs-on: ubuntu-latest
steps:
- uses: dessant/label-actions@v4

52
.github/workflows/label-issue.yml vendored Normal file
View file

@ -0,0 +1,52 @@
name: "Issue Labeler"
on:
issues:
types:
- opened
- reopened
- edited
jobs:
# When an issue is opened, perform a similarity check for potential duplicates.
# If some are found, add a label and comment listing the potential duplicate issues.
potential-duplicate:
name: Detect potential duplicate issues
runs-on: ubuntu-latest
steps:
- uses: wow-actions/potential-duplicates@v1
with:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# Issue title filter work with anymatch https://www.npmjs.com/package/anymatch.
# Any matched issue will stop detection immediately.
# You can specify multi filters in each line.
filter: ''
# Exclude keywords in title before detecting.
exclude: ''
# Label to set, when potential duplicates are detected.
label: 'potential duplicate'
# Get issues with state to compare. Supported state: 'all', 'closed', 'open'.
state: all
# If similarity is higher than this threshold([0,1]), issue will be marked as duplicate.
# Turn this up if the detection is too sensitive
threshold: 0.6
# Reactions to be add to comment when potential duplicates are detected.
# Available reactions: "-1", "+1", "confused", "laugh", "heart", "hooray", "rocket", "eyes"
# reactions: '-1'
# Comment to post when potential duplicates are detected.
comment: >
Potential duplicates: {{#issues}}
- [#{{ number }}] {{ title }} ({{ accuracy }}%)
{{/issues}}
# When an issue is opened, detect if it has an empty body or incomplete issue form.
# If it does, close the issue immediately.
empty-issues:
name: Close empty issues
runs-on: ubuntu-latest
steps:
- name: Run empty issues closer action
uses: rickstaa/empty-issues-closer-action@v1
env:
github_token: ${{ secrets.GITHUB_TOKEN }}
with:
close_comment: Closing this issue because it appears to be empty. Please update the issue for it to be reopened.
open_comment: Reopening this issue because the author provided more information.

View file

@ -3,6 +3,7 @@ on:
- pull_request_target
jobs:
# Apply labels to pull requests based on which files were edited
labeler:
permissions:
contents: read
@ -13,6 +14,7 @@ jobs:
uses: actions/labeler@v5
with:
sync-labels: true
# Apply labels to pull requests based on how many lines were edited
changed-lines-count-labeler:
permissions:
contents: read

4
.gitmodules vendored
View file

@ -1,6 +1,6 @@
[submodule "assets"]
path = assets
url = https://github.com/FunkinCrew/funkin.assets
url = https://github.com/FunkinCrew/Funkin-assets-secret
[submodule "art"]
path = art
url = https://github.com/FunkinCrew/funkin.art
url = https://github.com/FunkinCrew/Funkin-art-secret

2
assets

@ -1 +1 @@
Subproject commit bc7009b4242691faa5c4552f7ca8a2f28e8cb1d2
Subproject commit b029e067835b80be35ee4de149ac3c6cf2bb4c4c

View file

@ -6,7 +6,7 @@
"name": "EliteMasterEric"
}
],
"api_version": "0.1.0",
"api_version": "0.5.0",
"mod_version": "1.0.0",
"license": "Apache-2.0"
}

View file

@ -70,14 +70,14 @@
"name": "haxeui-core",
"type": "git",
"dir": null,
"ref": "22f7c5a8ffca90d4677cffd6e570f53761709fbc",
"ref": "c9d96b168ea2a19274ad7c766ab1a34b57baa793",
"url": "https://github.com/haxeui/haxeui-core"
},
{
"name": "haxeui-flixel",
"type": "git",
"dir": null,
"ref": "28bb710d0ae5d94b5108787593052165be43b980",
"ref": "013b9d4e56bfe9a034e028a8d685f0b274cb73c4",
"url": "https://github.com/haxeui/haxeui-flixel"
},
{

View file

@ -270,6 +270,7 @@ typedef PlayerResultsData =
{
var music:PlayerResultsMusicData;
var perfectGold:Array<PlayerResultsAnimationData>;
var perfect:Array<PlayerResultsAnimationData>;
var excellent:Array<PlayerResultsAnimationData>;
var great:Array<PlayerResultsAnimationData>;

View file

@ -184,7 +184,7 @@ class FlxAtlasSprite extends FlxAnimate
// Move to the first frame of the animation.
// goToFrameLabel(id);
trace('Playing animation $id');
// trace('Playing animation $id');
if ((id == null || id == "") || this.anim.symbolDictionary.exists(id) || (this.anim.getByName(id) != null))
{
this.anim.play(id, restart, false, startFrame);

View file

@ -258,7 +258,7 @@ class PolymodHandler
Polymod.blacklistImport('cpp.Lib');
// `Unserializer`
// Unserializerr.DEFAULT_RESOLVER.resolveClass() can access blacklisted packages
// Unserializer.DEFAULT_RESOLVER.resolveClass() can access blacklisted packages
Polymod.blacklistImport('Unserializer');
// `lime.system.CFFI`

View file

@ -472,9 +472,12 @@ class ResultState extends MusicBeatSubState
{
ease: FlxEase.quartOut,
onUpdate: _ -> {
clearPercentLerp = Math.round(clearPercentLerp);
clearPercentCounter.curNumber = Math.round(clearPercentCounter.curNumber);
// Only play the tick sound if the number increased.
if (clearPercentLerp != clearPercentCounter.curNumber)
{
trace('$clearPercentLerp and ${clearPercentCounter.curNumber}');
clearPercentLerp = clearPercentCounter.curNumber;
FunkinSound.playOnce(Paths.sound('scrollMenu'));
}

View file

@ -12,6 +12,7 @@ import funkin.util.assets.DataAssets;
import funkin.util.VersionUtil;
import haxe.Json;
import openfl.utils.Assets;
import flixel.graphics.frames.FlxFrame;
class CharacterDataParser
{
@ -281,41 +282,78 @@ class CharacterDataParser
}
/**
* TODO: Hardcode this.
* Returns the idle frame of a character.
*/
public static function getCharPixelIconAsset(char:String):String
public static function getCharPixelIconAsset(char:String):FlxFrame
{
var icon:String = char;
var charPath:String = "freeplay/icons/";
switch (icon)
// FunkinCrew please dont skin me alive for copying pixelated icon and changing it a tiny bit
switch (char)
{
case "bf-christmas" | "bf-car" | "bf-pixel" | "bf-holding-gf":
icon = "bf";
case "bf-christmas" | "bf-car" | "bf-pixel" | "bf-holding-gf" | "bf-dark":
charPath += "bfpixel";
case "monster-christmas":
icon = "monster";
charPath += "monsterpixel";
case "mom" | "mom-car":
icon = "mommy";
charPath += "mommypixel";
case "pico-blazin" | "pico-playable" | "pico-speaker":
icon = "pico";
case "gf-christmas" | "gf-car" | "gf-pixel" | "gf-tankmen":
icon = "gf";
charPath += "picopixel";
case "gf-christmas" | "gf-car" | "gf-pixel" | "gf-tankmen" | "gf-dark":
charPath += "gfpixel";
case "dad":
icon = "daddy";
charPath += "dadpixel";
case "darnell-blazin":
icon = "darnell";
charPath += "darnellpixel";
case "senpai-angry":
icon = "senpai";
charPath += "senpaipixel";
case "spooky-dark":
icon = "spooky";
charPath += "spookypixel";
case "tankman-atlas":
icon = "tankman";
charPath += "tankmanpixel";
case "pico-christmas" | "pico-dark":
charPath += "picopixel";
default:
charPath += '${char}pixel';
}
var path = Paths.image("freeplay/icons/" + icon + "pixel");
if (Assets.exists(path)) return path;
if (!Assets.exists(Paths.image(charPath)))
{
trace('[WARN] Character ${char} has no freeplay icon.');
return null;
}
// TODO: Hardcode some additional behavior or a fallback.
return null;
var isAnimated = Assets.exists(Paths.file('images/$charPath.xml'));
var frame:FlxFrame = null;
if (isAnimated)
{
var frames = Paths.getSparrowAtlas(charPath);
var idleFrame:FlxFrame = frames.frames.find(function(frame:FlxFrame):Bool {
return frame.name.startsWith('idle');
});
if (idleFrame == null)
{
trace('[WARN] Character ${char} has no idle in their freeplay icon.');
return null;
}
// so, haxe.ui.backend.AssetsImpl uses the parent width and height, which makes the image go crazy when rendered
// so this is a work around so that it uses the actual width and height
var imageGraphic = flixel.graphics.FlxGraphic.fromFrame(idleFrame);
var imageFrame = flixel.graphics.frames.FlxImageFrame.fromImage(imageGraphic);
frame = imageFrame.frame;
}
else
{
var imageFrame = flixel.graphics.frames.FlxImageFrame.fromImage(Paths.image(charPath));
frame = imageFrame.frame;
}
return frame;
}
/**

View file

@ -85,7 +85,8 @@ class StrumlineNote extends FlxSprite
noteStyle.applyStrumlineFrames(this);
noteStyle.applyStrumlineAnimations(this, this.direction);
this.setGraphicSize(Std.int(Strumline.STRUMLINE_SIZE * noteStyle.getStrumlineScale()));
var scale = noteStyle.getStrumlineScale();
this.scale.set(scale, scale);
this.updateHitbox();
noteStyle.applyStrumlineOffsets(this);

View file

@ -87,6 +87,7 @@ class SustainTrail extends FlxSprite
public var bottomClip:Float = 0.9;
public var isPixel:Bool;
public var noteStyleOffsets:Array<Float>;
var graphicWidth:Float = 0;
var graphicHeight:Float = 0;
@ -107,6 +108,7 @@ class SustainTrail extends FlxSprite
this.noteDirection = noteDirection;
setupHoldNoteGraphic(noteStyle);
noteStyleOffsets = noteStyle.getHoldNoteOffsets();
indices = new DrawData<Int>(12, true, TRIANGLE_VERTEX_INDICES);
@ -137,7 +139,6 @@ class SustainTrail extends FlxSprite
zoom = 1.0;
zoom *= noteStyle.fetchHoldNoteScale();
zoom *= 0.7;
// CALCULATE SIZE
graphicWidth = graphic.width / 8 * zoom; // amount of notes * 2
@ -202,7 +203,7 @@ class SustainTrail extends FlxSprite
{
width = graphicWidth;
height = graphicHeight;
offset.set(0, 0);
offset.set(noteStyleOffsets[0], noteStyleOffsets[1]);
origin.set(width * 0.5, height * 0.5);
}

View file

@ -93,7 +93,8 @@ class NoteStyle implements IRegistryEntry<NoteStyleData>
buildNoteAnimations(target);
// Set the scale.
target.setGraphicSize(Strumline.STRUMLINE_SIZE * getNoteScale());
var scale = getNoteScale();
target.scale.set(scale, scale);
target.updateHitbox();
}
@ -224,6 +225,13 @@ class NoteStyle implements IRegistryEntry<NoteStyleData>
return data?.scale ?? 1.0;
}
public function getHoldNoteOffsets():Array<Float>
{
var data = _data?.assets?.holdNote;
if (data == null && fallback != null) return fallback.getHoldNoteOffsets();
return data?.offsets ?? [0.0, 0.0];
}
public function applyStrumlineFrames(target:StrumlineNote):Void
{
// TODO: Add support for multi-Sparrow.
@ -304,9 +312,16 @@ class NoteStyle implements IRegistryEntry<NoteStyleData>
return thx.Arrays.filterNull(result);
}
public function getStrumlineOffsets():Array<Float>
{
var data = _data?.assets?.noteStrumline;
if (data == null && fallback != null) return fallback.getStrumlineOffsets();
return data?.offsets ?? [0.0, 0.0];
}
public function applyStrumlineOffsets(target:StrumlineNote):Void
{
var offsets = _data?.assets?.noteStrumline?.offsets ?? [0.0, 0.0];
var offsets = getStrumlineOffsets();
target.x += offsets[0];
target.y += offsets[1];
}
@ -575,7 +590,7 @@ class NoteStyle implements IRegistryEntry<NoteStyleData>
var result = _data.assets.judgementBad?.isPixel;
if (result == null && fallback != null) result = fallback.isJudgementSpritePixel(rating);
return result ?? false;
case "GO":
case "shit":
var result = _data.assets.judgementShit?.isPixel;
if (result == null && fallback != null) result = fallback.isJudgementSpritePixel(rating);
return result ?? false;

View file

@ -17,7 +17,7 @@ import thx.semver.Version;
@:nullSafety
class Save
{
public static final SAVE_DATA_VERSION:thx.semver.Version = "2.0.5";
public static final SAVE_DATA_VERSION:thx.semver.Version = "2.0.4";
public static final SAVE_DATA_VERSION_RULE:thx.semver.VersionRule = "2.0.x";
// We load this version's saves from a new save path, to maintain SOME level of backwards compatibility.
@ -34,19 +34,19 @@ class Save
{
if (_instance == null)
{
_instance = new Save(FlxG.save.data);
return _instance = load();
}
return _instance;
}
var data:RawSaveData;
public static function load():Void
public static function load():Save
{
trace("[SAVE] Loading save...");
// Bind save data.
loadFromSlot(1);
return loadFromSlot(1);
}
/**
@ -65,7 +65,9 @@ class Save
public static function getDefault():RawSaveData
{
return {
version: Save.SAVE_DATA_VERSION,
// Version number is an abstract(Array) internally.
// This means it copies by reference, so merging save data overides the version number lol.
version: thx.Dynamics.clone(Save.SAVE_DATA_VERSION),
volume: 1.0,
mute: false,
@ -434,7 +436,9 @@ class Save
{
if (!data.unlocks.charactersSeen.contains(character))
{
trace('Character seen: ' + character);
data.unlocks.charactersSeen.push(character);
trace('New characters seen list: ' + data.unlocks.charactersSeen);
flush();
}
}
@ -833,7 +837,7 @@ class Save
* If you set slot to `2`, it will load an independe
* @param slot
*/
static function loadFromSlot(slot:Int):Void
static function loadFromSlot(slot:Int):Save
{
trace("[SAVE] Loading save from slot " + slot + "...");
@ -851,12 +855,14 @@ class Save
trace('[SAVE] Found legacy save data, converting...');
var gameSave = SaveDataMigrator.migrateFromLegacy(legacySaveData);
FlxG.save.mergeData(gameSave.data, true);
return gameSave;
}
else
{
trace('[SAVE] No legacy save data found.');
var gameSave = new Save();
FlxG.save.mergeData(gameSave.data, true);
return gameSave;
}
}
else
@ -864,6 +870,8 @@ class Save
trace('[SAVE] Found existing save data.');
var gameSave = SaveDataMigrator.migrate(FlxG.save.data);
FlxG.save.mergeData(gameSave.data, true);
return gameSave;
}
}

View file

@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [2.0.4] - 2024-09-12
Note to self: Only update to 2.1.0 when migration is needed.
### Added
- `unlocks.charactersSeen:Array<String>` to `Save`
- `unlocks.oldChar:Bool` to `Save`
## [2.0.5] - 2024-05-21
### Fixed
- Resolved an issue where HTML5 wouldn't store the semantic version properly, causing the game to fail to load the save.

View file

@ -47,7 +47,6 @@ class CharSelectPlayer extends FlxAtlasSprite implements IBPMSyncedScriptedClass
//
if (getCurrentAnimation() == "idle")
{
trace('Player beat hit');
playAnimation("idle", true, false, false);
}
};

View file

@ -71,6 +71,7 @@ class CharSelectSubState extends MusicBeatSubState
var availableChars:Map<Int, String> = new Map<Int, String>();
var pressedSelect:Bool = false;
var selectTimer:FlxTimer = new FlxTimer();
var allowInput:Bool = false;
var selectSound:FunkinSound;
var unlockSound:FunkinSound;
@ -430,6 +431,8 @@ class CharSelectSubState extends MusicBeatSubState
overrideExisting: true,
restartTrack: true,
onLoad: function() {
allowInput = true;
@:privateAccess
gfChill.analyzer = new SpectralAnalyzer(FlxG.sound.music._channel.__audioSource, 7, 0.1);
#if desktop
@ -573,6 +576,8 @@ class CharSelectSubState extends MusicBeatSubState
overrideExisting: true,
restartTrack: true,
onLoad: function() {
allowInput = true;
@:privateAccess
gfChill.analyzer = new SpectralAnalyzer(FlxG.sound.music._channel.__audioSource, 7, 0.1);
#if desktop
@ -642,6 +647,7 @@ class CharSelectSubState extends MusicBeatSubState
function goToFreeplay():Void
{
allowInput = false;
autoFollow = false;
FlxTween.tween(cursor, {alpha: 0}, 0.8, {ease: FlxEase.expoOut});
@ -695,7 +701,7 @@ class CharSelectSubState extends MusicBeatSubState
syncAudio(elapsed);
if (!pressedSelect)
if (allowInput && !pressedSelect)
{
if (controls.UI_UP) holdTmrUp += elapsed;
if (controls.UI_UP_R)
@ -789,7 +795,7 @@ class CharSelectSubState extends MusicBeatSubState
gfChill.visible = true;
curChar = availableChars.get(getCurrentSelected());
if (!pressedSelect && controls.ACCEPT)
if (allowInput && !pressedSelect && controls.ACCEPT)
{
cursorConfirmed.visible = true;
cursorConfirmed.x = cursor.x - 2;
@ -817,7 +823,7 @@ class CharSelectSubState extends MusicBeatSubState
});
}
if (pressedSelect && controls.BACK)
if (allowInput && pressedSelect && controls.BACK)
{
cursorConfirmed.visible = false;
grpCursors.visible = true;
@ -847,7 +853,7 @@ class CharSelectSubState extends MusicBeatSubState
gfChill.visible = false;
if (controls.ACCEPT)
if (allowInput && controls.ACCEPT)
{
cursorDenied.visible = true;
cursorDenied.x = cursor.x - 2;

View file

@ -700,7 +700,7 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
function get_isCursorOverHaxeUI():Bool
{
return Screen.instance.hasSolidComponentUnderPoint(FlxG.mouse.screenX, FlxG.mouse.screenY);
return Screen.instance.hasSolidComponentUnderPoint(FlxG.mouse.viewX, FlxG.mouse.viewY);
}
/**
@ -3840,7 +3840,7 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
// Handle scroll anchor
if (scrollAnchorScreenPos != null)
{
var currentScreenPos = new FlxPoint(FlxG.mouse.screenX, FlxG.mouse.screenY);
var currentScreenPos = new FlxPoint(FlxG.mouse.viewX, FlxG.mouse.viewX);
var distance = currentScreenPos - scrollAnchorScreenPos;
var verticalDistance = distance.y;
@ -4121,8 +4121,8 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
var overlapsRenderedEvents:Bool = FlxG.mouse.overlaps(renderedEvents);
// Cursor position relative to the grid.
var cursorX:Float = FlxG.mouse.screenX - gridTiledSprite.x;
var cursorY:Float = FlxG.mouse.screenY - gridTiledSprite.y;
var cursorX:Float = FlxG.mouse.viewX - gridTiledSprite.x;
var cursorY:Float = FlxG.mouse.viewY - gridTiledSprite.y;
var overlapsSelectionBorder:Bool = overlapsGrid
&& ((cursorX % 40) < (GRID_SELECTION_BORDER_WIDTH / 2)
@ -4137,7 +4137,7 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
{
if (scrollAnchorScreenPos == null)
{
scrollAnchorScreenPos = new FlxPoint(FlxG.mouse.screenX, FlxG.mouse.screenY);
scrollAnchorScreenPos = new FlxPoint(FlxG.mouse.viewX, FlxG.mouse.viewY);
selectionBoxStartPos = null;
}
else
@ -4159,11 +4159,11 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
else if (notePreview != null && FlxG.mouse.overlaps(notePreview) && !isCursorOverHaxeUI)
{
// Clicked note preview
notePreviewScrollAreaStartPos = new FlxPoint(FlxG.mouse.screenX, FlxG.mouse.screenY);
notePreviewScrollAreaStartPos = new FlxPoint(FlxG.mouse.viewX, FlxG.mouse.viewY);
}
else if (!isCursorOverHaxeUI && (!overlapsGrid || overlapsSelectionBorder))
{
selectionBoxStartPos = new FlxPoint(FlxG.mouse.screenX, FlxG.mouse.screenY);
selectionBoxStartPos = new FlxPoint(FlxG.mouse.viewX, FlxG.mouse.viewY);
// Drawing selection box.
targetCursorMode = Crosshair;
}
@ -4188,7 +4188,7 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
{
// Clicked on the playhead scroll area.
// Move the playhead to the cursor position.
this.playheadPositionInPixels = FlxG.mouse.screenY - (GRID_INITIAL_Y_POS);
this.playheadPositionInPixels = FlxG.mouse.viewY - (GRID_INITIAL_Y_POS);
moveSongToScrollPosition();
// Cursor should be a grabby hand.
@ -4313,27 +4313,27 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
// Clicking and dragging.
// Scroll the screen if the mouse is above or below the grid.
if (FlxG.mouse.screenY < MENU_BAR_HEIGHT)
if (FlxG.mouse.viewY < MENU_BAR_HEIGHT)
{
// Scroll up.
var diff:Float = MENU_BAR_HEIGHT - FlxG.mouse.screenY;
var diff:Float = MENU_BAR_HEIGHT - FlxG.mouse.viewY;
scrollPositionInPixels -= diff * 0.5; // Too fast!
moveSongToScrollPosition();
}
else if (FlxG.mouse.screenY > (playbarHeadLayout?.y ?? 0.0))
else if (FlxG.mouse.viewY > (playbarHeadLayout?.y ?? 0.0))
{
// Scroll down.
var diff:Float = FlxG.mouse.screenY - (playbarHeadLayout?.y ?? 0.0);
var diff:Float = FlxG.mouse.viewY - (playbarHeadLayout?.y ?? 0.0);
scrollPositionInPixels += diff * 0.5; // Too fast!
moveSongToScrollPosition();
}
// Render the selection box.
var selectionRect:FlxRect = new FlxRect();
selectionRect.x = Math.min(FlxG.mouse.screenX, selectionBoxStartPos.x);
selectionRect.y = Math.min(FlxG.mouse.screenY, selectionBoxStartPos.y);
selectionRect.width = Math.abs(FlxG.mouse.screenX - selectionBoxStartPos.x);
selectionRect.height = Math.abs(FlxG.mouse.screenY - selectionBoxStartPos.y);
selectionRect.x = Math.min(FlxG.mouse.viewX, selectionBoxStartPos.x);
selectionRect.y = Math.min(FlxG.mouse.viewY, selectionBoxStartPos.y);
selectionRect.width = Math.abs(FlxG.mouse.viewX - selectionBoxStartPos.x);
selectionRect.height = Math.abs(FlxG.mouse.viewY - selectionBoxStartPos.y);
setSelectionBoxBounds(selectionRect);
targetCursorMode = Crosshair;
@ -4461,8 +4461,8 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
// Player is clicking and holding on note preview to scrub around.
targetCursorMode = Grabbing;
var clickedPosInPixels:Float = FlxMath.remapToRange(FlxG.mouse.screenY, (notePreview?.y ?? 0.0),
(notePreview?.y ?? 0.0) + (notePreview?.height ?? 0.0), 0, songLengthInPixels);
var clickedPosInPixels:Float = FlxMath.remapToRange(FlxG.mouse.viewY, (notePreview?.y ?? 0.0), (notePreview?.y ?? 0.0) + (notePreview?.height ?? 0.0),
0, songLengthInPixels);
scrollPositionInPixels = clickedPosInPixels;
moveSongToScrollPosition();
@ -4520,17 +4520,17 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
targetCursorMode = Grabbing;
// Scroll the screen if the mouse is above or below the grid.
if (FlxG.mouse.screenY < MENU_BAR_HEIGHT)
if (FlxG.mouse.viewY < MENU_BAR_HEIGHT)
{
// Scroll up.
var diff:Float = MENU_BAR_HEIGHT - FlxG.mouse.screenY;
var diff:Float = MENU_BAR_HEIGHT - FlxG.mouse.viewY;
scrollPositionInPixels -= diff * 0.5; // Too fast!
moveSongToScrollPosition();
}
else if (FlxG.mouse.screenY > (playbarHeadLayout?.y ?? 0.0))
else if (FlxG.mouse.viewY > (playbarHeadLayout?.y ?? 0.0))
{
// Scroll down.
var diff:Float = FlxG.mouse.screenY - (playbarHeadLayout?.y ?? 0.0);
var diff:Float = FlxG.mouse.viewY - (playbarHeadLayout?.y ?? 0.0);
scrollPositionInPixels += diff * 0.5; // Too fast!
moveSongToScrollPosition();
}
@ -4811,11 +4811,11 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
// Show the context menu connected to the note.
if (useSingleNoteContextMenu)
{
this.openNoteContextMenu(FlxG.mouse.screenX, FlxG.mouse.screenY, highlightedNote.noteData);
this.openNoteContextMenu(FlxG.mouse.viewX, FlxG.mouse.viewY, highlightedNote.noteData);
}
else
{
this.openSelectionContextMenu(FlxG.mouse.screenX, FlxG.mouse.screenY);
this.openSelectionContextMenu(FlxG.mouse.viewX, FlxG.mouse.viewY);
}
}
else
@ -4835,11 +4835,11 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
|| (isHighlightedEventSelected && currentEventSelection.length == 1);
if (useSingleEventContextMenu)
{
this.openEventContextMenu(FlxG.mouse.screenX, FlxG.mouse.screenY, highlightedEvent.eventData);
this.openEventContextMenu(FlxG.mouse.viewX, FlxG.mouse.viewY, highlightedEvent.eventData);
}
else
{
this.openSelectionContextMenu(FlxG.mouse.screenX, FlxG.mouse.screenY);
this.openSelectionContextMenu(FlxG.mouse.viewX, FlxG.mouse.viewY);
}
}
else
@ -4860,11 +4860,11 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
// Show the context menu connected to the note.
if (useSingleNoteContextMenu)
{
this.openHoldNoteContextMenu(FlxG.mouse.screenX, FlxG.mouse.screenY, highlightedHoldNote.noteData);
this.openHoldNoteContextMenu(FlxG.mouse.viewX, FlxG.mouse.viewY, highlightedHoldNote.noteData);
}
else
{
this.openSelectionContextMenu(FlxG.mouse.screenX, FlxG.mouse.screenY);
this.openSelectionContextMenu(FlxG.mouse.viewX, FlxG.mouse.viewY);
}
}
else
@ -5139,10 +5139,11 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
}
var songPos:Float = Conductor.instance.songPosition + Conductor.instance.instrumentalOffset;
var songPosMilliseconds:String = Std.string(Math.floor(Math.abs(songPos) % 1000)).lpad('0', 2).substr(0, 2);
var songPosSeconds:String = Std.string(Math.floor((Math.abs(songPos) / 1000) % 60)).lpad('0', 2);
var songPosMinutes:String = Std.string(Math.floor((Math.abs(songPos) / 1000) / 60)).lpad('0', 2);
if (songPos < 0) songPosMinutes = '-' + songPosMinutes;
var songPosString:String = '${songPosMinutes}:${songPosSeconds}';
var songPosString:String = '${songPosMinutes}:${songPosSeconds}:${songPosMilliseconds}';
if (playbarSongPos.value != songPosString) playbarSongPos.value = songPosString;
@ -5614,7 +5615,7 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
}
else
{
trace('Ignoring keybinds for View menu items because we are in live input mode (${currentLiveInputStyle}).');
// trace('Ignoring keybinds for View menu items because we are in live input mode (${currentLiveInputStyle}).');
}
}

View file

@ -95,7 +95,7 @@ class ChartEditorCharacterIconSelectorMenu extends ChartEditorBaseMenu
}
var LIMIT = 6;
charButton.icon = CharacterDataParser.getCharPixelIconAsset(charId);
charButton.icon = haxe.ui.util.Variant.fromImageData(CharacterDataParser.getCharPixelIconAsset(charId));
charButton.text = charData.name.length > LIMIT ? '${charData.name.substr(0, LIMIT)}.' : '${charData.name}';
charButton.onClick = _ -> {

View file

@ -221,7 +221,7 @@ class ChartEditorMetadataToolbox extends ChartEditorBaseToolbox
var charDataOpponent:Null<CharacterData> = CharacterDataParser.fetchCharacterData(chartEditorState.currentSongMetadata.playData.characters.opponent);
if (charDataOpponent != null)
{
buttonCharacterOpponent.icon = CharacterDataParser.getCharPixelIconAsset(chartEditorState.currentSongMetadata.playData.characters.opponent);
buttonCharacterOpponent.icon = haxe.ui.util.Variant.fromImageData(CharacterDataParser.getCharPixelIconAsset(chartEditorState.currentSongMetadata.playData.characters.opponent));
buttonCharacterOpponent.text = charDataOpponent.name.length > LIMIT ? '${charDataOpponent.name.substr(0, LIMIT)}.' : '${charDataOpponent.name}';
}
else
@ -233,7 +233,7 @@ class ChartEditorMetadataToolbox extends ChartEditorBaseToolbox
var charDataGirlfriend:Null<CharacterData> = CharacterDataParser.fetchCharacterData(chartEditorState.currentSongMetadata.playData.characters.girlfriend);
if (charDataGirlfriend != null)
{
buttonCharacterGirlfriend.icon = CharacterDataParser.getCharPixelIconAsset(chartEditorState.currentSongMetadata.playData.characters.girlfriend);
buttonCharacterGirlfriend.icon = haxe.ui.util.Variant.fromImageData(CharacterDataParser.getCharPixelIconAsset(chartEditorState.currentSongMetadata.playData.characters.girlfriend));
buttonCharacterGirlfriend.text = charDataGirlfriend.name.length > LIMIT ? '${charDataGirlfriend.name.substr(0, LIMIT)}.' : '${charDataGirlfriend.name}';
}
else
@ -245,7 +245,7 @@ class ChartEditorMetadataToolbox extends ChartEditorBaseToolbox
var charDataPlayer:Null<CharacterData> = CharacterDataParser.fetchCharacterData(chartEditorState.currentSongMetadata.playData.characters.player);
if (charDataPlayer != null)
{
buttonCharacterPlayer.icon = CharacterDataParser.getCharPixelIconAsset(chartEditorState.currentSongMetadata.playData.characters.player);
buttonCharacterPlayer.icon = haxe.ui.util.Variant.fromImageData(CharacterDataParser.getCharPixelIconAsset(chartEditorState.currentSongMetadata.playData.characters.player));
buttonCharacterPlayer.text = charDataPlayer.name.length > LIMIT ? '${charDataPlayer.name.substr(0, LIMIT)}.' : '${charDataPlayer.name}';
}
else

View file

@ -586,13 +586,13 @@ class FreeplayState extends MusicBeatSubState
}
};
exitMovers.set([fp, txtCompletion, fnfHighscoreSpr, txtCompletion, clearBoxSprite],
exitMovers.set([fp, txtCompletion, fnfHighscoreSpr, clearBoxSprite],
{
x: FlxG.width,
speed: 0.3
});
exitMoversCharSel.set([fp, txtCompletion, fnfHighscoreSpr, txtCompletion, clearBoxSprite],
exitMoversCharSel.set([fp, txtCompletion, fnfHighscoreSpr, clearBoxSprite],
{
y: -270,
speed: 0.8,
@ -1376,7 +1376,7 @@ class FreeplayState extends MusicBeatSubState
#if FEATURE_DEBUG_FUNCTIONS
if (FlxG.keys.justPressed.P)
{
FlxG.switchState(FreeplayState.build(
FlxG.switchState(() -> FreeplayState.build(
{
{
character: currentCharacterId == "pico" ? Constants.DEFAULT_CHARACTER : "pico",
@ -1777,12 +1777,13 @@ class FreeplayState extends MusicBeatSubState
FlxG.log.warn('WARN: could not find song with id (${daSong.songId})');
return;
}
var targetVariation:String = targetSong.getFirstValidVariation(currentDifficulty) ?? '';
var targetVariation:String = targetSong.getFirstValidVariation(currentDifficulty, currentCharacter) ?? '';
// TODO: This line of code makes me sad, but you can't really fix it without a breaking migration.
var suffixedDifficulty = (targetVariation != Constants.DEFAULT_VARIATION
&& targetVariation != 'erect') ? '$currentDifficulty-${targetVariation}' : currentDifficulty;
var songScore:Null<SaveScoreData> = Save.instance.getSongScore(daSong.songId, suffixedDifficulty);
trace(songScore);
intendedScore = songScore?.score ?? 0;
intendedCompletion = songScore == null ? 0.0 : ((songScore.tallies.sick + songScore.tallies.good) / songScore.tallies.totalNotes);
rememberedDifficulty = suffixedDifficulty;

View file

@ -113,7 +113,9 @@ class PlayableCharacter implements IRegistryEntry<PlayerData>
switch (rank)
{
case PERFECT | PERFECT_GOLD:
case PERFECT_GOLD:
return _data.results.perfectGold;
case PERFECT:
return _data.results.perfect;
case EXCELLENT:
return _data.results.excellent;

View file

@ -123,7 +123,7 @@ class MainMenuState extends MusicBeatState
}));
});
#if CAN_OPEN_LINKS
#if FEATURE_OPEN_URL
// In order to prevent popup blockers from triggering,
// we need to open the link as an immediate result of a keypress event,
// so we can't wait for the flicker animation to complete.
@ -234,7 +234,7 @@ class MainMenuState extends MusicBeatState
camFollow.setPosition(selected.getGraphicMidpoint().x, selected.getGraphicMidpoint().y);
}
#if CAN_OPEN_LINKS
#if FEATURE_OPEN_URL
function selectDonate()
{
WindowUtil.openURL(Constants.URL_ITCH);
@ -356,7 +356,7 @@ class MainMenuState extends MusicBeatState
#if FEATURE_DEBUG_FUNCTIONS
// Ctrl+Alt+Shift+P = Character Unlock screen
// Ctrl+Alt+Shift+W = Meet requirements for Pico Unlock
// Ctrl+Alt+Shift+L = Revoke requirements for Pico Unlock
// Ctrl+Alt+Shift+M = Revoke requirements for Pico Unlock
// Ctrl+Alt+Shift+R = Score/Rank conflict test
// Ctrl+Alt+Shift+N = Mark all characters as not seen
// Ctrl+Alt+Shift+E = Dump save data
@ -369,7 +369,7 @@ class MainMenuState extends MusicBeatState
if (FlxG.keys.pressed.CONTROL && FlxG.keys.pressed.ALT && FlxG.keys.pressed.SHIFT && FlxG.keys.justPressed.W)
{
FunkinSound.playOnce(Paths.sound('confirmMenu'));
// Give the user a score of 1 point on Weekend 1 story mode.
// Give the user a score of 1 point on Weekend 1 story mode (Easy difficulty).
// This makes the level count as cleared and displays the songs in Freeplay.
funkin.save.Save.instance.setLevelScore('weekend1', 'easy',
{
@ -389,27 +389,30 @@ class MainMenuState extends MusicBeatState
});
}
if (FlxG.keys.pressed.CONTROL && FlxG.keys.pressed.ALT && FlxG.keys.pressed.SHIFT && FlxG.keys.justPressed.L)
if (FlxG.keys.pressed.CONTROL && FlxG.keys.pressed.ALT && FlxG.keys.pressed.SHIFT && FlxG.keys.justPressed.M)
{
FunkinSound.playOnce(Paths.sound('confirmMenu'));
// Give the user a score of 0 points on Weekend 1 story mode.
// Give the user a score of 0 points on Weekend 1 story mode (all difficulties).
// This makes the level count as uncleared and no longer displays the songs in Freeplay.
funkin.save.Save.instance.setLevelScore('weekend1', 'easy',
{
score: 1,
tallies:
{
sick: 0,
good: 0,
bad: 0,
shit: 0,
missed: 0,
combo: 0,
maxCombo: 0,
totalNotesHit: 0,
totalNotes: 0,
}
});
for (diff in ['easy', 'normal', 'hard'])
{
funkin.save.Save.instance.setLevelScore('weekend1', diff,
{
score: 0,
tallies:
{
sick: 0,
good: 0,
bad: 0,
shit: 0,
missed: 0,
combo: 0,
maxCombo: 0,
totalNotesHit: 0,
totalNotes: 0,
}
});
}
}
if (FlxG.keys.pressed.CONTROL && FlxG.keys.pressed.ALT && FlxG.keys.pressed.SHIFT && FlxG.keys.justPressed.R)

View file

@ -273,11 +273,6 @@ class TitleState extends MusicBeatState
}
#end
if (Save.instance.charactersSeen.contains("pico"))
{
Save.instance.charactersSeen.remove("pico");
Save.instance.oldChar = false;
}
Conductor.instance.update();
/* if (FlxG.onMobile)

View file

@ -481,10 +481,6 @@ class Constants
public static final JUDGEMENT_BAD_COMBO_BREAK:Bool = true;
public static final JUDGEMENT_SHIT_COMBO_BREAK:Bool = true;
// % Sick
public static final RANK_PERFECT_PLAT_THRESHOLD:Float = 1.0; // % Sick
public static final RANK_PERFECT_GOLD_THRESHOLD:Float = 0.85; // % Sick
// % Hit
public static final RANK_PERFECT_THRESHOLD:Float = 1.00;
public static final RANK_EXCELLENT_THRESHOLD:Float = 0.90;

View file

@ -22,7 +22,7 @@ class WindowUtil
*/
public static function openURL(targetUrl:String):Void
{
#if CAN_OPEN_LINKS
#if FEATURE_OPEN_URL
#if linux
Sys.command('/usr/bin/xdg-open $targetUrl &');
#else
@ -40,7 +40,7 @@ class WindowUtil
*/
public static function openFolder(targetPath:String):Void
{
#if CAN_OPEN_LINKS
#if FEATURE_OPEN_URL
#if windows
Sys.command('explorer', [targetPath.replace('/', '\\')]);
#elseif mac
@ -59,7 +59,7 @@ class WindowUtil
*/
public static function openSelectFile(targetPath:String):Void
{
#if CAN_OPEN_LINKS
#if FEATURE_OPEN_URL
#if windows
Sys.command('explorer', ['/select,' + targetPath.replace('/', '\\')]);
#elseif mac