mirror of
https://github.com/FunkinCrew/Funkin.git
synced 2024-11-14 19:25:16 -05:00
Merge branch 'rewrite/master' into abnormalpoof/assets-getpath
This commit is contained in:
commit
d02e834460
45 changed files with 463 additions and 200 deletions
44
.github/label-actions.yml
vendored
Normal file
44
.github/label-actions.yml
vendored
Normal 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
29
.github/workflows/label-actions.yml
vendored
Normal 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
52
.github/workflows/label-issue.yml
vendored
Normal 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.
|
|
@ -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
4
.gitmodules
vendored
|
@ -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
2
assets
|
@ -1 +1 @@
|
|||
Subproject commit 16c1d30478875a5acbe92e4ec7d11234d1028286
|
||||
Subproject commit 72bb24ac9b0b9db4b2f9c38ef091e146ef16a1a4
|
|
@ -41,9 +41,6 @@ There are several useful build flags you can add to a build to affect how it wor
|
|||
- `-DFEATURE_STAGE_EDITOR` to forcibly enable the experimental stage editor.
|
||||
- `-DFEATURE_GHOST_TAPPING` to forcibly enable an experimental gameplay change to the anti-mash system.
|
||||
|
||||
# Troubleshooting - GO THROUGH THESE STEPS BEFORE OPENING ISSUES ON GITHUB!
|
||||
# Troubleshooting
|
||||
|
||||
- During the cloning process, you may experience an error along the lines of `error: RPC failed; curl 92 HTTP/2 stream 0 was not closed cleanly: PROTOCOL_ERROR (err 1)` due to poor connectivity. A common fix is to run ` git config --global http.postBuffer 4096M`.
|
||||
- Make sure your game directory has an `assets` folder! If it's missing, copy the path to your `funkin` folder and run `cd the\path\you\copied`. Then follow the guide starting from **Step 4**.
|
||||
- Check that your `assets` folder is not empty! If it is, go back to **Step 4** and follow the guide from there.
|
||||
- The compilation process often fails due to having the wrong versions of the required libraries. Many errors can be resolved by deleting the `.haxelib` folder and following the guide starting from **Step 5**.
|
||||
If you experience any issues during the compilation process, DO NOT open an issue on GitHub. Instead, check the [Troubleshooting Guide](TROUBLESHOOTING.md) for steps on how to resolve common problems.
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
# Troubleshooting Common Issues
|
||||
# Troubleshooting Common Compilation Issues
|
||||
|
||||
- Weird macro error with a very tall call stack: Restart Visual Studio Code
|
||||
- NOTE: This is caused by Polymod somewhere, and seems to only occur when there is another compile error somewhere in the program. There is a bounty up for it.
|
||||
|
@ -13,3 +13,11 @@
|
|||
|
||||
- `LINK : fatal error LNK1201: error writing to program database ''; check for insufficient disk space, invalid path, or insufficient privilege`
|
||||
- This error occurs if the PDB file located in your `export` folder is in use or exceeds 4 GB. Try deleting the `export` folder and building again from scratch.
|
||||
|
||||
- `error: RPC failed; curl 92 HTTP/2 stream 0 was not closed cleanly: PROTOCOL_ERROR (err 1)`
|
||||
- This error can happen during cloning as a result of poor network connectivity. A common fix is to run ` git config --global http.postBuffer 4096M` in your terminal.
|
||||
|
||||
- Repository is missing an `assets` folder, or `assets` folder is empty.
|
||||
- You did not clone the repository correctly! Copy the path to your `funkin` folder and run `cd the\path\you\copied`. Then follow the compilation guide starting from **Step 4**.
|
||||
|
||||
- Other compilation issues may be caused by installing bad library versions. Try deleting the `.haxelib` folder and following the guide starting from **Step 5**.
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
|
|
11
hmm.json
11
hmm.json
|
@ -35,13 +35,6 @@
|
|||
"ref": "951a0103a17bfa55eed86703ce50b4fb0d7590bc",
|
||||
"url": "https://github.com/FunkinCrew/flixel-text-input"
|
||||
},
|
||||
{
|
||||
"name": "flixel-ui",
|
||||
"type": "git",
|
||||
"dir": null,
|
||||
"ref": "27f1ba626f80a6282fa8a187115e79a4a2133dc2",
|
||||
"url": "https://github.com/HaxeFlixel/flixel-ui"
|
||||
},
|
||||
{
|
||||
"name": "flxanimate",
|
||||
"type": "git",
|
||||
|
@ -77,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"
|
||||
},
|
||||
{
|
||||
|
|
|
@ -941,6 +941,8 @@ class Project extends HXProject {
|
|||
var commitHash:String = process.stdout.readLine();
|
||||
var commitHashSplice:String = commitHash.substr(0, 7);
|
||||
|
||||
process.close();
|
||||
|
||||
return commitHashSplice;
|
||||
}
|
||||
|
||||
|
@ -955,6 +957,8 @@ class Project extends HXProject {
|
|||
|
||||
var branchName:String = branchProcess.stdout.readLine();
|
||||
|
||||
branchProcess.close();
|
||||
|
||||
return branchName;
|
||||
}
|
||||
|
||||
|
@ -979,6 +983,8 @@ class Project extends HXProject {
|
|||
}
|
||||
}
|
||||
|
||||
branchProcess.close();
|
||||
|
||||
return output.length > 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@ package;
|
|||
|
||||
import flixel.FlxGame;
|
||||
import flixel.FlxState;
|
||||
import funkin.Preferences;
|
||||
import funkin.util.logging.CrashHandler;
|
||||
import funkin.ui.debug.MemoryCounter;
|
||||
import funkin.save.Save;
|
||||
|
@ -22,12 +23,6 @@ class Main extends Sprite
|
|||
var gameHeight:Int = 720; // Height of the game in pixels (might be less / more in actual pixels depending on your zoom).
|
||||
var initialState:Class<FlxState> = funkin.InitState; // The FlxState the game starts with.
|
||||
var zoom:Float = -1; // If -1, zoom is automatically calculated to fit the window dimensions.
|
||||
#if (web || CHEEMS)
|
||||
var framerate:Int = 60; // How many frames per second the game should run at.
|
||||
#else
|
||||
// TODO: This should probably be in the options menu?
|
||||
var framerate:Int = 144; // How many frames per second the game should run at.
|
||||
#end
|
||||
var skipSplash:Bool = true; // Whether to skip the flixel splash screen that appears in release mode.
|
||||
var startFullscreen:Bool = false; // Whether to start the game in fullscreen on desktop targets
|
||||
|
||||
|
@ -109,7 +104,7 @@ class Main extends Sprite
|
|||
|
||||
// George recommends binding the save before FlxGame is created.
|
||||
Save.load();
|
||||
var game:FlxGame = new FlxGame(gameWidth, gameHeight, initialState, framerate, framerate, skipSplash, startFullscreen);
|
||||
var game:FlxGame = new FlxGame(gameWidth, gameHeight, initialState, Preferences.framerate, Preferences.framerate, skipSplash, startFullscreen);
|
||||
|
||||
// FlxG.game._customSoundTray wants just the class, it calls new from
|
||||
// create() in there, which gets called when it's added to stage
|
||||
|
@ -123,8 +118,6 @@ class Main extends Sprite
|
|||
game.debugger.interaction.addTool(new funkin.util.TrackerToolButtonUtil());
|
||||
#end
|
||||
|
||||
addChild(fpsCounter);
|
||||
|
||||
#if hxcpp_debug_server
|
||||
trace('hxcpp_debug_server is enabled! You can now connect to the game with a debugger.');
|
||||
#else
|
||||
|
|
|
@ -7,6 +7,35 @@ import funkin.save.Save;
|
|||
*/
|
||||
class Preferences
|
||||
{
|
||||
/**
|
||||
* FPS
|
||||
* @default `60`
|
||||
*/
|
||||
public static var framerate(get, set):Int;
|
||||
|
||||
static function get_framerate():Int
|
||||
{
|
||||
#if web
|
||||
return 60;
|
||||
#else
|
||||
return Save?.instance?.options?.framerate ?? 60;
|
||||
#end
|
||||
}
|
||||
|
||||
static function set_framerate(value:Int):Int
|
||||
{
|
||||
#if web
|
||||
return 60;
|
||||
#else
|
||||
var save:Save = Save.instance;
|
||||
save.options.framerate = value;
|
||||
save.flush();
|
||||
FlxG.updateFramerate = value;
|
||||
FlxG.drawFramerate = value;
|
||||
return value;
|
||||
#end
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether some particularly fowl language is displayed.
|
||||
* @default `true`
|
||||
|
|
|
@ -543,7 +543,7 @@ class FunkinSound extends FlxSound implements ICloneable<FunkinSound>
|
|||
*/
|
||||
public static function playOnce(key:String, volume:Float = 1.0, ?onComplete:Void->Void, ?onLoad:Void->Void):Null<FunkinSound>
|
||||
{
|
||||
var result = FunkinSound.load(key, volume, false, true, true, onComplete, onLoad);
|
||||
var result:Null<FunkinSound> = FunkinSound.load(key, volume, false, true, true, onComplete, onLoad);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
|
@ -264,12 +264,32 @@ class PlayerCharSelectData
|
|||
*/
|
||||
@:optional
|
||||
public var position:Null<Int>;
|
||||
|
||||
/**
|
||||
* The GF name to assign for this character.
|
||||
*/
|
||||
@:optional
|
||||
public var gf:PlayerCharSelectGFData;
|
||||
}
|
||||
|
||||
typedef PlayerCharSelectGFData =
|
||||
{
|
||||
@:optional
|
||||
public var assetPath:String;
|
||||
|
||||
@:optional
|
||||
public var animInfoPath:String;
|
||||
|
||||
@:optional
|
||||
@:default(false)
|
||||
public var visualizer:Bool;
|
||||
}
|
||||
|
||||
typedef PlayerResultsData =
|
||||
{
|
||||
var music:PlayerResultsMusicData;
|
||||
|
||||
var perfectGold:Array<PlayerResultsAnimationData>;
|
||||
var perfect:Array<PlayerResultsAnimationData>;
|
||||
var excellent:Array<PlayerResultsAnimationData>;
|
||||
var great:Array<PlayerResultsAnimationData>;
|
||||
|
|
|
@ -183,7 +183,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);
|
||||
|
|
|
@ -260,7 +260,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`
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
package funkin.modding.base;
|
||||
|
||||
/**
|
||||
* A script that can be tied to an FlxSprite.
|
||||
* Create a scripted class that extends FlxSprite to use this.
|
||||
* A script that can be tied to a FunkinSprite.
|
||||
* Create a scripted class that extends FunkinSprite to use this.
|
||||
*/
|
||||
@:hscriptClass
|
||||
class ScriptedFunkinSprite extends funkin.graphics.FunkinSprite implements HScriptedClass {}
|
||||
|
|
|
@ -1612,7 +1612,7 @@ class PlayState extends MusicBeatSubState
|
|||
|
||||
if (girlfriend != null)
|
||||
{
|
||||
girlfriend.characterType = CharacterType.GF;
|
||||
// Don't need to do anything.
|
||||
}
|
||||
else if (currentCharacterData.girlfriend != '')
|
||||
{
|
||||
|
@ -1630,8 +1630,6 @@ class PlayState extends MusicBeatSubState
|
|||
|
||||
if (dad != null)
|
||||
{
|
||||
dad.characterType = CharacterType.DAD;
|
||||
|
||||
//
|
||||
// OPPONENT HEALTH ICON
|
||||
//
|
||||
|
@ -1650,8 +1648,6 @@ class PlayState extends MusicBeatSubState
|
|||
|
||||
if (boyfriend != null)
|
||||
{
|
||||
boyfriend.characterType = CharacterType.BF;
|
||||
|
||||
//
|
||||
// PLAYER HEALTH ICON
|
||||
//
|
||||
|
@ -1993,6 +1989,7 @@ class PlayState extends MusicBeatSubState
|
|||
|
||||
// Skip this if the music is paused (GameOver, Pause menu, start-of-song offset, etc.)
|
||||
if (!(FlxG.sound.music?.playing ?? false)) return;
|
||||
|
||||
var timeToPlayAt:Float = Conductor.instance.songPosition - Conductor.instance.instrumentalOffset;
|
||||
FlxG.sound.music.pause();
|
||||
vocals.pause();
|
||||
|
|
|
@ -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'));
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@ import funkin.play.character.ScriptedCharacter.ScriptedSparrowCharacter;
|
|||
import funkin.util.assets.DataAssets;
|
||||
import funkin.util.VersionUtil;
|
||||
import haxe.Json;
|
||||
import flixel.graphics.frames.FlxFrame;
|
||||
|
||||
class CharacterDataParser
|
||||
{
|
||||
|
@ -280,41 +281,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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -32,7 +32,7 @@ class HealthIcon extends FunkinSprite
|
|||
* The character this icon is representing.
|
||||
* Setting this variable will automatically update the graphic.
|
||||
*/
|
||||
public var characterId(default, set):Null<String>;
|
||||
public var characterId(default, set):String = Constants.DEFAULT_HEALTH_ICON;
|
||||
|
||||
/**
|
||||
* Whether this health icon should automatically update its state based on the character's health.
|
||||
|
@ -115,7 +115,7 @@ class HealthIcon extends FunkinSprite
|
|||
*/
|
||||
static final POSITION_OFFSET:Int = 26;
|
||||
|
||||
public function new(char:String = 'bf', playerId:Int = 0)
|
||||
public function new(char:Null<String>, playerId:Int = 0)
|
||||
{
|
||||
super(0, 0);
|
||||
this.playerId = playerId;
|
||||
|
@ -130,7 +130,7 @@ class HealthIcon extends FunkinSprite
|
|||
snapToTargetSize();
|
||||
}
|
||||
|
||||
function set_characterId(value:Null<String>):Null<String>
|
||||
function set_characterId(value:Null<String>):String
|
||||
{
|
||||
if (value == characterId) return value;
|
||||
|
||||
|
@ -411,20 +411,9 @@ class HealthIcon extends FunkinSprite
|
|||
}
|
||||
}
|
||||
|
||||
function correctCharacterId(charId:Null<String>):String
|
||||
function iconExists(charId:String):Bool
|
||||
{
|
||||
if (charId == null)
|
||||
{
|
||||
return Constants.DEFAULT_HEALTH_ICON;
|
||||
}
|
||||
|
||||
if (!Assets.exists(Paths.image('icons/icon-$charId')))
|
||||
{
|
||||
FlxG.log.warn('No icon for character: $charId : using default placeholder face instead!');
|
||||
return Constants.DEFAULT_HEALTH_ICON;
|
||||
}
|
||||
|
||||
return charId;
|
||||
return Assets.exists(Paths.image('icons/icon-$charId'));
|
||||
}
|
||||
|
||||
function isNewSpritesheet(charId:String):Bool
|
||||
|
@ -434,11 +423,11 @@ class HealthIcon extends FunkinSprite
|
|||
|
||||
function loadCharacter(charId:Null<String>):Void
|
||||
{
|
||||
if (charId == null || correctCharacterId(charId) != charId)
|
||||
if (charId == null || !iconExists(charId))
|
||||
{
|
||||
// This will recursively trigger loadCharacter to be called again.
|
||||
characterId = correctCharacterId(charId);
|
||||
return;
|
||||
FlxG.log.warn('No icon for character: $charId : using default placeholder face instead!');
|
||||
characterId = Constants.DEFAULT_HEALTH_ICON;
|
||||
charId = characterId;
|
||||
}
|
||||
|
||||
isLegacyStyle = !isNewSpritesheet(charId);
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -464,6 +464,9 @@ class Stage extends FlxSpriteGroup implements IPlayStateScriptedClass implements
|
|||
#end
|
||||
}
|
||||
|
||||
// Set the characters type
|
||||
character.characterType = charType;
|
||||
|
||||
// Add the character to the scene.
|
||||
this.add(character);
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
@ -89,6 +91,7 @@ class Save
|
|||
options:
|
||||
{
|
||||
// Reasonable defaults.
|
||||
framerate: 60,
|
||||
naughtyness: true,
|
||||
downscroll: false,
|
||||
flashingLights: true,
|
||||
|
@ -433,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();
|
||||
}
|
||||
}
|
||||
|
@ -832,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 + "...");
|
||||
|
||||
|
@ -850,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
|
||||
|
@ -863,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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1133,6 +1142,12 @@ typedef SaveScoreTallyData =
|
|||
*/
|
||||
typedef SaveDataOptions =
|
||||
{
|
||||
/**
|
||||
* FPS
|
||||
* @default `60`
|
||||
*/
|
||||
var framerate:Int;
|
||||
|
||||
/**
|
||||
* Whether some particularly fowl language is displayed.
|
||||
* @default `true`
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -37,17 +37,25 @@ class MusicBeatSubState extends FlxSubState implements IEventHandler
|
|||
return _conductorInUse = value;
|
||||
}
|
||||
|
||||
public function new(bgColor:FlxColor = FlxColor.TRANSPARENT)
|
||||
{
|
||||
super();
|
||||
this.bgColor = bgColor;
|
||||
}
|
||||
|
||||
var controls(get, never):Controls;
|
||||
|
||||
inline function get_controls():Controls
|
||||
return PlayerSettings.player1.controls;
|
||||
|
||||
public function new(bgColor:FlxColor = FlxColor.TRANSPARENT)
|
||||
{
|
||||
super();
|
||||
this.bgColor = bgColor;
|
||||
|
||||
initCallbacks();
|
||||
}
|
||||
|
||||
function initCallbacks()
|
||||
{
|
||||
subStateOpened.add(onOpenSubStateComplete);
|
||||
subStateClosed.add(onCloseSubStateComplete);
|
||||
}
|
||||
|
||||
override function create():Void
|
||||
{
|
||||
super.create();
|
||||
|
|
|
@ -11,6 +11,7 @@ import funkin.modding.IScriptedClass.IBPMSyncedScriptedClass;
|
|||
import flixel.math.FlxMath;
|
||||
import funkin.modding.events.ScriptEvent;
|
||||
import funkin.vis.dsp.SpectralAnalyzer;
|
||||
import funkin.data.freeplay.player.PlayerRegistry;
|
||||
|
||||
class CharSelectGF extends FlxAtlasSprite implements IBPMSyncedScriptedClass
|
||||
{
|
||||
|
@ -27,7 +28,8 @@ class CharSelectGF extends FlxAtlasSprite implements IBPMSyncedScriptedClass
|
|||
|
||||
var analyzer:SpectralAnalyzer;
|
||||
|
||||
var curGF:GFChar = GF;
|
||||
var currentGFPath:Null<String>;
|
||||
var enableVisualizer:Bool = false;
|
||||
|
||||
public function new()
|
||||
{
|
||||
|
@ -97,7 +99,7 @@ class CharSelectGF extends FlxAtlasSprite implements IBPMSyncedScriptedClass
|
|||
|
||||
function drawFFT()
|
||||
{
|
||||
if (curGF == NENE)
|
||||
if (enableVisualizer)
|
||||
{
|
||||
var levels = analyzer.getLevels();
|
||||
var frame = anim.curSymbol.timeline.get("VIZ_bars").get(anim.curFrame);
|
||||
|
@ -172,28 +174,33 @@ class CharSelectGF extends FlxAtlasSprite implements IBPMSyncedScriptedClass
|
|||
*/
|
||||
public function switchGF(bf:String):Void
|
||||
{
|
||||
var prevGF:GFChar = curGF;
|
||||
switch (bf)
|
||||
{
|
||||
case "pico":
|
||||
curGF = NENE;
|
||||
case "bf":
|
||||
curGF = GF;
|
||||
default:
|
||||
curGF = GF;
|
||||
}
|
||||
var previousGFPath = currentGFPath;
|
||||
|
||||
var bfObj = PlayerRegistry.instance.fetchEntry(bf);
|
||||
var gfData = bfObj?.getCharSelectData()?.gf;
|
||||
currentGFPath = gfData?.assetPath != null ? Paths.animateAtlas(gfData?.assetPath) : null;
|
||||
|
||||
// We don't need to update any anims if we didn't change GF
|
||||
if (prevGF != curGF)
|
||||
trace('currentGFPath(${currentGFPath})');
|
||||
if (currentGFPath == null)
|
||||
{
|
||||
loadAtlas(Paths.animateAtlas("charSelect/" + curGF + "Chill"));
|
||||
this.visible = false;
|
||||
return;
|
||||
}
|
||||
else if (previousGFPath != currentGFPath)
|
||||
{
|
||||
this.visible = true;
|
||||
loadAtlas(currentGFPath);
|
||||
|
||||
animInInfo = FramesJSFLParser.parse(Paths.file("images/charSelect/" + curGF + "AnimInfo/" + curGF + "In.txt"));
|
||||
animOutInfo = FramesJSFLParser.parse(Paths.file("images/charSelect/" + curGF + "AnimInfo/" + curGF + "Out.txt"));
|
||||
enableVisualizer = gfData?.visualizer ?? false;
|
||||
|
||||
var animInfoPath = Paths.file('images/${gfData?.animInfoPath}');
|
||||
|
||||
animInInfo = FramesJSFLParser.parse(animInfoPath + '/In.txt');
|
||||
animOutInfo = FramesJSFLParser.parse(animInfoPath + '/Out.txt');
|
||||
}
|
||||
|
||||
playAnimation("idle", true, false, false);
|
||||
// addFrameCallback(getNextFrameLabel("idle"), () -> playAnimation("idle", true, false, false));
|
||||
|
||||
updateHitbox();
|
||||
}
|
||||
|
@ -213,9 +220,3 @@ enum FadeStatus
|
|||
FADE_OUT;
|
||||
FADE_IN;
|
||||
}
|
||||
|
||||
enum abstract GFChar(String) from String to String
|
||||
{
|
||||
var GF = "gf";
|
||||
var NENE = "nene";
|
||||
}
|
||||
|
|
|
@ -47,7 +47,6 @@ class CharSelectPlayer extends FlxAtlasSprite implements IBPMSyncedScriptedClass
|
|||
//
|
||||
if (getCurrentAnimation() == "idle")
|
||||
{
|
||||
trace('Player beat hit');
|
||||
playAnimation("idle", true, false, false);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -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)
|
||||
|
@ -786,10 +792,9 @@ class CharSelectSubState extends MusicBeatSubState
|
|||
&& availableChars.exists(getCurrentSelected())
|
||||
&& Save.instance.charactersSeen.contains(availableChars[getCurrentSelected()]))
|
||||
{
|
||||
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 +822,7 @@ class CharSelectSubState extends MusicBeatSubState
|
|||
});
|
||||
}
|
||||
|
||||
if (pressedSelect && controls.BACK)
|
||||
if (allowInput && pressedSelect && controls.BACK)
|
||||
{
|
||||
cursorConfirmed.visible = false;
|
||||
grpCursors.visible = true;
|
||||
|
@ -847,7 +852,7 @@ class CharSelectSubState extends MusicBeatSubState
|
|||
|
||||
gfChill.visible = false;
|
||||
|
||||
if (controls.ACCEPT)
|
||||
if (allowInput && controls.ACCEPT)
|
||||
{
|
||||
cursorDenied.visible = true;
|
||||
cursorDenied.x = cursor.x - 2;
|
||||
|
|
|
@ -238,6 +238,11 @@ class DebugBoundingState extends FlxState
|
|||
{
|
||||
movingCharacter = false;
|
||||
}
|
||||
|
||||
if (FlxG.mouse.justReleased)
|
||||
{
|
||||
movingCharacter = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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}).');
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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 = _ -> {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -585,13 +585,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,
|
||||
|
@ -1375,7 +1375,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",
|
||||
|
@ -1776,12 +1776,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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -77,6 +77,10 @@ class PreferencesMenu extends Page
|
|||
createPrefItemCheckbox('Unlocked Framerate', 'Enable to unlock the framerate', function(value:Bool):Void {
|
||||
Preferences.unlockedFramerate = value;
|
||||
}, Preferences.unlockedFramerate);
|
||||
#else
|
||||
createPrefItemNumber('FPS', 'The maximum framerate that the game targets', function(value:Float) {
|
||||
Preferences.framerate = Std.int(value);
|
||||
}, null, Preferences.framerate, 30, 300, 5, 0);
|
||||
#end
|
||||
}
|
||||
|
||||
|
@ -87,7 +91,6 @@ class PreferencesMenu extends Page
|
|||
// Indent the selected item.
|
||||
items.forEach(function(daItem:TextMenuItem) {
|
||||
var thyOffset:Int = 0;
|
||||
|
||||
// Initializing thy text width (if thou text present)
|
||||
var thyTextWidth:Int = 0;
|
||||
if (Std.isOfType(daItem, EnumPreferenceItem)) thyTextWidth = cast(daItem, EnumPreferenceItem).lefthandText.getWidth();
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -313,7 +313,6 @@ class LoadingState extends MusicBeatSubState
|
|||
FunkinSprite.cacheTexture(Paths.image('ui/popup/pixel/num7'));
|
||||
FunkinSprite.cacheTexture(Paths.image('ui/popup/pixel/num8'));
|
||||
FunkinSprite.cacheTexture(Paths.image('ui/popup/pixel/num9'));
|
||||
|
||||
FunkinSprite.cacheTexture(Paths.image('notes', 'shared'));
|
||||
FunkinSprite.cacheTexture(Paths.image('noteSplashes', 'shared'));
|
||||
FunkinSprite.cacheTexture(Paths.image('noteStrumline', 'shared'));
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -23,6 +23,8 @@ class GitCommit
|
|||
var commitHash:String = process.stdout.readLine();
|
||||
var commitHashSplice:String = commitHash.substr(0, 7);
|
||||
|
||||
process.close();
|
||||
|
||||
trace('Git Commit ID: ${commitHashSplice}');
|
||||
|
||||
// Generates a string expression
|
||||
|
@ -52,6 +54,7 @@ class GitCommit
|
|||
}
|
||||
|
||||
var branchName:String = branchProcess.stdout.readLine();
|
||||
branchProcess.close();
|
||||
trace('Git Branch Name: ${branchName}');
|
||||
|
||||
// Generates a string expression
|
||||
|
@ -84,6 +87,7 @@ class GitCommit
|
|||
try
|
||||
{
|
||||
output = branchProcess.stdout.readLine();
|
||||
branchProcess.close();
|
||||
}
|
||||
catch (e)
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue