Compare commits

...
92 Commits
Author SHA1 Message Date
Cameron Taylor 9908f973cf someone pls tell me how to use two different git submodules
Create and publish Docker image / build-and-push-image (push) Canceled after 0s
Build and Upload nightly game builds / build-game-on-host (macos) (push) Canceled after 0s
Build and Upload nightly game builds / build-game-on-host (windows) (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
2024-06-12 15:27:56 -04:00
Cameron Taylor ead37894cd Merge branch 'rewrite/master' 2024-06-12 15:26:40 -04:00
Cameron Taylor cce2ab7fff update project.xml for 0.4.1 lol 2024-06-12 15:05:32 -04:00
EricandCameron Taylor 48653ababd Update CHANGELOG.md 2024-06-12 15:01:27 -04:00
EricandCameron Taylor 7ce0544b18 Update CHANGELOG.md 2024-06-12 14:54:41 -04:00
Cameron Taylor f8ecddc5b3 added eric code to changelog 2024-06-12 14:54:41 -04:00
Cameron Taylor 1ebcae79fe changelog for 0.4.1 2024-06-12 14:54:41 -04:00
EliteMasterEric 47f885ae97 Charter credits for Eggnog Erect 2024-06-12 13:33:19 -04:00
Cameron TaylorandGitHub 47d5c4d141 Merge pull request #619 from FunkinCrew/freeplay-dad-smoother
freeplay bg nicer AA and proper sizing
2024-06-11 16:16:13 -04:00
Cameron TaylorandGitHub c325fdaa1b Merge pull request #618 from FunkinCrew/speaker-volume-desktop
[funk-378] reactive speaker to gamevolume on desktop
2024-06-11 16:16:02 -04:00
Cameron TaylorandGitHub b64af80eba Merge pull request #608 from FunkinCrew/bugfix/instrumental-id
Play song IDs based on the chart file's "instrumental" field, not the variation ID.
2024-06-11 16:15:24 -04:00
Cameron Taylor c05f053fe3 Merge branch 'rewrite/master' into bugfix/instrumental-id 2024-06-11 16:12:39 -04:00
Cameron Taylor 1e3ef61fc9 freeplay bg nicer AA and proper sizing 2024-06-11 15:57:45 -04:00
Cameron Taylor 37a15e0a0f reactive speaker to gamevolume on desktop 2024-06-11 12:13:10 -04:00
Cameron TaylorandGitHub 817c216d06 Merge pull request #617 from FunkinCrew/bugfix/save-highest-rank
[FUNK-387] Save high scores and high ranks separately.
2024-06-11 12:04:38 -04:00
Cameron TaylorandGitHub 381e0104e9 Merge pull request #616 from FunkinCrew/feature/freeplay-keybinds
[FUNK-391] Rebindable controls for the Freeplay menu
2024-06-11 11:49:24 -04:00
Cameron Taylor 5686bfcd6b ### Changed
- Tweaked the chart for Lit Up some more to fix some offset notes.Merge branch 'bugfix/spaz-charts' into rewrite/master
2024-06-11 11:27:57 -04:00
Cameron Taylor 93c0bd0b63 assets submod 2024-06-11 11:25:43 -04:00
EliteMasterEric b30faad7d9 Save high scores and high ranks separately. 2024-06-11 00:40:43 -04:00
EliteMasterEric c0a7e4f728 Readd camera events to Roses 2024-06-10 19:32:53 -04:00
Cameron Taylor 00021523bc lower volume on freeplay easter egg 2024-06-10 17:35:49 -04:00
Ikko Eltociear AshimineandCameron Taylor e8f8a0c181 chore: update MenuList.hx
lenth -> length
2024-06-10 16:45:22 -04:00
Cameron Taylor 13d49017ac removed compiling help and question templates 2024-06-10 16:45:22 -04:00
Cameron Taylor f91f4b2ddb simplified the bug template to have less clutter 2024-06-10 16:45:22 -04:00
DM-kunandCameron Taylor da61b72c48 crash fix 2024-06-10 16:21:41 -04:00
Cameron Taylor f31ea8fb73 add sound for changing sorting 2024-06-10 16:13:32 -04:00
gamerbrossandCameron Taylor 8f44d9606d Remove unnecessary scrollMenu sounds + adjust volume 2024-06-10 13:17:38 -04:00
Cameron Taylor 4691e3d249 Merge branch 'bugfix/chart-editor-event-toolbox-crash' into rewrite/master 2024-06-10 12:26:47 -04:00
Cameron Taylor cd2bbcb43b Merge branch 'ninjamuffin99/funk-292' into rewrite/master 2024-06-10 12:05:08 -04:00
Cameron Taylor b7d25bf04f Merge branch 'escape-quit' into rewrite/master 2024-06-10 12:04:30 -04:00
Cameron Taylor 5dcd3eb946 Merge branch 'heart-capsule-pos' into rewrite/master 2024-06-10 12:04:09 -04:00
Cameron Taylor b811aeec80 fix for pico explo 2024-06-09 16:15:33 -04:00
Cameron Taylor 55edb9ea14 pressing escape on title screen exits game 2024-06-09 15:38:22 -04:00
Cameron Taylor d974f12c72 Merge branch 'develop' into rewrite/master 2024-06-09 15:30:14 -04:00
Cameron Taylor f2d5a80bd1 completes funk-305 2024-06-09 15:06:45 -04:00
Cameron TaylorandGitHub 9a26837374 Merge pull request #2730 from eltociear/patch-2
chore: update MenuList.hx
2024-06-09 14:19:37 -04:00
Ikko Eltociear AshimineandGitHub bdaadfbfdd chore: update MenuList.hx
lenth -> length
2024-06-10 02:26:55 +09:00
Cameron Taylor 9f960f5c28 removed compiling help and question templates 2024-06-09 12:43:43 -04:00
Cameron Taylor 9455b6eadc simplified the bug template to have less clutter 2024-06-09 12:41:00 -04:00
Cameron TaylorandGitHub eb979a8625 Merge pull request #2701 from zacksgamerz/develop
Fixed that one mistake in .github/ISSUE_TEMPLATE/bug.md
2024-06-09 12:21:45 -04:00
EliteMasterEric 839d6a0841 A couple chart fixes 2024-06-09 02:27:36 -04:00
EliteMasterEric 09aa8fbf52 Rebindable controls for the Freeplay menu 2024-06-09 02:22:03 -04:00
zacksgamerzandGitHub bc80e39a85 you're to your 2024-06-08 19:07:22 +07:00
Cameron Taylor 45b43108d1 lower fft amount on desktop 2024-06-07 22:36:25 -04:00
EricandGitHub 9a78060329 Merge pull request #2451 from nebulazorua/abstract-optionname
abstract enum pagename
2024-06-07 22:02:18 -04:00
EricandGitHub 4169116129 Merge branch 'develop' into abstract-optionname 2024-06-07 21:44:28 -04:00
EricandGitHub 5bd9ff8c21 Merge pull request #2551 from gamerbross/bugfix/fast-enter-options
[BUGFIX] Options Menu not enabled in transIn
2024-06-07 21:36:21 -04:00
EricandGitHub f38f5a268b Merge branch 'develop' into bugfix/fast-enter-options 2024-06-07 21:35:56 -04:00
gamerbrossandEliteMasterEric 1172949a04 Fix Options Menu not enabled in transIn 2024-06-07 21:31:53 -04:00
EliteMasterEric d19e9e62fa Merge branch 'richtrash21/freeplay-camera-optimization' into develop 2024-06-07 21:21:11 -04:00
EliteMasterEric 2e4b94d528 Fix additional merge conflicts 2024-06-07 21:20:04 -04:00
EliteMasterEric 4382b3e16e Merge branch 'develop' into richtrash21/freeplay-camera-optimization 2024-06-07 21:13:13 -04:00
EricandGitHub 195663638e Merge pull request #2683 from Hundrec/patch-1
Fix botplay sustain release bug
2024-06-07 21:08:19 -04:00
EricandGitHub 9a8ba4183e Merge branch 'develop' into patch-1 2024-06-07 21:08:09 -04:00
EricandGitHub aace5e2326 Merge pull request #2684 from gamerbross/bugfix/camfollow-pause-game
[BUGFIX] Pause Camera Follow when pausing
2024-06-07 20:56:01 -04:00
gamerbross cd485213db Pause Camera Follow when pausing 2024-06-08 02:26:17 +02:00
gamerbross ee6c4478a9 Use FlxG.camera instead of camGame 2024-06-08 02:02:54 +02:00
HundrecandGitHub 393355b512 Fix botplay sustain release bug
Copied opponent's holdTimer code to the player's side
2024-06-07 19:59:02 -04:00
EliteMasterEric d39f3dc1e8 Merge branch 'main' into develop 2024-06-07 19:54:30 -04:00
Cameron Taylor 7b90a3cee3 lil changelog in progres 2024-06-07 14:36:14 -04:00
Cameron TaylorandGitHub 1d6315fe0e Merge pull request #610 from FunkinCrew/2hot-freeplay
regexp for numbers
2024-06-07 14:33:56 -04:00
Cameron Taylor 34c91dae76 dadbattle hard/erect fix 2024-06-07 14:24:57 -04:00
Cameron Taylor a0adbc72b3 regexp for numbers 2024-06-07 13:04:45 -04:00
Cameron TaylorandGitHub 7dfd682148 Merge pull request #2661 from Hundrec/patch-1
README grammar fix
2024-06-07 11:40:16 -04:00
Cameron TaylorandGitHub 0242a6b64f Merge pull request #2662 from An-enderman/patch-2
Update COMPILING, adding one step
2024-06-07 11:40:09 -04:00
Cameron TaylorandGitHub 62091523d2 Merge branch 'main' into patch-2 2024-06-07 11:40:02 -04:00
Cameron Taylor 6fd030cb30 Merge branch 'patch-1' into rewrite/master 2024-06-07 11:38:57 -04:00
Cameron Taylor 1e63998c74 Merge branch 'patch-2' into rewrite/master 2024-06-07 11:37:37 -04:00
An-endermanandGitHub d4a524bbcb Update COMPILING, adding one step
I added the step that says to download Git, because the command "hmm install" requires Git to work.
2024-06-07 16:40:37 +02:00
HundrecandGitHub 03cf3dcf99 README grammar fix 2024-06-07 03:29:58 -04:00
EliteMasterEric ca345e6c4f Play song IDs based on the chart file's "instrumental" field, not the variation ID. 2024-06-06 21:38:00 -04:00
EliteMasterEric 266049df65 Update assets submodule 2024-06-06 20:10:28 -04:00
EliteMasterEric fe5f1eb6ea Fix merge conflict 2024-06-06 17:11:30 -04:00
EliteMasterEric 70f027cc3f Fix another crash with the chart editor event toolbox 2024-06-06 16:44:47 -04:00
EliteMasterEric a81b6b2d6e Fix issue with rendering the grid in 3/4 time signature 2024-06-06 16:44:20 -04:00
EliteMasterEric 6fb19dc4d3 Update chart editor dropdowns to be searchable 2024-06-05 20:09:26 -04:00
EliteMasterEric 6d133f007d Fix a bug where the event data toolbox wouldn't rebuild, and it would crash. 2024-06-05 19:25:53 -04:00
EricandGitHub 3b74a14a0d Merge pull request #2610 from PurSnake/fixing
[BUGFIX] Correct characters scaling on stage
2024-05-30 23:54:38 -04:00
EricandGitHub 2380058820 Merge pull request #2328 from nebulazorua/new-judge-applying
New judge application logic
2024-05-30 16:10:17 -04:00
EricandGitHub 6cc9c3d968 Merge pull request #2409 from Burgerballs/scroll-speed-fix
[FEATURE] Scroll Speed Event
2024-05-29 23:22:03 -04:00
EricandGitHub 0388f887b5 Merge pull request #2565 from gamerbross/bugfix/charting-sustain-trails
[BUGFIX] Charting Editor Sustain Trails (2 bugs)
2024-05-29 22:54:49 -04:00
EricandGitHub b487adb169 Merge pull request #2629 from NotHyper-474/bugfix/cwd-preloader-issue
[BUGFIX?] Reset CWD before Preloader
2024-05-29 22:52:17 -04:00
richTrash21 4ca30a571d safety 2024-05-23 21:52:28 +04:00
richTrash21 1c352e4e11 simplify freeplay camera 2024-05-23 21:50:11 +04:00
gamerbross a73d65757c Fix Options Menu not enabled in transIn 2024-05-19 00:23:51 +02:00
nebulazorua e462b04b59 does notesplash 2024-05-15 20:46:08 +08:00
richandGitHub 7a19bd4b50 Merge branch 'FunkinCrew:main' into debelop-freeplay-patch 2024-05-15 16:31:57 +04:00
richandGitHub 59e409f8e6 ensure that only freeplay camera gets destroyed 2024-05-14 04:30:36 +04:00
richandGitHub 3810662f9f freeplay optimization 2024-05-14 04:20:23 +04:00
nebulazorua fa4fa8116c abstract enum pagename
should make adding modded optionspages better and easier
makes it so you dont have to leech off an unused PageName or write your own code for making modded options, helping with compatibility between mods.
2024-05-11 16:51:27 +08:00
nebulazorua 4b500f78e1 Revert change because i forgot to do it in a new branch oriignally lol 2024-05-08 20:30:47 +08:00
nebulazorua 2eaea3cdc5 Apply judgements through a seperate function to applyScore
Also adds more to the HitNoteScriptEvent, such as the noteDiff and also isComboBreak.
noteDiff is important as it lets you create stuff like notes with reduced hitboxes (i.e mines/"hurt notes") or millisecond hit displays. isComboBreak lets you set whether the judge combo broke, so you could in theory create custom judgements in scripts now with these changes (killer reimplementation in scripts? more likely than you'd think!)
2024-05-08 20:26:17 +08:00
39 changed files with 832 additions and 425 deletions
+31 -25
View File
@@ -5,40 +5,46 @@ title: 'Bug Report: [DESCRIBE YOUR BUG IN DETAIL HERE]'
labels: bug
---
[weed]: <> (FILL THIS ISSUE THING OUT AS MUCH AS POSSIBLE)
[weed]: <> (OR ELSE YOUR ISSUE WILL BE LESS LIKELY TO BE SOLVED!)
[weed]: <> (DO NOT POST ABOUT ISSUES FROM OTHER FNF MOD ENGINES! I CANNOT AND PROBABLY WON'T SOLVE THOSE!)
[weed]: <> (GO TO THEIR RESPECTIVE GITHUB ISSUES AND REPORT THEM THERE LOL!)
<!-- FILL THIS ISSUE THING OUT AS MUCH AS POSSIBLE
OR ELSE YOUR ISSUE WILL BE LESS LIKELY TO BE SOLVED!
[weed]: <> (ALSO MAKE SURE THAT YOU USE PROPER LABELS, IF YOU'RE RUNNING INTO COMPILER ISSUES, USE THE compiler issue LABEL!!!)
Do not post about issues from other FNF mod engines!
We cannot and probably won't solve those!
You can hopefully go to their respective GitHub issues and report them there, thank you :)
#### Please check for duplicates or similar issues, as well performing simple troubleshooting steps (such as clearing cookies, clearing AppData, trying another browser) before submitting an issue.
### If you are playing the game in a browser, what site are you playing it from?
Please check for duplicates or similar issues, as well performing simple troubleshooting steps (such as clearing cookies, clearing AppData, trying another browser) before submitting an issue.
[weed]: <> (Put an X in the [ ] thingies to fill out checkbox!)
[weed]: <> (something like [x] pretty much, don't screw up or you will look stupid)
From Joel On Software:
- [ ] [Newgrounds](https://www.newgrounds.com/portal/view/770371)
- [ ] [Itch.io](https://ninja-muffin24.itch.io/funkin)? Specify below
- - [ ] Windows
- - [ ] Mac
- - [ ] Linux
"It’s pretty easy to remember the rule for a good bug report. Every good bug report needs exactly three things.
### If you are playing the game in a browser, what browser are you using?
1. Steps to reproduce,
2. What you expected to see, and
3. What you saw instead."
[weed]: <> (Again, put an x in the [ ] box!)
-->
- [ ] Google Chrome (or chomium based like Brave, vivaldi, MS Edge)
- [ ] Firefox
- [ ] Safari
## Describe the bug
<!-- A clear and concise description of what the bug is. -->
## What version of the game are you using? Look in the bottom left corner of the main menu. (ex: 0.2.7, 0.2.1, shit like that)
## To Reproduce
<!-- Describe in DETAIL how to reproduce the bug/issue you are running into. -->
## Expected behavior
<!-- A clear and concise description of what you expected to happen. -->
## Screenshots/Video
<!-- If applicable, add screenshots/video to help explain your problem.
Remember to mark the area in the application thats impacted. -->
## Have you identified any steps to reproduce the bug? If so, please describe them below in as much detail as possible. Use images if possible.
## Desktop
- OS:
<!-- [e.g. Windows 10, 11, Mac, Linux Mint, Ubuntu, Arch (btw)] -->
- Browser
<!-- [e.g. chrome, safari, firefox, edge, operaGX] -->
- Version:
<!-- [e.g. 0.4.0, 0.3.3, this can be found in the bottom left corner of the main menu!] -->
## Please describe your issue. Provide extensive detail and images if possible.
## Additional context
<!-- Add any other context about the problem here. -->
## If you're game is FROZEN and you're playing a web version, press F12 to open up browser dev window, and go to console, and copy-paste whatever red error you're getting
<!-- If you're game is FROZEN and you're playing a web version, press F12 to open up browser dev window, and go to console, and copy-paste whatever red error you're getting -->
-25
View File
@@ -1,25 +0,0 @@
---
name: Compiling help
about: If you need help compiling the game, and you're running into issues. (Look through the 'compiling help' label in case it's been solved!)
title: 'Compiling help: [BRIEF DESCRIPTION / ERROR MESSAGE OUTPUT]'
labels: compiling help
---
[weed]: <> (FILL THIS ISSUE THING OUT AS MUCH AS POSSIBLE)
[weed]: <> (OR ELSE YOUR ISSUE WILL BE LESS LIKELY TO BE SOLVED!)
[weed]: <> (DO NOT POST ABOUT ISSUES FROM OTHER FNF MOD ENGINES! I CANNOT AND PROBABLY WON'T SOLVE THOSE!)
[weed]: <> (GO TO THEIR RESPECTIVE GITHUB ISSUES AND REPORT THEM THERE LOL!)
#### Please check for duplicates or similar compiler issues by filtering for 'compiler help'
[weed]: <> (Put an X in the [ ] thingies to fill out checkbox!)
[weed]: <> (something like [x] pretty much, don't screw up or you will look stupid)
- [ ] Windows
- [ ] Mac
- [ ] Linux
- [ ] HTML5
## Please describe your issue. Provide extensive detail and images if possible.
-12
View File
@@ -1,12 +0,0 @@
---
name: Question
about: Ask a general question
title: 'Question: '
labels: question
---
[weed]: <> (This isn't a place for AMA type questions, if you want to ask any of the devs something, reach out to them on twitter prob )
[weed]: <> (any biz bullshit can go to cameron.taylor.ninja@gmail.com)
#### Please check for duplicates or similar issues before asking your question.
## What is your question?
+42 -1
View File
@@ -4,6 +4,35 @@ All notable changes will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [0.4.1] - 2024-06-12
### Added
- Pressing ESCAPE on the title screen on desktop now exits the game, allowing you to exit the game while in fullscreen on desktop
- Freeplay menu controls (favoriting and switching categories) are now rebindable from the Options menu, and now have default binds on controllers.
### Changed
- Highscores and ranks are now saved separately, which fixes the issue where people would overwrite their saves with higher scores,
which would remove their rank if they had a lower one.
- A-Bot speaker now reacts to the user's volume preference on desktop (thanks to [M7theguy for the issue report/suggestion](https://github.com/FunkinCrew/Funkin/issues/2744)!)
- On Freeplay, heart icons are shifted to the right when you favorite a song that has no rank on it.
- Only play `scrollMenu` sound effect when there's a real change on the freeplay menu ([thanks gamerbross for the PR!](https://github.com/FunkinCrew/Funkin/pull/2741))
- Gave antialiasing to the edge of the dad graphic on Freeplay
- Rearranged some controls in the controls menu
- Made several chart revisions
- Re-enabled custom camera events in Roses (Erect/Nightmare)
- Tweaked the chart for Lit Up (Hard)
- Corrected the difficulty ratings for M.I.L.F. (Easy/Normal/Hard)
### Fixed
- Fixed an issue in the controls menu where some control binds would overlap their names
- Fixed crash when attempting to exit the gameover screen when also attempting to retry the song ([thanks DMMaster636 for the PR!](https://github.com/FunkinCrew/Funkin/pull/2709))
- Fix botplay sustain release bug ([thanks Hundrec!](Fix botplay sustain release bug #2683))
- Fix for the camera not pausing during a gameplay pause ([thanks gamerbross!](https://github.com/FunkinCrew/Funkin/pull/2684))
- Fixed issue where Pico's gameplay sprite would unintentionally appear on the gameover screen when dying on 2Hot from an explosion
- Freeplay previews properly fade volume during the BF idle animation
- Fixed bug where Dadbattle incorrectly appeared as Dadbattle Erect when returning to freeplay on Hard
- Fixed 2Hot not appearing under the "#" category in Freeplay menu
- Fixed a bug where the Chart Editor would crash when attempting to select an event with the Event toolbox open
- Improved offsets for Pico and Tankman opponents so they don't slide around as much.
- Fixed the black "temp" graphic on freeplay from being incorrectly sized / masked, now it's identical to the dad freeplay graphic
## [0.4.0] - 2024-06-06
### Added
- 2 new Erect remixes, Eggnog and Satin Panties. Check them out from the Freeplay menu!
@@ -32,11 +61,23 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Custom note styles are now properly supported for songs; add new notestyles via JSON, then select it for use from the Chart Editor Metadata toolbox. (thanks Keoiki!)
- Health icons now support a Winning frame without requiring a spritesheet, simply include a third frame in the icon file. (thanks gamerbross!)
- Remember that for more complex behaviors such as animations or transitions, you should use an XML file to define each frame.
- Improved the Event Toolbox in the Chart Editor; dropdowns are now bigger, include search field, and display elements in alphabetical order rather than a random order.
### Fixed
- Fixed an issue where Nene's visualizer would not play on Desktop builds
- Fixed a bug where the game would silently fail to load saves on HTML5
- Fixed some bugs with the props on the Story Menu not bopping properly
- Improved offsets for Pico and Tankman opponents so they don't slide around as much.
- Additional fixes to the Loading bar on HTML5 (thanks lemz1!)
- Fixed several bugs with the TitleState, including missing music when returning from the Main Menu (thanks gamerbross!)
- Fixed a camera bug in the Main Menu (thanks richTrash21!)
- Fixed a bug where changing difficulties in Story mode wouldn't update the score (thanks sectorA!)
- Fixed a crash in Freeplay caused by a level referencing an invalid song (thanks gamerbross!)
- Fixed a bug where pressing the volume keys would stop the Toy commercial (thanks gamerbross!)
- Fixed a bug where the Chart Editor Playtest would crash when losing (thanks gamerbross!)
- Fixed a bug where hold notes would display improperly in the Chart Editor when downscroll was enabled for gameplay (thanks gamerbross!)
- Fixed a bug where hold notes would be positioned wrong on downscroll (thanks MaybeMaru!)
- Removed a large number of unused imports to optimize builds (thanks Ethan-makes-music!)
- Improved debug logging for unscripted stages (thanks gamerbross!)
- Made improvements to compiling documentation (thanks gedehari!)
- Fixed a crash on Linux caused by an old version of hxCodec (thanks Noobz4Life!)
- Optimized animation handling for characters (thanks richTrash21!)
- Made improvements to compiling documentation (thanks gedehari!)
+1 -1
View File
@@ -2,7 +2,7 @@
<project xmlns="http://lime.openfl.org/project/1.0.4" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://lime.openfl.org/project/1.0.4 http://lime.openfl.org/xsd/project-1.0.4.xsd">
<!-- _________________________ Application Settings _________________________ -->
<app title="Friday Night Funkin'" file="Funkin" packageName="com.funkin.fnf" package="com.funkin.fnf" main="Main" version="0.4.0" company="ninjamuffin99" />
<app title="Friday Night Funkin'" file="Funkin" packageName="com.funkin.fnf" package="com.funkin.fnf" main="Main" version="0.4.1" company="ninjamuffin99" />
<!--Switch Export with Unique ApplicationID and Icon-->
<set name="APP_ID" value="0x0100f6c013bbc000" />
+1 -1
View File
@@ -2,7 +2,7 @@
Friday Night Funkin' is a rhythm game. Built using HaxeFlixel for Ludum Dare 47.
This game was made with love to Newgrounds and it's community. Extra love to Tom Fulp.
This game was made with love to Newgrounds and its community. Extra love to Tom Fulp.
- [Playable web demo on Newgrounds!](https://www.newgrounds.com/portal/view/770371)
- [Demo download builds for Windows, Mac, and Linux from Itch.io!](https://ninja-muffin24.itch.io/funkin)
+1 -1
Submodule art updated: 66572f85d8...faeba700c5
+1 -1
Submodule assets updated: 3b8235e953...2e1594ee4c
+7 -5
View File
@@ -6,9 +6,10 @@
- `git clone --recurse-submodules https://github.com/FunkinCrew/funkin.git`
- If you accidentally cloned without the `assets` submodule (aka didn't follow the step above), you can run `git submodule update --init --recursive` to get the assets in a foolproof way.
2. Install `hmm` (run `haxelib --global install hmm` and then `haxelib --global run hmm setup`)
3. Install all haxelibs of the current branch by running `hmm install`
4. Setup lime: `haxelib run lime setup`
5. Platform setup
3. Download Git from [git-scm.com](https://www.git-scm.com)
4. Install all haxelibs of the current branch by running `hmm install`
5. Setup lime: `haxelib run lime setup`
6. 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
@@ -16,9 +17,10 @@
- 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/)
- HTML5: Compiles without any extra setup
6. If you are targeting for native, you may need to run `lime rebuild PLATFORM` and `lime rebuild PLATFORM -debug`
7. `lime test PLATFORM` ! Add `-debug` to enable several debug features such as time travel (`PgUp`/`PgDn` in Play State).
7. If you are targeting for native, you may need to run `lime rebuild PLATFORM` and `lime rebuild PLATFORM -debug`
8. `lime test PLATFORM` ! Add `-debug` to enable several debug features such as time travel (`PgUp`/`PgDn` in Play State).
# Troubleshooting
- During the cloning process, you may experience an error along the lines of `error: RPC failed; curl 92 HTTP/2 stream 0 was not closed cleanly: PROTOCOL_ERROR (err 1)` due to poor connectivity. A common fix is to run ` git config --global http.postBuffer 4096M`.
+3 -3
View File
@@ -227,12 +227,12 @@ class FunkinSound extends FlxSound implements ICloneable<FunkinSound>
// already paused before we lost focus.
if (_lostFocus && !_alreadyPaused)
{
trace('Resuming audio (${this._label}) on focus!');
// trace('Resuming audio (${this._label}) on focus!');
resume();
}
else
{
trace('Not resuming audio (${this._label}) on focus!');
// trace('Not resuming audio (${this._label}) on focus!');
}
_lostFocus = false;
}
@@ -242,7 +242,7 @@ class FunkinSound extends FlxSound implements ICloneable<FunkinSound>
*/
override function onFocusLost():Void
{
trace('Focus lost, pausing audio!');
// trace('Focus lost, pausing audio!');
_lostFocus = true;
_alreadyPaused = _paused;
pause();
+6 -2
View File
@@ -54,12 +54,12 @@ class ABotVis extends FlxTypedSpriteGroup<FlxSprite>
public function initAnalyzer()
{
@:privateAccess
analyzer = new SpectralAnalyzer(snd._channel.__source, 7, 0.1, 30);
analyzer = new SpectralAnalyzer(snd._channel.__source, 7, 0.1, 40);
#if desktop
// On desktop it uses FFT stuff that isn't as optimized as the direct browser stuff we use on HTML5
// So we want to manually change it!
analyzer.fftN = 512;
analyzer.fftN = 256;
#end
// analyzer.maxDb = -35;
@@ -101,6 +101,10 @@ class ABotVis extends FlxTypedSpriteGroup<FlxSprite>
{
var animFrame:Int = Math.round(levels[i].value * 5);
#if desktop
animFrame = Math.round(animFrame * FlxG.sound.volume);
#end
animFrame = Math.floor(Math.min(5, animFrame));
animFrame = Math.floor(Math.max(0, animFrame));
+57 -19
View File
@@ -5,35 +5,73 @@ import flixel.system.FlxAssets.FlxShader;
class AngleMask extends FlxShader
{
@:glFragmentSource('
#pragma header
uniform vec2 endPosition;
void main()
{
vec4 base = texture2D(bitmap, openfl_TextureCoordv);
#pragma header
vec2 uv = openfl_TextureCoordv.xy;
uniform vec2 endPosition;
vec2 hash22(vec2 p) {
vec3 p3 = fract(vec3(p.xyx) * vec3(.1031, .1030, .0973));
p3 += dot(p3, p3.yzx + 33.33);
return fract((p3.xx + p3.yz) * p3.zy);
}
vec2 start = vec2(0.0, 0.0);
vec2 end = vec2(endPosition.x / openfl_TextureSize.x, 1.0);
// ====== GAMMA CORRECTION ====== //
// Helps with color mixing -- good to have by default in almost any shader
// See https://www.shadertoy.com/view/lscSzl
vec3 gamma(in vec3 color) {
return pow(color, vec3(1.0 / 2.2));
}
float dx = end.x - start.x;
float dy = end.y - start.y;
vec4 mainPass(vec2 fragCoord) {
vec4 base = texture2D(bitmap, fragCoord);
float angle = atan(dy, dx);
vec2 uv = fragCoord.xy;
uv.x -= start.x;
uv.y -= start.y;
vec2 start = vec2(0.0, 0.0);
vec2 end = vec2(endPosition.x / openfl_TextureSize.x, 1.0);
float uvA = atan(uv.y, uv.x);
float dx = end.x - start.x;
float dy = end.y - start.y;
if (uvA < angle)
gl_FragColor = base;
else
gl_FragColor = vec4(0.0);
float angle = atan(dy, dx);
}')
uv.x -= start.x;
uv.y -= start.y;
float uvA = atan(uv.y, uv.x);
if (uvA < angle)
return base;
else
return vec4(0.0);
}
vec4 antialias(vec2 fragCoord) {
const float AA_STAGES = 2.0;
const float AA_TOTAL_PASSES = AA_STAGES * AA_STAGES + 1.0;
const float AA_JITTER = 0.5;
// Run the shader multiple times with a random subpixel offset each time and average the results
vec4 color = mainPass(fragCoord);
for (float x = 0.0; x < AA_STAGES; x++)
{
for (float y = 0.0; y < AA_STAGES; y++)
{
vec2 offset = AA_JITTER * (2.0 * hash22(vec2(x, y)) - 1.0) / openfl_TextureSize.xy;
color += mainPass(fragCoord + offset);
}
}
return color / AA_TOTAL_PASSES;
}
void main() {
vec4 col = antialias(openfl_TextureCoordv);
// col.xyz = gamma(col.xyz);
gl_FragColor = col;
}')
public function new()
{
super();
+108 -52
View File
@@ -58,7 +58,11 @@ class Controls extends FlxActionSet
var _back = new FunkinAction(Action.BACK);
var _pause = new FunkinAction(Action.PAUSE);
var _reset = new FunkinAction(Action.RESET);
var _screenshot = new FunkinAction(Action.SCREENSHOT);
var _window_screenshot = new FunkinAction(Action.WINDOW_SCREENSHOT);
var _window_fullscreen = new FunkinAction(Action.WINDOW_FULLSCREEN);
var _freeplay_favorite = new FunkinAction(Action.FREEPLAY_FAVORITE);
var _freeplay_left = new FunkinAction(Action.FREEPLAY_LEFT);
var _freeplay_right = new FunkinAction(Action.FREEPLAY_RIGHT);
var _cutscene_advance = new FunkinAction(Action.CUTSCENE_ADVANCE);
var _debug_menu = new FunkinAction(Action.DEBUG_MENU);
var _debug_chart = new FunkinAction(Action.DEBUG_CHART);
@@ -66,7 +70,6 @@ class Controls extends FlxActionSet
var _volume_up = new FunkinAction(Action.VOLUME_UP);
var _volume_down = new FunkinAction(Action.VOLUME_DOWN);
var _volume_mute = new FunkinAction(Action.VOLUME_MUTE);
var _fullscreen = new FunkinAction(Action.FULLSCREEN);
var byName:Map<String, FunkinAction> = new Map<String, FunkinAction>();
@@ -233,10 +236,30 @@ class Controls extends FlxActionSet
inline function get_RESET()
return _reset.check();
public var SCREENSHOT(get, never):Bool;
public var WINDOW_FULLSCREEN(get, never):Bool;
inline function get_SCREENSHOT()
return _screenshot.check();
inline function get_WINDOW_FULLSCREEN()
return _window_fullscreen.check();
public var WINDOW_SCREENSHOT(get, never):Bool;
inline function get_WINDOW_SCREENSHOT()
return _window_screenshot.check();
public var FREEPLAY_FAVORITE(get, never):Bool;
inline function get_FREEPLAY_FAVORITE()
return _freeplay_favorite.check();
public var FREEPLAY_LEFT(get, never):Bool;
inline function get_FREEPLAY_LEFT()
return _freeplay_left.check();
public var FREEPLAY_RIGHT(get, never):Bool;
inline function get_FREEPLAY_RIGHT()
return _freeplay_right.check();
public var CUTSCENE_ADVANCE(get, never):Bool;
@@ -273,11 +296,6 @@ class Controls extends FlxActionSet
inline function get_VOLUME_MUTE()
return _volume_mute.check();
public var FULLSCREEN(get, never):Bool;
inline function get_FULLSCREEN()
return _fullscreen.check();
public function new(name, scheme:KeyboardScheme = null)
{
super(name);
@@ -294,7 +312,11 @@ class Controls extends FlxActionSet
add(_back);
add(_pause);
add(_reset);
add(_screenshot);
add(_window_screenshot);
add(_window_fullscreen);
add(_freeplay_favorite);
add(_freeplay_left);
add(_freeplay_right);
add(_cutscene_advance);
add(_debug_menu);
add(_debug_chart);
@@ -302,7 +324,6 @@ class Controls extends FlxActionSet
add(_volume_up);
add(_volume_down);
add(_volume_mute);
add(_fullscreen);
for (action in digitalActions) {
if (Std.isOfType(action, FunkinAction)) {
@@ -398,7 +419,11 @@ class Controls extends FlxActionSet
case BACK: _back;
case PAUSE: _pause;
case RESET: _reset;
case SCREENSHOT: _screenshot;
case WINDOW_SCREENSHOT: _window_screenshot;
case WINDOW_FULLSCREEN: _window_fullscreen;
case FREEPLAY_FAVORITE: _freeplay_favorite;
case FREEPLAY_LEFT: _freeplay_left;
case FREEPLAY_RIGHT: _freeplay_right;
case CUTSCENE_ADVANCE: _cutscene_advance;
case DEBUG_MENU: _debug_menu;
case DEBUG_CHART: _debug_chart;
@@ -406,7 +431,6 @@ class Controls extends FlxActionSet
case VOLUME_UP: _volume_up;
case VOLUME_DOWN: _volume_down;
case VOLUME_MUTE: _volume_mute;
case FULLSCREEN: _fullscreen;
}
}
@@ -466,8 +490,16 @@ class Controls extends FlxActionSet
func(_pause, JUST_PRESSED);
case RESET:
func(_reset, JUST_PRESSED);
case SCREENSHOT:
func(_screenshot, JUST_PRESSED);
case WINDOW_SCREENSHOT:
func(_window_screenshot, JUST_PRESSED);
case WINDOW_FULLSCREEN:
func(_window_fullscreen, JUST_PRESSED);
case FREEPLAY_FAVORITE:
func(_freeplay_favorite, JUST_PRESSED);
case FREEPLAY_LEFT:
func(_freeplay_left, JUST_PRESSED);
case FREEPLAY_RIGHT:
func(_freeplay_right, JUST_PRESSED);
case CUTSCENE_ADVANCE:
func(_cutscene_advance, JUST_PRESSED);
case DEBUG_MENU:
@@ -482,8 +514,6 @@ class Controls extends FlxActionSet
func(_volume_down, JUST_PRESSED);
case VOLUME_MUTE:
func(_volume_mute, JUST_PRESSED);
case FULLSCREEN:
func(_fullscreen, JUST_PRESSED);
}
}
@@ -678,7 +708,11 @@ class Controls extends FlxActionSet
bindKeys(Control.BACK, getDefaultKeybinds(scheme, Control.BACK));
bindKeys(Control.PAUSE, getDefaultKeybinds(scheme, Control.PAUSE));
bindKeys(Control.RESET, getDefaultKeybinds(scheme, Control.RESET));
bindKeys(Control.SCREENSHOT, getDefaultKeybinds(scheme, Control.SCREENSHOT));
bindKeys(Control.WINDOW_SCREENSHOT, getDefaultKeybinds(scheme, Control.WINDOW_SCREENSHOT));
bindKeys(Control.WINDOW_FULLSCREEN, getDefaultKeybinds(scheme, Control.WINDOW_FULLSCREEN));
bindKeys(Control.FREEPLAY_FAVORITE, getDefaultKeybinds(scheme, Control.FREEPLAY_FAVORITE));
bindKeys(Control.FREEPLAY_LEFT, getDefaultKeybinds(scheme, Control.FREEPLAY_LEFT));
bindKeys(Control.FREEPLAY_RIGHT, getDefaultKeybinds(scheme, Control.FREEPLAY_RIGHT));
bindKeys(Control.CUTSCENE_ADVANCE, getDefaultKeybinds(scheme, Control.CUTSCENE_ADVANCE));
bindKeys(Control.DEBUG_MENU, getDefaultKeybinds(scheme, Control.DEBUG_MENU));
bindKeys(Control.DEBUG_CHART, getDefaultKeybinds(scheme, Control.DEBUG_CHART));
@@ -686,7 +720,6 @@ class Controls extends FlxActionSet
bindKeys(Control.VOLUME_UP, getDefaultKeybinds(scheme, Control.VOLUME_UP));
bindKeys(Control.VOLUME_DOWN, getDefaultKeybinds(scheme, Control.VOLUME_DOWN));
bindKeys(Control.VOLUME_MUTE, getDefaultKeybinds(scheme, Control.VOLUME_MUTE));
bindKeys(Control.FULLSCREEN, getDefaultKeybinds(scheme, Control.FULLSCREEN));
bindMobileLol();
}
@@ -707,7 +740,11 @@ class Controls extends FlxActionSet
case Control.BACK: return [X, BACKSPACE, ESCAPE];
case Control.PAUSE: return [P, ENTER, ESCAPE];
case Control.RESET: return [R];
case Control.SCREENSHOT: return [F3]; // TODO: Change this back to PrintScreen
case Control.WINDOW_FULLSCREEN: return [F11]; // We use F for other things LOL.
case Control.WINDOW_SCREENSHOT: return [F3];
case Control.FREEPLAY_FAVORITE: return [F]; // Favorite a song on the menu
case Control.FREEPLAY_LEFT: return [Q]; // Switch tabs on the menu
case Control.FREEPLAY_RIGHT: return [E]; // Switch tabs on the menu
case Control.CUTSCENE_ADVANCE: return [Z, ENTER];
case Control.DEBUG_MENU: return [GRAVEACCENT];
case Control.DEBUG_CHART: return [];
@@ -715,8 +752,6 @@ class Controls extends FlxActionSet
case Control.VOLUME_UP: return [PLUS, NUMPADPLUS];
case Control.VOLUME_DOWN: return [MINUS, NUMPADMINUS];
case Control.VOLUME_MUTE: return [ZERO, NUMPADZERO];
case Control.FULLSCREEN: return [FlxKey.F11]; // We use F for other things LOL.
}
case Duo(true):
switch (control) {
@@ -732,7 +767,11 @@ class Controls extends FlxActionSet
case Control.BACK: return [H, X];
case Control.PAUSE: return [ONE];
case Control.RESET: return [R];
case Control.SCREENSHOT: return [PRINTSCREEN];
case Control.WINDOW_SCREENSHOT: return [F3];
case Control.WINDOW_FULLSCREEN: return [F11];
case Control.FREEPLAY_FAVORITE: return [F]; // Favorite a song on the menu
case Control.FREEPLAY_LEFT: return [Q]; // Switch tabs on the menu
case Control.FREEPLAY_RIGHT: return [E]; // Switch tabs on the menu
case Control.CUTSCENE_ADVANCE: return [G, Z];
case Control.DEBUG_MENU: return [GRAVEACCENT];
case Control.DEBUG_CHART: return [];
@@ -740,7 +779,6 @@ class Controls extends FlxActionSet
case Control.VOLUME_UP: return [PLUS];
case Control.VOLUME_DOWN: return [MINUS];
case Control.VOLUME_MUTE: return [ZERO];
case Control.FULLSCREEN: return [FlxKey.F];
}
case Duo(false):
@@ -757,15 +795,18 @@ class Controls extends FlxActionSet
case Control.BACK: return [ESCAPE];
case Control.PAUSE: return [ONE];
case Control.RESET: return [R];
case Control.SCREENSHOT: return [PRINTSCREEN];
case Control.WINDOW_SCREENSHOT: return [];
case Control.WINDOW_FULLSCREEN: return [];
case Control.FREEPLAY_FAVORITE: return [];
case Control.FREEPLAY_LEFT: return [];
case Control.FREEPLAY_RIGHT: return [];
case Control.CUTSCENE_ADVANCE: return [ENTER];
case Control.DEBUG_MENU: return [GRAVEACCENT];
case Control.DEBUG_MENU: return [];
case Control.DEBUG_CHART: return [];
case Control.DEBUG_STAGE: return [];
case Control.VOLUME_UP: return [NUMPADPLUS];
case Control.VOLUME_DOWN: return [NUMPADMINUS];
case Control.VOLUME_MUTE: return [NUMPADZERO];
case Control.FULLSCREEN: return [];
}
default:
@@ -856,34 +897,37 @@ class Controls extends FlxActionSet
public function addDefaultGamepad(id):Void
{
addGamepadLiteral(id, [
Control.ACCEPT => getDefaultGamepadBinds(Control.ACCEPT),
Control.BACK => getDefaultGamepadBinds(Control.BACK),
Control.UI_UP => getDefaultGamepadBinds(Control.UI_UP),
Control.UI_DOWN => getDefaultGamepadBinds(Control.UI_DOWN),
Control.UI_LEFT => getDefaultGamepadBinds(Control.UI_LEFT),
Control.UI_RIGHT => getDefaultGamepadBinds(Control.UI_RIGHT),
// don't swap A/B or X/Y for switch on these. A is always the bottom face button
Control.NOTE_UP => getDefaultGamepadBinds(Control.NOTE_UP),
Control.NOTE_DOWN => getDefaultGamepadBinds(Control.NOTE_DOWN),
Control.NOTE_LEFT => getDefaultGamepadBinds(Control.NOTE_LEFT),
Control.NOTE_RIGHT => getDefaultGamepadBinds(Control.NOTE_RIGHT),
Control.PAUSE => getDefaultGamepadBinds(Control.PAUSE),
Control.RESET => getDefaultGamepadBinds(Control.RESET),
// Control.SCREENSHOT => [],
// Control.VOLUME_UP => [RIGHT_SHOULDER],
// Control.VOLUME_DOWN => [LEFT_SHOULDER],
// Control.VOLUME_MUTE => [RIGHT_TRIGGER],
Control.WINDOW_FULLSCREEN => getDefaultGamepadBinds(Control.WINDOW_FULLSCREEN),
Control.WINDOW_SCREENSHOT => getDefaultGamepadBinds(Control.WINDOW_SCREENSHOT),
Control.CUTSCENE_ADVANCE => getDefaultGamepadBinds(Control.CUTSCENE_ADVANCE),
// Control.DEBUG_MENU
// Control.DEBUG_CHART
Control.FREEPLAY_FAVORITE => getDefaultGamepadBinds(Control.FREEPLAY_FAVORITE),
Control.FREEPLAY_LEFT => getDefaultGamepadBinds(Control.FREEPLAY_LEFT),
Control.FREEPLAY_RIGHT => getDefaultGamepadBinds(Control.FREEPLAY_RIGHT),
Control.VOLUME_UP => getDefaultGamepadBinds(Control.VOLUME_UP),
Control.VOLUME_DOWN => getDefaultGamepadBinds(Control.VOLUME_DOWN),
Control.VOLUME_MUTE => getDefaultGamepadBinds(Control.VOLUME_MUTE),
Control.DEBUG_MENU => getDefaultGamepadBinds(Control.DEBUG_MENU),
Control.DEBUG_CHART => getDefaultGamepadBinds(Control.DEBUG_CHART),
Control.DEBUG_STAGE => getDefaultGamepadBinds(Control.DEBUG_STAGE),
]);
}
function getDefaultGamepadBinds(control:Control):Array<FlxGamepadInputID> {
switch(control) {
case Control.ACCEPT: return [#if switch B #else A #end];
case Control.BACK: return [#if switch A #else B #end, FlxGamepadInputID.BACK];
case Control.BACK: return [#if switch A #else B #end];
case Control.UI_UP: return [DPAD_UP, LEFT_STICK_DIGITAL_UP];
case Control.UI_DOWN: return [DPAD_DOWN, LEFT_STICK_DIGITAL_DOWN];
case Control.UI_LEFT: return [DPAD_LEFT, LEFT_STICK_DIGITAL_LEFT];
@@ -893,15 +937,19 @@ class Controls extends FlxActionSet
case Control.NOTE_LEFT: return [DPAD_LEFT, X, LEFT_STICK_DIGITAL_LEFT, RIGHT_STICK_DIGITAL_LEFT];
case Control.NOTE_RIGHT: return [DPAD_RIGHT, B, LEFT_STICK_DIGITAL_RIGHT, RIGHT_STICK_DIGITAL_RIGHT];
case Control.PAUSE: return [START];
case Control.RESET: return [RIGHT_SHOULDER];
case Control.SCREENSHOT: return [];
case Control.VOLUME_UP: return [];
case Control.VOLUME_DOWN: return [];
case Control.VOLUME_MUTE: return [];
case Control.RESET: return [FlxGamepadInputID.BACK]; // Back (i.e. Select)
case Control.WINDOW_FULLSCREEN: [];
case Control.WINDOW_SCREENSHOT: [];
case Control.CUTSCENE_ADVANCE: return [A];
case Control.DEBUG_MENU: return [];
case Control.DEBUG_CHART: return [];
case Control.FULLSCREEN: return [];
case Control.FREEPLAY_FAVORITE: [FlxGamepadInputID.BACK]; // Back (i.e. Select)
case Control.FREEPLAY_LEFT: [LEFT_SHOULDER];
case Control.FREEPLAY_RIGHT: [RIGHT_SHOULDER];
case Control.VOLUME_UP: [];
case Control.VOLUME_DOWN: [];
case Control.VOLUME_MUTE: [];
case Control.DEBUG_MENU: [];
case Control.DEBUG_CHART: [];
case Control.DEBUG_STAGE: [];
default:
// Fallthrough.
}
@@ -1392,7 +1440,7 @@ class FlxActionInputDigitalAndroid extends FlxActionInputDigital
override public function check(Action:FlxAction):Bool
{
returnswitch(trigger)
return switch(trigger)
{
#if android
case PRESSED: FlxG.android.checkStatus(inputID, PRESSED) || FlxG.android.checkStatus(inputID, PRESSED);
@@ -1425,14 +1473,18 @@ enum Control
UI_RIGHT;
UI_DOWN;
RESET;
SCREENSHOT;
ACCEPT;
BACK;
PAUSE;
FULLSCREEN;
// CUTSCENE
CUTSCENE_ADVANCE;
// SCREENSHOT
// FREEPLAY
FREEPLAY_FAVORITE;
FREEPLAY_LEFT;
FREEPLAY_RIGHT;
// WINDOW
WINDOW_SCREENSHOT;
WINDOW_FULLSCREEN;
// VOLUME
VOLUME_UP;
VOLUME_DOWN;
@@ -1475,11 +1527,15 @@ enum abstract Action(String) to String from String
var BACK = "back";
var PAUSE = "pause";
var RESET = "reset";
var FULLSCREEN = "fullscreen";
// SCREENSHOT
var SCREENSHOT = "screenshot";
// WINDOW
var WINDOW_FULLSCREEN = "window_fullscreen";
var WINDOW_SCREENSHOT = "window_screenshot";
// CUTSCENE
var CUTSCENE_ADVANCE = "cutscene_advance";
// FREEPLAY
var FREEPLAY_FAVORITE = "freeplay_favorite";
var FREEPLAY_LEFT = "freeplay_left";
var FREEPLAY_RIGHT = "freeplay_right";
// VOLUME
var VOLUME_UP = "volume_up";
var VOLUME_DOWN = "volume_down";
+22 -2
View File
@@ -140,16 +140,36 @@ class HitNoteScriptEvent extends NoteScriptEvent
*/
public var score:Int;
public function new(note:NoteSprite, healthChange:Float, score:Int, judgement:String, comboCount:Int = 0):Void
/**
* If the hit causes a combo break.
*/
public var isComboBreak:Bool = false;
/**
* The time difference when the player hit the note
*/
public var hitDiff:Float = 0;
/**
* If the hit causes a notesplash
*/
public var doesNotesplash:Bool = false;
public function new(note:NoteSprite, healthChange:Float, score:Int, judgement:String, isComboBreak:Bool, comboCount:Int = 0, hitDiff:Float = 0,
doesNotesplash:Bool = false):Void
{
super(NOTE_HIT, note, healthChange, comboCount, true);
this.score = score;
this.judgement = judgement;
this.isComboBreak = isComboBreak;
this.doesNotesplash = doesNotesplash;
this.hitDiff = hitDiff;
}
public override function toString():String
{
return 'HitNoteScriptEvent(note=' + note + ', comboCount=' + comboCount + ', judgement=' + judgement + ', score=' + score + ')';
return 'HitNoteScriptEvent(note=' + note + ', comboCount=' + comboCount + ', judgement=' + judgement + ', score=' + score + ', isComboBreak='
+ isComboBreak + ', hitDiff=' + hitDiff + ', doesNotesplash=' + doesNotesplash + ')';
}
}
+4 -3
View File
@@ -71,7 +71,7 @@ class GameOverSubState extends MusicBeatSubState
var gameOverMusic:Null<FunkinSound> = null;
/**
* Whether the player has confirmed and prepared to restart the level.
* Whether the player has confirmed and prepared to restart the level or to go back to the freeplay menu.
* This means the animation and transition have already started.
*/
var isEnding:Bool = false;
@@ -237,15 +237,16 @@ class GameOverSubState extends MusicBeatSubState
}
// KEYBOARD ONLY: Restart the level when pressing the assigned key.
if (controls.ACCEPT && blueballed)
if (controls.ACCEPT && blueballed && !mustNotExit)
{
blueballed = false;
confirmDeath();
}
// KEYBOARD ONLY: Return to the menu when pressing the assigned key.
if (controls.BACK && !mustNotExit)
if (controls.BACK && !mustNotExit && !isEnding)
{
isEnding = true;
blueballed = false;
PlayState.instance.deathCounter = 0;
// PlayState.seenCutscene = false; // old thing...
+3 -2
View File
@@ -449,13 +449,14 @@ class PauseSubState extends MusicBeatSubState
*/
function changeSelection(change:Int = 0):Void
{
FunkinSound.playOnce(Paths.sound('scrollMenu'), 0.4);
var prevEntry:Int = currentEntry;
currentEntry += change;
if (currentEntry < 0) currentEntry = currentMenuEntries.length - 1;
if (currentEntry >= currentMenuEntries.length) currentEntry = 0;
if (currentEntry != prevEntry) FunkinSound.playOnce(Paths.sound('scrollMenu'), 0.4);
for (entryIndex in 0...currentMenuEntries.length)
{
var isCurrent:Bool = entryIndex == currentEntry;
+96 -81
View File
@@ -175,6 +175,12 @@ class PlayState extends MusicBeatSubState
*/
public var currentVariation:String = Constants.DEFAULT_VARIATION;
/**
* The currently selected instrumental ID.
* @default `''`
*/
public var currentInstrumental:String = '';
/**
* The currently active Stage. This is the object containing all the props.
*/
@@ -603,6 +609,7 @@ class PlayState extends MusicBeatSubState
currentSong = params.targetSong;
if (params.targetDifficulty != null) currentDifficulty = params.targetDifficulty;
if (params.targetVariation != null) currentVariation = params.targetVariation;
if (params.targetInstrumental != null) currentInstrumental = params.targetInstrumental;
isPracticeMode = params.practiceMode ?? false;
isBotPlayMode = params.botPlayMode ?? false;
isMinimalMode = params.minimalMode ?? false;
@@ -1211,6 +1218,9 @@ class PlayState extends MusicBeatSubState
cameraTweensPausedBySubState.add(cameraZoomTween);
}
// Pause camera follow
FlxG.camera.followLerp = 0;
for (tween in scrollSpeedTweens)
{
if (tween != null && tween.active)
@@ -1255,6 +1265,9 @@ class PlayState extends MusicBeatSubState
}
cameraTweensPausedBySubState.clear();
// Resume camera follow
FlxG.camera.followLerp = Constants.DEFAULT_CAMERA_FOLLOW_RATE;
if (currentConversation != null)
{
currentConversation.resumeMusic();
@@ -1968,7 +1981,7 @@ class PlayState extends MusicBeatSubState
if (!overrideMusic && !isGamePaused && currentChart != null)
{
currentChart.playInst(1.0, false);
currentChart.playInst(1.0, currentInstrumental, false);
}
if (FlxG.sound.music == null)
@@ -2115,7 +2128,8 @@ class PlayState extends MusicBeatSubState
// Call an event to allow canceling the note hit.
// NOTE: This is what handles the character animations!
var event:NoteScriptEvent = new HitNoteScriptEvent(note, 0.0, 0, 'perfect', 0);
var event:NoteScriptEvent = new HitNoteScriptEvent(note, 0.0, 0, 'perfect', false, 0);
dispatchEvent(event);
// Calling event.cancelEvent() skips all the other logic! Neat!
@@ -2211,7 +2225,7 @@ class PlayState extends MusicBeatSubState
// Call an event to allow canceling the note hit.
// NOTE: This is what handles the character animations!
var event:NoteScriptEvent = new HitNoteScriptEvent(note, 0.0, 0, 'perfect', 0);
var event:NoteScriptEvent = new HitNoteScriptEvent(note, 0.0, 0, 'perfect', false, 0);
dispatchEvent(event);
// Calling event.cancelEvent() skips all the other logic! Neat!
@@ -2269,11 +2283,20 @@ class PlayState extends MusicBeatSubState
if (holdNote == null || !holdNote.alive) continue;
// While the hold note is being hit, and there is length on the hold note...
if (!isBotPlayMode && holdNote.hitNote && !holdNote.missedNote && holdNote.sustainLength > 0)
if (holdNote.hitNote && !holdNote.missedNote && holdNote.sustainLength > 0)
{
// Grant the player health.
health += Constants.HEALTH_HOLD_BONUS_PER_SECOND * elapsed;
songScore += Std.int(Constants.SCORE_HOLD_BONUS_PER_SECOND * elapsed);
if (!isBotPlayMode)
{
health += Constants.HEALTH_HOLD_BONUS_PER_SECOND * elapsed;
songScore += Std.int(Constants.SCORE_HOLD_BONUS_PER_SECOND * elapsed);
}
// Make sure the player keeps singing while the note is held by the bot.
if (isBotPlayMode && currentStage != null && currentStage.getBoyfriend() != null && currentStage.getBoyfriend().isSinging())
{
currentStage.getBoyfriend().holdTimer = 0;
}
}
if (holdNote.missedNote && !holdNote.handledMiss)
@@ -2420,27 +2443,41 @@ class PlayState extends MusicBeatSubState
var daRating = Scoring.judgeNote(noteDiff, PBOT1);
var healthChange = 0.0;
var isComboBreak = false;
switch (daRating)
{
case 'sick':
healthChange = Constants.HEALTH_SICK_BONUS;
isComboBreak = Constants.JUDGEMENT_SICK_COMBO_BREAK;
case 'good':
healthChange = Constants.HEALTH_GOOD_BONUS;
isComboBreak = Constants.JUDGEMENT_GOOD_COMBO_BREAK;
case 'bad':
healthChange = Constants.HEALTH_BAD_BONUS;
isComboBreak = Constants.JUDGEMENT_BAD_COMBO_BREAK;
case 'shit':
isComboBreak = Constants.JUDGEMENT_SHIT_COMBO_BREAK;
healthChange = Constants.HEALTH_SHIT_BONUS;
}
// Send the note hit event.
var event:HitNoteScriptEvent = new HitNoteScriptEvent(note, healthChange, score, daRating, Highscore.tallies.combo + 1);
var event:HitNoteScriptEvent = new HitNoteScriptEvent(note, healthChange, score, daRating, isComboBreak, Highscore.tallies.combo + 1, noteDiff,
daRating == 'sick');
dispatchEvent(event);
// Calling event.cancelEvent() skips all the other logic! Neat!
if (event.eventCanceled) return;
Highscore.tallies.totalNotesHit++;
// Display the hit on the strums
playerStrumline.hitNote(note, !isComboBreak);
if (event.doesNotesplash) playerStrumline.playNoteSplash(note.noteData.getDirection());
if (note.isHoldNote && note.holdNoteSprite != null) playerStrumline.playNoteHoldCover(note.holdNoteSprite);
vocals.playerVolume = 1;
// Display the combo meter and add the calculation to the score.
popUpScore(note, event.score, event.judgement, event.healthChange);
applyScore(event.score, event.judgement, event.healthChange, event.isComboBreak);
popUpScore(event.judgement);
}
/**
@@ -2451,9 +2488,6 @@ class PlayState extends MusicBeatSubState
{
// If we are here, we already CALLED the onNoteMiss script hook!
health += healthChange;
songScore -= 10;
if (!isPracticeMode)
{
// messy copy paste rn lol
@@ -2493,14 +2527,9 @@ class PlayState extends MusicBeatSubState
}
vocals.playerVolume = 0;
Highscore.tallies.missed++;
if (Highscore.tallies.combo != 0) if (Highscore.tallies.combo >= 10) comboPopUps.displayCombo(0);
if (Highscore.tallies.combo != 0)
{
// Break the combo.
if (Highscore.tallies.combo >= 10) comboPopUps.displayCombo(0);
Highscore.tallies.combo = 0;
}
applyScore(-10, 'miss', healthChange, true);
if (playSound)
{
@@ -2588,20 +2617,12 @@ class PlayState extends MusicBeatSubState
// Redirect to the chart editor playing the current song.
if (controls.DEBUG_CHART)
{
if (isChartingMode)
{
if (FlxG.sound.music != null) FlxG.sound.music.pause(); // Don't reset song position!
this.close(); // This only works because PlayState is a substate!
}
else
{
disableKeys = true;
persistentUpdate = false;
FlxG.switchState(() -> new ChartEditorState(
{
targetSongId: currentSong.id,
}));
}
disableKeys = true;
persistentUpdate = false;
FlxG.switchState(() -> new ChartEditorState(
{
targetSongId: currentSong.id,
}));
}
#end
@@ -2632,46 +2653,24 @@ class PlayState extends MusicBeatSubState
}
/**
* Handles health, score, and rating popups when a note is hit.
* Handles applying health, score, and ratings.
*/
function popUpScore(daNote:NoteSprite, score:Int, daRating:String, healthChange:Float):Void
function applyScore(score:Int, daRating:String, healthChange:Float, isComboBreak:Bool)
{
if (daRating == 'miss')
{
// If daRating is 'miss', that means we made a mistake and should not continue.
FlxG.log.warn('popUpScore judged a note as a miss!');
// TODO: Remove this.
// comboPopUps.displayRating('miss');
return;
}
vocals.playerVolume = 1;
var isComboBreak = false;
switch (daRating)
{
case 'sick':
Highscore.tallies.sick += 1;
Highscore.tallies.totalNotesHit++;
isComboBreak = Constants.JUDGEMENT_SICK_COMBO_BREAK;
case 'good':
Highscore.tallies.good += 1;
Highscore.tallies.totalNotesHit++;
isComboBreak = Constants.JUDGEMENT_GOOD_COMBO_BREAK;
case 'bad':
Highscore.tallies.bad += 1;
Highscore.tallies.totalNotesHit++;
isComboBreak = Constants.JUDGEMENT_BAD_COMBO_BREAK;
case 'shit':
Highscore.tallies.shit += 1;
Highscore.tallies.totalNotesHit++;
isComboBreak = Constants.JUDGEMENT_SHIT_COMBO_BREAK;
default:
FlxG.log.error('Wuh? Buh? Guh? Note hit judgement was $daRating!');
case 'miss':
Highscore.tallies.missed += 1;
}
health += healthChange;
if (isComboBreak)
{
// Break the combo, but don't increment tallies.misses.
@@ -2683,15 +2682,23 @@ class PlayState extends MusicBeatSubState
Highscore.tallies.combo++;
if (Highscore.tallies.combo > Highscore.tallies.maxCombo) Highscore.tallies.maxCombo = Highscore.tallies.combo;
}
playerStrumline.hitNote(daNote, !isComboBreak);
if (daRating == 'sick')
{
playerStrumline.playNoteSplash(daNote.noteData.getDirection());
}
songScore += score;
}
/**
* Handles rating popups when a note is hit.
*/
function popUpScore(daRating:String, ?combo:Int):Void
{
if (daRating == 'miss')
{
// If daRating is 'miss', that means we made a mistake and should not continue.
FlxG.log.warn('popUpScore judged a note as a miss!');
// TODO: Remove this.
// comboPopUps.displayRating('miss');
return;
}
if (combo == null) combo = Highscore.tallies.combo;
if (!isPracticeMode)
{
@@ -2731,12 +2738,7 @@ class PlayState extends MusicBeatSubState
}
}
comboPopUps.displayRating(daRating);
if (Highscore.tallies.combo >= 10 || Highscore.tallies.combo == 0) comboPopUps.displayCombo(Highscore.tallies.combo);
if (daNote.isHoldNote && daNote.holdNoteSprite != null)
{
playerStrumline.playNoteHoldCover(daNote.holdNoteSprite);
}
if (combo >= 10 || combo == 0) comboPopUps.displayCombo(combo);
vocals.playerVolume = 1;
}
@@ -2823,8 +2825,13 @@ class PlayState extends MusicBeatSubState
deathCounter = 0;
// TODO: This line of code makes me sad, but you can't really fix it without a breaking migration.
// `easy`, `erect`, `normal-pico`, etc.
var suffixedDifficulty = (currentVariation != Constants.DEFAULT_VARIATION
&& currentVariation != 'erect') ? '$currentDifficulty-${currentVariation}' : currentDifficulty;
var isNewHighscore = false;
var prevScoreData:Null<SaveScoreData> = Save.instance.getSongScore(currentSong.id, currentDifficulty);
var prevScoreData:Null<SaveScoreData> = Save.instance.getSongScore(currentSong.id, suffixedDifficulty);
if (currentSong != null && currentSong.validScore)
{
@@ -2849,13 +2856,21 @@ class PlayState extends MusicBeatSubState
// adds current song data into the tallies for the level (story levels)
Highscore.talliesLevel = Highscore.combineTallies(Highscore.tallies, Highscore.talliesLevel);
if (!isPracticeMode && !isBotPlayMode && Save.instance.isSongHighScore(currentSong.id, currentDifficulty, data))
if (!isPracticeMode && !isBotPlayMode)
{
Save.instance.setSongScore(currentSong.id, currentDifficulty, data);
#if newgrounds
NGio.postScore(score, currentSong.id);
#end
isNewHighscore = true;
isNewHighscore = Save.instance.isSongHighScore(currentSong.id, suffixedDifficulty, data);
// If no high score is present, save both score and rank.
// If score or rank are better, save the highest one.
// If neither are higher, nothing will change.
Save.instance.applySongRank(currentSong.id, suffixedDifficulty, data);
if (isNewHighscore)
{
#if newgrounds
NGio.postScore(score, currentSong.id);
#end
}
}
}
@@ -3090,7 +3105,7 @@ class PlayState extends MusicBeatSubState
FlxG.camera.targetOffset.x += 20;
// Replace zoom animation with a fade out for now.
camGame.fade(FlxColor.BLACK, 0.6);
FlxG.camera.fade(FlxColor.BLACK, 0.6);
FlxTween.tween(camHUD, {alpha: 0}, 0.6,
{
@@ -3185,7 +3200,7 @@ class PlayState extends MusicBeatSubState
cancelAllCameraTweens();
}
FlxG.camera.follow(cameraFollowPoint, LOCKON, 0.04);
FlxG.camera.follow(cameraFollowPoint, LOCKON, Constants.DEFAULT_CAMERA_FOLLOW_RATE);
FlxG.camera.targetOffset.set();
if (resetZoom)
+2 -1
View File
@@ -53,8 +53,9 @@ class HealthIcon extends FunkinSprite
/**
* Apply the "bop" animation once every X steps.
* Defaults to once per beat.
*/
public var bopEvery:Int = 4;
public var bopEvery:Int = Constants.STEPS_PER_BEAT;
/**
* The amount, in degrees, to rotate the icon by when boping.
+89 -69
View File
@@ -356,7 +356,10 @@ class Scoring
// Perfect (Platinum) is a Sick Full Clear
var isPerfectGold = scoreData.tallies.sick == scoreData.tallies.totalNotes;
if (isPerfectGold) return ScoringRank.PERFECT_GOLD;
if (isPerfectGold)
{
return ScoringRank.PERFECT_GOLD;
}
// Else, use the standard grades
@@ -397,62 +400,79 @@ enum abstract ScoringRank(String)
var GOOD;
var SHIT;
@:op(A > B) static function compare(a:Null<ScoringRank>, b:Null<ScoringRank>):Bool
/**
* Converts ScoringRank to an integer value for comparison.
* Better ranks should be tied to a higher value.
*/
static function getValue(rank:Null<ScoringRank>):Int
{
if (rank == null) return -1;
switch (rank)
{
case PERFECT_GOLD:
return 5;
case PERFECT:
return 4;
case EXCELLENT:
return 3;
case GREAT:
return 2;
case GOOD:
return 1;
case SHIT:
return 0;
default:
return -1;
}
}
// Yes, we really need a different function for each comparison operator.
@:op(A > B) static function compareGT(a:Null<ScoringRank>, b:Null<ScoringRank>):Bool
{
if (a != null && b == null) return true;
if (a == null || b == null) return false;
var temp1:Int = 0;
var temp2:Int = 0;
var temp1:Int = getValue(a);
var temp2:Int = getValue(b);
// temp 1
switch (a)
{
case PERFECT_GOLD:
temp1 = 5;
case PERFECT:
temp1 = 4;
case EXCELLENT:
temp1 = 3;
case GREAT:
temp1 = 2;
case GOOD:
temp1 = 1;
case SHIT:
temp1 = 0;
default:
temp1 = -1;
}
// temp 2
switch (b)
{
case PERFECT_GOLD:
temp2 = 5;
case PERFECT:
temp2 = 4;
case EXCELLENT:
temp2 = 3;
case GREAT:
temp2 = 2;
case GOOD:
temp2 = 1;
case SHIT:
temp2 = 0;
default:
temp2 = -1;
}
if (temp1 > temp2)
{
return true;
}
else
{
return false;
}
return temp1 > temp2;
}
@:op(A >= B) static function compareGTEQ(a:Null<ScoringRank>, b:Null<ScoringRank>):Bool
{
if (a != null && b == null) return true;
if (a == null || b == null) return false;
var temp1:Int = getValue(a);
var temp2:Int = getValue(b);
return temp1 >= temp2;
}
@:op(A < B) static function compareLT(a:Null<ScoringRank>, b:Null<ScoringRank>):Bool
{
if (a != null && b == null) return true;
if (a == null || b == null) return false;
var temp1:Int = getValue(a);
var temp2:Int = getValue(b);
return temp1 < temp2;
}
@:op(A <= B) static function compareLTEQ(a:Null<ScoringRank>, b:Null<ScoringRank>):Bool
{
if (a != null && b == null) return true;
if (a == null || b == null) return false;
var temp1:Int = getValue(a);
var temp2:Int = getValue(b);
return temp1 <= temp2;
}
// @:op(A == B) isn't necessary!
/**
* Delay in seconds
*/
@@ -462,15 +482,15 @@ enum abstract ScoringRank(String)
{
case PERFECT_GOLD | PERFECT:
// return 2.5;
return 95/24;
return 95 / 24;
case EXCELLENT:
return 0;
case GREAT:
return 5/24;
return 5 / 24;
case GOOD:
return 3/24;
return 3 / 24;
case SHIT:
return 2/24;
return 2 / 24;
default:
return 3.5;
}
@@ -482,15 +502,15 @@ enum abstract ScoringRank(String)
{
case PERFECT_GOLD | PERFECT:
// return 2.5;
return 95/24;
return 95 / 24;
case EXCELLENT:
return 97/24;
return 97 / 24;
case GREAT:
return 95/24;
return 95 / 24;
case GOOD:
return 95/24;
return 95 / 24;
case SHIT:
return 95/24;
return 95 / 24;
default:
return 3.5;
}
@@ -502,15 +522,15 @@ enum abstract ScoringRank(String)
{
case PERFECT_GOLD | PERFECT:
// return 2.5;
return 129/24;
return 129 / 24;
case EXCELLENT:
return 122/24;
return 122 / 24;
case GREAT:
return 109/24;
return 109 / 24;
case GOOD:
return 107/24;
return 107 / 24;
case SHIT:
return 186/24;
return 186 / 24;
default:
return 3.5;
}
@@ -522,15 +542,15 @@ enum abstract ScoringRank(String)
{
case PERFECT_GOLD | PERFECT:
// return 2.5;
return 140/24;
return 140 / 24;
case EXCELLENT:
return 140/24;
return 140 / 24;
case GREAT:
return 129/24;
return 129 / 24;
case GOOD:
return 127/24;
return 127 / 24;
case SHIT:
return 207/24;
return 207 / 24;
default:
return 3.5;
}
+2 -2
View File
@@ -682,9 +682,9 @@ class SongDifficulty
FlxG.sound.cache(getInstPath(instrumental));
}
public function playInst(volume:Float = 1.0, looped:Bool = false):Void
public function playInst(volume:Float = 1.0, instId:String = '', looped:Bool = false):Void
{
var suffix:String = (variation != null && variation != '' && variation != 'default') ? '-$variation' : '';
var suffix:String = (instId != '') ? '-$instId' : '';
FlxG.sound.music = FunkinSound.load(Paths.inst(this.song.id, suffix), volume, looped, false, true);
+100 -2
View File
@@ -1,6 +1,7 @@
package funkin.save;
import flixel.util.FlxSave;
import funkin.util.FileUtil;
import funkin.input.Controls.Device;
import funkin.play.scoring.Scoring;
import funkin.play.scoring.Scoring.ScoringRank;
@@ -58,7 +59,7 @@ class Save
this.data = data;
// Make sure the verison number is up to date before we flush.
this.data.version = Save.SAVE_DATA_VERSION;
updateVersionToLatest();
}
public static function getDefault():RawSaveData
@@ -503,7 +504,7 @@ class Save
}
/**
* Apply the score the user achieved for a given song on a given difficulty.
* Directly set the score the user achieved for a given song on a given difficulty.
*/
public function setSongScore(songId:String, difficultyId:String, score:SaveScoreData):Void
{
@@ -518,6 +519,44 @@ class Save
flush();
}
/**
* Only replace the ranking data for the song, because the old score is still better.
*/
public function applySongRank(songId:String, difficultyId:String, newScoreData:SaveScoreData):Void
{
var newRank = Scoring.calculateRank(newScoreData);
if (newScoreData == null || newRank == null) return;
var song = data.scores.songs.get(songId);
if (song == null)
{
song = [];
data.scores.songs.set(songId, song);
}
var previousScoreData = song.get(difficultyId);
var previousRank = Scoring.calculateRank(previousScoreData);
if (previousScoreData == null || previousRank == null)
{
// Directly set the highscore.
setSongScore(songId, difficultyId, newScoreData);
return;
}
// Set the high score and the high rank separately.
var newScore:SaveScoreData =
{
score: (previousScoreData.score > newScoreData.score) ? previousScoreData.score : newScoreData.score,
tallies: (previousRank > newRank) ? previousScoreData.tallies : newScoreData.tallies
};
song.set(difficultyId, newScore);
flush();
}
/**
* Is the provided score data better than the current high score for the given song?
* @param songId The song ID to check.
@@ -543,6 +582,39 @@ class Save
return score.score > currentScore.score;
}
/**
* Is the provided score data better than the current rank for the given song?
* @param songId The song ID to check.
* @param difficultyId The difficulty to check.
* @param score The score to check the rank for.
* @return Whether the score's rank is better than the current rank.
*/
public function isSongHighRank(songId:String, difficultyId:String = 'normal', score:SaveScoreData):Bool
{
var newScoreRank = Scoring.calculateRank(score);
if (newScoreRank == null)
{
// The provided score is invalid.
return false;
}
var song = data.scores.songs.get(songId);
if (song == null)
{
song = [];
data.scores.songs.set(songId, song);
}
var currentScore = song.get(difficultyId);
var currentScoreRank = Scoring.calculateRank(currentScore);
if (currentScoreRank == null)
{
// There is no primary highscore for this song.
return true;
}
return newScoreRank > currentScoreRank;
}
/**
* Has the provided song been beaten on one of the listed difficulties?
* @param songId The song ID to check.
@@ -832,6 +904,29 @@ class Save
return cast legacySave.data;
}
}
/**
* Serialize this Save into a JSON string.
* @param pretty Whether the JSON should be big ol string (false),
* or formatted with tabs (true)
* @return The JSON string.
*/
public function serialize(pretty:Bool = true):String
{
var ignoreNullOptionals = true;
var writer = new json2object.JsonWriter<RawSaveData>(ignoreNullOptionals);
return writer.write(data, pretty ? ' ' : null);
}
public function updateVersionToLatest():Void
{
this.data.version = Save.SAVE_DATA_VERSION;
}
public function debug_dumpSave():Void
{
FileUtil.saveFile(haxe.io.Bytes.ofString(this.serialize()), [FileUtil.FILE_FILTER_JSON], null, null, './save.json', 'Write save data as JSON...');
}
}
/**
@@ -904,6 +999,9 @@ typedef SaveHighScoresData =
typedef SaveDataMods =
{
var enabledMods:Array<String>;
// TODO: Make this not trip up the serializer when debugging.
@:jignored
var modOptions:Map<String, Dynamic>;
}
+2 -2
View File
@@ -94,7 +94,7 @@ class MenuTypedList<T:MenuListItem> extends FlxTypedGroup<T>
if (newIndex != selectedIndex)
{
FunkinSound.playOnce(Paths.sound('scrollMenu'));
FunkinSound.playOnce(Paths.sound('scrollMenu'), 0.4);
selectItem(newIndex);
}
@@ -142,7 +142,7 @@ class MenuTypedList<T:MenuListItem> extends FlxTypedGroup<T>
*/
function navGrid(latSize:Int, latPrev:Bool, latNext:Bool, latAllowWrap:Bool, prev:Bool, next:Bool, allowWrap:Bool):Int
{
// The grid lenth along the variable-length axis
// The grid length along the variable-length axis
var size = Math.ceil(length / latSize);
// The selected position along the variable-length axis
var index = Math.floor(selectedIndex / latSize);
@@ -904,7 +904,7 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
function set_notePreviewDirty(value:Bool):Bool
{
trace('Note preview dirtied!');
// trace('Note preview dirtied!');
return notePreviewDirty = value;
}
@@ -6304,7 +6304,7 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
var tempNote:NoteSprite = new NoteSprite(NoteStyleRegistry.instance.fetchDefault());
tempNote.noteData = noteData;
tempNote.scrollFactor.set(0, 0);
var event:NoteScriptEvent = new HitNoteScriptEvent(tempNote, 0.0, 0, 'perfect', 0);
var event:NoteScriptEvent = new HitNoteScriptEvent(tempNote, 0.0, 0, 'perfect', false, 0);
dispatchEvent(event);
// Calling event.cancelEvent() skips all the other logic! Neat!
@@ -35,7 +35,15 @@ class SetItemSelectionCommand implements ChartEditorCommand
{
var eventSelected = this.events[0];
state.eventKindToPlace = eventSelected.eventKind;
if (state.eventKindToPlace == eventSelected.eventKind)
{
trace('Target event kind matches selection: ${eventSelected.eventKind}');
}
else
{
trace('Switching target event kind to match selection: ${state.eventKindToPlace} != ${eventSelected.eventKind}');
state.eventKindToPlace = eventSelected.eventKind;
}
// This code is here to parse event data that's not built as a struct for some reason.
// TODO: Clean this up or get rid of it.
@@ -201,7 +201,8 @@ class ChartEditorThemeHandler
// Selection borders horizontally in the middle.
for (i in 1...(Conductor.instance.stepsPerMeasure))
{
if ((i % Conductor.instance.beatsPerMeasure) == 0)
// There may be a different number of beats per measure, but there's always 4 steps per beat.
if ((i % Constants.STEPS_PER_BEAT) == 0)
{
state.gridBitmap.fillRect(new Rectangle(0, (ChartEditorState.GRID_SIZE * i) - (GRID_BEAT_DIVIDER_WIDTH / 2), state.gridBitmap.width,
GRID_BEAT_DIVIDER_WIDTH),
@@ -58,17 +58,8 @@ class ChartEditorEventDataToolbox extends ChartEditorBaseToolbox
function initialize():Void
{
toolboxEventsEventKind.dataSource = new ArrayDataSource();
var songEvents:Array<SongEvent> = SongEventRegistry.listEvents();
for (event in songEvents)
{
toolboxEventsEventKind.dataSource.add({text: event.getTitle(), value: event.id});
}
toolboxEventsEventKind.onChange = function(event:UIEvent) {
var eventType:String = event.data.value;
var eventType:String = event.data.id;
trace('ChartEditorToolboxHandler.buildToolboxEventDataLayout() - Event type changed: $eventType');
@@ -83,7 +74,7 @@ class ChartEditorEventDataToolbox extends ChartEditorBaseToolbox
return;
}
buildEventDataFormFromSchema(toolboxEventsDataGrid, schema);
buildEventDataFormFromSchema(toolboxEventsDataGrid, schema, chartEditorState.eventKindToPlace);
if (!_initializing && chartEditorState.currentEventSelection.length > 0)
{
@@ -98,14 +89,40 @@ class ChartEditorEventDataToolbox extends ChartEditorBaseToolbox
chartEditorState.notePreviewDirty = true;
}
}
toolboxEventsEventKind.value = chartEditorState.eventKindToPlace;
var startingEventValue = ChartEditorDropdowns.populateDropdownWithSongEvents(toolboxEventsEventKind, chartEditorState.eventKindToPlace);
trace('ChartEditorToolboxHandler.buildToolboxEventDataLayout() - Starting event kind: ${startingEventValue}');
toolboxEventsEventKind.value = startingEventValue;
}
public override function refresh():Void
{
super.refresh();
toolboxEventsEventKind.value = chartEditorState.eventKindToPlace;
var newDropdownElement = ChartEditorDropdowns.findDropdownElement(chartEditorState.eventKindToPlace, toolboxEventsEventKind);
if (newDropdownElement == null)
{
throw 'ChartEditorToolboxHandler.buildToolboxEventDataLayout() - Event kind not in dropdown: ${chartEditorState.eventKindToPlace}';
}
else if (toolboxEventsEventKind.value != newDropdownElement || lastEventKind != toolboxEventsEventKind.value.id)
{
toolboxEventsEventKind.value = newDropdownElement;
var schema:SongEventSchema = SongEventRegistry.getEventSchema(chartEditorState.eventKindToPlace);
if (schema == null)
{
trace('ChartEditorToolboxHandler.buildToolboxEventDataLayout() - Unknown event kind: ${chartEditorState.eventKindToPlace}');
}
else
{
trace('ChartEditorToolboxHandler.buildToolboxEventDataLayout() - Event kind changed: ${toolboxEventsEventKind.value.id} != ${newDropdownElement.id} != ${lastEventKind}, rebuilding form');
buildEventDataFormFromSchema(toolboxEventsDataGrid, schema, chartEditorState.eventKindToPlace);
}
}
else
{
trace('ChartEditorToolboxHandler.buildToolboxEventDataLayout() - Event kind not changed: ${toolboxEventsEventKind.value} == ${newDropdownElement} == ${lastEventKind}');
}
for (pair in chartEditorState.eventDataToPlace.keyValueIterator())
{
@@ -116,7 +133,7 @@ class ChartEditorEventDataToolbox extends ChartEditorBaseToolbox
if (field == null)
{
throw 'ChartEditorToolboxHandler.refresh() - Field "${fieldId}" does not exist in the event data form.';
throw 'ChartEditorToolboxHandler.refresh() - Field "${fieldId}" does not exist in the event data form for kind ${lastEventKind}.';
}
else
{
@@ -141,9 +158,15 @@ class ChartEditorEventDataToolbox extends ChartEditorBaseToolbox
}
}
function buildEventDataFormFromSchema(target:Box, schema:SongEventSchema):Void
var lastEventKind:String = 'unknown';
function buildEventDataFormFromSchema(target:Box, schema:SongEventSchema, eventKind:String):Void
{
trace(schema);
trace('Building event data form from schema for event kind: ${eventKind}');
// trace(schema);
lastEventKind = eventKind ?? 'unknown';
// Clear the frame.
target.removeAllComponents();
@@ -188,6 +211,9 @@ class ChartEditorEventDataToolbox extends ChartEditorBaseToolbox
var dropDown:DropDown = new DropDown();
dropDown.id = field.name;
dropDown.width = 200.0;
dropDown.dropdownSize = 10;
dropDown.dropdownWidth = 300;
dropDown.searchable = true;
dropDown.dataSource = new ArrayDataSource();
if (field.keys == null) throw 'Field "${field.name}" is of Enum type but has no keys.';
@@ -197,12 +223,15 @@ class ChartEditorEventDataToolbox extends ChartEditorBaseToolbox
for (optionName in field.keys.keys())
{
var optionValue:Null<Dynamic> = field.keys.get(optionName);
trace('$optionName : $optionValue');
// trace('$optionName : $optionValue');
dropDown.dataSource.add({value: optionValue, text: optionName});
}
dropDown.value = field.defaultValue;
// TODO: Add an option to customize sort.
dropDown.dataSource.sort('text', ASCENDING);
input = dropDown;
case STRING:
input = new TextField();
@@ -3,11 +3,13 @@ package funkin.ui.debug.charting.util;
import funkin.data.notestyle.NoteStyleRegistry;
import funkin.play.notes.notestyle.NoteStyle;
import funkin.data.stage.StageData;
import funkin.play.event.SongEvent;
import funkin.data.stage.StageRegistry;
import funkin.play.character.CharacterData;
import haxe.ui.components.DropDown;
import funkin.play.stage.Stage;
import funkin.play.character.BaseCharacter.CharacterType;
import funkin.data.event.SongEventRegistry;
import funkin.play.character.CharacterData.CharacterDataParser;
/**
@@ -81,6 +83,42 @@ class ChartEditorDropdowns
return returnValue;
}
public static function populateDropdownWithSongEvents(dropDown:DropDown, startingEventId:String):DropDownEntry
{
dropDown.dataSource.clear();
var returnValue:DropDownEntry = {id: "FocusCamera", text: "Focus Camera"};
var songEvents:Array<SongEvent> = SongEventRegistry.listEvents();
for (event in songEvents)
{
var value = {id: event.id, text: event.getTitle()};
if (startingEventId == event.id) returnValue = value;
dropDown.dataSource.add(value);
}
dropDown.dataSource.sort('text', ASCENDING);
return returnValue;
}
/**
* Given the ID of a dropdown element, find the corresponding entry in the dropdown's dataSource.
*/
public static function findDropdownElement(id:String, dropDown:DropDown):Null<DropDownEntry>
{
// Attempt to find the entry.
for (entryIndex in 0...dropDown.dataSource.size)
{
var entry = dropDown.dataSource.get(entryIndex);
if (entry.id == id) return entry;
}
// Not found.
return null;
}
/**
* Populate a dropdown with a list of note styles.
*/
+1 -1
View File
@@ -266,7 +266,7 @@ class DJBoyfriend extends FlxAtlasSprite
// Fade out music to 40% volume over 1 second.
// This helps make the TV a bit more audible.
FlxG.sound.music.fadeOut(1.0, 0.4);
FlxG.sound.music.fadeOut(1.0, 0.1);
// Play the cartoon at a random time between the start and 5 seconds from the end.
cartoonSnd.time = FlxG.random.float(0, Math.max(cartoonSnd.length - (5 * Constants.MS_PER_SEC), 0.0));
+65 -62
View File
@@ -230,6 +230,12 @@ class FreeplayState extends MusicBeatSubState
FlxTransitionableState.skipNextTransIn = true;
// dedicated camera for the state so we don't need to fuk around with camera scrolls from the mainmenu / elsewhere
funnyCam = new FunkinCamera('freeplayFunny', 0, 0, FlxG.width, FlxG.height);
funnyCam.bgColor = FlxColor.TRANSPARENT;
FlxG.cameras.add(funnyCam, false);
this.cameras = [funnyCam];
if (stickerSubState != null)
{
this.persistentUpdate = true;
@@ -285,7 +291,10 @@ class FreeplayState extends MusicBeatSubState
// Only display songs which actually have available difficulties for the current character.
var displayedVariations = song.getVariationsByCharId(currentCharacter);
trace(songId);
trace(displayedVariations);
var availableDifficultiesForSong:Array<String> = song.listDifficulties(displayedVariations, false);
trace(availableDifficultiesForSong);
if (availableDifficultiesForSong.length == 0) continue;
songs.push(new FreeplaySongData(levelId, songId, song, displayedVariations));
@@ -449,15 +458,20 @@ class FreeplayState extends MusicBeatSubState
add(dj);
bgDad = new FlxSprite(pinkBack.width * 0.75, 0).loadGraphic(Paths.image('freeplay/freeplayBGdad'));
bgDad.setGraphicSize(0, FlxG.height);
bgDad.updateHitbox();
bgDad = new FlxSprite(pinkBack.width * 0.74, 0).loadGraphic(Paths.image('freeplay/freeplayBGdad'));
bgDad.shader = new AngleMask();
bgDad.visible = false;
var blackOverlayBullshitLOLXD:FlxSprite = new FlxSprite(FlxG.width).makeGraphic(Std.int(bgDad.width), Std.int(bgDad.height), FlxColor.BLACK);
add(blackOverlayBullshitLOLXD); // used to mask the text lol!
// this makes the texture sizes consistent, for the angle shader
bgDad.setGraphicSize(0, FlxG.height);
blackOverlayBullshitLOLXD.setGraphicSize(0, FlxG.height);
bgDad.updateHitbox();
blackOverlayBullshitLOLXD.updateHitbox();
exitMovers.set([blackOverlayBullshitLOLXD, bgDad],
{
x: FlxG.width * 1.5,
@@ -466,7 +480,7 @@ class FreeplayState extends MusicBeatSubState
});
add(bgDad);
FlxTween.tween(blackOverlayBullshitLOLXD, {x: pinkBack.width * 0.76}, 0.7, {ease: FlxEase.quintOut});
FlxTween.tween(blackOverlayBullshitLOLXD, {x: pinkBack.width * 0.74}, 0.7, {ease: FlxEase.quintOut});
blackOverlayBullshitLOLXD.shader = bgDad.shader;
@@ -583,6 +597,8 @@ class FreeplayState extends MusicBeatSubState
generateSongList({filterType: FAVORITE}, true);
case 'ALL':
generateSongList(null, true);
case '#':
generateSongList({filterType: REGEXP, filterData: '0-9'}, true);
default:
generateSongList({filterType: REGEXP, filterData: str}, true);
}
@@ -591,6 +607,7 @@ class FreeplayState extends MusicBeatSubState
// that is, only if there's more than one song in the group!
if (grpCapsules.members.length > 0)
{
FunkinSound.playOnce(Paths.sound('scrollMenu'), 0.4);
curSelected = 1;
changeSelection();
}
@@ -652,6 +669,9 @@ class FreeplayState extends MusicBeatSubState
alsoOrangeLOL.visible = true;
grpTxtScrolls.visible = true;
// render optimisation
if (_parentState != null) _parentState.persistentDraw = false;
cardGlow.visible = true;
FlxTween.tween(cardGlow, {alpha: 0, "scale.x": 1.2, "scale.y": 1.2}, 0.45, {ease: FlxEase.sineOut});
@@ -956,16 +976,20 @@ class FreeplayState extends MusicBeatSubState
grpCapsules.members[curSelected].ranking.scale.set(20, 20);
grpCapsules.members[curSelected].blurredRanking.scale.set(20, 20);
grpCapsules.members[curSelected].ranking.animation.play(fromResults.newRank.getFreeplayRankIconAsset(), true);
// grpCapsules.members[curSelected].ranking.animation.curAnim.name, true);
if (fromResults?.newRank != null)
{
grpCapsules.members[curSelected].ranking.animation.play(fromResults.newRank.getFreeplayRankIconAsset(), true);
}
FlxTween.tween(grpCapsules.members[curSelected].ranking, {"scale.x": 1, "scale.y": 1}, 0.1);
grpCapsules.members[curSelected].blurredRanking.animation.play(fromResults.newRank.getFreeplayRankIconAsset(), true);
if (fromResults?.newRank != null)
{
grpCapsules.members[curSelected].blurredRanking.animation.play(fromResults.newRank.getFreeplayRankIconAsset(), true);
}
FlxTween.tween(grpCapsules.members[curSelected].blurredRanking, {"scale.x": 1, "scale.y": 1}, 0.1);
new FlxTimer().start(0.1, _ -> {
// trace(grpCapsules.members[curSelected].ranking.rank);
if (fromResults?.oldRank != null)
{
grpCapsules.members[curSelected].fakeRanking.visible = false;
@@ -994,7 +1018,6 @@ class FreeplayState extends MusicBeatSubState
FunkinSound.playOnce(Paths.sound('ranks/rankinnormal'));
}
rankCamera.zoom = 1.3;
// FlxTween.tween(rankCamera, {"zoom": 1.4}, 0.3, {ease: FlxEase.elasticOut});
FlxTween.tween(rankCamera, {"zoom": 1.5}, 0.3, {ease: FlxEase.backInOut});
@@ -1012,13 +1035,11 @@ class FreeplayState extends MusicBeatSubState
new FlxTimer().start(0.4, _ -> {
FlxTween.tween(funnyCam, {"zoom": 1}, 0.8, {ease: FlxEase.sineIn});
FlxTween.tween(rankCamera, {"zoom": 1.2}, 0.8, {ease: FlxEase.backIn});
// IntervalShake.shake(grpCapsules.members[curSelected], 0.8 + 0.5, 1 / 24, 0, 2, FlxEase.quadIn);
FlxTween.tween(grpCapsules.members[curSelected], {x: originalPos.x - 7, y: originalPos.y - 80}, 0.8 + 0.5, {ease: FlxEase.quartIn});
});
new FlxTimer().start(0.6, _ -> {
rankAnimSlam(fromResults);
// IntervalShake.shake(grpCapsules.members[curSelected].capsule, 0.3, 1 / 30, 0, 0.3, FlxEase.quartIn);
});
}
@@ -1183,51 +1204,9 @@ class FreeplayState extends MusicBeatSubState
// {
// rankAnimSlam(fromResultsParams);
// }
if (FlxG.keys.justPressed.G)
{
sparks.y -= 2;
trace(sparks.x, sparks.y);
}
if (FlxG.keys.justPressed.V)
{
sparks.x -= 2;
trace(sparks.x, sparks.y);
}
if (FlxG.keys.justPressed.N)
{
sparks.x += 2;
trace(sparks.x, sparks.y);
}
if (FlxG.keys.justPressed.B)
{
sparks.y += 2;
trace(sparks.x, sparks.y);
}
if (FlxG.keys.justPressed.I)
{
sparksADD.y -= 2;
trace(sparksADD.x, sparksADD.y);
}
if (FlxG.keys.justPressed.J)
{
sparksADD.x -= 2;
trace(sparksADD.x, sparksADD.y);
}
if (FlxG.keys.justPressed.L)
{
sparksADD.x += 2;
trace(sparksADD.x, sparksADD.y);
}
if (FlxG.keys.justPressed.K)
{
sparksADD.y += 2;
trace(sparksADD.x, sparksADD.y);
}
#end
if (FlxG.keys.justPressed.F && !busy)
if (controls.FREEPLAY_FAVORITE && !busy)
{
var targetSong = grpCapsules.members[curSelected]?.songData;
if (targetSong != null)
@@ -1571,6 +1550,8 @@ class FreeplayState extends MusicBeatSubState
{
clearDaCache(daSong.songName);
}
// remove and destroy freeplay camera
FlxG.cameras.remove(funnyCam);
}
function changeDiff(change:Int = 0, force:Bool = false):Void
@@ -1591,7 +1572,19 @@ class FreeplayState extends MusicBeatSubState
var daSong:Null<FreeplaySongData> = grpCapsules.members[curSelected].songData;
if (daSong != null)
{
var songScore:SaveScoreData = Save.instance.getSongScore(grpCapsules.members[curSelected].songData.songId, currentDifficulty);
// TODO: Make this actually be the variation you're focused on. We don't need to fetch the song metadata just to calculate it.
var targetSong:Song = SongRegistry.instance.fetchEntry(grpCapsules.members[curSelected].songData.songId);
if (targetSong == null)
{
FlxG.log.warn('WARN: could not find song with id (${grpCapsules.members[curSelected].songData.songId})');
return;
}
var targetVariation:String = targetSong.getFirstValidVariation(currentDifficulty);
// TODO: This line of code makes me sad, but you can't really fix it without a breaking migration.
var suffixedDifficulty = (targetVariation != Constants.DEFAULT_VARIATION
&& targetVariation != 'erect') ? '$currentDifficulty-${targetVariation}' : currentDifficulty;
var songScore:SaveScoreData = Save.instance.getSongScore(grpCapsules.members[curSelected].songData.songId, suffixedDifficulty);
intendedScore = songScore?.score ?? 0;
intendedCompletion = songScore == null ? 0.0 : ((songScore.tallies.sick + songScore.tallies.good) / songScore.tallies.totalNotes);
rememberedDifficulty = currentDifficulty;
@@ -1726,11 +1719,20 @@ class FreeplayState extends MusicBeatSubState
FlxG.log.warn('WARN: could not find song with id (${cap.songData.songId})');
return;
}
var targetDifficulty:String = currentDifficulty;
var targetVariation:String = targetSong.getFirstValidVariation(targetDifficulty);
var targetDifficultyId:String = currentDifficulty;
var targetVariation:String = targetSong.getFirstValidVariation(targetDifficultyId);
PlayStatePlaylist.campaignId = cap.songData.levelId;
var targetDifficulty:SongDifficulty = targetSong.getDifficulty(targetDifficultyId, targetVariation);
if (targetDifficulty == null)
{
FlxG.log.warn('WARN: could not find difficulty with id (${targetDifficultyId})');
return;
}
// TODO: Change this with alternate instrumentals
var targetInstId:String = targetDifficulty.characters.instrumental;
// Visual and audio effects.
FunkinSound.playOnce(Paths.sound('confirmMenu'));
dj.confirm();
@@ -1779,8 +1781,9 @@ class FreeplayState extends MusicBeatSubState
LoadingState.loadPlayState(
{
targetSong: targetSong,
targetDifficulty: targetDifficulty,
targetDifficulty: targetDifficultyId,
targetVariation: targetVariation,
targetInstrumental: targetInstId,
practiceMode: false,
minimalMode: false,
@@ -1817,12 +1820,12 @@ class FreeplayState extends MusicBeatSubState
function changeSelection(change:Int = 0):Void
{
if (!prepForNewRank) FunkinSound.playOnce(Paths.sound('scrollMenu'), 0.4);
var prevSelected:Int = curSelected;
curSelected += change;
if (!prepForNewRank && curSelected != prevSelected) FunkinSound.playOnce(Paths.sound('scrollMenu'), 0.4);
if (curSelected < 0) curSelected = grpCapsules.countLiving() - 1;
if (curSelected >= grpCapsules.countLiving()) curSelected = 0;
@@ -2076,7 +2079,7 @@ class FreeplaySongData
this.songDifficulties = song.listDifficulties(null, variations, false, false);
if (!this.songDifficulties.contains(currentDifficulty)) currentDifficulty = Constants.DEFAULT_DIFFICULTY;
var songDifficulty:SongDifficulty = song.getDifficulty(currentDifficulty, variations);
var songDifficulty:SongDifficulty = song.getDifficulty(currentDifficulty, null, variations);
if (songDifficulty == null) return;
this.songStartingBpm = songDifficulty.getStartingBPM();
this.songName = songDifficulty.songName;
+8 -2
View File
@@ -8,6 +8,7 @@ import flixel.tweens.FlxTween;
import flixel.tweens.FlxEase;
import flixel.util.FlxColor;
import flixel.util.FlxTimer;
import funkin.input.Controls;
import funkin.graphics.adobeanimate.FlxAtlasSprite;
class LetterSort extends FlxTypedSpriteGroup<FlxSprite>
@@ -69,14 +70,19 @@ class LetterSort extends FlxTypedSpriteGroup<FlxSprite>
changeSelection(0);
}
var controls(get, never):Controls;
inline function get_controls():Controls
return PlayerSettings.player1.controls;
override function update(elapsed:Float):Void
{
super.update(elapsed);
if (inputEnabled)
{
if (FlxG.keys.justPressed.E) changeSelection(1);
if (FlxG.keys.justPressed.Q) changeSelection(-1);
if (controls.FREEPLAY_LEFT) changeSelection(-1);
if (controls.FREEPLAY_RIGHT) changeSelection(1);
}
}
+20 -7
View File
@@ -219,7 +219,7 @@ class SongMenuItem extends FlxSpriteGroup
favIconBlurred.visible = false;
add(favIconBlurred);
favIcon = new FlxSprite(380, 40);
favIcon = new FlxSprite(favIconBlurred.x, favIconBlurred.y);
favIcon.frames = Paths.getSparrowAtlas('freeplay/favHeart');
favIcon.animation.addByPrefix('fav', 'favorite heart', 24, false);
favIcon.animation.play('fav');
@@ -294,21 +294,34 @@ class SongMenuItem extends FlxSpriteGroup
}
}
// 255, 27 normal
// 220, 27 favourited
/**
* Checks whether the song is favorited, and/or has a rank, and adjusts the clipping
* for the scenario when the text could be too long
*/
public function checkClip():Void
{
var clipSize:Int = 290;
var clipType:Int = 0;
if (ranking.visible == true) clipType += 1;
if (favIcon.visible == true) clipType = 2;
if (ranking.visible)
{
favIconBlurred.x = this.x + 370;
favIcon.x = favIconBlurred.x;
clipType += 1;
}
else
{
favIconBlurred.x = favIcon.x = this.x + 405;
}
if (favIcon.visible) clipType += 1;
switch (clipType)
{
case 2:
clipSize = 220;
clipSize = 210;
case 1:
clipSize = 255;
clipSize = 245;
}
songText.clipWidth = clipSize;
}
@@ -371,6 +371,33 @@ class MainMenuState extends MusicBeatState
}
});
}
if (FlxG.keys.pressed.CONTROL && FlxG.keys.pressed.ALT && FlxG.keys.pressed.SHIFT && FlxG.keys.justPressed.R)
{
// Give the user a hypothetical overridden score,
// and see if we can maintain that golden P rank.
funkin.save.Save.instance.setSongScore('tutorial', 'easy',
{
score: 1234567,
tallies:
{
sick: 0,
good: 0,
bad: 0,
shit: 1,
missed: 0,
combo: 0,
maxCombo: 0,
totalNotesHit: 1,
totalNotes: 10,
}
});
}
if (FlxG.keys.pressed.CONTROL && FlxG.keys.pressed.ALT && FlxG.keys.pressed.SHIFT && FlxG.keys.justPressed.E)
{
funkin.save.Save.instance.debug_dumpSave();
}
#end
if (FlxG.sound.music != null && FlxG.sound.music.volume < 0.8)
+16 -2
View File
@@ -28,6 +28,8 @@ class ControlsMenu extends funkin.ui.options.OptionsState.Page
[NOTE_UP, NOTE_DOWN, NOTE_LEFT, NOTE_RIGHT],
[UI_UP, UI_DOWN, UI_LEFT, UI_RIGHT, ACCEPT, BACK],
[CUTSCENE_ADVANCE],
[FREEPLAY_FAVORITE, FREEPLAY_LEFT, FREEPLAY_RIGHT],
[WINDOW_FULLSCREEN, WINDOW_SCREENSHOT],
[VOLUME_UP, VOLUME_DOWN, VOLUME_MUTE],
[DEBUG_MENU, DEBUG_CHART]
];
@@ -108,6 +110,18 @@ class ControlsMenu extends funkin.ui.options.OptionsState.Page
headers.add(new AtlasText(0, y, "CUTSCENE", AtlasFont.BOLD)).screenCenter(X);
y += spacer;
}
else if (currentHeader != "FREEPLAY_" && name.indexOf("FREEPLAY_") == 0)
{
currentHeader = "FREEPLAY_";
headers.add(new AtlasText(0, y, "FREEPLAY", AtlasFont.BOLD)).screenCenter(X);
y += spacer;
}
else if (currentHeader != "WINDOW_" && name.indexOf("WINDOW_") == 0)
{
currentHeader = "WINDOW_";
headers.add(new AtlasText(0, y, "WINDOW", AtlasFont.BOLD)).screenCenter(X);
y += spacer;
}
else if (currentHeader != "VOLUME_" && name.indexOf("VOLUME_") == 0)
{
currentHeader = "VOLUME_";
@@ -123,10 +137,10 @@ class ControlsMenu extends funkin.ui.options.OptionsState.Page
if (currentHeader != null && name.indexOf(currentHeader) == 0) name = name.substr(currentHeader.length);
var label = labels.add(new AtlasText(150, y, name, AtlasFont.BOLD));
var label = labels.add(new AtlasText(100, y, name, AtlasFont.BOLD));
label.alpha = 0.6;
for (i in 0...COLUMNS)
createItem(label.x + 400 + i * 300, y, control, i);
createItem(label.x + 550 + i * 400, y, control, i);
y += spacer;
}
+8 -15
View File
@@ -25,6 +25,8 @@ class OptionsState extends MusicBeatState
override function create():Void
{
persistentUpdate = true;
var menuBG = new FlxSprite().loadGraphic(Paths.image('menuBG'));
var hsv = new HSVShader();
hsv.hue = -0.6;
@@ -55,8 +57,6 @@ class OptionsState extends MusicBeatState
setPage(Controls);
}
// disable for intro transition
currentPage.enabled = false;
super.create();
}
@@ -86,13 +86,6 @@ class OptionsState extends MusicBeatState
}
}
override function finishTransIn()
{
super.finishTransIn();
currentPage.enabled = true;
}
function switchPage(name:PageName)
{
// TODO: Animate this transition?
@@ -266,11 +259,11 @@ class OptionsMenu extends Page
#end
}
enum PageName
enum abstract PageName(String)
{
Options;
Controls;
Colors;
Mods;
Preferences;
var Options = "options";
var Controls = "controls";
var Colors = "colors";
var Mods = "mods";
var Preferences = "preferences";
}
+2 -1
View File
@@ -387,6 +387,7 @@ class StoryMenuState extends MusicBeatState
function changeLevel(change:Int = 0):Void
{
var currentIndex:Int = levelList.indexOf(currentLevelId);
var prevIndex:Int = currentIndex;
currentIndex += change;
@@ -417,7 +418,7 @@ class StoryMenuState extends MusicBeatState
}
}
FunkinSound.playOnce(Paths.sound('scrollMenu'), 0.4);
if (currentIndex != prevIndex) FunkinSound.playOnce(Paths.sound('scrollMenu'), 0.4);
updateText();
updateBackground(previousLevelId);
+7
View File
@@ -265,6 +265,13 @@ class TitleState extends MusicBeatState
if (FlxG.keys.pressed.DOWN) FlxG.sound.music.pitch -= 0.5 * elapsed;
#end
#if desktop
if (FlxG.keys.justPressed.ESCAPE)
{
Sys.exit(0);
}
#end
Conductor.instance.update();
/* if (FlxG.onMobile)
+1
View File
@@ -19,6 +19,7 @@ import haxe.ui.containers.dialogs.Dialogs.FileDialogExtensionInfo;
class FileUtil
{
public static final FILE_FILTER_FNFC:FileFilter = new FileFilter("Friday Night Funkin' Chart (.fnfc)", "*.fnfc");
public static final FILE_FILTER_JSON:FileFilter = new FileFilter("JSON Data File (.json)", "*.json");
public static final FILE_FILTER_ZIP:FileFilter = new FileFilter("ZIP Archive (.zip)", "*.zip");
public static final FILE_FILTER_PNG:FileFilter = new FileFilter("PNG Image (.png)", "*.png");
+1 -1
View File
@@ -92,7 +92,7 @@ class WindowUtil
});
openfl.Lib.current.stage.addEventListener(openfl.events.KeyboardEvent.KEY_DOWN, (e:openfl.events.KeyboardEvent) -> {
for (key in PlayerSettings.player1.controls.getKeysForAction(FULLSCREEN))
for (key in PlayerSettings.player1.controls.getKeysForAction(WINDOW_FULLSCREEN))
{
if (e.keyCode == key)
{
@@ -103,7 +103,7 @@ class ScreenshotPlugin extends FlxBasic
public function hasPressedScreenshot():Bool
{
return PlayerSettings.player1.controls.SCREENSHOT;
return PlayerSettings.player1.controls.WINDOW_SCREENSHOT;
}
public function updatePreferences():Void