Compare commits

...
115 Commits
Author SHA1 Message Date
EricandGitHub 0b976b0d71 Merge pull request #4942 from AbnormalPoof/0.6.4-changelog-version-bump
Build and Upload nightly game builds / gather-changes (push) Canceled after 0s
Build and Upload nightly game builds / gather-tags (push) Canceled after 0s
Build and Upload nightly game builds / build-game-on-host (macos, macos) (push) Canceled after 0s
Build and Upload nightly game builds / build-game-on-host (windows, windows) (push) Canceled after 0s
Build and Upload nightly game builds / docker-image (push) Canceled after 0s
Build and Upload nightly game builds / build-game-in-container (html5) (push) Canceled after 0s
Build and Upload nightly game builds / build-game-in-container (linux) (push) Canceled after 0s
[DOCS] CHANGELOG for 0.6.4 + Bump version to 0.6.4
2025-05-02 22:28:13 -04:00
Abnormal ae1239c57d CHANGELOG for 0.6.4 2025-05-02 21:20:14 -05:00
Abnormal bfbbf9cb01 Bump game version to 0.6.4 2025-05-02 21:02:22 -05:00
EliteMasterEric d29bb47d22 Update assets submodule 2025-05-02 18:52:21 -04:00
EricandGitHub d29ecfb7c4 Merge pull request #4936 from CrusherNotDrip/bugfix/tooltip-chart-editor
[BUGFIX] Prevent the game from crashing when clicking a recent chart before tooltip shows up
2025-05-02 17:55:41 -04:00
EricandGitHub cdd17ce033 Merge pull request #4938 from AbnormalPoof/bugfix/quick-web-fix
2 more commits from #3032
2025-05-02 17:54:38 -04:00
EricandGitHub 8e8b26f029 Merge pull request #4564 from AbnormalPoof/bugfix/texture-atlas-looping
[BUGFIX] Fix texture atlas sprites looping infinitely
2025-05-02 17:52:13 -04:00
cyn0x8andAbnormal 6f43438cdb hopefully fix #4814 2025-05-02 16:41:03 -05:00
cyn0x8andAbnormal a74369c77e fixes + stronger sandboxing 2025-05-02 16:40:50 -05:00
CrusherNotDrip def1b74eb6 Stop the game from crashing when clicking a recent chart before tooltip appears 2025-05-02 16:40:31 -04:00
EricandGitHub c70fa7c94a Merge pull request #4933 from VioletSnowLeopard/patch2
Fix the Changelog on the develop branch again
2025-05-02 16:06:29 -04:00
Abnormal c0353bca2b remove extra callback (already gets called in _onAnimationComplete() by dispatching the animation name to onAnimationComplete 2025-05-02 13:53:30 -05:00
Abnormal f385cf9fd3 fix: Fix texture atlases looping indefinitely 2025-05-02 13:52:16 -05:00
EricandGitHub 301f71b428 Merge pull request #4930 from Hundrec/Lasercar/commit-recovery
<RECOVERY> Restore two of Lasercar's commits
2025-05-02 14:30:11 -04:00
EricandGitHub 189e028442 Merge pull request #4931 from ACrazyTown/fix/crash-log-memory-overflow
Fix memory overflow in crash log (Redo)
2025-05-02 14:30:03 -04:00
EricandGitHub a9647cf9fc Merge pull request #4617 from Lasercar/destroy-the-volume-plugin
[BUGFIX] Destroy the volume plugin when wiping save data
2025-05-02 14:29:54 -04:00
EricandGitHub 05b9d68645 Merge pull request #4227 from Lasercar/main-menu-not-remembering-freeplay-menu-selection-fix
Main menu not remembering freeplay menu selection fix
2025-05-02 14:29:29 -04:00
EricandGitHub 45f0f14ed9 Merge pull request #4318 from Lasercar/fix-strumline-offset-when-downscroll
Fix strumline offset when downscroll
2025-05-02 14:29:11 -04:00
EricandGitHub a8262a8d3b Merge pull request #3090 from anysad/fix-animation-file-save
[BUGFIX] Animation Editor not saving the file name
2025-05-02 14:21:46 -04:00
EricandGitHub 264c2d8e77 Merge pull request #4266 from NotHyper-474/bugfix/chart-editor-broken-resize
[BUGFIX] Chart Editor - Fix resolution breaking after returning from PlayState
2025-05-02 14:21:33 -04:00
EricandGitHub b2f231e889 Merge pull request #4871 from NotHyper-474/bugfix/initstate-spam-medal-crash-fix
[BUGFIX] Fix crash when spamming enter when opening game (properly this time)
2025-05-02 14:21:21 -04:00
VioletSnowLeopard 34bb201104 Fix the changelog again 2025-05-02 11:02:29 -04:00
HundrecandLasercar d9fcaf0e63 Restore Lasercar's changes
Dropped them somewhere whoopsie

Co-Authored-By: Lasercar <64717068+Lasercar@users.noreply.github.com>
2025-05-02 05:02:29 -06:00
EricandGitHub 56259b9143 Merge pull request #4923 from Hundrec/negative-freeplay-clear
[BUGFIX] Fix `Fix Fix scoring changes`
2025-05-01 23:43:49 -04:00
HundrecandHyper_ dc2acac152 no more negative clear percent shenanigans
"a thousand curses upon you for not testing your prs before making them /j"
- AbnormalPoof

Co-Authored-By: Hyper_ <40342021+NotHyper-474@users.noreply.github.com>
2025-05-01 21:23:55 -06:00
EricandGitHub bf5a669592 Merge pull request #4919 from Kade-github/real-capsule-fix
Sorting in freeplay is weird
2025-05-01 21:56:24 -04:00
kade-github 8b9775d91f the falsening by VioletSnowLeopard 2025-05-01 18:50:03 -07:00
EricandGitHub 6caeda9a9d Merge pull request #4898 from Lasercar/fix-fix-scoring-changes
[BUGFIX] Fix `Fix scoring changes`
2025-05-01 21:42:29 -04:00
EricandGitHub 9983556748 Merge pull request #4358 from VioletSnowLeopard/fix-special-pause-menu-chance
[BUGFIX] Fix the chance of getting the special pause menu
2025-05-01 21:40:58 -04:00
EliteMasterEric 651298e908 Update assets submodule 2025-05-01 21:37:52 -04:00
Hyper_ 142ea6db0c fix: Force UI Camera resize 2025-05-01 22:32:02 -03:00
EricandGitHub 5397924edd Merge pull request #4913 from VioletSnowLeopard/fix-switching-filters
[BUGFIX] Fix the Behavior of Selected Song when Changing Filters in Freeplay
2025-05-01 21:24:52 -04:00
EliteMasterEric 94bd18fe17 Merge remote-tracking branch 'public/main' into develop 2025-05-01 21:10:40 -04:00
EricandGitHub 664d9e0fb3 Merge pull request #4214 from Lasercar/freeplay-ui-fixes
Freeplay UI fixes
2025-05-01 21:07:51 -04:00
VioletSnowLeopard edf6889af9 fix switching filters to do its intended behavior 2025-05-01 20:57:39 -04:00
EricandGitHub c65dddacc0 Merge pull request #4894 from AbnormalPoof/chore/art-submod
[GITHUB] Update `art` submodule to the latest commit
2025-05-01 20:43:41 -04:00
EricandGitHub 659ea41206 Merge pull request #4649 from NotHyper-474/feature/chart-more-song-info
[ENHANCEMENT] Chart Editor - Display current beat & step
2025-05-01 20:37:40 -04:00
EricandGitHub 5cd47a4414 Merge pull request #4553 from VioletSnowLeopard/fix-dialogue-pause-menu
Change order of Restart and Skip in Dialogue pause menu
2025-05-01 20:37:18 -04:00
Eric 65699ee865 Update CONTRIBUTING.md 2025-05-01 01:38:44 -04:00
HundrecandEric d423eb3ddd Update Charting PR policy in CONTRIBUTING.md
We no longer accept chart modifications.
2025-05-01 01:38:44 -04:00
unknown c67085a46a Fix memory overflow in crash log 2025-04-30 23:41:14 +02:00
Hyper_ a83a4a599c fix: Null-check MedalList's internal map 2025-04-30 12:31:01 -03:00
Lasercar f6ac4cad43 Whoops, missed this one 2025-04-30 23:58:09 +10:00
VioletSnowLeopard 0101bae7ec convert decimal chance to percent 2025-04-30 09:31:22 -04:00
Abnormal 4c5335d7a3 art submod 2025-04-30 02:37:13 -05:00
EliteMasterEric b811ca91a6 Update link to art submodule to include latest assets 2025-04-30 02:01:54 -04:00
Hyper_andEric c5f2a74494 fix: Prevent loading invalid variation 2025-04-30 00:44:12 -04:00
KoloandEric 3e0dbe2758 performCleanup on reload 2025-04-30 00:43:37 -04:00
bbc0546c74 Shortened statement based on suggestion.
Co-authored-by: Abnormal <86753001+AbnormalPoof@users.noreply.github.com>
2025-04-30 00:42:15 -04:00
thesuperpig56andEric 617d5ffa06 Called the wrong character here, whoops! 2025-04-30 00:42:15 -04:00
thesuperpig56andEric 73114e2da6 Avoid crash when restarting song without characters. 2025-04-30 00:42:15 -04:00
KoloandEric 808698ace7 medal fix thing 2025-04-30 00:41:28 -04:00
VioletSnowLeopardandEric 832bc5bd83 fix two issues with random capsule 2025-04-30 00:37:08 -04:00
TechnikTilandEric b15e809c63 fix freeplay dj softlock 2025-04-29 18:01:55 -04:00
LasercarandEric 8074d57186 Don't add the default difficulty to song metadata
It'll now only add the current difficulty to the metadata if it doesn't exist in it when saved.
2025-04-29 18:01:23 -04:00
KoloandEric 31d3718e5c music file priority thing
(updated a misleading comment, lols!)
2025-04-29 16:27:21 -04:00
LasercarandEric 5fdbd23a17 Misses now actually make you miss your grade
Sustain notes no longer add to the miss tally
2025-04-29 16:24:50 -04:00
EricandGitHub 23a9e7f944 Merge pull request #4881 from Lasercar/fix-preferences-not-saving-due-to-enums-AGAIN
[BIGFIX] Fix Options not loading from Save Data
2025-04-29 16:23:47 -04:00
EricandGitHub 0397a41a7f Merge pull request #4883 from Hundrec/patch-11
[DOCS] Credit Lasercar for a crash fix from an assets PR
2025-04-29 16:23:31 -04:00
Lasercar afbb335993 Destroy the volume plugin 2025-04-29 20:23:52 +10:00
Lasercar 2bc1a31427 fix capsule jumpin and random capsule starting x position 2025-04-29 20:04:56 +10:00
Lasercar dafbb43532 capsule jump in 2025-04-29 19:59:35 +10:00
Lasercar 4978c89ac3 capsule options menu null reference fix 2025-04-29 19:57:31 +10:00
LasercarandLasercar 29b541af38 First rank overrides itself fix 2025-04-29 19:57:31 +10:00
LasercarandLasercar fc09350be7 This should fix the squashed capsule text, right? 2025-04-29 19:57:23 +10:00
LasercarandLasercar e1ca3c69f0 Fixed letter sort animation 2025-04-29 19:53:32 +10:00
LasercarandLasercar a15bd36943 Freeplay UI fixes
Input is disabled as soon as possible when a capsule is open
Input re-enables after capsule errors
instrument selector uses the capsule's target position as it's position, rather than the capsule's position
2025-04-29 19:53:32 +10:00
HundrecandGitHub 51605e50f8 Credit Lasercar for a crash fix from assets PR 2025-04-29 01:31:19 -06:00
Lasercar 3a1b573ea3 Fix save being loaded twice for no reason 2025-04-29 17:14:23 +10:00
Lasercar ef6b214872 Save vsync mode as string but get as vsync mode 2025-04-29 17:14:23 +10:00
EricandGitHub 8f2a8c8335 Merge pull request #4873 from NotHyper-474/patch-1
Remove leftover from merge-conflict in CHANGELOG
2025-04-28 17:59:02 -04:00
Hyper_andGitHub 7f5b4974c3 Update CHANGELOG.md
Remove left-over from merge conflict.
2025-04-28 18:30:39 -03:00
EricandGitHub d63782ee9d Merge pull request #4869 from ShadzXD/patch-3
[DOCS] Update CHANGELOG.MD to include my pull request.
2025-04-28 17:01:12 -04:00
EliteMasterEric 19b1c32124 Merge remote-tracking branch 'public/develop' into develop 2025-04-28 16:56:51 -04:00
ShadzXDandGitHub d183876514 Merge pull request #1 from Hundrec/patch-11
Tiny polish for Eggnog cutscene Changelog entry
2025-04-28 22:50:36 +02:00
HundrecandGitHub db0ac48192 Tiny polish for Eggnog cutscene Changelog entry 2025-04-28 14:47:42 -06:00
EricandGitHub ba37405e4b Merge pull request #4868 from Hundrec/remove-changelog
Remove Changelog from game files
2025-04-28 16:40:53 -04:00
ShadzXDandGitHub 66197b34f6 Update CHANGELOG.md 2025-04-28 22:40:26 +02:00
HundrecandHyper_ a7da71c8a8 Remove Changelog from game files
since it keeps getting revised after each release

Co-Authored-By: Hyper_ <40342021+NotHyper-474@users.noreply.github.com>
2025-04-28 14:38:52 -06:00
EricandGitHub 5bd081c2af Merge pull request #4866 from Hundrec/0.6.3-changelog-additions
[DOCS] Additional 0.6.3 Changelog bugfix entries + updated commit links
2025-04-28 16:26:51 -04:00
EricandGitHub aefc4db277 Merge branch 'main' into 0.6.3-changelog-additions 2025-04-28 16:26:43 -04:00
EricandGitHub adc14cc15d Merge pull request #4867 from FunkinCrew/develop2
Copied some files that weren't in main before back into develop
2025-04-28 16:21:54 -04:00
EricandGitHub a8294a9cce Merge pull request #4865 from FunkinCrew/0.6.3-release
Move public fix to main branch
2025-04-28 16:15:57 -04:00
EliteMasterEric 80569c806c Merge remote-tracking branch 'public/main' into 0.6.3-release 2025-04-28 16:15:09 -04:00
EliteMasterEric d6837eba2e Merge remote-tracking branch 'public/main' into 0.6.3-release 2025-04-28 16:14:37 -04:00
HundrecandGitHub 924b1cf386 Remove Newgrounds authentication entry
because it wasn't actually fixed
2025-04-27 20:43:09 -06:00
HundrecandGitHub 0839c16535 More 0.6.3 entries + updated commit links 2025-04-27 06:04:15 -06:00
HundrecandGitHub db3e012cb0 [DOCS] Changelog for 0.6.3 (#4816)
* Changelog for 0.6.3

* Clarify mod API version entry

* 0.6.3 Changelog tweaks
2025-04-26 05:18:01 -04:00
6c2ebff680 bump to 0.6.3 (#4448)
Co-authored-by: Eric <ericmyllyoja@gmail.com>
2025-04-26 00:48:37 -04:00
Eric 4555b6736e Rewrote recommendation to use Funkin haxelib and hmm 2025-04-25 21:41:16 -04:00
HundrecandEric 0c674ac23b Specify "flip horizontally" shortcut in Changelog entry 2025-04-25 21:37:11 -04:00
Eric c5e5ab16df Recommend Funkin's fork of hmm (fewer issues with Lime) 2025-04-25 17:50:45 -04:00
926d8c0517 Contributor's Guide Maintenance Policy
Co-authored-by: Hundrec <hundrecard@gmail.com>
Co-authored-by: Abnormal <86753001+AbnormalPoof@users.noreply.github.com>
2025-04-23 17:06:13 -04:00
HundrecandEric 34bb58015d Add Combo Milestones to Rejected Features list 2025-04-13 00:37:16 -04:00
AbnormalandEric d86fe68d80 docs: Add missing documentation to the remaining functions in Module 2025-04-12 00:54:04 -04:00
LasercarandEric 1434820d10 remove removed debug keys 2025-04-12 00:53:51 -04:00
HundrecandEric 08fb5b8459 Two more Chart Editor entries in Changelog 2025-04-12 00:53:29 -04:00
Hyper_andEric 8e8dcaa7f9 docs: (TROUBLESHOOTING.md) Correct outdated information about Lime troubleshooting
The commit of Lime that Funkin uses now includes Linux NDLLs. These are built on a system with GLibC 2.38 though which breaks compatibility with lots of stable distributions troubleshooting was added for those systems too.
2025-04-12 00:53:18 -04:00
Hyper_andEric b35059ec99 docs: (COMPILING.md) Remove outdated info about Lime fork 2025-04-12 00:53:18 -04:00
HundrecandEric fcb47ff4fc Grammatical fix in style-guide.md 2025-04-08 23:18:17 -04:00
HundrecandEric 3218ceeecd Consistent hyphens in CODESTYLE.md 2025-04-08 23:18:17 -04:00
HundrecandEric 1823373d7e Add a few fixes and changes from 0.6.0 2025-04-08 23:18:04 -04:00
HundrecandEric af14d42939 Oops, one more lil space 2025-04-08 23:18:04 -04:00
HundrecandEric 3dd3338ab2 Remove 0.6.0 Changelog entries that weren't implemented + polish 2025-04-08 23:18:04 -04:00
Hyper_ 26f2578bf2 fix: Pad number with 1 decimal place with zero 2025-04-08 16:02:03 -03:00
Hyper_ c32ade49b9 Implement suggestion: Fractional beat display 2025-04-07 23:59:55 -03:00
Hyper_ d4eee38fd2 feat: Show current beat and step next to song position 2025-04-07 21:08:01 -03:00
6543c58363 Restore Contributing Guide to latest version
Merge conflicts yay

Co-Authored-By: Abnormal <86753001+AbnormalPoof@users.noreply.github.com>
2025-04-06 03:50:32 -04:00
EliteMasterEric 158c015682 Use public URLs for git submodules 2025-04-04 15:16:58 -04:00
VioletSnowLeopard da9f17cf87 swap restart and skip in dialogue pause menu 2025-04-04 14:41:33 -04:00
EliteMasterEric d31ef12363 Use public submodule URLs (would be nice if this was automatic but oh well) 2025-04-04 14:28:12 -04:00
HundrecandLasercar bf36a86877 Remember selection when exiting to Title Screen 2025-03-18 20:47:21 +10:00
anysadandEric 9829103671 Fix Animation Editor not saving the file name 2025-03-17 07:13:14 -04:00
Lasercar ea93ec90cb Fix strumline offset when downscroll 2025-03-15 13:20:39 +10:00
Lasercar 07c872c775 A fix for a thing 2025-02-26 01:02:42 +10:00
45 changed files with 615 additions and 260 deletions
+1 -1
View File
@@ -45,7 +45,7 @@ body:
attributes:
label: Version
description: Which version are you playing on? The game version is in the bottom left corner of the main menu.
placeholder: ex. 0.6.2
placeholder: ex. 0.6.3
validations:
required: true
+1 -1
View File
@@ -46,7 +46,7 @@ body:
attributes:
label: Version
description: Which version are you playing on? The game version is in the bottom left corner of the main menu.
placeholder: ex. 0.6.2
placeholder: ex. 0.6.3
validations:
required: true
+1 -1
View File
@@ -34,7 +34,7 @@ body:
attributes:
label: Version
description: Which version are you compiling? The game version is in the bottom left corner of the main menu or in the project.hxp file.
placeholder: ex. 0.6.2
placeholder: ex. 0.6.3
validations:
required: true
+1 -1
View File
@@ -46,7 +46,7 @@ body:
attributes:
label: Version
description: Which version are you playing on? The game version is in the bottom left corner of the main menu.
placeholder: ex. 0.6.2
placeholder: ex. 0.6.3
validations:
required: true
+1
View File
@@ -4,6 +4,7 @@
APIStuff.hx
dump/
export/
project/
RECOVER_*.fla
shitAudio/
.build_time
+2 -2
View File
@@ -1,6 +1,6 @@
[submodule "assets"]
path = assets
url = https://github.com/FunkinCrew/Funkin-assets-secret
url = https://github.com/FunkinCrew/Funkin.assets
[submodule "art"]
path = art
url = https://github.com/FunkinCrew/Funkin-art-secret
url = https://github.com/FunkinCrew/Funkin.art
+134 -7
View File
@@ -6,6 +6,133 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [0.6.4] - 2025-05-02
### Changed
- Misses now actually reduce your clear percentage and rank, as Eric intended. ([5fdbd23](https://github.com/FunkinCrew/Funkin/commit/5fdbd23a17b8eaf21582283400be2c6444e8b198)) - by @Lasercar in [#4880](https://github.com/FunkinCrew/Funkin/pull/4880)
- The miss rebalance is now reflected on the Freeplay clear percent display. ([f6ac4ca](https://github.com/FunkinCrew/Funkin/commit/f6ac4cad43f4834a86a3fc156d6d39eca2c47c7e)) - by @Lasercar, @Hundrec, and @NotHyper-474 in [#4898](https://github.com/FunkinCrew/Funkin/pull/4898) and [#4923](https://github.com/FunkinCrew/Funkin/pull/4923)
### Fixed
- HTML5 builds are no longer literally unplayable. ([6f43438](https://github.com/FunkinCrew/Funkin/commit/6f43438cdbfecf26d4bcf62a0d9ff71e40333ac2)) - by @cyn0x8 in [#4398](https://github.com/FunkinCrew/Funkin/pull/4398)
- Medals no longer crash the game when obtained. ([808698a](https://github.com/FunkinCrew/Funkin/commit/808698ace7457bc76a8a52d415d63fa4ee5b9400)) - by @KoloInDaCrib in [#4815](https://github.com/FunkinCrew/Funkin/pull/4815)
- The game no longer crashes when reaching the main menu before authenticating with Newgrounds. ([a83a4a5](https://github.com/FunkinCrew/Funkin/commit/a83a4a599c2e407832ef9bbe47bb8b8c07ce712a)) - by @NotHyper-474 in [#4871](https://github.com/FunkinCrew/Funkin/pull/4871)
- User preferences and other settings are now properly saved after restarting the game. ([23a9e7f](https://github.com/FunkinCrew/Funkin/commit/23a9e7f944fb703160c2ed7b0bef38c70c5370db)) - by @Lasercar in [#4881](https://github.com/FunkinCrew/Funkin/pull/4881)
- Texture atlas sprites no longer loop infinitely, fixing issues with multiple cutscenes. ([f385cf9](https://github.com/FunkinCrew/Funkin/commit/f385cf9fd33e5358427f40dad3fecfed233c1706)) - by @AbnormalPoof in [#4564](https://github.com/FunkinCrew/Funkin/pull/4564)
- The Week 3 Pico Mix cutscene no longer breaks with Naughtyness turned off. ([e3aba5c](https://github.com/FunkinCrew/funkin.assets/commit/e3aba5c4faa8e8c705c3e0daf04e30db7ac5a136)) - by @Lasercar in [funkin.assets#169](https://github.com/FunkinCrew/funkin.assets/pull/169)
- Adjusted the pixel strumline’s position when Downscroll is enabled to match the regular notestyle. ([ea93ec9](https://github.com/FunkinCrew/Funkin/commit/ea93ec90cb5c5dbd4a5bea64114af58c70cb43f4)) - by @Lasercar in [#4318](https://github.com/FunkinCrew/Funkin/pull/4318)
- The Main Menu now correctly remembers your most recently selected menu item. ([05b9d68](https://github.com/FunkinCrew/Funkin/commit/05b9d68645b71c9cc36a5cb0c0e93af6acb36132)) - by @Lasercar and @Hundrec in [#4227](https://github.com/FunkinCrew/Funkin/pull/4227)
- Fixed an occasional softlock when returning to the Freeplay menu from a song. ([b15e809](https://github.com/FunkinCrew/Funkin/commit/b15e809c63664e039781592dcbdee4383e73800e)) - by @TechnikTil in [#4665](https://github.com/FunkinCrew/Funkin/pull/4665)
- Switching to and from the Freeplay Random capsule now behaves more consistently. ([832bc5b](https://github.com/FunkinCrew/Funkin/commit/832bc5bd83d49a646b9c8cb2b767602c848be908)) - by @VioletSnowLeopard in [#4885](https://github.com/FunkinCrew/Funkin/pull/4885)
- Changing Freeplay filters with the Random capsule selected now behaves more consistently. ([edf6889](https://github.com/FunkinCrew/Funkin/commit/edf6889af9e7f68caead9b8139178a36b4b5b2d6)) - by @VioletSnowLeopard in [#4913](https://github.com/FunkinCrew/Funkin/pull/4913)
- Switching between identical Freeplay filters no longer makes the songlist invisible. ([8b9775d](https://github.com/FunkinCrew/Funkin/commit/8b9775d91f4f2b5896a637a014b4be770319968e)) - by @VioletSnowLeopard in [#4919](https://github.com/FunkinCrew/Funkin/pull/4919)
- The millions place digit of the Freeplay score display now updates properly. ([d9fcaf0](https://github.com/FunkinCrew/Funkin/commit/d9fcaf0e6382b121f7773d23f4864364a1e6a577)) - by @Lasercar in [#4065](https://github.com/FunkinCrew/Funkin/pull/4065)
- The Freeplay clear percent display is now more consistently aligned. ([329182e](https://github.com/FunkinCrew/funkin.assets/commit/329182ea1b6839187a1d800b2d009a4c1874479d)) - by @Hundrec in [funkin.assets#37](https://github.com/FunkinCrew/funkin.assets/pull/37)
- The debris in Pico’s Great Results animation no longer grows in size. ([c108a7f](https://github.com/FunkinCrew/funkin.assets/commit/c108a7ff0d11bf328e7b232160b8f68c71e21bca)) - by @ThatRozebudDude in [funkin.assets#73](https://github.com/FunkinCrew/funkin.assets/pull/73)
- Fixed the song not starting if more than 32 sounds are playing at once. ([31d3718](https://github.com/FunkinCrew/Funkin/commit/31d3718e5c33371cacd495219f9cc3908244bf71)) - by @KoloInDaCrib in [#4352](https://github.com/FunkinCrew/Funkin/pull/4352)
- Hot reloading (pressing F5) during dialogue no longer crashes the game. ([3e0dbe2](https://github.com/FunkinCrew/Funkin/commit/3e0dbe2758d68ccf4ded1d08bec247ab05d70829)) - by @KoloInDaCrib in [#4769](https://github.com/FunkinCrew/Funkin/pull/4769)
- Restarting a song without either a player or an opponent no longer crashes the game, fixing minimal playtest mode. ([bbc0546](https://github.com/FunkinCrew/Funkin/commit/bbc0546c7450b929dc78ad9271171ea899478e9d)) - by @thesuperpig56 in [#4778](https://github.com/FunkinCrew/Funkin/pull/4778)
- The sound tray no longer behaves incorrectly after wiping save data. ([afbb335](https://github.com/FunkinCrew/Funkin/commit/afbb3359938f020707efd92a17419e3658528ea5)) - by @Lasercar in [#4617](https://github.com/FunkinCrew/Funkin/pull/4617)
- Opening a chart from the “Open Recent” section no longer crashes the Chart Editor. ([def1b74](https://github.com/FunkinCrew/Funkin/commit/def1b74eb6987272bc360cbf586ddcd1c26c6381)) - by @CrusherNotDrip in [#4936](https://github.com/FunkinCrew/Funkin/pull/4936)
- Loading an invalid variation in the Chart Editor no longer crashes the game. ([c5f2a74](https://github.com/FunkinCrew/Funkin/commit/c5f2a744940dbc685b25373fa2dabb548f0b26fa)) - by @NotHyper-474 in [#4391](https://github.com/FunkinCrew/Funkin/pull/4391)
- Default difficulties are no longer re-added when saving and loading a .FNFC chart. ([8074d57](https://github.com/FunkinCrew/Funkin/commit/8074d571860aba2c2f6f1c642d8d0e671ff5355e)) - by @Lasercar in [#4216](https://github.com/FunkinCrew/Funkin/pull/4216)
- The Chart Editor now resizes properly after entering Fullscreen during a playtest. ([142ea6d](https://github.com/FunkinCrew/Funkin/commit/142ea6db0c53f6f9288109604702c2e7e5bc6f18)) - by @NotHyper-474 in [#4266](https://github.com/FunkinCrew/Funkin/pull/4266)
- Added three missing hotkeys to the Chart Editor user guide. ([73ccb9a](https://github.com/FunkinCrew/funkin.assets/commit/73ccb9a80d08f3311f51cf88950692d7c1ea5d60)) - by @NotHyper-474 and @Hundrec in [funkin.assets#83](https://github.com/FunkinCrew/funkin.assets/pull/83)
- The “Skip Forward” button is no longer named “Skip Back” in the Chart Editor. ([78f9fb7](https://github.com/FunkinCrew/funkin.assets/commit/78f9fb7cb6eaf7466826f144a0142c008fbff2f8)) - by @Hundrec in [funkin.assets#22](https://github.com/FunkinCrew/funkin.assets/pull/22)
- Exporting a character .JSON from the Animation Editor now fills in the file name. ([a8262a8](https://github.com/FunkinCrew/Funkin/commit/a8262a8d3b4d2169327131e21c98f803da4a5ee4)) - by @anysad in [#3090](https://github.com/FunkinCrew/Funkin/pull/3090)
- Properly credited MtH as a Charter in Monster’s metadata. ([6a10799](https://github.com/FunkinCrew/funkin.assets/commit/6a10799a40eb2b2deb364bcd3cc4387abe8e8bc4)) - by @ChillyBeanBAM in [funkin.assets#66](https://github.com/FunkinCrew/funkin.assets/pull/66)
- Corrected the chances of a Pause Menu easter egg appearing. ([0101bae](https://github.com/FunkinCrew/Funkin/commit/0101bae7ecc800e26efd9590fdfa1305039b4461)) - by @VioletSnowLeopard in [#4358](https://github.com/FunkinCrew/Funkin/pull/4358)
- Removed spammy traces for Playable Pico’s animations. ([f87255d](https://github.com/FunkinCrew/funkin.assets/commit/f87255d4bcb7a7ce0dc920aefc36b98a96115c75)) - by @VioletSnowLeopard in [funkin.assets#179](https://github.com/FunkinCrew/funkin.assets/pull/179)
- Fixed memory overflowing in crash logs. ([189e028](https://github.com/FunkinCrew/Funkin/commit/189e028442c7fb892ce4dab62a5d08db658f3b2b)) - by @ACrazyTown in [#4589](https://github.com/FunkinCrew/Funkin/pull/4589)
### Removed
- The CHANGELOG.md file will no longer be included in builds. Visit the [Funkin' GitHub](https://github.com/FunkinCrew/Funkin/blob/main/CHANGELOG.md) to view the latest changes! ([a7da71c](https://github.com/FunkinCrew/Funkin/commit/a7da71c8a87baa440a0bc6e23d7e9b36c7574e14)) - by @Hundrec and @NotHyper-474 in [#4868](https://github.com/FunkinCrew/Funkin/pull/4868)
## New Contributors for 0.6.4
* @thesuperpig56 made their first contribution in [#4778](https://github.com/FunkinCrew/Funkin/pull/4778)
* @ThatRozebudDude made their first contribution in [funkin.assets#73](https://github.com/FunkinCrew/funkin.assets/pull/73)
## [0.6.3] - 2025-04-25
### Added
- New option in the Preferences menu: VSync!
- Set it to Off, On, or Adaptive
- Adaptive turns VSync off during FPS drops, which is better if supported by your graphics card.
- Doesn't work on Mac, sorry!
- Otis now has muzzle flashes when shooting.
- Added a little easter egg to one of Pico's Results Screen animations.
- Overhauled the sticker system to allow modders to easily add custom sticker sets. ([cdc468b](https://github.com/FunkinCrew/Funkin/commit/cdc468ba15683b3c0f54015e337673c77ddd7962)) - by @AbnormalPoof in [#4003](https://github.com/FunkinCrew/Funkin/pull/4003)
- Implemented a macro to optimize registries and entries. ([1497521](https://github.com/FunkinCrew/Funkin/commit/14975212a918adb1a5d96a349ec9e8e63c9fc64b)) - by @lemz1 in [#3694](https://github.com/FunkinCrew/Funkin/pull/3694)
- The macro is now used to retrieve base game assets. ([963e2ec](https://github.com/FunkinCrew/Funkin/commit/963e2ecd630fae24dae4206d315618cf4c4be6db)) - by @lemz1 in [#4707](https://github.com/FunkinCrew/Funkin/pull/4707)
- The Chart Editor now displays the current beat and step of the playhead. ([83bb3bb](https://github.com/FunkinCrew/Funkin/commit/83bb3bb5074ecb5f50ee21979711efcda9d8017d)) - by @NotHyper-474 in [#4649](https://github.com/FunkinCrew/Funkin/pull/4649)
### Changed
- The mod API version is now 0.6.3.
- Be sure to update the version in your mods' metadata, then ensure they are still working!
- Eric's scoring rebalance update!
- Misses (not ghost misses) are now worth -100 points, up from -10.
- Hold note trails now grant 20% less health.
- Dropping a hold note early now plays the miss animation and deducts health and score.
- Made a LOT of charting changes!
- Many missing, extra, and mistimed notes have been corrected.
- Stacked notes that were preventing full combos have been removed.
- Camera events have been adjusted to stay within the boundaries of the stage.
- Some songs have been recharted.
- The Freeplay menu can now always switch between variations.
- The nearest song with an Erect variation will be selected when switching.
- Switching difficulties now always plays the capsule jump-in animation.
- The "Random" capsule now plays animations consistent with other capsules.
- The Eggnog Erect cutscene can now be skipped. ([0303a03](https://github.com/FunkinCrew/funkin.assets/commit/1202651db8ea938fe11b6b734fbf7884d101e6ad)) - by @ShadzXD in [#62](https://github.com/FunkinCrew/funkin.assets/pull/62)
- Swapped the positions of “skip” and “restart” items in the dialogue pause menu for consistency. ([1f88a3b](https://github.com/FunkinCrew/Funkin/commit/1f88a3b6e13e9283ad680805deab5e27ba141d96)) - by @VioletSnowLeopard in [#4553](https://github.com/FunkinCrew/Funkin/pull/4553)
- The Controls menu now prevents unbinding essential UI controls to safeguard against softlocking save files. ([7eebce4](https://github.com/FunkinCrew/Funkin/commit/7eebce432d7627a1cf0bbd43f22a6f9bcb63ff65)) - by @VioletSnowLeopard in [#4382](https://github.com/FunkinCrew/Funkin/pull/4382)
- Renamed “Auto Pause” preference to “Pause on Unfocus” for clarity. ([52be941](https://github.com/FunkinCrew/Funkin/commit/52be941b4503da0ac76918e2482ab1804866f2cf)) - by @JackXson-Real in [#4346](https://github.com/FunkinCrew/Funkin/pull/4346)
- Overhauled `FileUtil`, introducing various fixes, new functions, and sandboxing. ([95ade2a](https://github.com/FunkinCrew/Funkin/commit/95ade2a08b7709e8208ec1b3e123bf5b4308ba10)) - by @cyn0x8 in [#3032](https://github.com/FunkinCrew/Funkin/pull/3032)
### Fixed
- Story mode medals are now awarded even without scoring a new personal best.
- Highscores are now submitted to Newgrounds even without scoring a new personal best.
- The Freeplay menu no longer displays songs without Erect variations when returning from an Erect variation song.
- Fixed Freeplay DJ animations for Boyfriend and Pico when idling (properly this time).
- Alternate instrumentals for Cocoa, Senpai, Roses, and Stress are now locked until their Pico Mix is beaten.
- The Roses Pico alternate instrumental is now offset to align with the original song's voices.
- Entering Stress or Stress (Pico Mix) a second time no longer crashes the game.
- Restarting Stress or Stress (Pico Mix) no longer spawns too many Tankmen in the background.
- Pico's game over animation now displays properly on Ugh (Pico Mix) and Guns (Pico Mix).
- Tankman's death lines now play for Boyfriend in Ugh, Guns, and Ugh Erect.
- Week 6 dialogue no longer plays for all non-default variations when entered through Freeplay.
- Nene (Pixel) now plays her knife raising animation when the player has low health.
- A-Bot's visualizer is now blank before the song starts.
- Debug editor tooltips no longer display behind windows.
- Clearing save data no longer crashes the game.
- Adding custom parameters to note kinds no longer crashes the Chart Editor. ([0a7bd31](https://github.com/FunkinCrew/Funkin/commit/0a7bd3111f59efbecfe097f8bbcfdefa5ace299d)) - by @Lasercar in [#136](https://github.com/FunkinCrew/funkin.assets/pull/136)
- Improved performance in the Freeplay menu before entering a song. ([2b7254f](https://github.com/FunkinCrew/Funkin/commit/2b7254fbd2356e9da91e216f178a88f17874a6eb)) - by @superpowers04 in [#4729](https://github.com/FunkinCrew/Funkin/pull/4729)
- Prevented a crash by capping Freeplay and Results screen score displays at their largest possible values (actual scores are not capped). ([51324e9](https://github.com/FunkinCrew/Funkin/commit/51324e9c283c43ca861d3369ba9b3e1db9c89765)) - by @KoloInDaCrib in [#3634](https://github.com/FunkinCrew/Funkin/pull/3634)
- The Animation Editor no longer crashes when opened. ([b40b4b0](https://github.com/FunkinCrew/Funkin/commit/b40b4b03692910afceff361cf6ca3298fd787e3c)) - by @sector-a in [#4582](https://github.com/FunkinCrew/Funkin/pull/4582)
- Disabled navigation in the Options menu while the Clear Save Data prompt is open. ([855deb5](https://github.com/FunkinCrew/Funkin/commit/855deb58280e850c0ad1581807c70f05d6b6a2cb)) - by @KoloInDaCrib in [#4703](https://github.com/FunkinCrew/Funkin/pull/4703)
- Save data is no longer wiped after failing to load the current save. ([068c9fb](https://github.com/FunkinCrew/Funkin/commit/068c9fb43d49ff6ea13e5a73f77a42207954be2c)) - by @KoloInDaCrib in [#4574](https://github.com/FunkinCrew/Funkin/pull/4574)
- Selecting a different type of event in the Chart Editor no longer crashes or resets the event to its default values. ([71ed154](https://github.com/FunkinCrew/Funkin/commit/71ed154b81abbd002d78c09c2dada8a2ad3fa73e)) - by @KoloInDaCrib in [#3913](https://github.com/FunkinCrew/Funkin/pull/3913)
- Deleting a stacked event in the Chart Editor now properly removes the deleted event’s sprite. ([3ad14ba](https://github.com/FunkinCrew/Funkin/commit/3ad14bac32096e45259997ab9957bec5fecf296f)) - by @NotHyper-474 in [#4724](https://github.com/FunkinCrew/Funkin/pull/4724)
- Patched a security vulnerability. ([53dec05](https://github.com/FunkinCrew/Funkin/commit/53dec057bee0a913d60e0c70d45dbb59a58620b0)) - by @nebulazorua in [#4740](https://github.com/FunkinCrew/Funkin/pull/4740)
- Added null safety to a bunch of classes.
- Even more tiny bug fixes.
## New Contributors for 0.6.3
* @JackXson-Real made their first contribution in [#4346](https://github.com/FunkinCrew/Funkin/pull/4346)
* @VioletSnowLeopard made their first contribution in [#4382](https://github.com/FunkinCrew/Funkin/pull/4382)
* @superpowers04 made their first contribution in [#4729](https://github.com/FunkinCrew/Funkin/pull/4729)
* @ShadzXD made their first contribution in [#62](https://github.com/FunkinCrew/Funkin/pull/4729)
## [0.6.2] - 2025-03-31
### Added
@@ -58,7 +185,7 @@ The Pit Stop 2 update!
- Added an option to launch the game in fullscreen. ([ee53ccd](https://github.com/FunkinCrew/Funkin/commit/ee53ccd32721e0790adfe82c60d4aca419db0a7f)) - by @AbnormalPoof in [#3738](https://github.com/FunkinCrew/Funkin/pull/3738)
- Added on-screen descriptions for each item in the Preferences menu. ([a17b0e8](https://github.com/FunkinCrew/Funkin/commit/a17b0e8b3cc1d56fcdc0b51eaca9fd57cdb5bce0)) - by @anysad in [#3872](https://github.com/FunkinCrew/Funkin/pull/3872)
- Added precise scrolling in the Chart Editor using Ctrl-Mouse Wheel. ([0d8e4a5](https://github.com/FunkinCrew/Funkin/commit/0d8e4a53305d6d069454812766300122f3581e31)) - by @ninjamuffin99 in [#3806](https://github.com/FunkinCrew/Funkin/pull/3806)
- Added a “None” option to the character selector in the Chart Editor. ([d9637d3](https://github.com/FunkinCrew/Funkin/commit/d9637d3a19466b9fc68a102676c46a74ef504909)) - by @Lasercar in [#4279](https://github.com/FunkinCrew/Funkin/pull/4279)
- Added a “None” option to the character selector in the Chart Editor. ([9c2ef02](https://github.com/FunkinCrew/Funkin/commit/9c2ef0236818883ad1275571dac49eab70ca0ea0)) - by @Lasercar in [#4279](https://github.com/FunkinCrew/Funkin/pull/4279)
- Added the ability to flip the character in the Animation Editor. ([de02137](https://github.com/FunkinCrew/Funkin/commit/de02137d7c7d1779e85aeda34743f506a5b9cc27)) - by @AbnormalPoof in [#3028](https://github.com/FunkinCrew/Funkin/pull/3028)
- Added offsets support for album titles. ([69d8570](https://github.com/FunkinCrew/Funkin/commit/69d8570a9eb06011ed6dd95fcbef83d90f7f8684)) - by @AbnormalPoof in [#3618](https://github.com/FunkinCrew/Funkin/pull/3618)
- Added three new properties to stage data: `angle`, `scroll`, and `alpha`. ([ff56b19](https://github.com/FunkinCrew/Funkin/commit/ff56b1948aef42bbb6bb4ede4f9b2012d49ab044)) - by @AbnormalPoof in [#3720](https://github.com/FunkinCrew/Funkin/pull/3720)
@@ -77,7 +204,7 @@ The Pit Stop 2 update!
- For example, the Zoom Camera event can now be set to 0.9857.
- Lots of improvements to GitHub issue and pull request organization. - by @Hundrec and @AbnormalPoof
- Overhauled the Changelog to improve readability and properly credit contributors. ([4383fcf](https://github.com/FunkinCrew/Funkin/commit/4383fcf32c280a1c0ee7b9c80d255611d497cabc)) - by @Hundrec in [#4296](https://github.com/FunkinCrew/Funkin/pull/4296) and [#4298](https://github.com/FunkinCrew/Funkin/pull/4298)
- Made various improvements to the screenshot function. ([9ce7bbc](https://github.com/FunkinCrew/Funkin/commit/9ce7bbcfbb8f30ae120c876194f89bc4c787f585)) - by @Lasercar in [#4082](https://github.com/FunkinCrew/Funkin/pull/4082)
- Made various improvements to the screenshot plugin. ([868932c](https://github.com/FunkinCrew/Funkin/commit/868932cd138fad4be5b541cbea3110e30479057b)) - by @Lasercar in [#4082](https://github.com/FunkinCrew/Funkin/pull/4082)
- Accept keybinds (Z and Space by default) can now be used to exit the Results screen. ([edb270d](https://github.com/FunkinCrew/Funkin/commit/edb270d15e41784dccbf75639ac731840e80fe23)) - by @JVNpixels in [#3799](https://github.com/FunkinCrew/Funkin/pull/3799)
- Reordered UI keybinds in the controls menu for consistency. ([a01bcc3](https://github.com/FunkinCrew/Funkin/commit/a01bcc3da836ec52851ca9de13ef459daf61269a)) - by @lemz1 in [#3027](https://github.com/FunkinCrew/Funkin/pull/3027)
- New save files now have default Freeplay controls for gamepads. ([2b7f62e](https://github.com/FunkinCrew/Funkin/commit/2b7f62edd33de5527e259d9e5643f926d35da734)) - by @MrMadera in [#3934](https://github.com/FunkinCrew/Funkin/pull/3934)
@@ -98,16 +225,16 @@ The Pit Stop 2 update!
- Reduced stuttering when resyncing instrumental and voices tracks. ([22d41d2](https://github.com/FunkinCrew/Funkin/commit/22d41d21b88acb7422a0afcda8414682710bd2ed)) - by @TechnikTil in [#3955](https://github.com/FunkinCrew/Funkin/pull/3955)
- Songs with only instrumental tracks no longer stutter. ([dfe02ec](https://github.com/FunkinCrew/Funkin/commit/dfe02ec668b61d6308f459c978d12a7487f9dc28)) - by @KoloInDaCrib in [#3861](https://github.com/FunkinCrew/Funkin/pull/3861)
- The debug mouse cursor no longer flickers before the Title Screen loads. ([1c12b84](https://github.com/FunkinCrew/Funkin/commit/1c12b8467eca350eb28138473360d5358fa620e2)) - by @sphis-Sinco in [#3881](https://github.com/FunkinCrew/Funkin/pull/3881)
- Unbound keys now display as [N/A] instead of crashing the game. ([94e5d3c](https://github.com/FunkinCrew/Funkin/commit/94e5d3ca258cbaa5d9ab6f0cb26feda83b3433a2)) - by @NotHyper-474 in [#4355](https://github.com/FunkinCrew/Funkin/pull/4355)
- Unbound keys now display as [N/A] instead of crashing the game. ([099c309](https://github.com/FunkinCrew/Funkin/commit/099c309f9babdc1ea99b7dbed3fdccf1e952fc8e)) - by @NotHyper-474 in [#4355](https://github.com/FunkinCrew/Funkin/pull/4355)
- Songs can no longer be spam-selected after selecting an instrumental in Freeplay. ([0e0c4ae](https://github.com/FunkinCrew/Funkin/commit/0e0c4aeb7745cfb9479685ccbb635cf3743cddbb)) - by @AbnormalPoof in [#3866](https://github.com/FunkinCrew/Funkin/pull/3866)
- The Random capsule can now switch to Erect/Nightmare difficulties in Freeplay. ([6f32747](https://github.com/FunkinCrew/Funkin/commit/6f327474f30374f50774f432ea3ccb6d02579445)) - by @KoloInDaCrib in [#3838](https://github.com/FunkinCrew/Funkin/pull/3838)
- The Random capsule can now switch to Erect/Nightmare difficulties in Freeplay. ([a90b911](https://github.com/FunkinCrew/Funkin/commit/a90b911653a1beaba57d64b1f05b840109fec42b)) - by @KoloInDaCrib in [#3838](https://github.com/FunkinCrew/Funkin/pull/3838)
- Fixed a rare bug where a song would not register as beaten. ([a3e2373](https://github.com/FunkinCrew/Funkin/commit/a3e23733db104b1ef00cfcff17db3a5d032a4d67)) - by @AbnormalPoof in [#3820](https://github.com/FunkinCrew/Funkin/pull/3820)
- The difficulty graphic on the Results screen no longer cuts off incorrectly. ([b13bf05](https://github.com/FunkinCrew/Funkin/commit/b13bf05d16ff2977309e0c7ba3f049c0134e8902)) - by @AbnormalPoof in [#4161](https://github.com/FunkinCrew/Funkin/pull/4161)
- Four-digit long Total Notes values in the Results screen no longer overflow to the right. ([2be4c0c](https://github.com/FunkinCrew/Funkin/commit/2be4c0c7196e018a43f9697f015179f3efc3fcdb)) - by @Hundrec in [#4356](https://github.com/FunkinCrew/Funkin/pull/4356)
- Four-digit long Total Notes values in the Results screen no longer overflow to the right. ([91a594c](https://github.com/FunkinCrew/Funkin/commit/91a594cc858ed086cd2146a1ac5d2379c6fdd27a)) - by @Hundrec in [#4356](https://github.com/FunkinCrew/Funkin/pull/4356)
- The Character Select screen no longer plays the unlock animation for some locked characters. ([7058126](https://github.com/FunkinCrew/Funkin/commit/7058126e99adb55e43f5f487b007d3efa9f324d5)) - by @AbnormalPoof in [#3748](https://github.com/FunkinCrew/Funkin/pull/3748)
- All time signatures in the Chart Editor now display the correct number of beat/step tick lines. ([e570dfb](https://github.com/FunkinCrew/Funkin/commit/e570dfb8e754f9cb29ac2d8fff6e8513bc68b630)) - by @Keoiki in [#2860](https://github.com/FunkinCrew/Funkin/pull/2860)
- The Debug menu now opens with the correct camera position. ([090ddd1](https://github.com/FunkinCrew/Funkin/commit/090ddd1f1c2aa48fdb83127b2235041643c99af5)) - by @ninjamuffin99 in [#3769](https://github.com/FunkinCrew/Funkin/pull/3769)
- Removed some Freeplay variables left over from legacy versions. ([6f6529f](https://github.com/FunkinCrew/Funkin/commit/6f6529f3c460721755dfdd0a7a26578c0de429d2)) - by @AbnormalPoof in [#4370](https://github.com/FunkinCrew/Funkin/pull/4370)
- Removed an unused Freeplay class left over from legacy versions. ([abe4ac8](https://github.com/FunkinCrew/Funkin/commit/abe4ac8485539cbebe527a9a75698950232b68d2)) - by @AbnormalPoof in [#4370](https://github.com/FunkinCrew/Funkin/pull/4370)
- Blacklisted an additional class for security. ([3492d41](https://github.com/FunkinCrew/Funkin/commit/3492d412c65c7f3fd61e6fc6c9410d8467122ab0)) - by @AbnormalPoof in [#4074](https://github.com/FunkinCrew/Funkin/pull/4074)
- Removed an unused class from Polymod blacklist. ([06c12e3](https://github.com/FunkinCrew/Funkin/commit/06c12e36c6bd6df4e2be32a3bec540172e79e162)) - by @AbnormalPoof in [#3729](https://github.com/FunkinCrew/Funkin/pull/3729)
- Many additional small bug fixes.
@@ -397,7 +524,7 @@ The Playable Pico Update!
- Botplay mode now handles the player's animations properly during hold notes. ([thanks Hundrec!](https://github.com/FunkinCrew/Funkin/pull/2683))
- Camera movement now pauses when the game is paused. ([thanks Matriculaso!](https://github.com/FunkinCrew/Funkin/pull/2684))
- Pico's gameplay sprite no longer appears on the gameover screen when dying from an explosion in 2hot.
- Freeplay previews now properly fade in volume during the BF idle animation.
- Freeplay previews now properly fade in volume during the DJ's idle animation.
- DadBattle no longer incorrectly appears as DadBattle Erect when returning to Freeplay on Hard.
- 2hot now appears under the "#" category in Freeplay menu.
- The Chart Editor no longer crashes when selecting an event with the Event toolbox open.
+1 -1
Submodule art updated: 78dc310219...8402339e2e
+1 -1
Submodule assets updated: ac932c19f9...c108a7ff0d
+7 -6
View File
@@ -13,19 +13,20 @@
- NOTE: By performing this operation, you are downloading Content which is proprietary and protected by national and international copyright and trademark laws. See [the LICENSE.md file for the Funkin.assets](https://github.com/FunkinCrew/funkin.assets/blob/main/LICENSE.md) repo for more information.
5. Run `haxelib --global install hmm` and then `haxelib --global run hmm setup` to install hmm.json
6. Run `hmm install` to install all haxelibs of the current branch
7. Run `haxelib run lime setup` to set up Lime
8. Perform additional platform setup
- If you have issues installing Lime, try utilizing Funkin's patched libraries for hmm and haxelib: `haxelib --global git haxelib https://github.com/FunkinCrew/haxelib.git` and `haxelib --global git hmm https://github.com/FunkinCrew/hmm.git`
8. Run `haxelib run lime setup` to set up Lime
9. Perform additional platform setup
- For Windows, download the [Visual Studio Build Tools](https://aka.ms/vs/17/release/vs_BuildTools.exe)
- When prompted, select "Individual Components" and make sure to download the following:
- MSVC v143 VS 2022 C++ x64/x86 build tools
- Windows 10/11 SDK
- Mac: [`lime setup mac` Documentation](https://lime.openfl.org/docs/advanced-setup/macos/)
- Linux: [`lime setup linux` Documentation](https://lime.openfl.org/docs/advanced-setup/linux/)
- Note: Funkin's fork currently doesn't come with the necessary binaries so you'll have to rebuild Lime. See [Troubleshooting](TROUBLESHOOTING.md#lime-related-issues).
- One of Funkin's dependencies uses libVLC, which requires you to install some packages to be able to compile: `sudo apt install libvlc-dev libvlccore-dev libvlccore9`
- One of Funkin's dependencies uses libVLC, which requires you to install some development packages to be able to compile.
Command for Ubuntu/Debian based systems: `sudo apt install libvlc-dev libvlccore-dev libvlccore9`
- HTML5: Compiles without any extra setup
9. If you are targeting for native, you may need to run `lime rebuild <PLATFORM>` and `lime rebuild <PLATFORM> -debug`
10. `lime test <PLATFORM>` to build and launch the game for your platform (for example, `lime test windows`)
10. If you are targeting for native, you may need to run `lime rebuild <PLATFORM>` and `lime rebuild <PLATFORM> -debug`
11. `lime test <PLATFORM>` to build and launch the game for your platform (for example, `lime test windows`)
## Build Flags
+20 -14
View File
@@ -74,6 +74,7 @@ Here's a list of commonly suggested features and the reasons why they won't be a
| Toggleable Ghost Tapping | https://github.com/FunkinCrew/Funkin/pull/2564#issuecomment-2119701802 |
| Perfectly Centered Strumlines | _same as above^_ |
| MultiKey, 9k, More than 4 keys, etc. | https://github.com/FunkinCrew/Funkin/issues/4243#issuecomment-2692371969 |
| Flashy Combo Milestones | https://github.com/FunkinCrew/Funkin/pull/4700#issuecomment-2798916579 |
| Losing Icons for DD and Parents | https://github.com/FunkinCrew/Funkin/issues/3048#issuecomment-2243491536 |
| Playable GF / Speaker BF / Speaker Pico | https://github.com/FunkinCrew/Funkin/issues/2953#issuecomment-2216985230 |
| Fresh (Chill Mix) as Title Screen Music | https://github.com/FunkinCrew/Funkin/pull/4282#issuecomment-2709334718 |
@@ -154,11 +155,23 @@ Choose the `develop` branch if you modify:
Choosing the right base branch helps keep your commit history clean and avoid merge conflicts.
Once you’re satisfied with the changes you’ve made, open a PR and base it on the same branch you previously chose.
## Merge conflicts and rebasing
## Maintaining your pull request
Keeping your pull request clean and easy to review increases the chance that it will be accepted!
Our maintenance policy is as follows:
- If we require changes to your PR, we will label your PR `status: needs revision`.
- We may also leave a comment under your PR specifying what changes you should make.
- If you receive a comment, you have 90 days to implement the requested changes.
- After this period, your PR will be closed due to inactivity and labeled `status: stale`.
- Even after your PR is closed, you may request for us to reopen it. Just be sure to address the issues!
This policy ensures that PRs awaiting review are up to date and ready to merge.
### Merge conflicts and rebasing
Some game updates introduce significant breaking changes that may create merge conflicts in your PR. To resolve them, you will need to update or rebase your PR.
Most merge conflicts are small and will only require you to modify a few files to resolve them.
However, some changes are so big that your commit history will look like a mess!
However, some changes are so big that your commit history will be a total mess!
In this case, you will have to perform a [**rebase**](https://docs.github.com/en/get-started/using-git/about-git-rebase).
This process reapplies your changes on top of the updated branch and cleanly resolves the merge conflicts.
@@ -392,22 +405,15 @@ If you simultaneously modify files from both repositories, then open two separat
Be sure to choose `main` as the base branch for `funkin.assets` PRs, as no `develop` branch exists for that repository.
### Charting PRs
Charting PRs make changes such as **adding/removing notes** or **adjusting the placement of song events**.
Charting PRs make changes such as **adjusting chart metadata**.
This involves modifying one or several of the `funkin.assets` repository's `.json` chart files, found in the `preload/data/songs/` directory.
These PRs should only be opened in the `funkin.assets` repository.
This involves modifying one or several of the `funkin.assets` repository's `*-metadata.json` files, found in the `preload/data/songs/` directory.
> [!CAUTION]
> **No Major Recharts!** Any PR that makes major chart modifications will be rejected.
> Keep your PRs to small tweaks and fixes.
> We **do not** accept changes to the chart `.json` file itself.
> If you find an error in the game's charts, please open an issue in the `Funkin` repo, and the Funkin' Crew will review it and make tweaks themselves as necessary.
Here are some guidelines for opening a Charting PR:
- **Explain the issue.** Which song, variation, difficulty, and section/timestamp is the problem in? Help us understand with screenshots and videos.
- **Show your changes.** How does the chart look with your changes? Provide screenshots and videos here as well.
- **Minimize the diff.** If your changes are very small (e.g. a few notes), do not re-export the chart using the Chart Editor. Instead, manually edit the `.json` chart files to help GitHub display your changes cleanly.
If your PR is accepted, you will be credited as a GitHub contributor (but not as a charter in the Pause Menu).
These PRs should only be opened in the `funkin.assets` repository.
# Closing
Thank you for reading the Contributing Guide.
-5
View File
@@ -12,9 +12,6 @@ Most of this functionality is only available on debug builds of the game!
- `CTRL-SHIFT-L`: ***FORCE CRASH***: Immediately crash the game with a detailed crash log and a stack trace.
## Loading State
- `SPACE`: Trace callbacks.
## **Play State**
- `H`: ***HIDE UI***: Makes the user interface invisible. Works in Pause Menu, great for screenshots.
- `1`: ***END SONG***: Immediately ends the song and moves to Results Screen on Freeplay, or next song on Story Mode.
@@ -31,8 +28,6 @@ Most of this functionality is only available on debug builds of the game!
- `T`: ***TEST RANK ANIMATION***: Play the Gold Perfect rank animation on the currently selected song.
- `SHIFT-ACCEPT`: ***BOTPLAY MODE***: Start a song with Botplay mode enabled.
- `CTRL-Switch Song`: Play the first unlocked alternate instrumental as the song preview.
- `CTRL-LEFT`/`RIGHT`/`UP`/`DOWN`: ***OFFSET BF DJ IN CARTOON STATE***: While BF DJ's TV animation is playing, offset the DJ by 1 pixel in the opposite direction. `SHIFT` to move 10 pixels, `ALT` to move 0.1 pixels.
- `CTRL-C`: ***TRIGGER DJ CARTOON***: Play the Freeplay DJ's cartoon animation. Press again to return to its regular animation.
## **Title State**
- `ESCAPE`: ***QUIT***: Quit the game.
+5 -2
View File
@@ -36,7 +36,8 @@
(NOTE: Make sure you do this via `hmm` (e.g `hmm reinstall -f lime`) to guarantee you get Funkin's version of Lime.)
- `Uncaught exception - Could not find lime.ndll.` ... `Advanced users may run "lime rebuild cpp" instead.`
- Usually specific to Linux. Running the commands below should fix it.
- If on Linux:
- The binaries GLibC version might more recent than the one your system supports. Running the commands below should fix it.
```
cd .haxelib/lime/git
git submodule init
@@ -47,4 +48,6 @@
sudo apt install libgl1-mesa-dev libglu1-mesa-dev g++ g++-multilib gcc-multilib libasound2-dev libx11-dev libxext-dev libxi-dev libxrandr-dev libxinerama-dev libpulse-dev
lime rebuild cpp -64 -release -clean
```
For Windows or MacOS you can download pre-built binaries from [Funkin's Lime](https://github.com/FunkinCrew/lime/tree/dev-funkin/ndll).
- The binaries are missing for some reason. You can download pre-built binaries from [Funkin's Lime](https://github.com/FunkinCrew/lime/tree/dev-funkin/ndll).
You should copy them to `.haxelib/lime/git/ndll/<PLATFORM>64/`, where `<PLATFORM>` is the current platform you're on, which can be either Windows, Linux or MacOS.
+2 -3
View File
@@ -25,7 +25,7 @@ class Project extends HXProject {
* REMEMBER TO CHANGE THIS WHEN THE GAME UPDATES!
* You only have to change it here, the rest of the game will query this value.
*/
static final VERSION:String = "0.6.3";
static final VERSION:String = "0.6.4";
/**
* The game's name. Used as the default window title.
@@ -773,13 +773,12 @@ class Project extends HXProject {
addAssetLibrary("weekend1", shouldEmbed, shouldPreload);
addAssetPath("assets/weekend1", "assets/weekend1", "weekend1", ["*"], exclude, shouldEmbed);
// Art asset library (where README and CHANGELOG pull from)
// Art asset library (where README pulls from)
var shouldEmbedArt = false;
var shouldPreloadArt = false;
addAssetLibrary("art", shouldEmbedArt, shouldPreloadArt);
addAsset("art/readme.txt", "do NOT readme.txt", "art", shouldEmbedArt);
addAsset("LICENSE.md", "LICENSE.md", "art", shouldEmbedArt);
addAsset("CHANGELOG.md", "CHANGELOG.md", "art", shouldEmbedArt);
}
/**
+11 -8
View File
@@ -62,14 +62,6 @@ class Main extends Sprite
function init(?event:Event):Void
{
#if web
// set this variable (which is a function) from the lime version at lime/_internal/backend/html5/HTML5Application.hx
// The framerate cap will more thoroughly initialize via Preferences in InitState.hx
funkin.Preferences.lockedFramerateFunction = untyped js.Syntax.code("window.requestAnimationFrame");
#end
WindowUtil.setVSyncMode(funkin.Preferences.vsyncMode);
if (hasEventListener(Event.ADDED_TO_STAGE))
{
removeEventListener(Event.ADDED_TO_STAGE, init);
@@ -107,6 +99,17 @@ class Main extends Sprite
// George recommends binding the save before FlxGame is created.
Save.load();
// Don't call anything from the preferences until the save is loaded!
#if web
// set this variable (which is a function) from the lime version at lime/_internal/backend/html5/HTML5Application.hx
// The framerate cap will more thoroughly initialize via Preferences in InitState.hx
funkin.Preferences.lockedFramerateFunction = untyped js.Syntax.code("window.requestAnimationFrame");
#end
WindowUtil.setVSyncMode(funkin.Preferences.vsyncMode);
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
+28 -2
View File
@@ -185,15 +185,41 @@ class Preferences
static function get_vsyncMode():lime.ui.WindowVSyncMode
{
return Save?.instance?.options?.vsyncMode ?? lime.ui.WindowVSyncMode.OFF;
var value = Save?.instance?.options?.vsyncMode ?? "Off";
return switch (value)
{
case "Off":
lime.ui.WindowVSyncMode.OFF;
case "On":
lime.ui.WindowVSyncMode.ON;
case "Adaptive":
lime.ui.WindowVSyncMode.ADAPTIVE;
default:
lime.ui.WindowVSyncMode.OFF;
};
}
static function set_vsyncMode(value:lime.ui.WindowVSyncMode):lime.ui.WindowVSyncMode
{
var string;
switch (value)
{
case lime.ui.WindowVSyncMode.OFF:
string = "Off";
case lime.ui.WindowVSyncMode.ON:
string = "On";
case lime.ui.WindowVSyncMode.ADAPTIVE:
string = "Adaptive";
default:
string = "Off";
};
WindowUtil.setVSyncMode(value);
var save:Save = Save.instance;
save.options.vsyncMode = value;
save.options.vsyncMode = string;
save.flush();
return value;
}
+3 -2
View File
@@ -44,7 +44,8 @@ class Medals
if (NewgroundsClient.instance.isLoggedIn())
{
var medalList = NewgroundsClient.instance.medals;
if (medalList == null) return;
@:privateAccess
if (medalList == null || medalList._map == null) return;
var medalData:Null<MedalData> = medalList.get(medal.getId());
@:privateAccess
@@ -67,7 +68,7 @@ class Medals
NewgroundsMedalPlugin.play(medalData.value, medalData.name, medalGraphic);
});
#else
if (medalJSON == null) loadMedalJSON();
if ((medalJSON?.length ?? 0) == 0) loadMedalJSON();
// We have to use a medal image from the game files. We use a Base64 encoded image that NG spits out.
// TODO: Wait, don't they give us the medal icon?
+58 -4
View File
@@ -14,6 +14,10 @@ import funkin.util.tools.ICloneable;
import funkin.util.flixel.sound.FlxPartialSound;
import funkin.Paths.PathsFunction;
import lime.app.Promise;
import lime.media.AudioSource;
import openfl.events.Event;
import openfl.media.Sound;
import openfl.media.SoundChannel;
import openfl.media.SoundMixer;
#if (openfl >= "8.0.0")
@@ -108,6 +112,11 @@ class FunkinSound extends FlxSound implements ICloneable<FunkinSound>
return _waveformData;
}
/**
* If true, the game will forcefully add this sound's channel to the list of playing sounds.
*/
public var important:Bool = false;
/**
* Are we in a state where the song should play but time is negative?
*/
@@ -145,6 +154,14 @@ class FunkinSound extends FlxSound implements ICloneable<FunkinSound>
else
{
super.update(elapsedSec);
@:privateAccess
{
if (important && _channel != null && !SoundMixer.__soundChannels.contains(_channel))
{
SoundMixer.__soundChannels.push(_channel);
}
}
}
}
@@ -431,13 +448,14 @@ class FunkinSound extends FlxSound implements ICloneable<FunkinSound>
* @param persist Whether to keep this `FunkinSound` between states, or destroy it.
* @param onComplete Called when the sound finished playing.
* @param onLoad Called when the sound finished loading. Called immediately for succesfully loaded embedded sounds.
* @param important If `true`, the sound channel will forcefully be added onto the channel array, even if full. Use sparingly!
* @return A `FunkinSound` object, or `null` if the sound could not be loaded.
*/
public static function load(embeddedSound:FlxSoundAsset, volume:Float = 1.0, looped:Bool = false, autoDestroy:Bool = false, autoPlay:Bool = false,
persist:Bool = false, ?onComplete:Void->Void, ?onLoad:Void->Void):Null<FunkinSound>
persist:Bool = false, ?onComplete:Void->Void, ?onLoad:Void->Void, important:Bool = false):Null<FunkinSound>
{
@:privateAccess
if (SoundMixer.__soundChannels.length >= SoundMixer.MAX_ACTIVE_CHANNELS)
if (SoundMixer.__soundChannels.length >= SoundMixer.MAX_ACTIVE_CHANNELS && !important)
{
FlxG.log.error('FunkinSound could not play sound, channels exhausted! Found ${SoundMixer.__soundChannels.length} active sound channels.');
return null;
@@ -462,6 +480,7 @@ class FunkinSound extends FlxSound implements ICloneable<FunkinSound>
sound.volume = volume;
sound.group = FlxG.sound.defaultSoundGroup;
sound.persist = persist;
sound.important = important;
// Make sure to add the sound to the list.
// If it's already in, it won't get re-added.
@@ -534,15 +553,50 @@ class FunkinSound extends FlxSound implements ICloneable<FunkinSound>
this._label = 'unknown';
}
@:access(openfl.media.Sound)
@:access(openfl.media.SoundChannel)
@:access(openfl.media.SoundMixer)
override function startSound(startTime:Float)
{
if (!important)
{
super.startSound(startTime);
return;
}
_time = startTime;
_paused = false;
if (_sound == null) return;
// Create a channel manually if the sound is considered important.
var pan:Float = FlxMath.bound(SoundMixer.__soundTransform.pan + _transform.pan, -1, 1);
var volume:Float = FlxMath.bound(SoundMixer.__soundTransform.volume * _transform.volume, 0, MAX_VOLUME);
var audioSource:AudioSource = new AudioSource(_sound.__buffer);
audioSource.offset = Std.int(startTime);
audioSource.gain = volume;
var position:lime.math.Vector4 = audioSource.position;
position.x = pan;
position.z = -1 * Math.sqrt(1 - Math.pow(pan, 2));
audioSource.position = position;
_channel = new SoundChannel(_sound, audioSource, _transform);
_channel.addEventListener(Event.SOUND_COMPLETE, stopped);
pitch = _pitch;
active = true;
}
/**
* Play a sound effect once, then destroy it.
* @param key
* @param volume
* @return A `FunkinSound` object, or `null` if the sound could not be loaded.
*/
public static function playOnce(key:String, volume:Float = 1.0, ?onComplete:Void->Void, ?onLoad:Void->Void):Null<FunkinSound>
public static function playOnce(key:String, volume:Float = 1.0, ?onComplete:Void->Void, ?onLoad:Void->Void, important:Bool = false):Null<FunkinSound>
{
var result:Null<FunkinSound> = FunkinSound.load(key, volume, false, true, true, false, onComplete, onLoad);
var result:Null<FunkinSound> = FunkinSound.load(key, volume, false, true, true, false, onComplete, onLoad, important);
return result;
}
@@ -66,6 +66,8 @@ class FlxAtlasSprite extends FlxAnimate
throw 'FlxAtlasSprite not initialized properly. Are you sure the path (${path}) exists?';
}
onAnimationComplete.add(cleanupAnimation);
// This defaults the sprite to play the first animation in the atlas,
// then pauses it. This ensures symbols are intialized properly.
this.anim.play('');
@@ -317,7 +319,6 @@ class FlxAtlasSprite extends FlxAnimate
else if (fr != null && anim.curFrame != anim.length - 1)
{
anim.curFrame--;
cleanupAnimation(currentAnimation ?? "");
_onAnimationComplete();
}
}
+6 -2
View File
@@ -80,8 +80,10 @@ class PolymodHandler
*/
public static function loadAllMods():Void
{
#if sys
// Create the mod root if it doesn't exist.
createModRoot();
#end
trace('Initializing Polymod (using all mods)...');
loadModsById(getAllModIds());
}
@@ -91,9 +93,10 @@ class PolymodHandler
*/
public static function loadEnabledMods():Void
{
#if sys
// Create the mod root if it doesn't exist.
createModRoot();
#end
trace('Initializing Polymod (using configured mods)...');
loadModsById(Save.instance.enabledModIds);
}
@@ -103,9 +106,10 @@ class PolymodHandler
*/
public static function loadNoMods():Void
{
#if sys
// Create the mod root if it doesn't exist.
createModRoot();
#end
// We still need to configure the debug print calls etc.
trace('Initializing Polymod (using no mods)...');
loadModsById([]);
+1 -1
View File
@@ -255,7 +255,7 @@ class Countdown
var path = noteStyle.getCountdownSoundPath(step);
if (path == null) return null;
return FunkinSound.playOnce(path, Constants.COUNTDOWN_VOLUME);
return FunkinSound.playOnce(path, Constants.COUNTDOWN_VOLUME, null, null, true);
}
public static function decrement(step:CountdownStep):CountdownStep
+12 -17
View File
@@ -878,7 +878,6 @@ class PlayState extends MusicBeatSubState
// so the song doesn't start too early :D
Conductor.instance.update(-5000, false);
// Reset camera zooming
cameraBopIntensity = Constants.DEFAULT_BOP_INTENSITY;
hudCameraZoomIntensity = (cameraBopIntensity - 1.0) * 2.0;
@@ -898,16 +897,9 @@ class PlayState extends MusicBeatSubState
Countdown.performCountdown();
});
// Reset the health icons.
if (currentStage.getBoyfriend() != null)
{
currentStage.getBoyfriend().initHealthIcon(false);
}
if (currentStage.getDad() != null)
{
currentStage.getDad().initHealthIcon(true);
}
currentStage?.getBoyfriend()?.initHealthIcon(false);
currentStage?.getDad()?.initHealthIcon(true);
needsReset = false;
}
@@ -956,7 +948,7 @@ class PlayState extends MusicBeatSubState
// Attempt to pause the game.
if ((controls.PAUSE || androidPause) && isInCountdown && mayPauseGame && !justUnpaused)
{
var event = new PauseScriptEvent(FlxG.random.bool(1 / 1000));
var event = new PauseScriptEvent(FlxG.random.bool((1 / 1000) * 100));
dispatchEvent(event);
@@ -1146,7 +1138,7 @@ class PlayState extends MusicBeatSubState
if (!isMinimalMode)
{
if (iconP1 != null) iconP1.updatePosition();
if (iconP1 != null) iconP2.updatePosition();
if (iconP2 != null) iconP2.updatePosition();
}
// Transition to the game over substate.
@@ -1429,9 +1421,10 @@ class PlayState extends MusicBeatSubState
*/
override function reloadAssets():Void
{
performCleanup();
funkin.modding.PolymodHandler.forceReloadAssets();
lastParams.targetSong = SongRegistry.instance.fetchEntry(currentSong.id);
this.remove(currentStage);
LoadingState.loadPlayState(lastParams);
}
@@ -1797,13 +1790,13 @@ class PlayState extends MusicBeatSubState
// Position the player strumline on the right half of the screen
playerStrumline.x = FlxG.width / 2 + Constants.STRUMLINE_X_OFFSET; // Classic style
// playerStrumline.x = FlxG.width - playerStrumline.width - Constants.STRUMLINE_X_OFFSET; // Centered style
playerStrumline.y = Preferences.downscroll ? FlxG.height - playerStrumline.height - Constants.STRUMLINE_Y_OFFSET : Constants.STRUMLINE_Y_OFFSET;
playerStrumline.y = Preferences.downscroll ? FlxG.height - playerStrumline.height - Constants.STRUMLINE_Y_OFFSET - noteStyle.getStrumlineOffsets()[1] : Constants.STRUMLINE_Y_OFFSET;
playerStrumline.zIndex = 1001;
playerStrumline.cameras = [camHUD];
// Position the opponent strumline on the left half of the screen
opponentStrumline.x = Constants.STRUMLINE_X_OFFSET;
opponentStrumline.y = Preferences.downscroll ? FlxG.height - opponentStrumline.height - Constants.STRUMLINE_Y_OFFSET : Constants.STRUMLINE_Y_OFFSET;
opponentStrumline.y = Preferences.downscroll ? FlxG.height - opponentStrumline.height - Constants.STRUMLINE_Y_OFFSET - noteStyle.getStrumlineOffsets()[1] : Constants.STRUMLINE_Y_OFFSET;
opponentStrumline.zIndex = 1000;
opponentStrumline.cameras = [camHUD];
@@ -2425,7 +2418,7 @@ class PlayState extends MusicBeatSubState
dispatchEvent(event);
trace('Penalizing score by ${event.score} and health by ${event.healthChange} for dropping hold note (is combo break: ${event.isComboBreak})!');
applyScore(event.score, 'miss', event.healthChange, event.isComboBreak);
applyScore(event.score, '', event.healthChange, event.isComboBreak);
// Play the miss sound.
vocals.playerVolume = 0;
@@ -2736,7 +2729,7 @@ class PlayState extends MusicBeatSubState
#end
// 9: Toggle the old icon.
if (FlxG.keys.justPressed.NINE) iconP1.toggleOldIcon();
if (FlxG.keys.justPressed.NINE && iconP1 != null) iconP1.toggleOldIcon();
#if FEATURE_DEBUG_FUNCTIONS
// PAGEUP: Skip forward two sections.
@@ -2765,6 +2758,8 @@ class PlayState extends MusicBeatSubState
Highscore.tallies.shit += 1;
case 'miss':
Highscore.tallies.missed += 1;
default:
// Nothing!
}
health += healthChange;
if (isComboBreak)
+2 -1
View File
@@ -488,7 +488,8 @@ class ResultState extends MusicBeatSubState
FlxTween.tween(bgFlash, {alpha: 0}, 5 / 24);
// NOTE: Only divide if totalNotes > 0 to prevent divide-by-zero errors.
var clearPercentFloat = params.scoreData.tallies.totalNotes == 0 ? 0.0 : (params.scoreData.tallies.sick +
params.scoreData.tallies.good) / params.scoreData.tallies.totalNotes * 100;
params.scoreData.tallies.good
- params.scoreData.tallies.missed) / params.scoreData.tallies.totalNotes * 100;
clearPercentTarget = Math.floor(clearPercentFloat);
// Prevent off-by-one errors.
@@ -65,7 +65,7 @@ class ClearPercentCounter extends FlxTypedSpriteGroup<FlxSprite>
var seperatedScore:Array<Int> = [];
var tempCombo:Int = Math.round(curNumber);
while (tempCombo != 0)
while (tempCombo > 0 && tempCombo != 0)
{
seperatedScore.push(tempCombo % 10);
tempCombo = Math.floor(tempCombo / 10);
+1 -1
View File
@@ -384,7 +384,7 @@ class Scoring
// Final Grade = (Sick + Good - Miss) / (Total Notes)
var grade = (scoreData.tallies.sick + scoreData.tallies.good) / scoreData.tallies.totalNotes;
var grade = (scoreData.tallies.sick + scoreData.tallies.good - scoreData.tallies.missed) / scoreData.tallies.totalNotes;
if (grade == Constants.RANK_PERFECT_THRESHOLD)
{
+8 -3
View File
@@ -801,7 +801,7 @@ class SongDifficulty
{
var suffix:String = (instId != '') ? '-$instId' : '';
FlxG.sound.music = FunkinSound.load(Paths.inst(this.song.id, suffix), volume, looped, false, true);
FlxG.sound.music = FunkinSound.load(Paths.inst(this.song.id, suffix), volume, looped, false, true, false, null, null, true);
// Workaround for a bug where FlxG.sound.music.update() was being called twice.
FlxG.sound.list.remove(FlxG.sound.music);
@@ -948,16 +948,21 @@ class SongDifficulty
for (playerVoice in playerVoiceList)
{
if (!Assets.exists(playerVoice)) continue;
result.addPlayerVoice(FunkinSound.load(playerVoice));
result.addPlayerVoice(FunkinSound.load(playerVoice, 1.0, false, false, false, false, null, null, true));
}
// Add opponent vocals.
for (opponentVoice in opponentVoiceList)
{
if (!Assets.exists(opponentVoice)) continue;
result.addOpponentVoice(FunkinSound.load(opponentVoice));
result.addOpponentVoice(FunkinSound.load(opponentVoice, 1.0, false, false, false, false, null, null, true));
}
// Sometimes the sounds don't set their important value to true, so we have to do this manually.
result.forEach(function(snd:FunkinSound) {
snd.important = true;
});
result.playerVoicesOffset = offsets.getVocalOffset(characters.player, instId);
result.opponentVoicesOffset = offsets.getVocalOffset(characters.opponent, instId);
+3 -3
View File
@@ -115,7 +115,7 @@ class Save
zoomCamera: true,
debugDisplay: false,
autoPause: true,
vsyncMode: lime.ui.WindowVSyncMode.OFF,
vsyncMode: 'Off',
strumlineBackgroundOpacity: 0,
autoFullscreen: false,
inputOffset: 0,
@@ -1401,9 +1401,9 @@ typedef SaveDataOptions =
/**
* If enabled, the game will utilize VSync (or adaptive VSync) on startup.
* @default `OFF`
* @default `Off`
*/
var vsyncMode:lime.ui.WindowVSyncMode;
var vsyncMode:String;
/**
* If >0, the game will display a semi-opaque background under the notes.
@@ -572,7 +572,7 @@ class DebugBoundingState extends FlxState
_file.addEventListener(Event.COMPLETE, onSaveComplete);
_file.addEventListener(Event.CANCEL, onSaveCancel);
_file.addEventListener(IOErrorEvent.IO_ERROR, onSaveError);
_file.save(saveString,);
_file.save(saveString, fileName);
}
}
@@ -1334,7 +1334,6 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
result = [];
trace('Initializing blank chart for difficulty ' + selectedDifficulty);
currentSongChartData.notes.set(selectedDifficulty, result);
currentSongMetadata.playData.difficulties.pushUnique(selectedDifficulty);
return result;
}
return result;
@@ -1343,7 +1342,6 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
function set_currentSongChartNoteData(value:Array<SongNoteData>):Array<SongNoteData>
{
currentSongChartData.notes.set(selectedDifficulty, value);
currentSongMetadata.playData.difficulties.pushUnique(selectedDifficulty);
return value;
}
@@ -1636,9 +1634,6 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
noteTooltipsDirty = true;
notePreviewViewportBoundsDirty = true;
// Make sure the difficulty we selected is in the list of difficulties.
currentSongMetadata.playData.difficulties.pushUnique(selectedDifficulty);
return selectedDifficulty;
}
@@ -3230,7 +3225,7 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
#if sys
// TODO: Is there a way to open a folder and highlight a file in it?
var absoluteBackupsPath:String = Path.join([Sys.getCwd(), ChartEditorImportExportHandler.BACKUPS_PATH]);
WindowUtil.openFolder(absoluteBackupsPath);
FileUtil.openFolder(absoluteBackupsPath);
return true;
#else
trace('No file system access, cannot open backups folder.');
@@ -5843,6 +5838,7 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
{
uiCamera.revive();
FlxG.cameras.reset(uiCamera);
uiCamera.onResize();
add(this.root);
}
@@ -91,6 +91,8 @@ class ChartEditorWelcomeDialog extends ChartEditorBaseDialog
#end
linkRecentChart.onClick = function(_event) {
linkRecentChart.hide();
this.hideDialog(DialogButton.CANCEL);
// Load chart from file
@@ -117,6 +117,12 @@ class ChartEditorImportExportHandler
{
state.songMetadata = newSongMetadata;
state.songChartData = newSongChartData;
state.selectedDifficulty = state.availableDifficulties[0];
if (!newSongMetadata.exists(state.selectedVariation))
{
state.selectedVariation = Constants.DEFAULT_VARIATION;
}
Conductor.instance.forceBPM(null); // Disable the forced BPM.
Conductor.instance.instrumentalOffset = state.currentInstrumentalOffset; // Loads from the metadata.
@@ -343,6 +349,12 @@ class ChartEditorImportExportHandler
var variations = state.availableVariations;
if (state.currentSongMetadata.playData.difficulties.pushUnique(state.selectedDifficulty))
{
// Just in case the user deleted all or didn't add a difficulty
state.difficultySelectDirty = true;
}
for (variation in variations)
{
var variationId:String = variation;
@@ -1267,7 +1267,7 @@ class StageEditorState extends UIState
case "open folder":
#if sys
var absoluteBackupsPath:String = haxe.io.Path.join([Sys.getCwd(), BACKUPS_PATH]);
WindowUtil.openFolder(absoluteBackupsPath);
FileUtil.openFolder(absoluteBackupsPath);
#end
case "test stage":
@@ -5,7 +5,6 @@ import haxe.ui.containers.dialogs.Dialog.DialogButton;
import funkin.util.FileUtil;
import haxe.io.Path;
import funkin.util.DateUtil;
import funkin.util.WindowUtil;
using StringTools;
@@ -57,7 +56,7 @@ class BackupAvailableDialog extends Dialog
// :[
#if sys
var absoluteBackupsPath:String = Path.join([Sys.getCwd(), StageEditorState.BACKUPS_PATH]);
WindowUtil.openFolder(absoluteBackupsPath);
FileUtil.openFolder(absoluteBackupsPath);
#end
}
@@ -24,6 +24,10 @@ class CapsuleOptionsMenu extends FlxSpriteGroup
var busy:Bool = false;
var leftArrow:InstrumentalSelector;
var rightArrow:InstrumentalSelector;
public function new(parent:FreeplayState, x:Float = 0, y:Float = 0, instIds:Array<String>):Void
{
super(x, y);
@@ -41,8 +45,8 @@ class CapsuleOptionsMenu extends FlxSpriteGroup
currentInstrumental.setFormat('VCR OSD Mono', 40, FlxTextAlign.CENTER, true);
final PAD = 4;
var leftArrow = new InstrumentalSelector(parent, PAD, 30, false, parent.getControls());
var rightArrow = new InstrumentalSelector(parent, capsuleMenuBG.width - leftArrow.width - PAD, 30, true, parent.getControls());
leftArrow = new InstrumentalSelector(parent, PAD, 30, false, parent.getControls());
rightArrow = new InstrumentalSelector(parent, capsuleMenuBG.width - leftArrow.width - PAD, 30, true, parent.getControls());
var label:FlxText = new FlxText(0, 5, capsuleMenuBG.width, 'INSTRUMENTAL');
label.setFormat('VCR OSD Mono', 24, FlxTextAlign.CENTER, true);
@@ -109,6 +113,8 @@ class CapsuleOptionsMenu extends FlxSpriteGroup
{
// Play in reverse.
capsuleMenuBG.animation.play('open', true, true);
if (leftArrow.moveShitDownTimer != null) leftArrow.moveShitDownTimer.cancel();
if (rightArrow.moveShitDownTimer != null) rightArrow.moveShitDownTimer.cancel();
capsuleMenuBG.animation.finishCallback = function(_) {
parent.cleanupCapsuleOptionsMenu();
queueDestroy = true;
@@ -136,6 +142,8 @@ class InstrumentalSelector extends FunkinSprite
var baseScale:Float = 0.6;
public var moveShitDownTimer:FlxTimer;
public function new(parent:FreeplayState, x:Float, y:Float, flipped:Bool, controls:Controls)
{
super(x, y);
@@ -174,7 +182,7 @@ class InstrumentalSelector extends FunkinSprite
scale.x = scale.y = 0.5 * baseScale;
new FlxTimer().start(2 / 24, function(tmr) {
moveShitDownTimer = new FlxTimer().start(2 / 24, function(tmr) {
scale.x = scale.y = 1 * baseScale;
whiteShader.colorSet = false;
updateHitbox();
+2
View File
@@ -168,6 +168,8 @@ class CapsuleText extends FlxSpriteGroup
public function resetText():Void
{
scale.x = 1;
scale.y = 1;
if (moveTween != null) moveTween.cancel();
if (moveTimer != null) moveTimer.cancel();
whiteText.offset.x = 0;
+1 -1
View File
@@ -87,7 +87,7 @@ class FreeplayDJ extends FlxAtlasSprite
case Intro:
// Play the intro animation then leave this state immediately.
var animPrefix = playableCharData.getAnimationPrefix('intro');
if (getCurrentAnimation() != animPrefix) playFlashAnimation(animPrefix, true);
if (getCurrentAnimation() != animPrefix || !this.anim.isPlaying) playFlashAnimation(animPrefix, true);
timeIdling = 0;
case Idle:
// We are in this state the majority of the time.
+1 -1
View File
@@ -35,7 +35,7 @@ class FreeplayScore extends FlxTypedSpriteGroup<ScoreNum>
loopNum--;
}
while (loopNum > 0)
while (loopNum >= 0)
{
group.members[loopNum].digit = 0;
loopNum--;
+46 -34
View File
@@ -501,19 +501,19 @@ class FreeplayState extends MusicBeatSubState
switch (str)
{
case 'fav':
generateSongList({filterType: FAVORITE}, true);
generateSongList({filterType: FAVORITE}, true, false);
case 'ALL':
generateSongList(null, true);
generateSongList(null, true, false);
case '#':
generateSongList({filterType: REGEXP, filterData: '0-9'}, true);
generateSongList({filterType: REGEXP, filterData: '0-9'}, true, false);
default:
generateSongList({filterType: REGEXP, filterData: str}, true);
generateSongList({filterType: REGEXP, filterData: str}, true, false);
}
// If the current song is still in the list (aka not null?), we'll land on it
// If the current song is still in the list, or if it was random, we'll land on it
// Otherwise we want to land on the first song of the group, rather than random song when changing letter sorts
// that is, only if there's more than one song in the group!
if (curSong != null && currentFilteredSongs.length > 1)
if (curSong == null || currentFilteredSongs.contains(curSong))
{
changeSelection();
}
@@ -638,7 +638,8 @@ class FreeplayState extends MusicBeatSubState
allDifficulties = SongRegistry.instance.listAllDifficulties(currentCharacterId);
// Generates song list with the starter params (who our current character is, last remembered difficulty, etc.)
generateSongList(null, false);
// Set this to false if you prefer the 50% transparency on the capsules when they first appear.
generateSongList(null, true);
// dedicated camera for the state so we don't need to fuk around with camera scrolls from the mainmenu / elsewhere
funnyCam.bgColor = FlxColor.TRANSPARENT;
@@ -734,10 +735,10 @@ class FreeplayState extends MusicBeatSubState
// Initialize the random capsule, with empty/blank info (which we display once bf/pico does his hand)
var randomCapsule:SongMenuItem = grpCapsules.recycle(SongMenuItem);
randomCapsule.initPosition(FlxG.width, 0);
randomCapsule.initData(null, styleData);
randomCapsule.initData(null, styleData, 1);
randomCapsule.y = randomCapsule.intendedY(0) + 10;
randomCapsule.targetPos.x = randomCapsule.x;
randomCapsule.alpha = 0;
randomCapsule.alpha = 0.5;
randomCapsule.songText.visible = false;
randomCapsule.favIcon.visible = false;
randomCapsule.favIconBlurred.visible = false;
@@ -749,8 +750,7 @@ class FreeplayState extends MusicBeatSubState
if (fromCharSelect) randomCapsule.forcePosition();
else
{
// randomCapsule.initJumpIn(0, force);
randomCapsule.forcePosition();
randomCapsule.initJumpIn(0, force);
}
var hsvShader:HSVShader = new HSVShader();
@@ -765,7 +765,7 @@ class FreeplayState extends MusicBeatSubState
var funnyMenu:SongMenuItem = grpCapsules.recycle(SongMenuItem);
funnyMenu.initPosition(FlxG.width, 0);
funnyMenu.initData(tempSong, styleData);
funnyMenu.initData(tempSong, styleData, i + 1);
funnyMenu.onConfirm = function() {
capsuleOnOpenDefault(funnyMenu);
};
@@ -776,10 +776,10 @@ class FreeplayState extends MusicBeatSubState
funnyMenu.hsvShader = hsvShader;
funnyMenu.newText.animation.curAnim.curFrame = 45 - ((i * 4) % 45);
// This stops the bounce-in animation.
funnyMenu.forcePosition();
// funnyMenu.initJumpIn(0, force);
// Stop the bounce-in animation when returning to freeplay from the character selection screen.
if (fromCharSelect) funnyMenu.forcePosition();
else
funnyMenu.initJumpIn(0, force);
grpCapsules.add(funnyMenu);
}
@@ -1717,14 +1717,14 @@ class FreeplayState extends MusicBeatSubState
{
touchTimer = 0;
var previousVariation:String = currentVariation;
var daSong:Null<FreeplaySongData> = grpCapsules.members[curSelected].freeplayData;
// Available variations for current character. We get this since bf is usually `default` variation, and `pico` is `pico`
// but sometimes pico can be the default variation (weekend 1 songs), and bf can be `bf` variation (darnell)
var characterVariations:Array<String> = grpCapsules.members[curSelected].freeplayData?.data.getVariationsByCharacter(currentCharacter) ?? Constants.DEFAULT_VARIATION_LIST;
var characterVariations:Array<String> = daSong?.data.getVariationsByCharacter(currentCharacter) ?? Constants.DEFAULT_VARIATION_LIST;
var difficultiesAvailable:Array<String> = allDifficulties;
// Gets all available difficulties for our character, via our available variations
var songDifficulties:Array<String> = grpCapsules.members[curSelected].freeplayData?.data.listDifficulties(null,
characterVariations) ?? Constants.DEFAULT_DIFFICULTY_LIST;
var songDifficulties:Array<String> = daSong?.data.listDifficulties(null, characterVariations) ?? Constants.DEFAULT_DIFFICULTY_LIST;
var currentDifficultyIndex:Int = difficultiesAvailable.indexOf(currentDifficulty);
@@ -1737,15 +1737,16 @@ class FreeplayState extends MusicBeatSubState
// Update the current difficulty
currentDifficulty = difficultiesAvailable[currentDifficultyIndex];
// For when we change the difficulty, but the song doesn't have that difficulty!
if (!songDifficulties.contains(difficultiesAvailable[currentDifficultyIndex]))
if (daSong != null && !songDifficulties.contains(difficultiesAvailable[currentDifficultyIndex]))
{
curSelected = findClosestDiff(characterVariations, difficultiesAvailable[currentDifficultyIndex]);
rememberedSongId = grpCapsules.members[curSelected].freeplayData?.data.id;
daSong = grpCapsules.members[curSelected].freeplayData;
rememberedSongId = daSong?.data.id;
}
for (variation in characterVariations)
{
if (grpCapsules.members[curSelected].freeplayData?.data.hasDifficulty(currentDifficulty, variation) ?? false)
if (daSong?.data.hasDifficulty(currentDifficulty, variation) ?? false)
{
currentVariation = variation;
rememberedVariation = variation;
@@ -1753,7 +1754,6 @@ class FreeplayState extends MusicBeatSubState
}
}
var daSong:Null<FreeplaySongData> = grpCapsules.members[curSelected].freeplayData;
if (daSong != null)
{
var targetSong:Null<Song> = SongRegistry.instance.fetchEntry(daSong.data.id);
@@ -1765,9 +1765,10 @@ class FreeplayState extends MusicBeatSubState
var songScore:Null<SaveScoreData> = Save.instance.getSongScore(daSong.data.id, currentDifficulty, currentVariation);
intendedScore = songScore?.score ?? 0;
intendedCompletion = songScore == null ? 0.0 : ((songScore.tallies.sick + songScore.tallies.good) / songScore.tallies.totalNotes);
intendedCompletion = songScore == null ? 0.0 : Math.max(0, ((songScore.tallies.sick +
songScore.tallies.good - songScore.tallies.missed) / songScore.tallies.totalNotes));
rememberedDifficulty = currentDifficulty;
grpCapsules.members[curSelected].refreshDisplay();
grpCapsules.members[curSelected].refreshDisplay((prepForNewRank == true) ? false : true);
}
else
{
@@ -1873,11 +1874,15 @@ class FreeplayState extends MusicBeatSubState
*/
function capsuleOnOpenDefault(cap:SongMenuItem):Void
{
busy = true;
letterSort.inputEnabled = false;
var targetSongId:String = cap?.freeplayData?.data.id ?? 'unknown';
var targetSongNullable:Null<Song> = SongRegistry.instance.fetchEntry(targetSongId);
if (targetSongNullable == null)
{
FlxG.log.warn('WARN: could not find song with id (${targetSongId})');
busy = false;
letterSort.inputEnabled = true;
return;
}
var targetSong:Song = targetSongNullable;
@@ -1891,6 +1896,8 @@ class FreeplayState extends MusicBeatSubState
if (targetDifficulty == null)
{
FlxG.log.warn('WARN: could not find difficulty with id (${targetDifficultyId})');
busy = false;
letterSort.inputEnabled = true;
return;
}
@@ -1920,9 +1927,7 @@ class FreeplayState extends MusicBeatSubState
function openInstrumentalList(cap:SongMenuItem, instrumentalIds:Array<String>):Void
{
busy = true;
capsuleOptionsMenu = new CapsuleOptionsMenu(this, cap.x + 175, cap.y + 115, instrumentalIds);
capsuleOptionsMenu = new CapsuleOptionsMenu(this, cap.targetPos.x + 175, cap.targetPos.y + 115, instrumentalIds);
capsuleOptionsMenu.cameras = [funnyCam];
capsuleOptionsMenu.zIndex = 10000;
add(capsuleOptionsMenu);
@@ -1937,6 +1942,7 @@ class FreeplayState extends MusicBeatSubState
public function cleanupCapsuleOptionsMenu():Void
{
this.busy = false;
letterSort.inputEnabled = true;
if (capsuleOptionsMenu != null)
{
@@ -1950,9 +1956,6 @@ class FreeplayState extends MusicBeatSubState
*/
function capsuleOnConfirmDefault(cap:SongMenuItem, ?targetInstId:String):Void
{
busy = true;
letterSort.inputEnabled = false;
PlayStatePlaylist.isStoryMode = false;
var targetSongId:String = cap?.freeplayData?.data.id ?? 'unknown';
@@ -1960,6 +1963,8 @@ class FreeplayState extends MusicBeatSubState
if (targetSongNullable == null)
{
FlxG.log.warn('WARN: could not find song with id (${targetSongId})');
busy = false;
letterSort.inputEnabled = true;
return;
}
var targetSong:Song = targetSongNullable;
@@ -1971,6 +1976,8 @@ class FreeplayState extends MusicBeatSubState
if (targetDifficulty == null)
{
FlxG.log.warn('WARN: could not find difficulty with id (${currentDifficulty})');
busy = false;
letterSort.inputEnabled = true;
return;
}
@@ -2061,10 +2068,11 @@ class FreeplayState extends MusicBeatSubState
{
var songScore:Null<SaveScoreData> = Save.instance.getSongScore(daSongCapsule.freeplayData.data.id, currentDifficulty, currentVariation);
intendedScore = songScore?.score ?? 0;
intendedCompletion = songScore == null ? 0.0 : ((songScore.tallies.sick + songScore.tallies.good) / songScore.tallies.totalNotes);
intendedCompletion = songScore == null ? 0.0 : ((songScore.tallies.sick +
songScore.tallies.good - songScore.tallies.missed) / songScore.tallies.totalNotes);
rememberedSongId = daSongCapsule.freeplayData.data.id;
changeDiff();
daSongCapsule.refreshDisplay();
daSongCapsule.refreshDisplay((prepForNewRank == true) ? false : true);
}
else
{
@@ -2072,6 +2080,8 @@ class FreeplayState extends MusicBeatSubState
intendedCompletion = 0.0;
rememberedSongId = null;
albumRoll.albumId = null;
changeDiff();
daSongCapsule.refreshDisplay();
}
for (index => capsule in grpCapsules.members)
@@ -2080,8 +2090,10 @@ class FreeplayState extends MusicBeatSubState
capsule.selected = index == curSelected + 1;
capsule.curSelected = curSelected;
capsule.targetPos.y = capsule.intendedY(index - curSelected);
capsule.targetPos.x = 270 + (60 * (Math.sin(index - curSelected)));
capsule.targetPos.x = capsule.intendedX(index - curSelected);
if (index < curSelected) capsule.targetPos.y -= 100; // another 100 for good measure
}
+4 -1
View File
@@ -204,6 +204,9 @@ class FreeplayLetter extends FlxAtlasSprite
this.anim.play(animLetters[letterInd] + " move");
this.anim.pause();
curLetter = letterInd;
this.anim.onComplete.add(function() {
this.anim.play(animLetters[curLetter] + " move");
});
}
}
@@ -231,7 +234,7 @@ class FreeplayLetter extends FlxAtlasSprite
animName = "T move";
}
this.anim.play(animName);
this.anim.play(animName, true);
if (curSelection != curLetter)
{
this.anim.pause();
+28 -10
View File
@@ -74,6 +74,9 @@ class SongMenuItem extends FlxSpriteGroup
var sparkleTimer:FlxTimer;
var index:Int;
public var curSelected:Int;
public function new(x:Float, y:Float)
{
super(x, y);
@@ -390,7 +393,7 @@ class SongMenuItem extends FlxSpriteGroup
return evilTrail.color;
}
public function refreshDisplay():Void
public function refreshDisplay(updateRank:Bool = true):Void
{
if (freeplayData == null)
{
@@ -408,7 +411,7 @@ class SongMenuItem extends FlxSpriteGroup
pixelIcon.visible = true;
updateBPM(Std.int(freeplayData.songStartingBpm) ?? 0);
updateDifficultyRating(freeplayData.difficultyRating ?? 0);
updateScoringRank(freeplayData.scoringRank);
if (updateRank) updateScoringRank(freeplayData.scoringRank);
newText.visible = freeplayData.isNew;
favIcon.visible = freeplayData.isFav;
favIconBlurred.visible = freeplayData.isFav;
@@ -489,7 +492,7 @@ class SongMenuItem extends FlxSpriteGroup
spr.visible = value;
}
if (value) textAppear();
textAppear();
updateSelected();
}
@@ -500,10 +503,12 @@ class SongMenuItem extends FlxSpriteGroup
this.y = y;
}
public function initData(freeplayData:Null<FreeplaySongData>, ?styleData:FreeplayStyle = null):Void
public function initData(freeplayData:Null<FreeplaySongData>, ?styleData:FreeplayStyle = null, index:Int = null):Void
{
this.freeplayData = freeplayData;
if (index != null) this.index = index;
// im so mad i have to do this but im pretty sure with the capsules recycling i cant call the new function properly :/
// if thats possible someone Please change the new function to be something like
// capsule.frames = Paths.getSparrowAtlas(styleData == null ? 'freeplay/freeplayCapsule/capsule/freeplayCapsule' : styleData.getCapsuleAssetKey()); thank u luv u
@@ -531,7 +536,7 @@ class SongMenuItem extends FlxSpriteGroup
var frameOutTypeBeat:Int = 0;
var xFrames:Array<Float> = [1.7, 1.8, 0.85, 0.85, 0.97, 0.97, 1];
var xPosLerpLol:Array<Float> = [0.9, 0.4, 0.16, 0.16, 0.22, 0.22, 0.245]; // NUMBERS ARE JANK CUZ THE SCALING OR WHATEVER
var xPosLerpLol:Array<Float> = [0, 0, 0.16, 0.16, 0.22, 0.22, 0.245]; // NUMBERS ARE JANK CUZ THE SCALING OR WHATEVER
var xPosOutLerpLol:Array<Float> = [0.245, 0.75, 0.98, 0.98, 1.2]; // NUMBERS ARE JANK CUZ THE SCALING OR WHATEVER
public var realScaled:Float = 0.8;
@@ -542,9 +547,6 @@ class SongMenuItem extends FlxSpriteGroup
new FlxTimer().start((1 / 24) * maxTimer, function(doShit) {
doJumpIn = true;
});
new FlxTimer().start((0.09 * maxTimer) + 0.85, function(lerpTmr) {
doLerp = true;
});
@@ -605,12 +607,19 @@ class SongMenuItem extends FlxSpriteGroup
capsule.scale.x = xFrames[frameInTypeBeat];
capsule.scale.y = 1 / xFrames[frameInTypeBeat];
x = FlxG.width * xPosLerpLol[Std.int(Math.min(frameInTypeBeat, xPosLerpLol.length - 1))];
targetPos.x = FlxG.width * xPosLerpLol[Std.int(Math.min(frameInTypeBeat, xPosLerpLol.length - 1))];
capsule.scale.x *= realScaled;
capsule.scale.y *= realScaled;
frameInTypeBeat += 1;
// Move the targetPos set to the if statement below if you want them to shift to their target positions after jumping in instead
// I have no idea why this if instead of frameInTypeBeat == xFrames.length works even though they're the same thing
if (targetPos.x <= 320) targetPos.x = intendedX(index - curSelected);
}
else if (frameInTypeBeat == xFrames.length)
{
doJumpIn = false;
}
}
@@ -624,13 +633,17 @@ class SongMenuItem extends FlxSpriteGroup
capsule.scale.x = xFrames[frameOutTypeBeat];
capsule.scale.y = 1 / xFrames[frameOutTypeBeat];
x = FlxG.width * xPosOutLerpLol[Std.int(Math.min(frameOutTypeBeat, xPosOutLerpLol.length - 1))];
this.x = FlxG.width * xPosOutLerpLol[Std.int(Math.min(frameOutTypeBeat, xPosOutLerpLol.length - 1))];
capsule.scale.x *= realScaled;
capsule.scale.y *= realScaled;
frameOutTypeBeat += 1;
}
else if (frameOutTypeBeat == xFrames.length)
{
doJumpOut = false;
}
}
if (doLerp)
@@ -654,6 +667,11 @@ class SongMenuItem extends FlxSpriteGroup
}
}
public function intendedX(index:Int):Float
{
return 270 + (60 * (Math.sin(index)));
}
public function intendedY(index:Int):Float
{
return (index * ((height * realScaled) + 10)) + 120;
@@ -99,6 +99,7 @@ class MainMenuState extends MusicBeatState
createMenuItem('freeplay', 'mainmenu/freeplay', function() {
persistentDraw = true;
persistentUpdate = false;
rememberedSelectedIndex = menuItems.selectedIndex;
// Freeplay has its own custom transition
FlxTransitionableState.skipNextTransIn = true;
FlxTransitionableState.skipNextTransOut = true;
@@ -413,6 +414,7 @@ class MainMenuState extends MusicBeatState
if (controls.BACK && menuItems.enabled && !menuItems.busy)
{
rememberedSelectedIndex = menuItems.selectedIndex;
FlxG.switchState(() -> new TitleState());
FunkinSound.playOnce(Paths.sound('cancelMenu'));
}
+138 -57
View File
@@ -52,24 +52,44 @@ class FileUtil
/**
* Paths which should not be deleted or modified by scripts.
*/
private static final PROTECTED_PATHS:Array<String> = [
'',
'assets',
'manifest',
'manifest/*',
'plugins',
'plugins/*',
'Funkin.exe',
'Funkin',
'libvlc.dll',
'libvlccore.dll',
'lime.ndll'
];
public static var PROTECTED_PATHS(get, never):Array<String>;
public static function get_PROTECTED_PATHS():Array<String>
{
final protected:Array<String> = [
'',
'.',
'assets',
'assets/*',
'backups',
'backups/*',
'manifest',
'manifest/*',
'plugins',
'plugins/*',
'Funkin.exe',
'Funkin',
'icon.ico',
'libvlc.dll',
'libvlccore.dll',
'lime.ndll',
'scores.json'
];
#if sys
for (i in 0...protected.length)
{
protected[i] = sys.FileSystem.fullPath(Path.join([gameDirectory, protected[i]]));
}
#end
return protected;
}
/**
* Invalid filesystem characters.
* Regex for invalid filesystem characters.
*/
private static final INVALID_CHARS:Array<String> = [':', '*', '?', '"', '<', '>', '|'];
public static final INVALID_CHARS:EReg = ~/[:*?"<>|\n\r\t]/g;
#if sys
private static var _gameDirectory:Null<String> = null;
@@ -82,7 +102,7 @@ class FileUtil
return _gameDirectory;
}
return _gameDirectory = Path.directory(Path.normalize(sys.FileSystem.fullPath(Sys.programPath())));
return _gameDirectory = sys.FileSystem.fullPath(Path.directory(Sys.programPath()));
}
#end
@@ -601,8 +621,6 @@ class FileUtil
throw 'Target path is a directory, not a file: "$path"';
}
createDirIfNotExists(Path.directory(path));
var shouldWrite:Bool = true;
switch (mode)
{
@@ -791,14 +809,14 @@ class FileUtil
*/
public static function createDirIfNotExists(dir:String):Void
{
#if sys
if (!directoryExists(dir))
{
#if sys
sys.FileSystem.createDirectory(dir);
#else
throw 'Directory creation is not supported on this platform.';
#end
}
#else
throw 'Directory creation is not supported on this platform.';
#end
}
/**
@@ -1121,8 +1139,64 @@ class FileUtil
};
}
public static function openFolder(pathFolder:String) // what is this for??
WindowUtil.openFolder(pathFolder);
/**
* Runs platform-specific code to open a path in the file explorer.
*
* @param pathFolder The path of the folder to open.
*/
public static function openFolder(pathFolder:String):Void
{
#if sys
pathFolder = pathFolder.trim();
if (!directoryExists(pathFolder))
{
throw 'Path is not a directory: "$pathFolder"';
}
#if windows
Sys.command('explorer', [pathFolder.replace('/', '\\')]);
#elseif mac
// mac could be fuckie with where the log folder is relative to the game file...
// if this comment is still here... it means it has NOT been verified on mac yet!
//
// FileUtil.hx note: this was originally used to open the logs specifically!
// thats why the above comment is there!
Sys.command('open', [pathFolder]);
#elseif linux
// TODO: implement linux
// some shit with xdg-open :thinking: emoji...
#end
#else
throw 'External folder open is not supported on this platform.';
#end
}
/**
* Runs platform-specific code to open a file explorer and select a specific file.
*
* @param path The path of the file to select.
*/
public static function openSelectFile(path:String):Void
{
#if sys
path = path.trim();
if (!pathExists(path))
{
throw 'Path does not exist: "$path"';
}
#if windows
Sys.command('explorer', ['/select,', path.replace('/', '\\')]);
#elseif mac
Sys.command('open', ['-R', path]);
#elseif linux
// TODO: unsure of the linux equivalent to opening a folder and then "selecting" a file.
Sys.command('open', [path]);
#end
#else
throw 'External file selection is not supported on this platform.';
#end
}
private static function convertTypeFilter(?typeFilter:Array<FileFilter>):Null<String>
{
@@ -1157,7 +1231,8 @@ class FileUtilSandboxed
*/
public static function sanitizePath(path:String):String
{
if (path == null)
path = (path ?? '').trim();
if (path == '')
{
#if sys
return FileUtil.gameDirectory;
@@ -1171,19 +1246,14 @@ class FileUtilSandboxed
path = path.substring(path.lastIndexOf(':') + 1);
}
path = path.trim().replace('\\', '/');
path = path.replace('\\', '/');
while (path.contains('//'))
{
path = path.replace('//', '/');
}
@:privateAccess for (char in FileUtil.INVALID_CHARS)
{
path = path.replace(char, '');
}
var parts:Array<String> = path.split('/');
var sanitized:Array<String> = new Array<String>();
final parts:Array<String> = FileUtil.INVALID_CHARS.replace(path, '').split('/');
final sanitized:Array<String> = new Array<String>();
for (part in parts)
{
switch (part)
@@ -1193,25 +1263,31 @@ class FileUtilSandboxed
case '..':
sanitized.pop();
default:
sanitized.push(part);
sanitized.push(part.trim());
}
}
var ret:String = sanitized.join('/');
if (sanitized.length == 0)
{
#if sys
return FileUtil.gameDirectory;
#else
return '';
#end
}
#if sys
var realPath:String = Path.normalize(sys.FileSystem.fullPath(Path.join([FileUtil.gameDirectory, ret])));
// ^ TODO: figure out how to get "real" path of symlinked paths
if (!realPath.startsWith(FileUtil.gameDirectory.toString()))
// TODO: figure out how to get "real" path of symlinked paths
final realPath:String = sys.FileSystem.fullPath(Path.join([FileUtil.gameDirectory, sanitized.join('/')]));
if (!realPath.startsWith(FileUtil.gameDirectory))
{
return FileUtil.gameDirectory;
}
ret = realPath;
return realPath;
#else
return sanitized.join('/');
#end
return ret;
}
/**
@@ -1219,9 +1295,9 @@ class FileUtilSandboxed
* @param path The path to check.
* @return Whether the path is protected.
*/
public static function isProtected(path:String):Bool
public static function isProtected(path:String, sanitizeFirst:Bool = true):Bool
{
path = sanitizePath(path);
if (sanitizeFirst) path = sanitizePath(path);
@:privateAccess for (protected in FileUtil.PROTECTED_PATHS)
{
if (path == protected || (protected.contains('*') && path.startsWith(protected.substring(0, protected.indexOf('*')))))
@@ -1298,7 +1374,7 @@ class FileUtilSandboxed
public static function saveFilesAsZIPToPath(resources:Array<Entry>, path:String, mode:FileWriteMode = Skip):Bool
{
if (isProtected(path = sanitizePath(path))) throw 'Cannot write to protected path: $path';
if (isProtected(path = sanitizePath(path), false)) throw 'Cannot write to protected path: $path';
return FileUtil.saveFilesAsZIPToPath(resources, path, mode);
}
@@ -1329,32 +1405,32 @@ class FileUtilSandboxed
public static function writeStringToPath(path:String, data:String, mode:FileWriteMode = Skip):Void
{
if (isProtected(path = sanitizePath(path))) throw 'Cannot write to protected path: $path';
if (isProtected(path = sanitizePath(path), false)) throw 'Cannot write to protected path: $path';
FileUtil.writeStringToPath(path, data, mode);
}
public static function writeBytesToPath(path:String, data:Bytes, mode:FileWriteMode = Skip):Void
{
if (isProtected(path = sanitizePath(path))) throw 'Cannot write to protected path: $path';
if (isProtected(path = sanitizePath(path), false)) throw 'Cannot write to protected path: $path';
FileUtil.writeBytesToPath(path, data, mode);
}
public static function appendStringToPath(path:String, data:String):Void
{
if (isProtected(path = sanitizePath(path))) throw 'Cannot write to protected path: $path';
if (isProtected(path = sanitizePath(path), false)) throw 'Cannot write to protected path: $path';
FileUtil.appendStringToPath(path, data);
}
public static function moveFile(path:String, destination:String):Void
{
if (isProtected(path = sanitizePath(path))) throw 'Cannot move protected path: $path';
if (isProtected(destination = sanitizePath(destination))) throw 'Cannot move to protected path: $destination';
if (isProtected(path = sanitizePath(path), false)) throw 'Cannot move protected path: $path';
if (isProtected(destination = sanitizePath(destination), false)) throw 'Cannot move to protected path: $destination';
FileUtil.moveFile(path, destination);
}
public static function deleteFile(path:String):Void
{
if (isProtected(path = sanitizePath(path))) throw 'Cannot delete protected path: $path';
if (isProtected(path = sanitizePath(path), false)) throw 'Cannot delete protected path: $path';
FileUtil.deleteFile(path);
}
@@ -1390,14 +1466,14 @@ class FileUtilSandboxed
public static function moveDir(path:String, destination:String, ?ignore:Array<String>, strict:Bool = true):Void
{
if (isProtected(path = sanitizePath(path))) throw 'Cannot move protected path: "$path"';
if (isProtected(destination = sanitizePath(destination))) throw 'Cannot move to protected path: "$destination"';
if (isProtected(path = sanitizePath(path), false)) throw 'Cannot move protected path: "$path"';
if (isProtected(destination = sanitizePath(destination), false)) throw 'Cannot move to protected path: "$destination"';
FileUtil.moveDir(path, destination, ignore, strict);
}
public static function deleteDir(path:String, recursive:Bool = false, ?ignore:Array<String>):Void
{
if (isProtected(path = sanitizePath(path))) throw 'Cannot delete protected path: "$path"';
if (isProtected(path = sanitizePath(path), false)) throw 'Cannot delete protected path: "$path"';
FileUtil.deleteDir(path, recursive, ignore);
}
@@ -1413,7 +1489,7 @@ class FileUtilSandboxed
public static function rename(path:String, newName:String, keepExtension:Bool = true):Void
{
if (isProtected(path = sanitizePath(path))) throw 'Cannot rename protected path: "$path"';
if (isProtected(path = sanitizePath(path), false)) throw 'Cannot rename protected path: "$path"';
FileUtil.rename(path, sanitizePath(newName), keepExtension);
}
@@ -1442,9 +1518,14 @@ class FileUtilSandboxed
return FileUtil.makeZIPEntryFromBytes(name, data);
}
public static function openFolder(pathFolder:String)
public static function openFolder(pathFolder:String):Void
{
FileUtil.openFolder(pathFolder);
FileUtil.openFolder(sanitizePath(pathFolder));
}
public static function openSelectFile(path:String):Void
{
FileUtil.openSelectFile(sanitizePath(path));
}
}
+4 -4
View File
@@ -17,10 +17,10 @@ class MemoryUtil
{
#if cpp
var result:String = 'HXCPP-Immix:';
result += '\n- Memory Used: ${cpp.vm.Gc.memInfo(cpp.vm.Gc.MEM_INFO_USAGE)} bytes';
result += '\n- Memory Reserved: ${cpp.vm.Gc.memInfo(cpp.vm.Gc.MEM_INFO_RESERVED)} bytes';
result += '\n- Memory Current Pool: ${cpp.vm.Gc.memInfo(cpp.vm.Gc.MEM_INFO_CURRENT)} bytes';
result += '\n- Memory Large Pool: ${cpp.vm.Gc.memInfo(cpp.vm.Gc.MEM_INFO_LARGE)} bytes';
result += '\n- Memory Used: ${cpp.vm.Gc.memInfo64(cpp.vm.Gc.MEM_INFO_USAGE)} bytes';
result += '\n- Memory Reserved: ${cpp.vm.Gc.memInfo64(cpp.vm.Gc.MEM_INFO_RESERVED)} bytes';
result += '\n- Memory Current Pool: ${cpp.vm.Gc.memInfo64(cpp.vm.Gc.MEM_INFO_CURRENT)} bytes';
result += '\n- Memory Large Pool: ${cpp.vm.Gc.memInfo64(cpp.vm.Gc.MEM_INFO_LARGE)} bytes';
result += '\n- HXCPP Debugger: ${#if HXCPP_DEBUGGER 'Enabled' #else 'Disabled' #end}';
result += '\n- HXCPP Exp Generational Mode: ${#if HXCPP_GC_GENERATIONAL 'Enabled' #else 'Disabled' #end}';
result += '\n- HXCPP Exp Moving GC: ${#if HXCPP_GC_MOVING 'Enabled' #else 'Disabled' #end}';
+39 -48
View File
@@ -16,6 +16,39 @@ using StringTools;
#end
class WindowUtil
{
/**
* A regex to match valid URLs.
*/
public static final URL_REGEX:EReg = ~/^https?:\/?\/?(?:www\.)?[-a-zA-Z0-9@:%_\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b(?:[-a-zA-Z0-9()@:%_\+.~#?&\/=]*)$/;
/**
* Sanitizes a URL via a regex.
*
* @param targetUrl The URL to sanitize.
* @return The sanitized URL, or an empty string if the URL is invalid.
*/
public static function sanitizeURL(targetUrl:String):String
{
targetUrl = (targetUrl ?? '').trim();
if (targetUrl == '')
{
return '';
}
final lowerUrl:String = targetUrl.toLowerCase();
if (!lowerUrl.startsWith('http:') && !lowerUrl.startsWith('https:'))
{
targetUrl = 'http://' + targetUrl;
}
if (URL_REGEX.match(targetUrl))
{
return URL_REGEX.matched(0);
}
return '';
}
/**
* Runs platform-specific code to open a URL in a web browser.
* @param targetUrl The URL to open.
@@ -28,6 +61,12 @@ class WindowUtil
else if (protocol[0] != 'http' && protocol[0] != 'https') throw "openURL can only open http and https links.";
#if FEATURE_OPEN_URL
targetUrl = sanitizeURL(targetUrl);
if (targetUrl == '')
{
throw 'Invalid URL: "$targetUrl"';
}
#if linux
Sys.command('/usr/bin/xdg-open $targetUrl &');
#else
@@ -63,54 +102,6 @@ class WindowUtil
}
#end
/**
* Runs platform-specific code to open a path in the file explorer.
* @param targetPath The path to open.
*/
public static function openFolder(targetPath:String):Void
{
#if html5
throw 'Cannot open URLs on this platform.';
#else
if (!sys.FileSystem.exists(targetPath) || !sys.FileSystem.isDirectory(targetPath)) throw 'openFolder should only be used to open existing folders.';
#if FEATURE_OPEN_URL
#if windows
Sys.command('explorer', [targetPath.replace('/', '\\')]);
#elseif mac
Sys.command('open', [targetPath]);
#elseif linux
Sys.command('open', [targetPath]);
#end
#else
throw 'Cannot open URLs on this platform.';
#end
#end
}
/**
* Runs platform-specific code to open a file explorer and select a specific file.
* @param targetPath The path of the file to select.
*/
public static function openSelectFile(targetPath:String):Void
{
#if html5
throw 'Cannot open URLs on this platform.';
#else
#if FEATURE_OPEN_URL
#if windows
Sys.command('explorer', ['/select,' + targetPath.replace('/', '\\')]);
#elseif mac
Sys.command('open', ['-R', targetPath]);
#elseif linux
// TODO: unsure of the linux equivalent to opening a folder and then "selecting" a file.
Sys.command('open', [targetPath]);
#end
#else
throw 'Cannot open URLs on this platform.';
#end
#end
}
/**
* Dispatched when the game window is closed.
*/
@@ -31,4 +31,11 @@ class VolumePlugin extends FlxBasic
else if (PlayerSettings.player1.controls.VOLUME_DOWN) FlxG.sound.changeVolume(-0.1);
}
}
override public function destroy():Void
{
if (FlxG.plugins.list.contains(this)) FlxG.plugins.remove(this);
super.destroy();
}
}