Compare commits

...
406 Commits
Author SHA1 Message Date
Cameron Taylor 3746545452 update changelog for 0.5.2
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-10-11 22:06:07 -04:00
Cameron Taylor b4c48893bc more small little changelog template stuff 2024-10-11 22:01:19 -04:00
AbnormalandGitHub a42240e6a5 docs: Delete Modding.md since we have a separate modding documentation (#3651) 2024-10-11 19:24:41 -04:00
Cameron Taylor 91b4544f7e docs(changelog): create a git cliff template for easier changelog stuff 2024-10-11 19:22:57 -04:00
Cameron Taylor 9c8ba2c053 shader fix for title screen doh 2024-10-10 16:29:05 -04:00
Cameron Taylor 19abcb5009 bump version to 0.5.2 2024-10-10 13:58:11 -04:00
Cameron Taylor 1189c226ee some selection shader stuff in progress 2024-10-10 13:28:00 -04:00
Cameron Taylor 097dbf5bb4 feat: Added InverseDotsShader that emulates flash selections 2024-10-10 13:28:00 -04:00
Cameron Taylor 8890cbf270 pixel perfect mouse check rather than hitbox 2024-10-10 13:28:00 -04:00
Cameron Taylor 623985a2cc mac keyboard shortcuts on stage editor 2024-10-10 13:28:00 -04:00
Cameron Taylor 8cd7f2a5b1 stage editor ui files 2024-10-10 13:28:00 -04:00
KoloandCameron Taylor 0a5419d7fc the stage editor shit 2024-10-10 13:28:00 -04:00
lemz1andCameron Taylor b2647fe09f fix: disable flickering when changing FPS in the options menu 2024-10-10 13:01:39 -04:00
Kn1ghtNightandCameron Taylor e66290c55f fix: anti alias / smooth the volume sound tray 2024-10-08 14:29:03 -04:00
Eric 31d1b3e246 Finish the sentence. 2024-10-08 14:15:30 -04:00
HundrecandEric 880615e707 Remove extra asterisks in Funkin' Debug Hotkeys.md
Those stars might have been indicators for something, but I don't see any note related to them.
2024-10-08 14:15:30 -04:00
HundrecandEric 7d5d80d515 Fix typos in CODESTYLE.md 2024-10-08 14:15:30 -04:00
HundrecandEric 6848815e80 Adjust line count labeler comment 2024-10-08 14:15:30 -04:00
HundrecandEric 5d10bb9f54 Rename troubleshooting.md to fix link in COMPILING.md 2024-10-08 14:15:30 -04:00
HundrecandEric f6a5a9d8ce Wait now it should do it 2024-10-08 14:15:30 -04:00
HundrecandEric 9695e79134 Label me Docs 2024-10-08 14:15:30 -04:00
AbnormalandEric 3267c61258 blacklist one additional class 2024-10-08 14:02:40 -04:00
KoloandCameron Taylor 903b3fc599 fix: Don't restart the FreeplayState song preview when changing the difficulty within the same variation
pulled from the wrong branch, oops!

last update i hope

wrong spellings im gonna kms
2024-10-08 13:56:14 -04:00
Victor GandGitHub 0d60929f18 Fix window not closing when specified 2024-10-05 21:24:24 +02:00
EliteMasterEric bc546e86aa Clean up documentation in StrumlineNote 2024-10-05 13:34:08 -04:00
EliteMasterEric de5cca1120 Add some cutom logic to determine if this.active is needed. 2024-10-05 13:34:08 -04:00
DaWaterMaloneandEric 3aa4591bab Fixed Modded StrumlineNote Sprite Looping Animation
Within the playStatic function on the StrumlineNote.hx, setting this.active = true; will fix looping animations for modded in StrumlineNote sprites. Leaving this.active = false; will stop any modded StrumlineNote sprite animation when the player or opponent hits chart notes.
2024-10-05 13:34:08 -04:00
EliteMasterEricandCameron Taylor bc8f506193 Update changelog 2024-10-04 12:41:45 -04:00
EliteMasterEricandCameron Taylor f52472a476 fix: Exiting the chart editor doesn't crash the game anymore 2024-10-04 12:41:45 -04:00
Cameron Taylor ab5bda3ee5 fix: Character Select cursor moves properly at lower framerates 2024-10-04 12:32:36 -04:00
amyspark-ng ✨andCameron Taylor 777978f5a5 fix: stopped allowing F1 to create more than one help dialog window in the Charting Editor 2024-10-04 12:17:36 -04:00
EliteMasterEricandCameron Taylor 711e0a6b75 fix: Main menu music doesn't cut out when switching states anymore. 2024-10-04 12:15:20 -04:00
EliteMasterEricandCameron Taylor 1fde59f999 fix: The dialog now shows up on the animation debugger view 2024-10-04 12:15:20 -04:00
BurgerballsandCameron Taylor 165ad60155 fix: center preloader 'fnf' and 'dsp' text so it doesn't clip anymore 2024-10-04 12:09:33 -04:00
Cameron Taylor d2e29879fe fix: Song.getFirstValidVariation() now properly takes into account multiple variations/difficulty input
freeplay implement for NEW song stuff w/ assets submod

save data crap and crud

rank icon fixes for fixed pico menu
2024-10-04 12:01:45 -04:00
Cameron Taylor 4fa9a0daaa docs: add additional variation input parameter to Save.hasBeatenSong() to allow usage of the function by inputting a variation id 2024-10-04 12:01:45 -04:00
Cameron Taylor c0314c85ec fix(freeplay)!: Proper variation / difficulty loading for Freeplay Menu
Previously the game would load variations in a `variation-difficulty` string format, but now we map it out better and filter it based on that, rather than messing around with suffixes and whatnot. If you have a mod that depended on the functionality of the `variation-difficulty` format, you should accomodate that functionality in another way

re-add freeplay song preview

song names and icons implemented again

implement the scoring rank, bpm, and difficulty crud

albumId loading fix
2024-10-04 12:01:45 -04:00
Cameron Taylor f862fb2c3e load in data for pico songs 2024-10-04 12:01:45 -04:00
Cameron Taylor d7f5070317 properly display pico vs darnell songs along with pico mixes 2024-10-04 12:01:45 -04:00
Cameron Taylor 1d2bd61119 fix: picos songs properly load on freeplay 2024-10-04 12:01:45 -04:00
EliteMasterEricandHundrec a4ed55721f Fix duplicate combo counter on combo break
Co-authored-by: Eric <ericmyllyoja@gmail.com>
Co-authored-by: Hundrec <hundrecard@gmail.com>
2024-10-04 08:09:18 -04:00
EricandGitHub f1b6e6c4e4 Merge pull request #3537 from afreetoplaynoob/patch-1
Enhancement: Properly format the chart editor playbar
2024-10-03 23:55:33 -04:00
Cameron Taylor 29b6763290 fix(debug): no more fullscreening when typing "F" in the flixel debugger console 2024-10-03 22:49:07 -04:00
KoloandCameron Taylor 410cfe972d fix: fix the user song offsets being applied incorrectly 2024-10-03 21:25:34 -04:00
lemzandCameron Taylor 39b1a42cfe fix: fix crash in LatencyState when exiting / cleaning up state data 2024-10-03 21:25:34 -04:00
EliteMasterEricandCameron Taylor b0b73c8399 fix: Add additional classes to Polymod Blacklist 2024-10-03 21:25:34 -04:00
Hyper_andCameron Taylor 5141ac13df Remove duplicate import 2024-10-03 21:25:34 -04:00
Victor GandCameron Taylor 45a5160b06 Fix PlayState compilation crashes 2024-10-03 21:25:34 -04:00
EliteMasterEricandCameron Taylor 89ee33e9b9 Update changelog for v0.5.1
Fix typo and start changelog for next hotfix
2024-10-03 21:25:34 -04:00
Cartridge-ManandCameron Taylor 4b54118731 docs: Added modding docs link in readme
Wrong Link, Whoops!
2024-10-03 21:25:34 -04:00
ACrazyTownandCameron Taylor dbf66ac250 fix: Stop allowing inputs after selecting a character 2024-10-03 21:25:34 -04:00
afreetoplaynoobandGitHub 79eb7d633c Properly format the chart editor playbar
Minor change, but this makes the song time in the chart editor follow a proper time format.
2024-10-02 08:32:21 -03:00
EricandGitHub f61789e453 Merge pull request #3509 from FunkinCrew/bugfix/git-submodule-url
Fix an issue where .gitmodules would point to the wrong repository
2024-10-01 02:31:11 -04:00
EliteMasterEric 1da0da249d Fix an issue where .gitmodules would point to the wrong repository 2024-10-01 02:30:26 -04:00
Cameron Taylor 6cd1dec3d4 Merge branch 'main' into develop 2024-09-30 18:07:26 -04:00
HundrecandCameron Taylor 2175beaa65 style: Fix some misspellings and grammar in code documentation
fowl -> foul, among other things
2024-09-30 18:06:38 -04:00
HundrecandCameron Taylor 6df80ba69d style: Fix some misspellings and grammar in code documentation
fowl -> foul, among other things
2024-09-30 17:49:25 -04:00
HundrecandCameron Taylor 67f7b638fb docs(github): Improvements to Github Issues templates 2024-09-30 17:49:25 -04:00
HundrecandCameron Taylor 399869cdcc docs(github): Improvements to Github Issues templates 2024-09-30 17:41:50 -04:00
gamerbrossandCameron Taylor c5a76cf1d5 another little fix 2024-09-30 17:17:20 -04:00
gamerbrossandCameron Taylor 30a9887136 Fix bf changing twice on enter 2024-09-30 17:17:20 -04:00
gamerbrossandCameron Taylor 9324359d2f Some fixes to Character Select 2024-09-30 17:17:20 -04:00
Cameron Taylor 4a9ad53695 submods 2024-09-30 12:50:24 -04:00
Cameron Taylor 5d013a1aa7 submods 2024-09-30 12:49:44 -04:00
Cameron Taylor 0971a0bb4c music persist fixes for title screen
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-09-30 10:53:27 -04:00
Cameron Taylor 136e7358b1 bump project version 2024-09-30 10:40:19 -04:00
Cameron TaylorandGitHub 84ff83759f Merge pull request #805 from FunkinCrew/bugfix/two-fixes
[PUBLIC PR] Two bug fixes
2024-09-30 10:33:20 -04:00
Cameron TaylorandGitHub 9d3131bc8d Merge branch 'rewrite/master' into bugfix/two-fixes 2024-09-30 10:25:58 -04:00
EliteMasterEric 90f6f80a71 Fix issues with animation offsets breaking on restart on characters with high offstes. 2024-09-29 07:06:11 -04:00
EliteMasterEric e3ed153a7c Add a "persist" argument to FunkinSound to prevent Results music from continuing in Freeplay. 2024-09-29 06:59:49 -04:00
Cameron Taylor 66781181fa Merge branch 'rewrite/master' of github.com:FunkinCrew/Funkin-secret into rewrite/master 2024-09-28 12:37:24 -04:00
Cameron Taylor 93039c3d65 intro text stuff 2024-09-28 12:37:12 -04:00
Cameron TaylorandGitHub a1370157a4 Merge pull request #803 from FunkinCrew/abnormalpoof/stage-prop-flipx
[PUBLIC PR] Add flipX and flipY parameters to Stage props
2024-09-28 12:30:57 -04:00
EliteMasterEric 7ce7d7839e Update stage data version after adding new values. 2024-09-28 09:51:41 -04:00
EliteMasterEric 042dfb7442 Merge branch 'rewrite/master' into abnormalpoof/stage-prop-flipx 2024-09-28 09:18:41 -04:00
Cameron Taylor 7a3d983bba Merge branch 'feature/discord-rpc-resurrected' into rewrite/master 2024-09-27 17:47:59 -04:00
Cameron Taylor ac3e2b2560 discord api mac 2024-09-27 17:45:54 -04:00
Cameron Taylor db0944712d Merge branch 'rewrite/master' into bugfix/mod-dev-fixes 2024-09-27 17:27:59 -04:00
Cameron Taylor fb1b3cc1cd Merge branch 'bugfix/week-7-pico-stress' into rewrite/master 2024-09-27 17:00:54 -04:00
Cameron Taylor 007a32dc9c assets submod 2024-09-27 17:00:31 -04:00
Cameron Taylor 9a57762a9c Merge remote-tracking branch 'origin/bugfix/web-screenshots' into rewrite/master 2024-09-27 16:56:12 -04:00
Cameron TaylorandGitHub 06fee5599c Merge pull request #796 from FunkinCrew/lemz1/completion-fix
[PUBLIC PR] Fix an issue where getting the same rank (but a different clear %) will override the rating
2024-09-27 16:50:53 -04:00
AbnormalPoof cd2b458da2 add flipx and flipy 2024-09-27 15:15:35 -05:00
EliteMasterEric 8a8160dfe7 Update assets submodule 2024-09-27 14:26:46 -04:00
EliteMasterEric 5630e74584 Rework Freeplay variation handling... again. 2024-09-27 14:26:08 -04:00
EliteMasterEric 067f52ca91 Kill intro music when leaving Results state. 2024-09-27 14:25:32 -04:00
EliteMasterEric 2eb5208c46 Hide the pixel icon in the Results screen when there's no matching character 2024-09-27 14:25:17 -04:00
EliteMasterEric b5f3996236 Properly sort difficulties/variations. Validate variation IDs (alphanumeric only) 2024-09-27 12:21:17 -04:00
EliteMasterEric 378179d1f7 Change crash keybind to Ctrl-Alt-Shift-L 2024-09-27 12:20:36 -04:00
EliteMasterEric f1c1e63375 Use more dynamic API version rules for checking mod versions. 2024-09-27 12:19:41 -04:00
EricandGitHub ec749c7157 Merge pull request #3465 from AbnormalPoof/patch-5
chore: Add a link to `credits.json`
2024-09-27 03:56:08 -04:00
EliteMasterEric e321861b9f Fix an issue where animations wouldn't loop properly on AnimateAtlasCharacters. 2024-09-27 03:09:59 -04:00
EliteMasterEric c4ed31b246 Fix a bug where force-ending a song could occasionally try to draw destroyed sprites. 2024-09-27 02:52:01 -04:00
EliteMasterEric 2053f0d691 Fix a missing import in Pico (Blazin) 2024-09-27 02:51:31 -04:00
AbnormalandGitHub ffd76963bd Update README.md 2024-09-26 21:04:23 +00:00
Cameron TaylorandGitHub 4669ac03a9 Merge pull request #795 from FunkinCrew/nebulazorua/classic-camera-fix
[PUBLIC PR] Fix an issue where the Classic FocusCamera event would cause the camera to snap in place
2024-09-25 19:25:45 -04:00
Cameron TaylorandGitHub cb16a8d55e Merge pull request #793 from FunkinCrew/cyn0x8/module-ondestroy-fix
[PUBLIC PR] Fix an issue when interacting with modules during onDestroy()
2024-09-25 19:24:48 -04:00
Cameron TaylorandGitHub e1aa25a249 Merge pull request #791 from FunkinCrew/actions-manual-output
Allow for manual configuration + artifact saving for Github Actions
2024-09-25 19:24:14 -04:00
EliteMasterEric 67126b33fa Suppress some spammy log calls 2024-09-25 10:02:18 -04:00
EliteMasterEric a84ae6069e Fix an issue where Pico wouldn't shoot in Stress 2024-09-25 10:02:11 -04:00
EricandGitHub c3f982b32c Merge pull request #3435 from NotHyper-474/patch/upgrade-example-mods
Chore: Upgrade Example Mods to latest API version
2024-09-25 08:52:55 -04:00
EricandGitHub 67bce85343 Merge branch 'develop' into patch/upgrade-example-mods 2024-09-25 08:51:57 -04:00
EliteMasterEric 998bbb213a Merge branch 'rewrite/master' into nebulazorua/classic-camera-fix 2024-09-25 08:48:20 -04:00
EliteMasterEric 8d02a3f984 A bunch of controls fixes 2024-09-25 08:39:57 -04:00
EricandGitHub 85763813ae Merge branch 'develop' into patch-2 2024-09-25 07:38:14 -04:00
EricandGitHub b29296288e Merge pull request #3438 from TechnikTil/fix-develop-branch
[BUGFIX] Fix develop branch
2024-09-25 06:55:39 -04:00
EliteMasterEric 5693d626b5 Update so that album art works. 2024-09-25 03:58:43 -04:00
EliteMasterEric 84d8c02920 Update art repo 2024-09-25 00:39:37 -04:00
EliteMasterEric ec9b5db210 Create shader for Week 5 once and reuse it rather than recreating it every frame. 2024-09-23 21:41:48 -04:00
Cameron Taylor 7e75308423 capitalization hxCodec 2024-09-23 18:51:48 -04:00
Cameron Taylor 073dbaa023 Merge remote-tracking branch 'origin/bugfix/input-offsets-crash' into rewrite/master 2024-09-23 18:48:22 -04:00
Cameron Taylor f6697f8ddc Merge branch 'bugfix/html5-video-error' into rewrite/master 2024-09-23 18:47:48 -04:00
Cameron Taylor 78d0ad9956 Merge remote-tracking branch 'origin/feature/tracy' into rewrite/master 2024-09-23 17:41:01 -04:00
EliteMasterEric 52f5c24f96 Add frame market support, and enable on demand tracing. 2024-09-23 16:09:34 -04:00
Cameron TaylorandGitHub 252b87c451 Merge pull request #763 from FunkinCrew/feature/tracy
Add Tracy support for performance profiling
2024-09-23 15:03:33 -04:00
EliteMasterEric 0389cd6760 Fix a compile issue on HTML5 with video sprites 2024-09-23 14:45:12 -04:00
Cameron Taylor 29c860ed43 Merge branch 'pico-burp-fix' into rewrite/master 2024-09-23 13:12:00 -04:00
Cameron Taylor a86cfded2a assets submod 2024-09-23 13:11:36 -04:00
Cameron Taylor 3d5482660c Merge branch 'week2-death-fix' into rewrite/master 2024-09-23 13:10:52 -04:00
Cameron Taylor 299f4840cf assets submod 2024-09-23 13:10:44 -04:00
Cameron Taylor 8749372725 Merge remote-tracking branch 'origin/docs/updated-changelog' into rewrite/master 2024-09-23 13:09:52 -04:00
Cameron Taylor 50f65177cb Merge branch 'rewrite/master' into spirit-trail 2024-09-23 13:09:03 -04:00
Cameron Taylor 1c2a403dea Merge branch 'rewrite/master' into kadedev/fix-audio-offsets 2024-09-23 13:07:32 -04:00
FabsTheFabs 84ce43eff7 assets submod 2024-09-23 03:46:14 +01:00
Til Tjardes cca997b724 fix develop branch cuz git is on crack 2024-09-22 17:59:18 -06:00
Hyper_ 298bc9496b Upgrade API versions 2024-09-22 18:05:25 -03:00
FabsTheFabs 2edb318901 assets submod 2024-09-22 20:11:37 +01:00
Cameron TaylorandGitHub 15bce04a50 Merge pull request #783 from FunkinCrew/nothyper474/chart-selection
[PUBLIC PR] Chart Editor: Fi bug where selecting area left of the chart would select the player's left notes
2024-09-22 13:30:32 -04:00
Cameron TaylorandGitHub 5c6d72d8d5 Merge pull request #782 from FunkinCrew/cyn0x8/funkinsound-persist
[PUBLIC PR] If FunkinSound.persist is true, don't destroy it when switching states
2024-09-22 13:30:17 -04:00
Cameron TaylorandGitHub 1937529c1f Merge pull request #779 from FunkinCrew/cutscene-volume-math-fix
proper audio scaling for hxcodec / desktop
2024-09-22 13:29:59 -04:00
EliteMasterEric 0bf1bead03 Fix some issues causing the Input Offsets view to crash on web. 2024-09-22 12:14:15 -04:00
Cameron Taylor 58508755f9 revert extra flxtrail function 2024-09-22 10:57:00 -04:00
lemzandGitHub bcb7bc4cbc Merge branch 'develop' into completion-fix 2024-09-22 16:12:17 +02:00
EliteMasterEric 28d50a4567 Merge branch 'rewrite/master' into nothyper474/chart-selection 2024-09-22 01:10:56 -04:00
EricandGitHub 6a113addca Merge branch 'develop' into bugfix/chart-selection 2024-09-22 01:09:37 -04:00
EliteMasterEric c7238fcfd1 Stop the volume tray from hiding as long as the game is muted 2024-09-22 00:45:30 -04:00
EliteMasterEric 29a7005d8a Fix a bug where you can hear the game a little when setting the volume to 0 ticks 2024-09-22 00:44:57 -04:00
EliteMasterEric d23ae7c55b Merge remote-tracking branch 'public/develop' into docs/updated-changelog 2024-09-21 23:31:25 -04:00
EliteMasterEric d11acfd83b Merge remote-tracking branch 'public/main' into docs/updated-changelog 2024-09-21 23:31:21 -04:00
EricandGitHub 754e2edbeb Merge pull request #3420 from JVNpixels/patch-4
[DOCUMENTATION/BUG-FIX] Fix changelog for v0.5.0
2024-09-21 23:12:57 -04:00
EliteMasterEric 5548fd52f4 Update default mod so it actually loads 2024-09-21 20:33:59 -04:00
EliteMasterEric 6c743b3b89 Remove some spammy trace calls. 2024-09-21 20:33:51 -04:00
Cameron Taylor e978f5df76 fix for spirit's trail 2024-09-21 16:32:44 -04:00
JVN-PixelsandGitHub 3601b50e32 Update CHANGELOG.md 2024-09-21 10:29:08 -07:00
JVN-PixelsandGitHub e535ae4ca6 Change line 12
The songs from Weekend 1 have moved line
2024-09-21 10:19:00 -07:00
JVN-PixelsandGitHub ec8ecc6163 Update CHANGELOG.md 2024-09-21 10:14:09 -07:00
JVN-PixelsandGitHub 01e9888839 Update CHANGELOG.md
Fixes changelog for the 0.5.0 update!
2024-09-21 10:07:41 -07:00
EliteMasterEric 2c73b241e8 Rework offset+vocal sync handling to fix the "Swing Mode" bug 2024-09-21 06:33:47 -04:00
EricandGitHub 3ef238a2f6 Merge pull request #3282 from TechnikTil/playsound-typo
[DOCUMENTATION] playSound Typo in NoteScriptEvent
2024-09-21 05:45:35 -04:00
Cameron Taylor 690f3090b7 proper audio scaling for hxcodec / desktop 2024-09-20 20:11:12 -04:00
Cameron Taylor a41d3033d5 small Assets -> OpenFLAssets fix 2024-09-20 18:20:40 -04:00
Cameron Taylor d02e834460 Merge branch 'rewrite/master' into abnormalpoof/assets-getpath 2024-09-20 18:13:13 -04:00
Cameron Taylor 2a6eadcbff Merge branch 'justkolosaki/char-select-gf' into rewrite/master 2024-09-20 18:11:14 -04:00
Cameron Taylor 78cde16af2 assets submod 2024-09-20 18:10:47 -04:00
Cameron TaylorandGitHub 4946e7f4c7 Merge pull request #765 from FunkinCrew/lethrial/fps-counter-bugfix
[PUBLIC PR] Fix bug where FPS counter would display even if Debug Display option was disabled
2024-09-20 16:52:02 -04:00
Cameron Taylor 8a9b1b4727 Merge branch 'bugfix/cocoa-erect-stacked-note' into rewrite/master 2024-09-20 16:51:39 -04:00
Cameron Taylor 5f64d89d0e assets submod 2024-09-20 16:51:21 -04:00
EliteMasterEric 143ef88e6f Update assets submodule 2024-09-20 03:42:48 -04:00
Cameron Taylor cb4ac352e6 Merge branch 'lemz1/fps-setting' into rewrite/master 2024-09-20 00:29:19 -04:00
Cameron Taylor ccb2e1889f Merge branch 'lemz1/substate-event-dispatch' into rewrite/master 2024-09-20 00:25:53 -04:00
Cameron Taylor 9045ae2d9c assets submod 2024-09-20 00:25:38 -04:00
Cameron TaylorandGitHub e3a13bee8c Merge pull request #773 from FunkinCrew/process-cleanup
close sys.io.Process stuff when we're done with them
2024-09-20 00:24:10 -04:00
Cameron TaylorandGitHub 426bff3bf5 Merge pull request #768 from FunkinCrew/kadedev/addcharacter-type
[PUBLIC PR] Move characterType assignment to Stage.addCharacter
2024-09-20 00:23:53 -04:00
EricandGitHub 249ff69f9f Merge branch 'rewrite/master' into lemz1/fps-setting 2024-09-20 00:05:17 -04:00
Cameron Taylor 4af4c2defc Merge branch 'lemz1/fps-setting' into rewrite/master 2024-09-19 23:56:04 -04:00
Cameron TaylorandGitHub 76bf5df57f Merge branch 'rewrite/master' into lemz1/fps-setting 2024-09-19 23:34:51 -04:00
Cameron TaylorandGitHub c46483722e Merge pull request #767 from FunkinCrew/techniktil/chart-editor-icons
[PUBLIC PR] [FUNK-717] Fix pixel icons in the chart editor
2024-09-19 23:31:40 -04:00
Cameron TaylorandGitHub 69bcd0834e Merge branch 'rewrite/master' into techniktil/chart-editor-icons 2024-09-19 23:31:26 -04:00
Cameron TaylorandGitHub 29e89c8acb Merge branch 'rewrite/master' into actualmandm/char-select-crash 2024-09-19 22:50:18 -04:00
Cameron Taylor 778ce54047 Merge branch 'rewrite/master' of github.com:FunkinCrew/Funkin-secret into rewrite/master 2024-09-19 22:49:59 -04:00
Cameron Taylor 47ed9d7fb2 Merge branch 'rewrite/master' into dombomb64/note-style-scaling 2024-09-19 22:35:16 -04:00
Cameron TaylorandGitHub 00c1428c0f Merge pull request #774 from FunkinCrew/abnormalpoof/opening-urls
[PUBLIC PR] Fix Merch button being missing from the main menu
2024-09-19 22:31:44 -04:00
Cameron TaylorandGitHub 0b908b3cab Merge branch 'rewrite/master' into abnormalpoof/opening-urls 2024-09-19 22:31:12 -04:00
Cameron Taylor 50de041251 Merge branch 'public-release/develop' into rewrite/master 2024-09-19 22:11:05 -04:00
Kade f9186b67a7 less tolerance 2024-09-19 17:00:52 -07:00
Kade a8aeae4f7f do not include offset in vocal (they're offset by inst)
Fix a tiny little issue with vocal resync @ start
2024-09-19 14:26:18 -07:00
Kade 4d73e0cc47 fix some interesting issues with this
redundant trace removal
2024-09-19 14:26:18 -07:00
Kade b03c8a9cf8 Limit the song time to 0 and the songs max length
use the new bool to tell if we should start the song

add a public static bool to countdown: finished
2024-09-19 14:26:18 -07:00
EliteMasterEricandCameron Taylor 3cbba8ba29 Resolve merge issues. 2024-09-19 17:16:31 -04:00
EliteMasterEric bfee63f588 Update hmm.json 2024-09-19 11:15:56 -04:00
EliteMasterEric 35aa8731d0 Better status messages, buttons, updated album art, basic chart editor support 2024-09-19 11:13:05 -04:00
EliteMasterEric 8fd84f9d13 Functioning Discord Rich Presence! 2024-09-19 10:03:16 -04:00
EliteMasterEric 25cafe7550 Resolve merge issues. 2024-09-19 04:22:05 -04:00
EliteMasterEric 7d6fa19ff4 Merge remote-tracking branch 'secret/rewrite/master' into lemz1/substate-event-dispatch 2024-09-19 04:20:24 -04:00
EliteMasterEric 9f0bc2bd52 Refactor char select GF data handling. 2024-09-19 04:16:40 -04:00
EricandGitHub d81e09b1c3 Merge branch 'rewrite/master' into abnormalpoof/opening-urls 2024-09-19 03:46:46 -04:00
EricandGitHub a128afedf7 Merge pull request #772 from FunkinCrew/results-sfx-fix
Results Percentage Sound Spam Fix
2024-09-19 03:24:52 -04:00
Cameron Taylor 472d41a893 close sys.io.Process stuff when we're done with them 2024-09-18 16:15:10 -04:00
Cameron Taylor 215e20cabe Merge remote-tracking branch 'origin/docs/issue-management-actions' into rewrite/master 2024-09-18 15:25:51 -04:00
Cameron Taylor 3c30575727 Merge branch 'kadedev/chart-editor-fixes' into rewrite/master 2024-09-18 15:23:07 -04:00
Cameron Taylor f30c0cff49 Merge branch 'feature/gold-perfect-anim-for-modders' into rewrite/master 2024-09-18 15:20:38 -04:00
Cameron Taylor fc6e194d20 assets submod 2024-09-18 15:20:15 -04:00
Cameron Taylor 35005df32a Merge branch 'feature/pico-character-script' into rewrite/master 2024-09-18 15:17:37 -04:00
Cameron Taylor 62149aea39 assets submod 2024-09-18 15:16:56 -04:00
Cameron TaylorandGitHub fdddfba3be Merge pull request #760 from FunkinCrew/bugfix/pico-mix-highscores
Fix bugs with highscore display in Freeplay (FUNK-714)
2024-09-18 15:14:46 -04:00
Cameron Taylor ab3b976f3c fix rounding for sound results sfx 2024-09-18 15:07:15 -04:00
lemzandGitHub e02bb9b21c Merge branch 'develop' into completion-fix 2024-09-18 18:19:31 +02:00
lemzandGitHub afcb57aaf0 Merge branch 'develop' into substate-dispatch-event-fix 2024-09-18 18:18:57 +02:00
KoloandGitHub 99657da1f9 accidentally also put the save changes oops 2024-09-18 17:46:13 +02:00
KoloandGitHub 3bb981adb0 Update CharSelectGF.hx 2024-09-18 17:32:37 +02:00
KoloandGitHub 50a5304ad4 Update PlayerData.hx 2024-09-18 17:30:23 +02:00
KoloandGitHub a4b59d14bf applySongRank fix
fixes the bug with the percent being overriden when the song has the same letter rank but lower percent (eg. E Rank with 99% being overriden by E Rank with 93%)
2024-09-18 13:40:02 +02:00
EliteMasterEric 9d5cde0bf1 Update assets submodule 2024-09-18 06:48:45 -04:00
EliteMasterEric 5efbff044b Resolve merge issues 2024-09-18 06:32:06 -04:00
EliteMasterEric a469385cdb Resolve merge issues 2024-09-18 06:22:02 -04:00
EricandGitHub 970816592f Merge branch 'develop' into bugfix/charselect-crash 2024-09-18 06:20:44 -04:00
EliteMasterEric ba90a6abe0 Add behavior when setting status: rejected 2024-09-18 06:08:18 -04:00
EliteMasterEric d54dc6179a Add several new Github Actions for issue management 2024-09-18 06:02:13 -04:00
EliteMasterEric b5ed7f40d4 Remove redundant character type assignment 2024-09-18 05:24:57 -04:00
EliteMasterEric b28af79eb3 Fix build issues 2024-09-18 05:18:16 -04:00
EricandGitHub 5f563f0555 Merge branch 'develop' into chart-editor-icon-fix 2024-09-18 05:10:30 -04:00
EliteMasterEric 1beb21e57a Replace all instances of openfl/lime Assets with funkin.Assets 2024-09-18 05:04:32 -04:00
EliteMasterEric b6b2248aa3 Make funkin.Assets and funkin.Paths default imports for all scripts 2024-09-18 05:04:10 -04:00
EliteMasterEric d30fe61ca0 Add a bunch of other functions to funkin.Assets, and add documentation 2024-09-18 05:03:04 -04:00
EliteMasterEric 7b7d5deed5 Tweaks to framerate preference 2024-09-18 03:13:21 -04:00
EliteMasterEric 19e6029fb2 Fix some compilation errors 2024-09-18 03:13:10 -04:00
EliteMasterEric 2a5269c2a7 Disable on demand telemetry 2024-09-18 02:30:48 -04:00
EliteMasterEric f7fb640e52 Copy TracyProfiler from pull request 2024-09-18 02:29:11 -04:00
EliteMasterEric 119148acf0 Define for enabling/disabling log trace 2024-09-18 02:11:31 -04:00
EricandGitHub 598a3bea24 Merge branch 'develop' into fps-setting 2024-09-18 02:09:38 -04:00
EricandGitHub b03d320c12 Merge pull request #3139 from AbnormalPoof/patch-1
chore: Update ScriptedFunkinSprite.hx
2024-09-18 01:58:40 -04:00
EliteMasterEric 61d23b9985 Use branch of HXCPP 2024-09-17 20:56:54 -04:00
EliteMasterEric b70983a0e4 Build arguments for Tracy 2024-09-17 20:50:09 -04:00
Kade de07497ae3 Make addCharacter actually set the characters type 2024-09-17 17:29:12 -07:00
Lethrial ea9dab4b73 Update Main.hx 2024-09-18 00:25:20 +01:00
Michael f2b3f47e73 Disable input in CharSelect until stayFunky plays 2024-09-17 15:57:50 -07:00
dombomb64 6e33cac9ec ...Okay it wasn't that simple 2024-09-17 16:47:16 -04:00
EricandGitHub dab417b391 Merge branch 'rewrite/master' into kadedev/chart-editor-fixes 2024-09-17 16:15:02 -04:00
dombomb64 0706192cbe Fix note scaling with one simple trick! 2024-09-17 13:50:59 -04:00
Cameron Taylor 7fbbc5cf95 save artifacts on html5 and linux? 2024-09-17 04:48:30 -04:00
Cameron Taylor 4939b09fb0 manual build artifacts 2024-09-17 04:43:34 -04:00
AbnormalPoof aae7dcdada fix crash when opening urls 2024-09-16 23:35:23 -05:00
Til Tjardes e6525d0129 stop being on the kickstarter crack me 2024-09-16 20:44:29 -06:00
EricandGitHub 6efdbde8da Merge branch 'develop' into fps-setting 2024-09-16 22:09:54 -04:00
Til Tjardes b7c3f5ac9f Chart Editor Icons are fixed now! 2024-09-16 20:04:04 -06:00
EliteMasterEric 811caf6b70 Suppress a spammy log trace 2024-09-16 21:54:33 -04:00
EliteMasterEric d710318830 Update HaxeUI 2024-09-16 21:54:24 -04:00
EricandGitHub 1fc835494d Merge pull request #3020 from anysad/custom-popups-countdowns
[ENHANCEMENT] Custom Popups and Countdowns
2024-09-16 20:56:26 -04:00
EliteMasterEric 2e9223ec72 Merge remote-tracking branch 'origin/develop' into anysad/custom-popups-countdowns 2024-09-16 20:50:13 -04:00
Kade 9624b57e44 This does fix it now 2024-09-16 17:23:49 -07:00
Kade 7d2b946e9c depreciated screen X/Y to view X/Y 2024-09-16 17:13:14 -07:00
Kade 5a877a14a0 only show last two digits
digit
2024-09-16 17:13:13 -07:00
Kade 535ac0e528 add milliseconds to the playbar in charting state
remove laggy redundant traces

Revert "remove laggy redundant traces"

This reverts commit 204113840473dd5069f5d508d50e15e21104b45a.
2024-09-16 17:13:13 -07:00
EricandGitHub 35b5957715 Merge pull request #3007 from anysad/tutorial-hey-events
[CLEANUP] Softcode Tutorial HEY! events from code to JSON
2024-09-16 19:33:04 -04:00
EliteMasterEric e915b637c5 Merge remote-tracking branch 'origin/develop' into anysad/tutorial-hey-events 2024-09-16 19:09:58 -04:00
EricandGitHub f38a95bbf7 Merge branch 'develop' into fps-setting 2024-09-16 18:59:55 -04:00
EricandGitHub ebfce9f990 Merge pull request #2820 from gamerbross/bugfix/animation-editor
[ENHANCEMENT/BUGFIX] Few animation editor bugfixes and improvements
2024-09-16 18:48:50 -04:00
EricandGitHub 359e4b41e5 Merge branch 'develop' into bugfix/animation-editor 2024-09-16 18:48:33 -04:00
EricandGitHub b0c9365c56 Merge pull request #2942 from FlooferLand/new-settings-items
New settings widgets (Number, Checkbox, Enum)
2024-09-16 18:42:48 -04:00
EricandGitHub 65fddd95bb Merge branch 'develop' into new-settings-items 2024-09-16 18:42:43 -04:00
EricandGitHub f1d3ace247 Merge pull request #2925 from gamerbross/bugfix/character-danceevery
[BUGFIX] Implement `danceEvery` for Characters
2024-09-16 18:42:40 -04:00
EricandGitHub 9e90e67673 Merge branch 'develop' into bugfix/character-danceevery 2024-09-16 18:42:32 -04:00
EricandGitHub 3ce7cd6990 Merge pull request #2903 from AbnormalPoof/develop
[ENHANCEMENT] Enable auto-pause for Video Cutscenes
2024-09-16 18:42:20 -04:00
EricandGitHub d4cd2d031c Merge branch 'develop' into develop 2024-09-16 18:41:33 -04:00
EricandGitHub 081d2d8fd8 Merge pull request #2992 from gamerbross/bugfix/charteditor-liveinput-number-6
[BUGFIX + REFACTOR] ChartEditor Live Input
2024-09-16 18:40:24 -04:00
EricandGitHub 99f4d13e47 Merge branch 'develop' into bugfix/charteditor-liveinput-number-6 2024-09-16 18:40:12 -04:00
EricandGitHub 8cad10263e Merge branch 'develop' into bugfix/animation-editor 2024-09-16 18:37:35 -04:00
EricandGitHub 8470880e4a Merge pull request #2926 from gamerbross/tweak/funkinsound-playonce-return-value
[CODE TWEAK] `FunkinSound.playOnce` return the created sound
2024-09-16 18:36:53 -04:00
EricandGitHub 6bde7c34a0 Merge branch 'develop' into tweak/funkinsound-playonce-return-value 2024-09-16 18:36:45 -04:00
EricandGitHub 3ac10fb45c Merge pull request #2981 from gamerbross/bugfix/forced-sustaintrail-alpha
[BUGFIX] SustainTrail forced alpha
2024-09-16 18:35:31 -04:00
EricandGitHub fb0b277a9c Merge branch 'develop' into bugfix/forced-sustaintrail-alpha 2024-09-16 18:35:17 -04:00
EricandGitHub 519a6f3412 Merge pull request #2873 from JVNpixels/JVNPixels-story-menu-scrolling-fixed
[ENHANCEMENT]: Story Mode Menu Mouse Scrolling
2024-09-16 18:34:58 -04:00
EricandGitHub 27f700dd98 Merge branch 'develop' into JVNPixels-story-menu-scrolling-fixed 2024-09-16 18:34:43 -04:00
EricandGitHub f015976521 Merge pull request #2712 from gamerbross/bugfix/freeplay-difficulty-stack-overflow
[BUGFIX] Song with no "Normal" causes Stack Overflow
2024-09-16 18:34:06 -04:00
EricandGitHub 265039b025 Merge branch 'develop' into bugfix/freeplay-difficulty-stack-overflow 2024-09-16 18:33:57 -04:00
EricandGitHub 8c6cb72d47 Merge pull request #2986 from AppleHair/bugfix/cancel-menu-sound
[BUGFIX] Fixed `cancelMenu` sound not playing after switching state
2024-09-16 18:30:02 -04:00
EricandGitHub b3221c0e3f Merge branch 'develop' into bugfix/cancel-menu-sound 2024-09-16 18:29:51 -04:00
EricandGitHub c7cb03dd1d Merge pull request #2990 from gamerbross/bugfix/f5-reload-chart
[BUGFIX] F5 now reloads the chart in the PlayState
2024-09-16 18:29:39 -04:00
EricandGitHub a7c0512503 Merge branch 'develop' into bugfix/f5-reload-chart 2024-09-16 18:29:33 -04:00
EricandGitHub 74a94d0080 Merge branch 'develop' into bugfix/charteditor-liveinput-number-6 2024-09-16 18:28:22 -04:00
EricandGitHub d214ae1747 Merge pull request #3058 from Burgerballs/fix-sync
Use chart inst offset for song resync + other resync fixes
2024-09-16 18:27:35 -04:00
EricandGitHub 6ee1bddacb Merge branch 'develop' into fix-sync 2024-09-16 18:27:27 -04:00
EricandGitHub 8b96d1bbac Merge pull request #2863 from gamerbross/bugfix/stickers-f5-crash
[BUGFIX] Crash after coming back from stickers and pressing F5
2024-09-16 18:26:42 -04:00
EricandGitHub d4e11f786c Merge branch 'develop' into bugfix/stickers-f5-crash 2024-09-16 18:26:31 -04:00
EricandGitHub 724c415016 Merge pull request #2739 from gamerbross/bugfix/chart-key
[BUGFIX] When pressing chart key while charting, chart gets reset
2024-09-16 18:25:42 -04:00
EricandGitHub 055ae5b932 Merge branch 'develop' into bugfix/chart-key 2024-09-16 18:25:35 -04:00
EricandGitHub 85e9dbb959 Merge pull request #2713 from KarimAkra-Stuff/memory-counter-fix
[BUGFIX] Fixed memory counter displaying negative numbers
2024-09-16 18:25:15 -04:00
EricandGitHub c5060b6eec Merge pull request #2749 from NotHyper-474/path-trace-fix
Fix small oversight in LoadingState
2024-09-16 18:24:42 -04:00
EricandGitHub df77d11896 Merge branch 'develop' into path-trace-fix 2024-09-16 18:24:34 -04:00
EricandGitHub aa2d934f22 Merge pull request #3036 from AppleHair/bugfix/freeplay-infinite-recursion
[BUGFIX] Prevented infinite recursion on freeplay when a song doesn't have the `normal` difficulty
2024-09-16 18:24:22 -04:00
EricandGitHub 3f6ad6f8ad Merge branch 'develop' into bugfix/freeplay-infinite-recursion 2024-09-16 18:24:15 -04:00
EricandGitHub 45efd78931 Merge pull request #3037 from AppleHair/bugfix/valid-vari-story-mode
[BUGFIX] Ensure the variation used for the next song is valid.
2024-09-16 18:23:50 -04:00
EricandGitHub b95e228322 Merge branch 'develop' into bugfix/valid-vari-story-mode 2024-09-16 18:23:39 -04:00
EricandGitHub c9e2e7bef5 Merge pull request #3005 from gamerbross/bugfix/default-face-icon
[BUGFIX] Default health icon (face) not used
2024-09-16 18:23:23 -04:00
EricandGitHub bab4ac4902 Merge branch 'develop' into bugfix/default-face-icon 2024-09-16 18:21:20 -04:00
EricandGitHub b8d1341a21 Merge pull request #2850 from MaybeMaru/constants
Use constants pixels per ms
2024-09-16 18:20:46 -04:00
EricandGitHub 55e0970e4c Merge branch 'develop' into constants 2024-09-16 18:20:35 -04:00
EricandGitHub 82c2d54079 Merge pull request #2567 from gamerbross/bugfix/pause-sticker-zoom
[BUGFIX] Pause Menu and Stickers have same zoom as HUD
2024-09-16 18:20:20 -04:00
EricandGitHub c4b475e86a Merge branch 'develop' into bugfix/pause-sticker-zoom 2024-09-16 18:20:11 -04:00
EricandGitHub 9fddb727b8 Merge pull request #2724 from KarimAkra-Stuff/FlxPartialSound-openfl/polymod-support
[BUGFIX] Fixed Polymod and Mods Support in FlxPartialSound
2024-09-16 18:19:20 -04:00
lemz 224d930ae6 Update PreferencesMenu.hx 2024-09-17 00:17:56 +02:00
EricandGitHub 3b9d400f57 Merge pull request #3328 from FunkinCrew/docs/troubleshooting-update
[DOCS] Update to troubleshooting guide
2024-09-16 18:17:25 -04:00
EliteMasterEric f8d0ddef34 Update troubleshooting guide 2024-09-16 18:17:07 -04:00
lemz 18edadb712 Merge branch 'fps-setting' of https://github.com/lemz1/Funkin into fps-setting 2024-09-17 00:16:33 +02:00
lemz 80fc0cd526 Update Preferences.hx 2024-09-17 00:16:27 +02:00
lemzandGitHub e7674ec31c Merge branch 'develop' into fps-setting 2024-09-17 00:13:49 +02:00
AbnormalandGitHub 0b531c5b21 add getPath 2024-09-16 22:13:16 +00:00
EricandGitHub 8efcd1eae1 Merge pull request #2584 from FunkinCrew/docs/compiling-guide
[DOCS] Update compiling guide with more troubleshooting
2024-09-16 18:12:55 -04:00
EricandGitHub 06485518db Merge branch 'develop' into docs/compiling-guide 2024-09-16 18:12:49 -04:00
EricandGitHub 57523c9439 Merge pull request #3035 from 7oltan/character-path-fix
FIXES CHARACTER PATH ONLY CHECKING IN SHARED
2024-09-16 18:10:25 -04:00
EricandGitHub 42544ee757 Merge branch 'develop' into character-path-fix 2024-09-16 18:10:09 -04:00
Til Tjardes 4be4570c94 Merge branch 'main' of https://github.com/FunkinCrew/Funkin into playsound-typo 2024-09-16 16:08:58 -06:00
lemzandGitHub d0ec26c44a Merge branch 'develop' into completion-fix 2024-09-17 00:08:19 +02:00
lemzandGitHub 8252b2a6b3 Merge branch 'develop' into substate-dispatch-event-fix 2024-09-17 00:07:25 +02:00
EricandGitHub a5ac717677 Merge branch 'develop' into bugfix/freeplay-difficulty-stack-overflow 2024-09-16 18:03:47 -04:00
EricandGitHub ea2e6506c8 Merge pull request #2494 from cyn0x8/flash_fix
consistent flashing
2024-09-16 18:03:18 -04:00
EricandGitHub 1e8d3c715b Merge branch 'develop' into flash_fix 2024-09-16 18:03:05 -04:00
Cameron Taylor 4bc2510d3c Merge remote-tracking branch 'origin/bugfix/pixel-shit-aliasing' into rewrite/master 2024-09-16 17:40:44 -04:00
Cameron Taylor 0574f8b07b Merge remote-tracking branch 'origin/dadbattle-pico-chart-fix' into rewrite/master 2024-09-16 17:31:05 -04:00
Cameron Taylor 11224c5999 Merge remote-tracking branch 'origin/bugfix/song-credits-fixes' into rewrite/master 2024-09-16 17:24:56 -04:00
Cameron Taylor 367e3e9008 priv modules 2024-09-16 17:18:42 -04:00
Cameron Taylor a27c4ae24f pub modules art 2024-09-16 17:14:45 -04:00
Cameron Taylor 1f21e1114b pub modules 2024-09-16 17:12:11 -04:00
EliteMasterEric 16aff6e7c3 Fix bugs with highscore display in Freeplay 2024-09-14 21:37:02 -04:00
EliteMasterEric 9f3af1ab94 Add a separate Gold Perfect animation for modders 2024-09-14 20:56:21 -04:00
EliteMasterEric e23a85682a Update some script files. 2024-09-14 20:26:39 -04:00
EliteMasterEric fd6ca6e267 Remove some spammy log traces. 2024-09-14 20:26:33 -04:00
EliteMasterEric d5c7e4ffdb Fix bug where Pico would become locked on every game restart. 2024-09-14 20:26:19 -04:00
EliteMasterEric 688abb5571 Update example mod's API version so it actually loads. 2024-09-14 20:25:45 -04:00
Til Tjardes 0a8719088d techniktil coming back with another typo lets go 2024-09-14 15:06:03 -06:00
EliteMasterEric df87d677e1 Typo lol 2024-09-14 17:00:41 -04:00
EliteMasterEric 517984d120 Fix a bug where Shit judgement would always display with anti-aliasing. 2024-09-13 18:46:49 -04:00
FabsTheFabs 3fba55a422 assets submod 2024-09-13 21:36:20 +01:00
EliteMasterEric 178389ea0b Fix two song credits 2024-09-12 23:28:43 -04:00
AbnormalandGitHub 16905c8210 Update ScriptedFunkinSprite.hx 2024-09-08 21:48:48 +00:00
lemz 77346696f8 Update MusicBeatSubState.hx 2024-09-07 19:49:08 +02:00
cynandGitHub df266e66d3 dont do that 2024-09-04 19:24:14 -07:00
cynandGitHub 00c7767f8a Update FunkinSound.hx 2024-08-23 20:17:10 -07:00
cynandGitHub c62b53ebe9 Merge branch 'FunkinCrew:main' into flash_fix 2024-08-23 20:09:41 -07:00
Hyper_ d43042fd36 Fix out of bounds note selection 2024-08-05 20:02:23 -03:00
Burgerballs 964f6878c3 Update PlayState.hx 2024-07-23 19:02:09 +01:00
Burgerballs 8778ab1d0e Update PlayState.hx 2024-07-23 18:09:39 +01:00
Burgerballs 59ad15aee4 Merge branch 'develop' of https://github.com/FunkinCrew/Funkin into develop 2024-07-23 18:05:54 +01:00
AppleHairandGitHub c8caeb42de A fix requested by Eric 2024-07-23 11:34:26 +03:00
anysad ba96b11196 hopefully final polish? 2024-07-18 17:56:54 +03:00
anysad ff1ab1eb42 welcome fallback note styles! 2024-07-17 23:19:18 +03:00
AppleHairandGitHub 4d81aa0fe6 [BUGFIX] Ensure the variation used for the next song is valid.
When playing in story mode, `PlayState` assumes all the songs use the same variation, which is usually true, but not guaranteed. This PR makes `PlayState` use the `getFirstValidVariation` method to find the valid variation instead of using the `currentVariation` variable, which might not be valid.
2024-07-17 18:00:07 +03:00
AppleHairandGitHub 691da783fc Updated to extend #2712 2024-07-17 10:20:48 +03:00
AppleHairandGitHub a93cd05aeb Added a comment 2024-07-16 22:36:11 +03:00
anysad ee44981995 you know what, make countdown sprites a little bigger 2024-07-16 22:02:05 +03:00
AppleHairandGitHub 5e1d25e791 [BUGFIX] Prevented infinite recursion on freeplay when a song doesn't have the normal difficulty
Any attempt to create a song without the `normal` difficulty will result in a silent crash when opening freeplay. After some debugging, I discovered that the issue is caused by infinite recursion, which gets triggered at the start of `FreeplaySongData`'s `updateValues`.
2024-07-16 21:17:53 +03:00
anysad f8a0627fd2 goodbye scripts, hello notestyles! 2024-07-16 20:53:12 +03:00
7oltan f8232911cb FIX CHARACTER PATHS ISSUE 2024-07-16 12:52:51 +03:00
anysad aed100df47 how the hell did I miss these? 2024-07-13 23:39:56 +03:00
anysad 9d3c043f8a cache textures at their new locations! 2024-07-13 23:29:26 +03:00
anysad 2547fbb8f4 remove trace 2024-07-13 23:08:16 +03:00
anysad 2993e17278 custom popups and countdowns yay!!! 2024-07-13 22:45:58 +03:00
lemz 0c5815c176 add completion check 2024-07-13 21:27:14 +02:00
AppleHairandGitHub 97e69c6343 Merge branch 'develop' into bugfix/cancel-menu-sound 2024-07-12 18:28:14 +03:00
lemzandGitHub 51c304a6fa Merge branch 'develop' into fps-setting 2024-07-12 06:37:22 +02:00
anysad 47a2cf4e5d Add HEY! song events to Tutorial 2024-07-11 18:12:50 +03:00
anysad a12b0e6ec3 Add HEY! song events to Tutorial 2024-07-11 18:10:45 +03:00
lemzandGitHub 2be22055cc Merge branch 'develop' into fps-setting 2024-07-11 10:25:16 +02:00
gamerbross 2fb55ba3ed Fix default health icon not used 2024-07-11 06:59:22 +02:00
gamerbross 9ad2bb35f9 ChartEditor Live Input Code Refactor + 6 key fix 2024-07-10 01:26:16 +02:00
gamerbrossandGitHub 481f7ab61a Fix F5 chart not reloading 2024-07-10 00:23:06 +02:00
AppleHair 717894300d [BUGFIX] Fixed cancelMenu sound not playing after switching state. 2024-07-09 19:59:31 +03:00
gamerbrossandGitHub f82f0d3b05 Remove SustainTrail forced alpha 2024-07-08 03:17:28 +02:00
lemz 927e37b35b use new numberpreferenceitem 2024-07-02 17:18:46 +02:00
FlooferLand! be5e0aafeb Added getWidth 2024-07-01 14:44:23 +03:00
FlooferLand! 488fc6888f Added new settings items 2024-07-01 14:42:50 +03:00
PixelandGitHub 8e81f6bdf4 Merge branch 'develop' into JVNPixels-story-menu-scrolling-fixed 2024-06-29 17:00:54 -07:00
gamerbrossandGitHub 09c8a2600e Fix null safety compiling 2024-06-29 22:54:25 +02:00
lemzandGitHub 0a7902c4b4 Merge branch 'develop' into fps-setting 2024-06-29 14:27:31 +02:00
gamerbross 02dd7e7264 Implement danceEvery for Characters 2024-06-27 21:05:01 +02:00
gamerbrossandGitHub 91bc63004a FunkinSound.playOnce return sound 2024-06-27 21:00:25 +02:00
lemz f3e04114eb use new offsets 2024-06-25 17:05:15 +02:00
AbnormalPoof ef2885ed0e video cutscene autopause magic 2024-06-24 03:55:59 -05:00
lemz 3b3b9d97ba use different implementation 2024-06-23 21:03:30 +02:00
PixelandGitHub be38ae6c00 Extra newline removal.
Removes the extra line in code.
2024-06-22 19:23:40 -07:00
0589624d11 Update source/funkin/ui/story/StoryMenuState.hx
Co-authored-by: gamerbross <55158797+gamerbross@users.noreply.github.com>
2024-06-21 22:46:07 -07:00
PixelandGitHub dd7a894b51 Update StoryMenuState.hx 2024-06-21 08:42:51 -07:00
gamerbross 73efd963b9 Fix crash after pressing F5 and coming back from stickers 2024-06-20 07:24:36 +02:00
MaybeMaru 250ec840ef Add missing constants 2024-06-18 15:11:00 +02:00
gamerbross ba4677857a Few animation editor bugfixes 2024-06-15 20:23:55 +02:00
lemzandGitHub e3159745fb Merge branch 'develop' into fps-setting 2024-06-13 09:02:27 +02:00
gamerbrossandGitHub b7eaa238e0 Revert camCutscene rename 2024-06-12 00:34:04 +02:00
NotHyper-474 fb71f9087d Fix trace 2024-06-10 23:12:28 -03:00
gamerbross 9618cd2128 Fix chart reset when charting and pressing chart key 2024-06-10 16:53:32 +02:00
lemzandGitHub 9468d95506 Merge branch 'develop' into fps-setting 2024-06-10 12:21:46 +02:00
Karim AkraandGitHub 4997bc27fd remove the library strip 2024-06-09 12:47:17 +03:00
gamerbross 73982fbd60 Fix Stack Overflow if song doesn't have "normal" difficulty 2024-06-09 00:29:55 +02:00
Karim AkraandGitHub 7904a6a20f use Math.fround instead of Math.round 2024-06-09 01:25:21 +03:00
Karim AkraandGitHub ade4aeb3f7 get Float instead of Int in cpp (Float is 64-bit in so it works easier than Int64) 2024-06-09 01:24:02 +03:00
lemzandGitHub e46108fa15 Merge branch 'develop' into fps-setting 2024-06-08 13:03:45 +02:00
lemzandGitHub 7346a46975 Merge branch 'develop' into fps-setting 2024-06-07 20:37:54 +02:00
lemzandGitHub 5baa4c7ef7 Merge branch 'develop' into fps-setting 2024-05-31 11:52:10 +02:00
lemzandGitHub 4ce79cc386 Merge branch 'develop' into fps-setting 2024-05-30 22:23:34 +02:00
lemzandGitHub 11fee0f200 Merge branch 'develop' into fps-setting 2024-05-30 13:54:22 +02:00
lemz 26b357df72 Merge branch 'fps-setting' of https://github.com/lemz1/Funkin into fps-setting 2024-05-30 00:22:18 +02:00
lemz 4a531888b5 Update PreferencesMenu.hx 2024-05-30 00:22:10 +02:00
lemzandGitHub 262bcc4d8b Merge branch 'develop' into fps-setting 2024-05-29 18:45:09 +02:00
lemzandGitHub 088ff3744a Merge branch 'develop' into fps-setting 2024-05-29 07:26:35 +02:00
lemzandGitHub 01b1ce679c Merge branch 'develop' into fps-setting 2024-05-29 06:42:46 +02:00
lemz 267fd0eadc alpha stuff and correct text positioning 2024-05-25 16:30:08 +02:00
lemz 814d72cb3f sounds 2024-05-25 03:06:27 +02:00
lemz b75f6e5853 Update PreferencesMenu.hx 2024-05-25 02:19:11 +02:00
lemz dd6d12de23 rename vars 2024-05-25 01:20:10 +02:00
lemz f86a163692 Merge branch 'develop' into fps-setting 2024-05-25 01:16:34 +02:00
lemz e0fe7cb1eb add fps option 2024-05-25 01:11:34 +02:00
EliteMasterEric 47cbd4b620 Update compiling guide with more troubleshooting 2024-05-21 19:11:10 -04:00
gamerbross 0a6f1abd33 Fix references to camCutscene 2024-05-20 23:52:45 +02:00
gamerbross 92b84168e1 Add camOther to fix zooms on pause and stickers 2024-05-20 02:56:57 +02:00
nebulazorua fae625a795 last commit, if merged, would've likely caused issues if going from tween to classic
should be fixed now?
2024-05-15 20:42:11 +08:00
cynandGitHub c49b66f0e4 flash fix 2024-05-13 11:23:16 -07:00
nebulazorua 3cc7f7407d fix focuscamera CLASSIC breaking zooms and snapping 2024-05-08 21:08:17 +08:00
140 changed files with 6699 additions and 1147 deletions
+23 -17
View File
@@ -6,41 +6,45 @@ body:
- type: checkboxes
attributes:
label: Issue Checklist
description: Be sure to complete these steps to increase the chances of your issue being addressed!
options:
- label: I have properly named the issue
- label: I have checked the issues/discussions pages to see if the issue has been previously reported
- label: I have properly named my issue
- label: I have checked the Issues/Discussions pages to see if my issue has already been reported
- type: dropdown
attributes:
label: What platform are you using?
label: Platform
description: Which platform are you playing on?
options:
- Newgrounds (Web)
- Itch.io (Web)
- Newgrounds (Web/HTML5)
- Itch.io (Web/HTML5)
- Itch.io (Downloadable Build) - Windows
- Itch.io (Downloadable Build) - MacOS
- Itch.io (Downloadable Build) - Linux
- Compiled from GitHub Source Code
validations:
required: true
- type: dropdown
attributes:
label: If you are playing on a browser, which one are you using?
label: Browser
description: (Web/HTML5 users only) Which browser are you playing on?
options:
- Google Chrome
- Microsoft Edge
- Firefox
- Opera
- Safari
- Other (Specify below)
- Other (Specify in Description field)
- type: input
attributes:
label: Version
description: What version are you using?
placeholder: ex. 0.4.1
description: Which version are you playing on? The game version is in the bottom left corner of the main menu.
placeholder: ex. 0.5.0
validations:
required: true
- type: markdown
attributes:
value: "## Describe your bug."
@@ -49,14 +53,16 @@ body:
attributes:
value: "### Please do not report issues from other engines. These must be reported in their respective repositories."
- type: markdown
attributes:
value: "#### Provide as many details as you can."
- type: textarea
attributes:
label: Context (Provide images, videos, etc.)
label: Description (include any images, videos, errors, or crash logs)
description: Provide as much detail as you can. The better others understand your issue, the more they can help you!
placeholder: Describe your issue here...
validations:
required: true
- type: textarea
attributes:
label: Steps to reproduce (or crash logs, errors, etc.)
label: Steps to Reproduce
description: What steps can other people take to reliably encounter this issue?
placeholder: 1. Open the game...
+28 -20
View File
@@ -6,65 +6,73 @@ body:
- type: checkboxes
attributes:
label: Issue Checklist
description: Be sure to complete these steps to increase the chances of your issue being addressed!
options:
- label: I have properly named the issue
- label: I have checked the issues/discussions pages to see if the issue has been previously reported
- label: I have properly named my issue
- label: I have checked the Issues/Discussions pages to see if my issue has already been reported
- type: dropdown
attributes:
label: What platform are you using?
label: Platform
description: Which platform are you playing on?
options:
- Newgrounds (Web)
- Itch.io (Web)
- Newgrounds (Web/HTML5)
- Itch.io (Web/HTML5)
- Itch.io (Downloadable Build) - Windows
- Itch.io (Downloadable Build) - MacOS
- Itch.io (Downloadable Build) - Linux
- Compiled from GitHub Source Code
validations:
required: true
- type: dropdown
attributes:
label: If you are playing on a browser, which one are you using?
label: Browser
description: (Web/HTML5 users only) Which browser are you playing on?
options:
- Google Chrome
- Microsoft Edge
- Firefox
- Opera
- Safari
- Other (Specify below)
- Other (Specify in Description field)
- type: input
attributes:
label: Version
description: What version are you using?
placeholder: ex. 0.4.1
description: Which version are you playing on? The game version is in the bottom left corner of the main menu.
placeholder: ex. 0.5.0
validations:
required: true
- type: markdown
attributes:
value: "## Describe your issue."
value: "## Describe the crash."
- type: markdown
attributes:
value: "### Please do not report issues from other engines. These must be reported in their respective repositories."
- type: markdown
attributes:
value: "#### Provide as many details as you can."
- type: textarea
attributes:
label: Context (Provide screenshots or videos of the crash happening)
- type: textarea
attributes:
label: Steps to reproduce
label: Description
description: Include screenshots or videos of the crash happening. Provide as much detail as you can.
placeholder: Describe the crash here...
validations:
required: true
- type: textarea
attributes:
label: Crash logs (can be found in the logs folder where Funkin.exe is)
label: Steps to Reproduce
description: What steps can other people take to reliably trigger this crash?
placeholder: 1. Open the game...
validations:
required: true
- type: textarea
attributes:
label: Crash logs
description: These can be found in the logs folder where Funkin.exe is.
placeholder: Upload your logs here...
validations:
required: true
+5 -2
View File
@@ -6,10 +6,13 @@ body:
- type: checkboxes
attributes:
label: Issue Checklist
description: Be sure to complete these steps to increase the chances of your suggestion being considered!
options:
- label: I have properly named the enhancement
- label: I have checked the issues/discussions pages to see if the enhancement has been previously suggested
- label: I have properly named my enhancement
- label: I have checked the Issues/Discussions pages to see if my enhancement has already been suggested
- type: textarea
attributes:
label: What is your suggestion, and why should it be implemented?
validations:
required: true
+1 -1
View File
@@ -7,6 +7,6 @@ medium:
min: 10
max: 99
# Add 'large' to any changes for more than 100 lines
# Add 'large' to any changes of at least 100 lines
large:
min: 100
+44
View File
@@ -0,0 +1,44 @@
# Configuration for Label Actions - https://github.com/dessant/label-actions
# Automatically close issues and pull requests when the `status: duplicate` label is applied
'status: duplicate':
issues:
# Post a comment
comment: >
This issue is a duplicate. Please direct all discussion to the original issue.
# Close the issue
close: true
# Remove other status labels
unlabel:
- 'status: pending triage'
# Set a close reason
close-reason: 'not planned'
prs:
# Post a comment
comment: >
This pull request is a duplicate. Please direct all discussion to the original pull request.
# Remove other status labels
unlabel:
- 'status: pending triage'
# Close the pull request
close: true
# Set a close reason
close-reason: 'not planned'
'status: rejected':
issues:
# Close the issue
close: true
# Remove other status labels
unlabel:
- 'status: pending triage'
# Set a close reason
close-reason: 'not planned'
prs:
# Close the pull request
close: true
# Remove other status labels
unlabel:
- 'status: pending triage'
# Set a close reason
close-reason: 'not planned'
+2 -2
View File
@@ -1,11 +1,11 @@
# Add Documentation tag to PR's changing markdown files, or anyhting in the docs folder
# Add Documentation tag to PR's changing markdown files, or anything in the docs folder
Documentation:
- changed-files:
- any-glob-to-any-file:
- docs/*
- '**/*.md'
# Adds Haxe tag to PR's changing haxe code files
# Add Haxe tag to PR's changing haxe code files
Haxe:
- changed-files:
- any-glob-to-any-file: '**/*.hx'
+25 -3
View File
@@ -2,6 +2,15 @@ name: Build and Upload nightly game builds
on:
workflow_dispatch:
inputs:
build-defines:
type: string
description: Build defines to use
default: '-DGITHUB_BUILD'
save-artifact:
type: boolean
description: Save the build artifact to Github Actions (sends to itch otherwise)
default: false
push:
paths-ignore:
- '**/Dockerfile'
@@ -53,13 +62,20 @@ jobs:
- name: Build game
if: ${{ matrix.target == 'windows' }}
run: |
haxelib run lime build windows -v -release -DGITHUB_BUILD
haxelib run lime build windows -v -release ${{ github.event.inputs.build-defines }}
timeout-minutes: 120
- name: Build game
if: ${{ matrix.target != 'windows' }}
run: |
haxelib run lime build ${{ matrix.target }} -v -release --times -DGITHUB_BUILD
haxelib run lime build ${{ matrix.target }} -v -release --times ${{ github.event.inputs.build-defines }}
timeout-minutes: 120
- name: Save build artifact to Github Actions
if: ${{ github.event.inputs.save-artifact }}
uses: actions/upload-artifact@v4
with:
name: build-${{ matrix.target }}
path: export/release/${{matrix.target}}/bin/
- name: Upload build artifacts
uses: ./.github/actions/upload-itch
@@ -125,9 +141,15 @@ jobs:
- name: Build game
run: |
haxelib run lime build ${{ matrix.target }} -v -release --times -DGITHUB_BUILD
haxelib run lime build ${{ matrix.target }} -v -release --times ${{ github.event.inputs.build-defines }}
timeout-minutes: 120
- name: Save build artifact to Github Actions
if: ${{ github.event.inputs.save-artifact }}
uses: actions/upload-artifact@v4
with:
name: build-${{ matrix.target }}
path: export/release/${{matrix.target}}/bin/
- name: Upload build artifacts
uses: ./.github/actions/upload-itch
with:
+29
View File
@@ -0,0 +1,29 @@
# Perform actions when labels are applied to issues, discussions, or pull requests
# See .github/label-actions.yml
name: 'Label Actions'
on:
issues:
types:
- labeled
- unlabeled
pull_request_target:
types:
- labeled
- unlabeled
discussion:
types:
- labeled
- unlabeled
permissions:
contents: read
issues: write
pull-requests: write
discussions: write
jobs:
action:
runs-on: ubuntu-latest
steps:
- uses: dessant/label-actions@v4
+52
View File
@@ -0,0 +1,52 @@
name: "Issue Labeler"
on:
issues:
types:
- opened
- reopened
- edited
jobs:
# When an issue is opened, perform a similarity check for potential duplicates.
# If some are found, add a label and comment listing the potential duplicate issues.
potential-duplicate:
name: Detect potential duplicate issues
runs-on: ubuntu-latest
steps:
- uses: wow-actions/potential-duplicates@v1
with:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# Issue title filter work with anymatch https://www.npmjs.com/package/anymatch.
# Any matched issue will stop detection immediately.
# You can specify multi filters in each line.
filter: ''
# Exclude keywords in title before detecting.
exclude: ''
# Label to set, when potential duplicates are detected.
label: 'potential duplicate'
# Get issues with state to compare. Supported state: 'all', 'closed', 'open'.
state: all
# If similarity is higher than this threshold([0,1]), issue will be marked as duplicate.
# Turn this up if the detection is too sensitive
threshold: 0.6
# Reactions to be add to comment when potential duplicates are detected.
# Available reactions: "-1", "+1", "confused", "laugh", "heart", "hooray", "rocket", "eyes"
# reactions: '-1'
# Comment to post when potential duplicates are detected.
comment: >
Potential duplicates: {{#issues}}
- [#{{ number }}] {{ title }} ({{ accuracy }}%)
{{/issues}}
# When an issue is opened, detect if it has an empty body or incomplete issue form.
# If it does, close the issue immediately.
empty-issues:
name: Close empty issues
runs-on: ubuntu-latest
steps:
- name: Run empty issues closer action
uses: rickstaa/empty-issues-closer-action@v1
env:
github_token: ${{ secrets.GITHUB_TOKEN }}
with:
close_comment: Closing this issue because it appears to be empty. Please update the issue for it to be reopened.
open_comment: Reopening this issue because the author provided more information.
@@ -3,6 +3,7 @@ on:
- pull_request_target
jobs:
# Apply labels to pull requests based on which files were edited
labeler:
permissions:
contents: read
@@ -13,6 +14,7 @@ jobs:
uses: actions/labeler@v5
with:
sync-labels: true
# Apply labels to pull requests based on how many lines were edited
changed-lines-count-labeler:
permissions:
contents: read
+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
+10
View File
@@ -96,6 +96,11 @@
"target": "windows",
"args": ["-debug", "-DFEATURE_DEBUG_FUNCTIONS"]
},
{
"label": "Windows / Debug (Tracy)",
"target": "windows",
"args": ["-debug", "-DFEATURE_DEBUG_TRACY", "-DFEATURE_DEBUG_FUNCTIONS"]
},
{
"label": "Linux / Debug",
"target": "linux",
@@ -106,6 +111,11 @@
"target": "hl",
"args": ["-debug"]
},
{
"label": "Windows / Debug (Discord)",
"target": "windows",
"args": ["-debug", "-DFEATURE_DEBUG_FUNCTIONS", "-DFEATURE_DISCORD_RPC"]
},
{
"label": "Windows / Debug (FlxAnimate Test)",
"target": "windows",
+127 -4
View File
@@ -4,24 +4,146 @@ 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.5.2] - 2024-10-11
### Changed
- (docs) Delete Modding.md since we have a separate modding documentation ([a42240e](https://github.com/FunkinCrew/Funkin/commit/a42240e6a595d33034f2c887bf38a350d1fa0f15)) - by @AbnormalPoof in [#3651](https://github.com/FunkinCrew/Funkin/pull/3651)
- (docs) Create a git cliff template for easier changelog stuff ([91b4544](https://github.com/FunkinCrew/Funkin/commit/91b4544f7ebc51485e3e28c3d716ba6ee69ad885)) - by @ninjamuffin99 in [#3652](https://github.com/FunkinCrew/Funkin/pull/3652)
- Added InverseDotsShader that emulates flash selections ([097dbf5](https://github.com/FunkinCrew/Funkin/commit/097dbf5bb4346d431d8ca9f0ec4bc5b5e6f4523f)) - by @ninjamuffin99
- (docs) Add additional `variation` input parameter to `Save.hasBeatenSong()` to allow usage of the function by inputting a variation id ([4fa9a0d](https://github.com/FunkinCrew/Funkin/commit/4fa9a0daaa67e0977460b147bd1f74a118e3e2a5)) - by @ninjamuffin99
- (docs) Added modding docs link in readme ([4b54118](https://github.com/FunkinCrew/Funkin/commit/4b54118731e26118111e06558ae4853c577fe4bb)) - by @Cartridge-Man
- Fix some misspellings and grammar in code documentation ([2175bea](https://github.com/FunkinCrew/Funkin/commit/2175beaa651e009332202985be4b7eb4ed36e5a4)) - by @Hundrec
- (docs) Improvements to Github Issues templates ([399869c](https://github.com/FunkinCrew/Funkin/commit/399869cdccc9c5ac27cecfbcdc33c3d7eb4b348c)) - by @Hundrec in [#3458](https://github.com/FunkinCrew/Funkin/pull/3458)
- Fix some misspellings and grammar in code documentation ([6df80ba](https://github.com/FunkinCrew/Funkin/commit/6df80ba69d0e24269f40471f83462cab7d5e13cf)) - by @Hundrec in [#3477](https://github.com/FunkinCrew/Funkin/pull/3477)
- (docs) Improvements to Github Issues templates ([67f7b63](https://github.com/FunkinCrew/Funkin/commit/67f7b638fb76840b868cbfa70a1c6063577984c5)) - by @Hundrec
### Fixed
- Disable flickering when changing FPS in the options menu ([b2647fe](https://github.com/FunkinCrew/Funkin/commit/b2647fe09f5281ce7074b26d47bc1524764168ee)) - by @lemz1 in [#3629](https://github.com/FunkinCrew/Funkin/pull/3629)
- Anti alias / smooth the volume sound tray ([e66290c](https://github.com/FunkinCrew/Funkin/commit/e66290c55f7141402223644f06ec8a69edeee089)) - by @Kn1ghtNight in [#2853](https://github.com/FunkinCrew/Funkin/pull/2853)
- Don't restart the FreeplayState song preview when changing the difficulty within the same variation ([903b3fc](https://github.com/FunkinCrew/Funkin/commit/903b3fc59905a70802618a1cd67407722ea956ed)) - by @JustKolosaki in [#3587](https://github.com/FunkinCrew/Funkin/pull/3587)
- Exiting the chart editor doesn't crash the game anymore ([f52472a](https://github.com/FunkinCrew/Funkin/commit/f52472a4767388b22cfbab0f5f7860f6e6762856)) - by @EliteMasterEric
- Character Select cursor moves properly at lower framerates ([ab5bda3](https://github.com/FunkinCrew/Funkin/commit/ab5bda3ee573a6e03595ec6941e6de38df851889)) - by @ninjamuffin99 in [#3507](https://github.com/FunkinCrew/Funkin/pull/3507)
- Stopped allowing F1 to create more than one help dialog window in the Charting Editor ([777978f](https://github.com/FunkinCrew/Funkin/commit/777978f5a544e1b7c89b47dcc365f734eb6d0df1)) - by @amyspark-ng
- Main menu music doesn't cut out when switching states anymore. ([711e0a6](https://github.com/FunkinCrew/Funkin/commit/711e0a6b7547eb04113e9318dab900f01ad576a5)) - by @EliteMasterEric in [#3530](https://github.com/FunkinCrew/Funkin/pull/3530)
- The dialog now shows up on the animation debugger view ([1fde59f](https://github.com/FunkinCrew/Funkin/commit/1fde59f999eac94eb10fc22094885de2f5310705)) - by @EliteMasterEric
- Center preloader 'fnf' and 'dsp' text so it doesn't clip anymore ([165ad60](https://github.com/FunkinCrew/Funkin/commit/165ad6015539a295e9eefdaef291c312e9566b26)) - by @Burgerballs in [#3567](https://github.com/FunkinCrew/Funkin/pull/3567)
- `Song.getFirstValidVariation()` now properly takes into account multiple variations/difficulty input ([d2e2987](https://github.com/FunkinCrew/Funkin/commit/d2e29879fe2acc6febfe0f335f655b741d630c34)) - by @ninjamuffin99 in [#3506](https://github.com/FunkinCrew/Funkin/pull/3506)
- (freeplay) Proper variation / difficulty loading for Freeplay Menu ([c0314c8](https://github.com/FunkinCrew/Funkin/commit/c0314c85ecd5116641aff3de8e9153f7fe48e79c)) - by @ninjamuffin99
- Picos songs properly load on freeplay ([1d2bd61](https://github.com/FunkinCrew/Funkin/commit/1d2bd61119e5f418df7f11d7ef2a0fdedee17d3d)) - by @ninjamuffin99
- (debug) No more fullscreening when typing "F" in the flixel debugger console ([29b6763](https://github.com/FunkinCrew/Funkin/commit/29b6763290df05d42039806f3d142740568c80f0)) - by @ninjamuffin99
- Fix the user song offsets being applied incorrectly ([410cfe9](https://github.com/FunkinCrew/Funkin/commit/410cfe972d6df9de4d4d128375cf8380c4f06d92)) - by @JustKolosaki
- Fix crash in LatencyState when exiting / cleaning up state data ([39b1a42](https://github.com/FunkinCrew/Funkin/commit/39b1a42cfeafe2b7be8b66e2fe529e853d9ae197)) - by @lemz1
- Add additional classes to Polymod Blacklist ([b0b73c8](https://github.com/FunkinCrew/Funkin/commit/b0b73c83994f33118c6a69550da9ec8ec1c07adc)) - by @EliteMasterEric
- Stop allowing inputs after selecting a character ([dbf66ac](https://github.com/FunkinCrew/Funkin/commit/dbf66ac250137262866d75f7c1387645b35d88d0)) - by @ACrazyTown
- Fixed an issue where the player and girlfriend would disappear or overlap themselves in Character Select (community fix by gamerbross)
- Fixed an issue where the game would show the wrong girlfriend in Character Select (community fix by gamerbross)
- Fixed an issue where the cursor wouldn't update properly in Character Select (community fix by gamerbross)
- Fixed an issue where the player would display double after entering character select or when spamming buttons (community fix by gamerbross)
## New Contributors for 0.5.2
* @Kn1ghtNight made their first contribution in [#2853](https://github.com/FunkinCrew/Funkin/pull/2853)
* @DaWaterMalone made their first contribution
* @amyspark-ng made their first contribution
* @Cartridge-Man made their first contribution
* @afreetoplaynoob made their first contribution
## [0.5.1] - 2024-09-30
### Added
- Readded the Merch button to the main menu.
- Click it to check out our Makeship campaign!
- Added Discord Rich Presence support. People can now see what song you are playing from Discord!
- We'll get mod support working for this eventually.
- Added an FPS limit option to the Preferences menu.
- You can now change how high the game tries to push your frame rate, from as little as 30 to as high as 300.
- Added support for the Tracy instrumenation-based profiling tool in development environments. Enable it with the `-DFEATURE_DEBUG_TRACY` compilation flag.
- For the people who aren't nerds, this is a tool for tracking down performance issues!
- Playable Character data now defines an asset location for an Animate Atlas to display Girlfriend.
- This includes the option to display a visualizer, if configured correctly.
- Separated the Perfect and Perfect (Gold) animations in the Playable Character data.
- Base game just uses the same animation for both, but modders can split the animations up on their custom characters now.
- Added a bunch of Flash project files from the Weekend 1 and Playable Pico updates to the `Funkin.art` repository.
- Added the `flipX` and `flipY` parameters to props in the Stage data. (community feature by abnormalpoof)
### Changed
- The game's mod API version check is now more dynamic.
- The update accepts mods with API version `0.5.0` as well as `0.5.1`.
- Pico is no longer unlocked for all players automatically.
- You need to beat Weekend 1 in Story Mode in order to unlock him in Character Select.
- Removed some of the more spammy `trace()` calls to improve debugging a bit.
- Improved some of the compilation and modding documentation.
- The game now complains if you create a song variation with symbols in the name.
- Switched the force crash keybind from Ctrl-Shift-L to Ctrl-Alt-Shift-L.
- Added some additional functions to `funkin.Assets` after `openfl.utils.Assets` had to get blacklisted from scripts.
### Fixed
- Fixed an issue where DadBattle (Pico Mix) was not properly credited to `TeraVex (ft. Saruky)`.
- Fixed an issue where DadBattle (Pico Mix) was missing charts on the Normal and Easy difficulty.
- Fixed an issue where Spookeez (Pico Mix) was not properly credited to `Six Impala (ft. Saster)`.
- Fixed an issue where the "Shit!" judgement would display with anti-aliasing in Week 6.
- Fixed an issue where Pico Erect could be played with different instrumentals.
- Fixed an issue where Pico would not play his shooting animations in Stress.
- Fixed an issue where Freeplay would display no custom songs when switching characters.
- Fixed an issue where Freeplay would sometimes display the wrong text on the capsules.
- Fixed an issue where duplicate difficulties from custom variations wouldn't display properly in Freeplay.
- Fixed an issue where custom note styles would sometimes just use default values rather than using the fallback note style.
- Fixed an issue where custom note styles would randomly fail to fetch information about their fallback note style.
- Fixed an issue where the Screenshots and Chart Editor binds displayed in the controls menu on Web builds (where they are disabled).
- Fixed an issue where the Stage Editor bind displayed in the controls menu even when the feature was disabled.
- Fixed an issue where the Freeplay Character Select keybind displayed weird in the keybinds menu.
- Fixed an issue where setting the input offset or visual offset too high would cause the song to skip.
- Fixed an issue where video cutscenes would not scale their volume properly.
- Fixed an issue where Cocoa Erect (Erect difficulty) had a tap note stacked on top of a hold note,
- Fixed an issue where the game would stutter when playing on the Week 5 Remix stage.
- Fixed an issue where the save data version number wouldn't get written to save data properly.
- Fixed an issue where the example mod could not be loaded.
- Fixed an issue where a script error would display when entering Blazin'.
- Fixed an issue where pressing F5 to force reload a song would sometimes cause the game to crash.
- Fixed an issue where animations on Animate Atlas characters would throw a bunch of warnings in the console.
- Fixed an issue where characters with high offsets would shift over after the player dies or restarts.
- Fixed an issue where Pico wouldn't play out his full burp animation in South (Pico Mix).
- Fixed an issue where Results screen audio could continue into Freeplay or even gameplay.
- Fixed an issue where some audio tracks would get destroyed even if they were flagged as persistent.
- Fixed an issue where the audio track would stay muted if you missed a note just before Pico burps.
- Fixed an issue where the curtains in Week 1 would display in front of larger characters.
- Fixed an issue where Boyfriend wouldn't play his death animation properly on Week 2's Remix stage.
- Fixed an issue in Freeplay where the clear % would not display after switching characters.
- Fixed an issue in Freeplay where character remixes would display the base song's highscore.
- Fixed an issue where Pico would become locked every time the game starts, and you would have to watch the unlock animation each game boot.
- The animation should now play only once per save file.
- Fixed an issue where Spirit's trail in Week 6 would not display correctly.
- Fixed an issue where the Input Offsets menu would crash when entering it before playing a song on web builds.
- Fixed an issue where the Results screen would spam the percentage tick noise instead of playing when the value changes.
- Fixed an issue where parts of the Chart Editor could not be interacted with. (community fix by KadeDeveloper)
- Fixed an issue where classic FocusCamera song events could cause the camera to snap in place. (community fix by NebulaZorua)
- Fixed an issue where achieving the same rank on a song (but a different clear %) would override your clear %, even if it was lower. (community fix by lemz1)
- Fixed an issue where the FPS counter would display even if Debug Display was turned off. (community fix by Lethrial)
- Fixed an issue where selecting the area to the left of the Chart Editor would select some of the player's notes (community fix by NotHyper474)
- Fixed an issue where pixel icons in the Chart Editor would not display correctly. (community fix by Techniktil)
- Fixed an issue where `Stage.addCharacter` would not properly assign the `characterType`. (community fix by KadeDeveloper)
- Fixed an issue where players should interact with Character Select during the unlock sequence, causing a crash. (community fix by actualmandm)
- Fixed an issue where hold notes in Week 6 were not scaled/positioned correctly. (community fix by dombomb64)
- Fixed an issue where audio offets would not interact with the Chart Editor properly. (community fix by KadeDev)
- Fixed an issue where fetching Modules during the `onDestroy` event would fail at random. (community fix by cyn0x8)
- Fixed an issue where `onSubStateOpenEnd` and `onSubStateCloseEnd` script events would not always get called. (community fix by lemz1)
## [0.5.0] - 2024-09-12
### Added
- Added a new Character Select screen to switch between playable characters in Freeplay
- Modding isn't 100% there but we're working on it!
- Added Pico as a playable character! Unlock him by completing Weekend 1 (if you haven't already done that)
- The songs from Weekend 1 have moved; you must now switch to Pico in Freeplay to access them
- Added 10 new Pico remixes! Access them by selecting Pico from in the Character Select screen
- The songs from Weekend 1 have moved; you must now switch to Pico via Character Select screen in Freeplay to access them
- Added 11 new Pico remixes! Access them by selecting Pico from in the Character Select screen
- Bopeebo (Pico Mix)
- Fresh (Pico Mix)
- DadBattle (Pico Mix)
- Spookeez (Pico Mix)
- South (Pico Mix)
- Pico (Pico Mix)
- Philly Nice (Pico Mix)
- Blammed (Pico Mix)
- Blammed (Pico Mix)
- Eggnog (Pico Mix)
- Ugh (Pico Mix)
- Guns (Pico Mix)
- Added 1 new Boyfriend remix! Access it by selecting Pico from in the Character Select screen
- Added 1 new Boyfriend remix! Access it by completing Weekend 1 as Pico and then selecting Boyfriend from in the Character Select screen
- Darnell (BF Mix)
- Added 2 new Erect remixes! Access them by switching difficulty on the song
- Cocoa Erect
@@ -39,6 +161,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- These display on Pico remixes, as well as when playing Weekend 1.
- Implemented support for scripted Note Kinds. You can use HScript define a different note style to display for these notes as well as custom behavior. (community feature by lemz1)
- Implemented support for Numeric and Selector options in the Options menu. (community feature by FlooferLand)
- Implemented new animations for Tankman and Pico
## Changed
- Girlfriend and Nene now perform previously unused animations when you achieve a large combo, or drop a large combo.
- The pixel character icons in the Freeplay menu now display an animation!
+3 -3
View File
@@ -4,14 +4,14 @@ Code style is enforced using Visual Studio Code extensions.
## .hx
Formatting is handled by the `nadako.vshaxe` extension, which includes Haxe Formatter.
Haxe Formatter automatically resolves issues such as intentation style and line breaks, and can be configured in `hxformat.json`.
Haxe Formatter automatically resolves issues such as indentation style and line breaks, and can be configured in `hxformat.json`.
Code Quality is handled by the `vshaxe.haxe-checkstyle` extension, which includes Haxe Checkstyle.
### Haxe Checkstyle Notes
* Checks can be escalated to display as different serverities in the Problems window.
* Checks can be escalated to display as different severities in the Problems window.
* Checks can be disabled by setting the severity to `IGNORE`.
* `IndentationCharacter` checks what is used to indent, `Indentation` checks how deep the intentation is.
* `IndentationCharacter` checks what is used to indent, `Indentation` checks how deep the indentation is.
* `CommentedOutCode` check is in place because old code should be retrieved via Git history.
* TODO items: Enable these one-by-one and fix them to improve the overall code quality.
- Reconfigure `MethodLength`
-13
View File
@@ -1,13 +0,0 @@
# RIGHT NOW THE MODS FOLDER DOES NOT WORK ENTIRELY JUST YET!!!
## THIS IS WORK IN PROGRESS!!!
# QUICK AND DIRTY MOD GUIDE
With the 0.2.6 update, I added a bit of a slightly nicer mod support backend.
It's POLYMOD, which is made by Lars Doucet: https://github.com/larsiusprime/polymod
You may have noticed that there's a new folder in the assets. MODS. Within it you will see 2 files. modList.txt, and a folder called introMod.
modList.txt will load any folder into the game. Put the folder you want to load into a new line in modList.txt, and reboot the game.
Now you may be wondering, what do I put in the folder? Well later down it'll get a bit more complicated, especially as I'll make the IN-GAME mod loader nicer.
+5 -1
View File
@@ -17,9 +17,13 @@ To learn how to install the necessary dependencies and compile the game from sou
Please check out our [Contributor's guide](./CONTRIBUTORS.md) on how you can actively participate in the development of Friday Night Funkin'.
# Modding
Feel free to start learning to mod the game by reading our [documentation](https://funkincrew.github.io/funkin-modding-docs/) and guide to modding.
# Credits and Special Thanks
Full credits can be found in-game, or wherever the credits.json file is.
Full credits can be found in-game, or in the `credits.json` file which is located [here](https://github.com/FunkinCrew/funkin.assets/blob/main/exclude/data/credits.json).
## Programming
- [ninjamuffin99](https://twitter.com/ninja_muffin99) - Lead Programmer
+1 -1
Submodule art updated: 0dee03f11a...fbd3e3df77
+1 -1
Submodule assets updated: bc7009b424...4abd6cc06e
+90
View File
@@ -0,0 +1,90 @@
# git-cliff ~ configuration file
# https://git-cliff.org/docs/configuration
[remote.github]
owner = "FunkinCrew"
repo = "Funkin"
# To bypass "you have reached your rate limit!", you can input a github token either as an environment variable
# or alongside the `git cliff` command like so `git cliff --github-token TOKEN_HERE`
# Personally I like to use the github cli `gh` tool to get a token
# `git cliff --github-token $(gh auth token)`
[changelog]
# template for the changelog body
# https://keats.github.io/tera/docs/#introduction
body = """
{%- macro remote_url() -%}
https://github.com/{{ remote.github.owner }}/{{ remote.github.repo }}
{%- endmacro -%}
{% if version -%}
## [{{ version | trim_start_matches(pat="v") }}] - {{ timestamp | date(format="%Y-%m-%d") }}
{% else -%}
## [Unreleased]
{% endif -%}
{% for group, commits in commits | group_by(attribute="group") %}
### {{ group | upper_first }}
{%- for commit in commits %}
- {% if commit.scope %}({{commit.scope}}) {% endif %}{{ commit.message | split(pat="\n") | first | upper_first | trim }} \
([{{ commit.id | truncate(length=7, end="") }}]({{self::remote_url()}}/commit/{{ commit.id }})) -\
{% if commit.remote.username %} by @{{ commit.remote.username }}
{%- elif commit.author.name %} by {{ commit.author.name }}
{%- endif -%}
{% if commit.remote.pr_number %} in \
[#{{ commit.remote.pr_number }}]({{ self::remote_url() }}/pull/{{ commit.remote.pr_number }}) \
{%- endif -%}
{% if commit.links | length != 0 %}\
[#{{ commit.links }}]({{ self::remote_url() }}/pull/{{ commit.remote.pr_number }}) \
{%- endif -%}
{% endfor %}
{% endfor %}
{%- if github.contributors | filter(attribute="is_first_time", value=true) | length != 0 %}
## New Contributors
{%- endif -%}
{% for contributor in github.contributors | filter(attribute="is_first_time", value=true) %}
* @{{ contributor.username }} made their first contribution
{%- if contributor.pr_number %} in \
[#{{ contributor.pr_number }}]({{ self::remote_url() }}/pull/{{ contributor.pr_number }}) \
{%- endif %}
{%- endfor %}\n
"""
# remove the leading and trailing whitespace from the templates
trim = true
[git]
# parse the commits based on https://www.conventionalcommits.org
conventional_commits = true
# filter out the commits that are not conventional
filter_unconventional = true
# regex for preprocessing the commit messages
commit_preprocessors = [
# remove issue numbers from commits
{ pattern = '\((\w+\s)?#([0-9]+)\)', replace = "" },
]
# regex for parsing and grouping commits
commit_parsers = [
{ message = "^docs", group = "Changed", scope="docs" },
{ message = "^[a|A]dd", group = "Added" },
{ message = "^[s|S]upport", group = "Added" },
{ message = "^[r|R]emove", group = "Removed" },
{ message = "^.*: add", group = "Added" },
{ message = "^.*: support", group = "Added" },
{ message = "^.*: remove", group = "Removed" },
{ message = "^.*: delete", group = "Removed" },
{ message = "^test", group = "Fixed" },
{ message = "^fix", group = "Fixed" },
{ message = "^.*: fix", group = "Fixed" },
{ message = "^.*", group = "Changed" },
]
# filter out the commits that are not matched by commit parsers
filter_commits = false
# sort the tags topologically
topo_order = false
# sort the commits inside sections by oldest/newest order
sort_commits = "newest"
+4 -6
View File
@@ -34,16 +34,14 @@ There are several useful build flags you can add to a build to affect how it wor
- `-DGITHUB_BUILD` will enable in-game debug functions (such as the ability to time travel in a song by pressing `PgUp`/`PgDn`), without enabling the other stuff
- `-DFEATURE_POLYMOD_MODS` or `-DNO_FEATURE_POLYMOD_MODS` to forcibly enable or disable modding support.
- `-DREDIRECT_ASSETS_FOLDER` or `-DNO_REDIRECT_ASSETS_FOLDER` to forcibly enable or disable asset redirection.
- This feature causes the game to load exported assets from the project's assets folder rather than the exported one. Great for fast iteration, but the game
- This feature causes the game to load exported assets from the project's assets folder rather than the exported one. Great for fast iteration, but the game will break if you try to zip it up and send it to someone, so it's disabled for release builds.
- `-DFEATURE_DISCORD_RPC` or `-DNO_FEATURE_DISCORD_RPC` to forcibly enable or disable support for Discord Rich Presence.
- `-DFEATURE_VIDEO_PLAYBACK` or `-DNO_FEATURE_VIDEO_PLAYBACK` to forcibly enable or disable video cutscene support.
- `-DFEATURE_CHART_EDITOR` or `-DNO_FEATURE_CHART_EDITOR` to forcibly enable or disable the chart editor in the Debug menu.
- `-DFEATURE_SCREENSHOTS` or `-DNO_FEATURE_SCREENSHOTS` to forcibly enable or disable the screenshots feature.
- `-DFEATURE_STAGE_EDITOR` to forcibly enable the experimental stage editor.
- `-DFEATURE_GHOST_TAPPING` to forcibly enable an experimental gameplay change to the anti-mash system.
# Troubleshooting - GO THROUGH THESE STEPS BEFORE OPENING ISSUES ON GITHUB!
# Troubleshooting
- During the cloning process, you may experience an error along the lines of `error: RPC failed; curl 92 HTTP/2 stream 0 was not closed cleanly: PROTOCOL_ERROR (err 1)` due to poor connectivity. A common fix is to run ` git config --global http.postBuffer 4096M`.
- Make sure your game directory has an `assets` folder! If it's missing, copy the path to your `funkin` folder and run `cd the\path\you\copied`. Then follow the guide starting from **Step 4**.
- Check that your `assets` folder is not empty! If it is, go back to **Step 4** and follow the guide from there.
- The compilation process often fails due to having the wrong versions of the required libraries. Many errors can be resolved by deleting the `.haxelib` folder and following the guide starting from **Step 5**.
If you experience any issues during the compilation process, DO NOT open an issue on GitHub. Instead, check the [Troubleshooting Guide](TROUBLESHOOTING.md) for steps on how to resolve common problems.
+3 -3
View File
@@ -15,8 +15,8 @@ Most of this functionality is only available on debug builds of the game!
- `2`: ***GAIN HEALTH***: Debug function, add 10% to the player's health.
- `3`: ***LOSE HEALTH***: Debug function, subtract 5% to the player's health.
- `9`: NEATO!
- `PAGEUP` (MacOS: `Fn-Up`): ***FORWARDS TIME TRAVEL****: Move forward by 2 sections. Hold SHIFT to move forward by 20 sections instead.
- `PAGEDOWN` (MacOS: `Fn-Down`): ***BACKWARDS TIME TRAVEL****: Move backward by 2 sections. Hold SHIFT to move backward by 20 sections instead.
- `PAGEUP` (MacOS: `Fn-Up`): ***FORWARDS TIME TRAVEL***: Move forward by 2 sections. Hold SHIFT to move forward by 20 sections instead.
- `PAGEDOWN` (MacOS: `Fn-Down`): ***BACKWARDS TIME TRAVEL***: Move backward by 2 sections. Hold SHIFT to move backward by 20 sections instead.
## **Freeplay State**
- `F` (Freeplay Menu) - Move to Favorites
@@ -27,5 +27,5 @@ Most of this functionality is only available on debug builds of the game!
- `Y` - WOAH
## **Main Menu**
- `~`: ***DEBUG****: Opens a menu to access the Chart Editor and other work-in-progress editors. Rebindable in the options menu.
- `~`: ***DEBUG***: Opens a menu to access the Chart Editor and other work-in-progress editors. Rebindable in the options menu.
- `CTRL-ALT-SHIFT-W`: ***ALL ACCESS***: Unlocks all songs in Freeplay. Only available on debug builds.
@@ -1,4 +1,4 @@
# Troubleshooting Common Issues
# Troubleshooting Common Compilation Issues
- Weird macro error with a very tall call stack: Restart Visual Studio Code
- NOTE: This is caused by Polymod somewhere, and seems to only occur when there is another compile error somewhere in the program. There is a bounty up for it.
@@ -13,3 +13,11 @@
- `LINK : fatal error LNK1201: error writing to program database ''; check for insufficient disk space, invalid path, or insufficient privilege`
- This error occurs if the PDB file located in your `export` folder is in use or exceeds 4 GB. Try deleting the `export` folder and building again from scratch.
- `error: RPC failed; curl 92 HTTP/2 stream 0 was not closed cleanly: PROTOCOL_ERROR (err 1)`
- This error can happen during cloning as a result of poor network connectivity. A common fix is to run ` git config --global http.postBuffer 4096M` in your terminal.
- Repository is missing an `assets` folder, or `assets` folder is empty.
- You did not clone the repository correctly! Copy the path to your `funkin` folder and run `cd the\path\you\copied`. Then follow the compilation guide starting from **Step 4**.
- Other compilation issues may be caused by installing bad library versions. Try deleting the `.haxelib` folder and following the guide starting from **Step 5**.
+1 -1
View File
@@ -6,7 +6,7 @@
"name": "EliteMasterEric"
}
],
"api_version": "0.1.0",
"api_version": "0.5.0",
"mod_version": "1.0.0",
"license": "Apache-2.0"
}
+1 -1
View File
@@ -6,7 +6,7 @@
"name": "EliteMasterEric"
}
],
"api_version": "0.1.0",
"api_version": "0.5.0",
"mod_version": "1.0.0",
"license": "Apache-2.0"
}
+12 -19
View File
@@ -7,13 +7,6 @@
"ref": "a1eab7b9bf507b87200a3341719054fe427f3b15",
"url": "https://github.com/FunkinCrew/FlxPartialSound.git"
},
{
"name": "discord_rpc",
"type": "git",
"dir": null,
"ref": "2d83fa863ef0c1eace5f1cf67c3ac315d1a3a8a5",
"url": "https://github.com/FunkinCrew/linc_discord-rpc"
},
{
"name": "flixel",
"type": "git",
@@ -25,7 +18,7 @@
"name": "flixel-addons",
"type": "git",
"dir": null,
"ref": "9c6fb47968e894eb36bf10e94725cd7640c49281",
"ref": "7424db4e9164ff46f224a7c47de1b732d2542dd7",
"url": "https://github.com/FunkinCrew/flixel-addons"
},
{
@@ -35,13 +28,6 @@
"ref": "951a0103a17bfa55eed86703ce50b4fb0d7590bc",
"url": "https://github.com/FunkinCrew/flixel-text-input"
},
{
"name": "flixel-ui",
"type": "git",
"dir": null,
"ref": "27f1ba626f80a6282fa8a187115e79a4a2133dc2",
"url": "https://github.com/HaxeFlixel/flixel-ui"
},
{
"name": "flxanimate",
"type": "git",
@@ -77,14 +63,14 @@
"name": "haxeui-core",
"type": "git",
"dir": null,
"ref": "22f7c5a8ffca90d4677cffd6e570f53761709fbc",
"ref": "51c23588614397089a5ce182cddea729f0be6fa0",
"url": "https://github.com/haxeui/haxeui-core"
},
{
"name": "haxeui-flixel",
"type": "git",
"dir": null,
"ref": "28bb710d0ae5d94b5108787593052165be43b980",
"ref": "da27e833947f32ef007ed11f523aa5524f5a5d54",
"url": "https://github.com/haxeui/haxeui-flixel"
},
{
@@ -105,8 +91,8 @@
"name": "hxcpp",
"type": "git",
"dir": null,
"ref": "904ea40643b050a5a154c5e4c33a83fd2aec18b1",
"url": "https://github.com/HaxeFoundation/hxcpp"
"ref": "c6bac3d6c7d683f25104296b2f4c50f8c90b8349",
"url": "https://github.com/cortex-engine/hxcpp"
},
{
"name": "hxcpp-debug-server",
@@ -115,6 +101,13 @@
"ref": "147294123f983e35f50a966741474438069a7a8f",
"url": "https://github.com/FunkinCrew/hxcpp-debugger"
},
{
"name": "hxdiscord_rpc",
"type": "git",
"dir": null,
"ref": "82c47ecc1a454b7dd644e4fcac7e91155f176dec",
"url": "https://github.com/FunkinCrew/hxdiscord_rpc"
},
{
"name": "hxjsonast",
"type": "git",
+46 -5
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.5.0";
static final VERSION:String = "0.5.2";
/**
* The game's name. Used as the default window title.
@@ -149,6 +149,21 @@ class Project extends HXProject {
*/
static final FEATURE_DEBUG_FUNCTIONS:FeatureFlag = "FEATURE_DEBUG_FUNCTIONS";
/**
* `-DFEATURE_DEBUG_TRACY`
* If this flag is enabled, the game will have the necessary hooks for the Tracy profiler.
* Only enable this if you're using the correct fork of Haxe to support this.
* @see https://github.com/HaxeFoundation/hxcpp/pull/1153
*/
static final FEATURE_DEBUG_TRACY:FeatureFlag = "FEATURE_DEBUG_TRACY";
/**
* `-DFEATURE_LOG_TRACE`
* If this flag is enabled, the game will print debug traces to the console.
* Disable to improve performance a bunch.
*/
static final FEATURE_LOG_TRACE:FeatureFlag = "FEATURE_LOG_TRACE";
/**
* `-DFEATURE_DISCORD_RPC`
* If this flag is enabled, the game will enable the Discord Remote Procedure Call library.
@@ -199,6 +214,12 @@ class Project extends HXProject {
*/
static final FEATURE_OPEN_URL:FeatureFlag = "FEATURE_OPEN_URL";
/**
* `-DFEATURE_SCREENSHOTS`
* If this flag is enabled, the game will support the screenshots feature.
*/
static final FEATURE_SCREENSHOTS:FeatureFlag = "FEATURE_SCREENSHOTS";
/**
* `-DFEATURE_CHART_EDITOR`
* If this flag is enabled, the Chart Editor will be accessible from the debug menu.
@@ -453,14 +474,14 @@ class Project extends HXProject {
// Should be true on debug builds or if GITHUB_BUILD is enabled.
FEATURE_DEBUG_FUNCTIONS.apply(this, isDebug() || GITHUB_BUILD.isEnabled(this));
FEATURE_LOG_TRACE.apply(this, isDebug());
// Should default to true on workspace builds and false on release builds.
REDIRECT_ASSETS_FOLDER.apply(this, isDebug() && isDesktop());
// Should be true on release, non-tester builds.
// Should be true on desktop, release, non-tester builds.
// We don't want testers to accidentally leak songs to their Discord friends!
// TODO: Re-enable this.
FEATURE_DISCORD_RPC.apply(this, false && !FEATURE_DEBUG_FUNCTIONS.isEnabled(this));
FEATURE_DISCORD_RPC.apply(this, isDesktop() && !FEATURE_DEBUG_FUNCTIONS.isEnabled(this));
// Should be true only on web builds.
// Audio context issues only exist there.
@@ -478,6 +499,10 @@ class Project extends HXProject {
// Should be true except on web builds.
// Chart editor doesn't work there.
FEATURE_CHART_EDITOR.apply(this, !isWeb());
// Should be true except on web builds.
// Screenshots doesn't work there.
FEATURE_SCREENSHOTS.apply(this, !isWeb());
}
/**
@@ -516,6 +541,16 @@ class Project extends HXProject {
// Cleaner looking compiler errors.
setHaxedef("message.reporting", "pretty");
if (FEATURE_DEBUG_TRACY.isEnabled(this)) {
setHaxedef("HXCPP_TELEMETRY"); // Enable telemetry
setHaxedef("HXCPP_TRACY"); // Enable Tracy telemetry
setHaxedef("HXCPP_TRACY_MEMORY"); // Track memory allocations
setHaxedef("HXCPP_TRACY_ON_DEMAND"); // Only collect telemetry when Tracy is open and reachable
// setHaxedef("HXCPP_TRACY_INCLUDE_CALLSTACKS"); // Inspect callstacks per zone, inflating telemetry data
setHaxedef("absolute-paths"); // Fix source locations so Tracy can see them
}
}
/**
@@ -618,7 +653,7 @@ class Project extends HXProject {
}
if (FEATURE_DISCORD_RPC.isEnabled(this)) {
addHaxelib('discord_rpc'); // Discord API
addHaxelib('hxdiscord_rpc'); // Discord API
}
if (FEATURE_NEWGROUNDS.isEnabled(this)) {
@@ -941,6 +976,8 @@ class Project extends HXProject {
var commitHash:String = process.stdout.readLine();
var commitHashSplice:String = commitHash.substr(0, 7);
process.close();
return commitHashSplice;
}
@@ -955,6 +992,8 @@ class Project extends HXProject {
var branchName:String = branchProcess.stdout.readLine();
branchProcess.close();
return branchName;
}
@@ -979,6 +1018,8 @@ class Project extends HXProject {
}
}
branchProcess.close();
return output.length > 0;
}
+2 -9
View File
@@ -2,6 +2,7 @@ package;
import flixel.FlxGame;
import flixel.FlxState;
import funkin.Preferences;
import funkin.util.logging.CrashHandler;
import funkin.ui.debug.MemoryCounter;
import funkin.save.Save;
@@ -22,12 +23,6 @@ class Main extends Sprite
var gameHeight:Int = 720; // Height of the game in pixels (might be less / more in actual pixels depending on your zoom).
var initialState:Class<FlxState> = funkin.InitState; // The FlxState the game starts with.
var zoom:Float = -1; // If -1, zoom is automatically calculated to fit the window dimensions.
#if (web || CHEEMS)
var framerate:Int = 60; // How many frames per second the game should run at.
#else
// TODO: This should probably be in the options menu?
var framerate:Int = 144; // How many frames per second the game should run at.
#end
var skipSplash:Bool = true; // Whether to skip the flixel splash screen that appears in release mode.
var startFullscreen:Bool = false; // Whether to start the game in fullscreen on desktop targets
@@ -109,7 +104,7 @@ class Main extends Sprite
// George recommends binding the save before FlxGame is created.
Save.load();
var game:FlxGame = new FlxGame(gameWidth, gameHeight, initialState, framerate, framerate, skipSplash, startFullscreen);
var game:FlxGame = new FlxGame(gameWidth, gameHeight, initialState, Preferences.framerate, Preferences.framerate, skipSplash, startFullscreen);
// FlxG.game._customSoundTray wants just the class, it calls new from
// create() in there, which gets called when it's added to stage
@@ -123,8 +118,6 @@ class Main extends Sprite
game.debugger.interaction.addTool(new funkin.util.TrackerToolButtonUtil());
#end
addChild(fpsCounter);
#if hxcpp_debug_server
trace('hxcpp_debug_server is enabled! You can now connect to the game with a debugger.');
#else
+102
View File
@@ -0,0 +1,102 @@
/*
* Pulled from Tracey profiler PR
* @see https://github.com/HaxeFoundation/haxe/pull/11772
*/
package cpp.vm.tracy;
#if (!HXCPP_TRACY)
#error "This class cannot be used without -D HXCPP_TRACY"
#end
enum abstract PlotFormatType(cpp.UInt8) from cpp.UInt8 to cpp.UInt8
{
var Number = 0;
var Memory = 1;
var Percentage = 2;
}
@:include('hx/TelemetryTracy.h')
extern class Native_TracyProfiler
{
/**
Mark a frame. Call this at the end of each frame loop.
**/
@:native('::__hxcpp_tracy_framemark')
public static function frameMark():Void;
/**
Print a message into Tracy's log.
**/
@:native('::__hxcpp_tracy_message')
public static function message(_msg:String, ?_color:Int = 0x000000):Void;
/**
Tracy can collect additional information about the profiled application,
which will be available in the trace description.
This can include data such as the source repository revision,
the application’s environment (dev/prod), etc.
**/
@:native('::__hxcpp_tracy_message_app_info')
public static function messageAppInfo(_info:String):Void;
/**
Plot a named value to tracy. This will generate a graph in the profiler for you.
**/
@:native('::__hxcpp_tracy_plot')
public static function plot(_name:String, _val:cpp.Float32):Void;
/**
Configure how values are plotted and displayed.
**/
@:native('::__hxcpp_tracy_plot_config')
public static function plotConfig(_name:String, _format:PlotFormatType, ?_step:Bool = false, ?_fill:Bool = false, ?_color:Int = 0x000000):Void;
/**
Set a name for the current thread this function is called in. Supply an optional groupHint so threads become grouped in Tracy's UI.
**/
@:native('::__hxcpp_tracy_set_thread_name_and_group')
public static function setThreadName(_name:String, ?_groupHint:Int = 1):Void;
/**
Create a custom named scoped zone in your code.
**/
@:native('HXCPP_TRACY_ZONE')
public static function zoneScoped(_name:String):Void;
}
#if (scriptable || cppia)
class Cppia_TracyProfiler
{
@:inheritDoc(cpp.vm.tracy.Native_TracyProfiler.frameMark)
public static function frameMark()
Native_TracyProfiler.frameMark();
@:inheritDoc(cpp.vm.tracy.Native_TracyProfiler.message)
public static function message(_msg:String, ?_color:Int = 0x000000)
Native_TracyProfiler.message(_msg, _color);
@:inheritDoc(cpp.vm.tracy.Native_TracyProfiler.messageAppInfo)
public static function messageAppInfo(_info:String)
Native_TracyProfiler.messageAppInfo(_info);
@:inheritDoc(cpp.vm.tracy.Native_TracyProfiler.plot)
public static function plot(_name:String, _val:Float)
Native_TracyProfiler.plot(_name, _val);
@:inheritDoc(cpp.vm.tracy.Native_TracyProfiler.plotConfig)
public static function plotConfig(_name:String, _format:PlotFormatType, ?_step:Bool = false, ?_fill:Bool = false, ?_color:Int = 0x000000)
Native_TracyProfiler.plotConfig(_name, _format, _step, _fill, _color);
@:inheritDoc(cpp.vm.tracy.Native_TracyProfiler.setThreadName)
public static function setThreadName(_name:String, ?_groupHint:Int = 1)
Native_TracyProfiler.setThreadName(_name, _groupHint);
@:inheritDoc(cpp.vm.tracy.Native_TracyProfiler.zoneScoped)
public static function zoneScoped(_name:String)
Native_TracyProfiler.zoneScoped(_name);
}
typedef TracyProfiler = Cppia_TracyProfiler;
#else
typedef TracyProfiler = Native_TracyProfiler;
#end
+136 -13
View File
@@ -1,38 +1,161 @@
package funkin;
import openfl.utils.Future;
/**
* A wrapper around `openfl.utils.Assets` which disallows access to the harmful functions.
* Later we'll add Funkin-specific caching to this.
*/
class Assets
{
public static function getText(path:String):String
/**
* Get the file system path for an asset
* @param path The asset path to load from, relative to the assets folder
* @return The path to the asset on the file system
*/
public static function getPath(path:String):String
{
return openfl.utils.Assets.getText(path);
}
public static function getMusic(path:String):openfl.media.Sound
{
return openfl.utils.Assets.getMusic(path);
}
public static function getBitmapData(path:String):openfl.display.BitmapData
{
return openfl.utils.Assets.getBitmapData(path);
return openfl.utils.Assets.getPath(path);
}
/**
* Load bytes from an asset
* May cause stutters or throw an error if the asset is not cached
* @param path The asset path to load from
* @return The byte contents of the file
*/
public static function getBytes(path:String):haxe.io.Bytes
{
return openfl.utils.Assets.getBytes(path);
}
/**
* Load bytes from an asset asynchronously
* @param path The asset path to load from
* @return A future which promises to return the byte contents of the file
*/
public static function loadBytes(path:String):Future<openfl.utils.ByteArray>
{
return openfl.utils.Assets.loadBytes(path);
}
/**
* Load text from an asset.
* May cause stutters or throw an error if the asset is not cached
* @param path The asset path to load from
* @return The text contents of the file
*/
public static function getText(path:String):String
{
return openfl.utils.Assets.getText(path);
}
/**
* Load text from an asset asynchronously
* @param path The asset path to load from
* @return A future which promises to return the text contents of the file
*/
public static function loadText(path:String):Future<String>
{
return openfl.utils.Assets.loadText(path);
}
/**
* Load a Sound file from an asset
* May cause stutters or throw an error if the asset is not cached
* @param path The asset path to load from
* @return The loaded sound
*/
public static function getSound(path:String):openfl.media.Sound
{
return openfl.utils.Assets.getSound(path);
}
/**
* Load a Sound file from an asset asynchronously
* @param path The asset path to load from
* @return A future which promises to return the loaded sound
*/
public static function loadSound(path:String):Future<openfl.media.Sound>
{
return openfl.utils.Assets.loadSound(path);
}
/**
* Load a Sound file from an asset, with optimizations specific to long-duration music
* May cause stutters or throw an error if the asset is not cached
* @param path The asset path to load from
* @return The loaded sound
*/
public static function getMusic(path:String):openfl.media.Sound
{
return openfl.utils.Assets.getMusic(path);
}
/**
* Load a Sound file from an asset asynchronously, with optimizations specific to long-duration music
* @param path The asset path to load from
* @return A future which promises to return the loaded sound
*/
public static function loadMusic(path:String):Future<openfl.media.Sound>
{
return openfl.utils.Assets.loadMusic(path);
}
/**
* Load a Bitmap from an asset
* May cause stutters or throw an error if the asset is not cached
* @param path The asset path to load from
* @return The loaded Bitmap image
*/
public static function getBitmapData(path:String):openfl.display.BitmapData
{
return openfl.utils.Assets.getBitmapData(path);
}
/**
* Load a Bitmap from an asset asynchronously
* @param path The asset path to load from
* @return The future which promises to return the loaded Bitmap image
*/
public static function loadBitmapData(path:String):Future<openfl.display.BitmapData>
{
return openfl.utils.Assets.loadBitmapData(path);
}
/**
* Determines whether the given asset of the given type exists.
* @param path The asset path to check
* @param type The asset type to check
* @return Whether the asset exists
*/
public static function exists(path:String, ?type:openfl.utils.AssetType):Bool
{
return openfl.utils.Assets.exists(path, type);
}
public static function list(type:openfl.utils.AssetType):Array<String>
/**
* Retrieve a list of all assets of the given type
* @param type The asset type to check
* @return A list of asset paths
*/
public static function list(?type:openfl.utils.AssetType):Array<String>
{
return openfl.utils.Assets.list(type);
}
public static function hasLibrary(name:String):Bool
{
return openfl.utils.Assets.hasLibrary(name);
}
public static function getLibrary(name:String):lime.utils.AssetLibrary
{
return openfl.utils.Assets.getLibrary(name);
}
public static function loadLibrary(name:String):Future<openfl.utils.AssetLibrary>
{
return openfl.utils.Assets.loadLibrary(name);
}
}
+24 -4
View File
@@ -275,6 +275,13 @@ class Conductor
return Save.instance.options.audioVisualOffset;
}
public var combinedOffset(get, never):Float;
function get_combinedOffset():Float
{
return instrumentalOffset + audioVisualOffset + inputOffset;
}
/**
* The number of beats in a measure. May be fractional depending on the time signature.
*/
@@ -397,20 +404,32 @@ class Conductor
*/
public function update(?songPos:Float, applyOffsets:Bool = true, forceDispatch:Bool = false)
{
var currentTime:Float = (FlxG.sound.music != null) ? FlxG.sound.music.time : 0.0;
var currentLength:Float = (FlxG.sound.music != null) ? FlxG.sound.music.length : 0.0;
if (songPos == null)
{
songPos = (FlxG.sound.music != null) ? FlxG.sound.music.time : 0.0;
songPos = currentTime;
}
// Take into account instrumental and file format song offsets.
songPos += applyOffsets ? (instrumentalOffset + formatOffset + audioVisualOffset) : 0;
songPos += applyOffsets ? (combinedOffset) : 0;
var oldMeasure:Float = this.currentMeasure;
var oldBeat:Float = this.currentBeat;
var oldStep:Float = this.currentStep;
// If the song is playing, limit the song position to the length of the song or beginning of the song.
if (FlxG.sound.music != null && FlxG.sound.music.playing)
{
this.songPosition = Math.min(currentLength, Math.max(0, songPos));
}
else
{
this.songPosition = songPos;
}
// Set the song position we are at (for purposes of calculating note positions, etc).
this.songPosition = songPos;
currentTimeChange = timeChanges[0];
if (this.songPosition > 0.0)
@@ -430,7 +449,8 @@ class Conductor
else if (currentTimeChange != null && this.songPosition > 0.0)
{
// roundDecimal prevents representing 8 as 7.9999999
this.currentStepTime = FlxMath.roundDecimal((currentTimeChange.beatTime * Constants.STEPS_PER_BEAT) + (this.songPosition - currentTimeChange.timeStamp) / stepLengthMs, 6);
this.currentStepTime = FlxMath.roundDecimal((currentTimeChange.beatTime * Constants.STEPS_PER_BEAT)
+ (this.songPosition - currentTimeChange.timeStamp) / stepLengthMs, 6);
this.currentBeatTime = currentStepTime / Constants.STEPS_PER_BEAT;
this.currentMeasureTime = currentStepTime / stepsPerMeasure;
this.currentStep = Math.floor(currentStepTime);
+22 -20
View File
@@ -1,42 +1,42 @@
package funkin;
import funkin.data.freeplay.player.PlayerRegistry;
import funkin.ui.debug.charting.ChartEditorState;
import funkin.ui.transition.LoadingState;
import flixel.FlxState;
import flixel.addons.transition.FlxTransitionableState;
import flixel.addons.transition.FlxTransitionSprite.GraphicTransTileDiamond;
import flixel.addons.transition.TransitionData;
import flixel.FlxSprite;
import flixel.FlxState;
import flixel.graphics.FlxGraphic;
import flixel.math.FlxPoint;
import flixel.math.FlxRect;
import flixel.FlxSprite;
import flixel.system.debug.log.LogStyle;
import flixel.util.FlxColor;
import funkin.util.macro.MacroUtil;
import funkin.util.WindowUtil;
import funkin.play.PlayStatePlaylist;
import openfl.display.BitmapData;
import funkin.data.story.level.LevelRegistry;
import funkin.data.notestyle.NoteStyleRegistry;
import funkin.data.freeplay.style.FreeplayStyleRegistry;
import funkin.data.event.SongEventRegistry;
import funkin.data.stage.StageRegistry;
import funkin.data.dialogue.conversation.ConversationRegistry;
import funkin.data.dialogue.dialoguebox.DialogueBoxRegistry;
import funkin.data.dialogue.speaker.SpeakerRegistry;
import funkin.data.freeplay.album.AlbumRegistry;
import funkin.data.freeplay.player.PlayerRegistry;
import funkin.data.freeplay.style.FreeplayStyleRegistry;
import funkin.data.notestyle.NoteStyleRegistry;
import funkin.data.song.SongRegistry;
import funkin.data.event.SongEventRegistry;
import funkin.data.stage.StageRegistry;
import funkin.data.story.level.LevelRegistry;
import funkin.modding.module.ModuleHandler;
import funkin.play.character.CharacterData.CharacterDataParser;
import funkin.play.notes.notekind.NoteKindManager;
import funkin.modding.module.ModuleHandler;
import funkin.play.PlayStatePlaylist;
import funkin.ui.debug.charting.ChartEditorState;
import funkin.ui.title.TitleState;
import funkin.ui.transition.LoadingState;
import funkin.util.CLIUtil;
import funkin.util.CLIUtil.CLIParams;
import funkin.util.macro.MacroUtil;
import funkin.util.TimerUtil;
import funkin.util.TrackerUtil;
import funkin.util.WindowUtil;
import openfl.display.BitmapData;
#if FEATURE_DISCORD_RPC
import Discord.DiscordClient;
import funkin.api.discord.DiscordClient;
#end
/**
@@ -125,10 +125,10 @@ class InitState extends FlxState
// DISCORD API SETUP
//
#if FEATURE_DISCORD_RPC
DiscordClient.initialize();
DiscordClient.instance.init();
Application.current.onExit.add(function(exitCode) {
DiscordClient.shutdown();
lime.app.Application.current.onExit.add(function(exitCode) {
DiscordClient.instance.shutdown();
});
#end
@@ -148,10 +148,12 @@ class InitState extends FlxState
#if FEATURE_DEBUG_FUNCTIONS
funkin.util.plugins.MemoryGCPlugin.initialize();
#end
#if FEATURE_SCREENSHOTS
funkin.util.plugins.ScreenshotPlugin.initialize();
#end
funkin.util.plugins.EvacuateDebugPlugin.initialize();
funkin.util.plugins.ForceCrashPlugin.initialize();
funkin.util.plugins.ReloadAssetsDebugPlugin.initialize();
funkin.util.plugins.ScreenshotPlugin.initialize();
funkin.util.plugins.VolumePlugin.initialize();
funkin.util.plugins.WatchPlugin.initialize();
+2 -3
View File
@@ -2,7 +2,6 @@ package funkin;
import flixel.graphics.frames.FlxAtlasFrames;
import openfl.utils.AssetType;
import openfl.utils.Assets as OpenFlAssets;
/**
* A core class which handles determining asset paths.
@@ -44,11 +43,11 @@ class Paths
if (currentLevel != null)
{
var levelPath:String = getLibraryPathForce(file, currentLevel);
if (OpenFlAssets.exists(levelPath, type)) return levelPath;
if (Assets.exists(levelPath, type)) return levelPath;
}
var levelPath:String = getLibraryPathForce(file, 'shared');
if (OpenFlAssets.exists(levelPath, type)) return levelPath;
if (Assets.exists(levelPath, type)) return levelPath;
return getPreloadPath(file);
}
+30 -1
View File
@@ -8,7 +8,36 @@ import funkin.save.Save;
class Preferences
{
/**
* Whether some particularly fowl language is displayed.
* FPS
* @default `60`
*/
public static var framerate(get, set):Int;
static function get_framerate():Int
{
#if web
return 60;
#else
return Save?.instance?.options?.framerate ?? 60;
#end
}
static function set_framerate(value:Int):Int
{
#if web
return 60;
#else
var save:Save = Save.instance;
save.options.framerate = value;
save.flush();
FlxG.updateFramerate = value;
FlxG.drawFramerate = value;
return value;
#end
}
/**
* Whether some particularly foul language is displayed.
* @default `true`
*/
public static var naughtyness(get, set):Bool;
-91
View File
@@ -1,91 +0,0 @@
package funkin.api.discord;
import Sys.sleep;
#if FEATURE_DISCORD_RPC
import discord_rpc.DiscordRpc;
#end
class DiscordClient
{
#if FEATURE_DISCORD_RPC
public function new()
{
trace("Discord Client starting...");
DiscordRpc.start(
{
clientID: "814588678700924999",
onReady: onReady,
onError: onError,
onDisconnected: onDisconnected
});
trace("Discord Client started.");
while (true)
{
DiscordRpc.process();
sleep(2);
// trace("Discord Client Update");
}
DiscordRpc.shutdown();
}
public static function shutdown()
{
DiscordRpc.shutdown();
}
static function onReady()
{
DiscordRpc.presence(
{
details: "In the Menus",
state: null,
largeImageKey: 'icon',
largeImageText: "Friday Night Funkin'"
});
}
static function onError(_code:Int, _message:String)
{
trace('Error! $_code : $_message');
}
static function onDisconnected(_code:Int, _message:String)
{
trace('Disconnected! $_code : $_message');
}
public static function initialize()
{
var DiscordDaemon = sys.thread.Thread.create(() -> {
new DiscordClient();
});
trace("Discord Client initialized");
}
public static function changePresence(details:String, ?state:String, ?smallImageKey:String, ?hasStartTimestamp:Bool, ?endTimestamp:Float)
{
var startTimestamp:Float = if (hasStartTimestamp) Date.now().getTime() else 0;
if (endTimestamp > 0)
{
endTimestamp = startTimestamp + endTimestamp;
}
DiscordRpc.presence(
{
details: details,
state: state,
largeImageKey: 'icon',
largeImageText: "Friday Night Funkin'",
smallImageKey: smallImageKey,
// Obtained times are in milliseconds so they are divided so Discord can use it
startTimestamp: Std.int(startTimestamp / 1000),
endTimestamp: Std.int(endTimestamp / 1000)
});
// trace('Discord RPC Updated. Arguments: $details, $state, $smallImageKey, $hasStartTimestamp, $endTimestamp');
}
#end
}
+204
View File
@@ -0,0 +1,204 @@
package funkin.api.discord;
#if FEATURE_DISCORD_RPC
import hxdiscord_rpc.Discord;
import hxdiscord_rpc.Types;
import sys.thread.Thread;
class DiscordClient
{
static final CLIENT_ID:String = "816168432860790794";
public static var instance(get, never):DiscordClient;
static var _instance:Null<DiscordClient> = null;
static function get_instance():DiscordClient
{
if (DiscordClient._instance == null) _instance = new DiscordClient();
if (DiscordClient._instance == null) throw "Could not initialize singleton DiscordClient!";
return DiscordClient._instance;
}
var handlers:DiscordEventHandlers;
private function new()
{
trace('[DISCORD] Initializing event handlers...');
handlers = DiscordEventHandlers.create();
handlers.ready = cpp.Function.fromStaticFunction(onReady);
handlers.disconnected = cpp.Function.fromStaticFunction(onDisconnected);
handlers.errored = cpp.Function.fromStaticFunction(onError);
}
public function init():Void
{
trace('[DISCORD] Initializing connection...');
// Discord.initialize(CLIENT_ID, handlers, true, null);
Discord.Initialize(CLIENT_ID, cpp.RawPointer.addressOf(handlers), 1, null);
createDaemon();
}
var daemon:Thread = null;
function createDaemon():Void
{
daemon = Thread.create(doDaemonWork);
}
function doDaemonWork():Void
{
while (true)
{
trace('[DISCORD] Performing client update...');
#if DISCORD_DISABLE_IO_THREAD
Discord.updateConnection();
#end
Discord.runCallbacks();
Sys.sleep(2);
}
}
public function shutdown():Void
{
trace('[DISCORD] Shutting down...');
Discord.shutdown();
}
public function setPresence(params:DiscordClientPresenceParams):Void
{
trace('[DISCORD] Updating presence... (${params})');
Discord.updatePresence(buildPresence(params));
}
function buildPresence(params:DiscordClientPresenceParams):DiscordRichPresence
{
var presence = DiscordRichPresence.create();
// Presence should always be playing the game.
presence.type = DiscordActivityType_Playing;
// Text when hovering over the large image. We just leave this as the game name.
presence.largeImageText = "Friday Night Funkin'";
// State should be generally what the person is doing, like "In the Menus" or "Pico (Pico Mix) [Freeplay Hard]"
presence.state = cast(params.state, Null<String>);
// Details should be what the person is specifically doing, including stuff like timestamps (maybe something like "03:24 elapsed").
presence.details = cast(params.details, Null<String>);
// The large image displaying what the user is doing.
// This should probably be album art.
// IMPORTANT NOTE: This can be an asset key uploaded to Discord's developer panel OR any URL you like.
presence.largeImageKey = cast(params.largeImageKey, Null<String>) ?? "album-volume1";
trace('[DISCORD] largeImageKey: ${presence.largeImageKey}');
// TODO: Make this use the song's album art.
// presence.largeImageKey = "icon";
// presence.largeImageKey = "https://f4.bcbits.com/img/a0746694746_16.jpg";
// The small inset image for what the user is doing.
// This can be the opponent's health icon?
// NOTE: Like largeImageKey, this can be a URL, or an asset key.
presence.smallImageKey = cast(params.smallImageKey, Null<String>);
// NOTE: In previous versions, this showed as "Elapsed", but now shows as playtime and doesn't look good
// presence.startTimestamp = time - 10;
// presence.endTimestamp = time + 30;
final button1:DiscordButton = DiscordButton.create();
button1.label = "Play on Web";
button1.url = Constants.URL_NEWGROUNDS;
presence.buttons[0] = button1;
final button2:DiscordButton = DiscordButton.create();
button2.label = "Download";
button2.url = Constants.URL_ITCH;
presence.buttons[1] = button2;
return presence;
}
// TODO: WHAT THE FUCK get this pointer bullfuckery out of here
private static function onReady(request:cpp.RawConstPointer<DiscordUser>):Void
{
trace('[DISCORD] Client has connected!');
final username:String = request[0].username;
final globalName:String = request[0].username;
final discriminator:Int = Std.parseInt(request[0].discriminator);
if (discriminator != 0)
{
trace('[DISCORD] User: ${username}#${discriminator} (${globalName})');
}
else
{
trace('[DISCORD] User: @${username} (${globalName})');
}
}
private static function onDisconnected(errorCode:Int, message:cpp.ConstCharStar):Void
{
trace('[DISCORD] Client has disconnected! ($errorCode) "${cast (message, String)}"');
}
private static function onError(errorCode:Int, message:cpp.ConstCharStar):Void
{
trace('[DISCORD] Client has received an error! ($errorCode) "${cast (message, String)}"');
}
// public var type(get, set):DiscordActivityType;
// public var state(get, set):String;
// public var details(get, set):String;
// public var startTimestamp(get, set):Int;
// public var endTimestamp(get, set):Int;
// public var largeImageKey(get, set):String;
// public var largeImageText(get, set):String;
// public var smallImageKey(get, set):String;
// public var smallImageText(get, set):String;
//
//
// public var partyId(get, set)
// public var partySize(get, set)
// public var partyMax(get, set)
// public var partyPrivacy(get, set)
//
// public var buttons(get, set)
//
// public var matchSecret(get, set)
// public var joinSecret(get, set)
// public var spectateSecret(get, set)
}
typedef DiscordClientPresenceParams =
{
/**
* The first row of text below the game title.
*/
var state:String;
/**
* The second row of text below the game title.
* Use `null` to display no text.
*/
var details:Null<String>;
/**
* A large, 4-row high image to the left of the content.
*/
var ?largeImageKey:String;
/**
* A small, inset image to the bottom right of `largeImageKey`.
*/
var ?smallImageKey:String;
}
#end
+13 -6
View File
@@ -390,7 +390,7 @@ class FunkinSound extends FlxSound implements ICloneable<FunkinSound>
}
else
{
var music = FunkinSound.load(pathToUse, params?.startingVolume ?? 1.0, params.loop ?? true, false, true, params.onComplete);
var music = FunkinSound.load(pathToUse, params?.startingVolume ?? 1.0, params.loop ?? true, false, true, params.persist ?? false, params.onComplete);
if (music != null)
{
FlxG.sound.music = music;
@@ -430,12 +430,13 @@ class FunkinSound extends FlxSound implements ICloneable<FunkinSound>
* @param autoDestroy Whether to destroy this sound when it finishes playing.
* Leave this value set to `false` if you want to re-use this `FunkinSound` instance.
* @param autoPlay Whether to play the sound immediately or wait for a `play()` call.
* @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.
* @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,
?onComplete:Void->Void, ?onLoad:Void->Void):Null<FunkinSound>
persist:Bool = false, ?onComplete:Void->Void, ?onLoad:Void->Void):Null<FunkinSound>
{
@:privateAccess
if (SoundMixer.__soundChannels.length >= SoundMixer.MAX_ACTIVE_CHANNELS)
@@ -462,7 +463,7 @@ class FunkinSound extends FlxSound implements ICloneable<FunkinSound>
if (autoPlay) sound.play();
sound.volume = volume;
sound.group = FlxG.sound.defaultSoundGroup;
sound.persist = true;
sound.persist = persist;
// Make sure to add the sound to the list.
// If it's already in, it won't get re-added.
@@ -513,7 +514,7 @@ class FunkinSound extends FlxSound implements ICloneable<FunkinSound>
});
soundRequest.future.onComplete(function(partialSound) {
var snd = FunkinSound.load(partialSound, volume, looped, autoDestroy, autoPlay, onComplete, onLoad);
var snd = FunkinSound.load(partialSound, volume, looped, autoDestroy, autoPlay, false, onComplete, onLoad);
promise.complete(snd);
});
}
@@ -543,18 +544,19 @@ class FunkinSound extends FlxSound implements ICloneable<FunkinSound>
*/
public static function playOnce(key:String, volume:Float = 1.0, ?onComplete:Void->Void, ?onLoad:Void->Void):Null<FunkinSound>
{
var result = FunkinSound.load(key, volume, false, true, true, onComplete, onLoad);
var result:Null<FunkinSound> = FunkinSound.load(key, volume, false, true, true, false, onComplete, onLoad);
return result;
}
/**
* Stop all sounds in the pool and allow them to be recycled.
*/
public static function stopAllAudio(musicToo:Bool = false):Void
public static function stopAllAudio(musicToo:Bool = false, persistToo:Bool = false):Void
{
for (sound in pool)
{
if (sound == null) continue;
if (!persistToo && sound.persist) continue;
if (!musicToo && sound == FlxG.sound.music) continue;
sound.destroy();
}
@@ -628,6 +630,11 @@ typedef FunkinSoundPlayMusicParams =
var ?partialParams:PartialSoundParams;
/**
* Whether the sound should be destroyed on state switches
*/
var ?persist:Bool;
var ?onComplete:Void->Void;
var ?onLoad:Void->Void;
}
@@ -264,12 +264,32 @@ class PlayerCharSelectData
*/
@:optional
public var position:Null<Int>;
/**
* The GF name to assign for this character.
*/
@:optional
public var gf:PlayerCharSelectGFData;
}
typedef PlayerCharSelectGFData =
{
@:optional
public var assetPath:String;
@:optional
public var animInfoPath:String;
@:optional
@:default(false)
public var visualizer:Bool;
}
typedef PlayerResultsData =
{
var music:PlayerResultsMusicData;
var perfectGold:Array<PlayerResultsAnimationData>;
var perfect:Array<PlayerResultsAnimationData>;
var excellent:Array<PlayerResultsAnimationData>;
var great:Array<PlayerResultsAnimationData>;
+4
View File
@@ -5,6 +5,10 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [1.0.2]
### Added
- Added the ability to specify `flipX` and `flipY` on stage props to horizontally or vertically flip, respectively.
## [1.0.1]
### Added
- Added the ability to specify a hexadecimal color in the `assetPath` field instead of a texture key.
+46
View File
@@ -20,6 +20,10 @@ class StageData
@:optional
public var cameraZoom:Null<Float>;
@:default("shared")
@:optional
public var directory:Null<String>;
public function new()
{
this.version = StageRegistry.STAGE_DATA_VERSION;
@@ -118,6 +122,22 @@ typedef StageDataProp =
@:default(false)
var isPixel:Bool;
/**
* If set to true, the prop will be flipped horizontally.
* @default false
*/
@:optional
@:default(false)
var flipX:Bool;
/**
* If set to true, the prop will be flipped vertically.
* @default false
*/
@:optional
@:default(false)
var flipY:Bool;
/**
* Either the scale of the prop as a float, or the [w, h] scale as an array of two floats.
* Pro tip: On pixel-art levels, save the sprite small and set this value to 6 or so to save memory.
@@ -182,6 +202,32 @@ typedef StageDataProp =
@:default("sparrow")
@:optional
var animType:String;
/**
* The angle of the prop, as a float.
* @default 1.0
*/
@:optional
@:default(0.0)
var angle:Float;
/**
* The blend mode of the prop, as a string.
* Just like in photoshop.
* @default Nothing.
*/
@:default("")
@:optional
var blend:String;
/**
* The color of the prop overlay, as a hex string.
* White overlays, or the ones with the value #FFFFFF, do not appear.
* @default `#FFFFFF`
*/
@:default("#FFFFFF")
@:optional
var color:String;
};
typedef StageDataCharacter =
+2 -2
View File
@@ -11,9 +11,9 @@ class StageRegistry extends BaseRegistry<Stage, StageData>
* Handle breaking changes by incrementing this value
* and adding migration to the `migrateStageData()` function.
*/
public static final STAGE_DATA_VERSION:thx.semver.Version = "1.0.0";
public static final STAGE_DATA_VERSION:thx.semver.Version = "1.0.2";
public static final STAGE_DATA_VERSION_RULE:thx.semver.VersionRule = "1.0.x";
public static final STAGE_DATA_VERSION_RULE:thx.semver.VersionRule = ">=1.0.0 <=1.0.2";
public static var instance(get, never):StageRegistry;
static var _instance:Null<StageRegistry> = null;
+40
View File
@@ -0,0 +1,40 @@
package funkin.effects;
import flixel.addons.effects.FlxTrail;
import funkin.play.stage.Bopper;
import flixel.FlxSprite;
import flixel.system.FlxAssets;
/**
* An offshoot of FlxTrail, but accomodates the way Funkin
* does offsets for characters. example, fixes Spirits trail
*/
class FunkTrail extends FlxTrail
{
/**
* Creates a new FunkTrail effect for a specific FlxSprite.
*
* @param Target The FlxSprite the trail is attached to.
* @param Graphic The image to use for the trailsprites. Optional, uses the sprite's graphic if null.
* @param Length The amount of trailsprites to create.
* @param Delay How often to update the trail. 0 updates every frame.
* @param Alpha The alpha value for the very first trailsprite.
* @param Diff How much lower the alpha of the next trailsprite is.
*/
public function new(Target:FlxSprite, ?Graphic:FlxGraphicAsset, Length:Int = 10, Delay:Int = 3, Alpha:Float = 0.4, Diff:Float = 0.05)
{
super(Target, Graphic, Length, Delay, Alpha, Diff);
}
override public function update(elapsed:Float):Void
{
if (target is Bopper)
{
var targ:Bopper = cast target;
@:privateAccess effectOffset.set((targ.animOffsets[0] - targ.globalOffsets[0]) * targ.scale.x,
(targ.animOffsets[1] - targ.globalOffsets[1]) * targ.scale.y);
}
super.update(elapsed);
}
}
+12
View File
@@ -238,6 +238,18 @@ class FunkinSprite extends FlxSprite
return true;
}
/**
* @param id The animation ID to check.
* @return Whether the animation is dynamic (has multiple frames). `false` for static, one-frame animations.
*/
public function isAnimationDynamic(id:String):Bool
{
if (this.animation == null) return false;
var animData = this.animation.getByName(id);
if (animData == null) return false;
return animData.numFrames > 1;
}
/**
* Acts similarly to `makeGraphic`, but with improved memory usage,
* at the expense of not being able to paint onto the resulting sprite.
@@ -7,7 +7,6 @@ import flxanimate.frames.FlxAnimateFrames;
import flixel.graphics.frames.FlxFrame;
import flixel.system.FlxAssets.FlxGraphicAsset;
import openfl.display.BitmapData;
import openfl.utils.Assets;
import flixel.math.FlxPoint;
import flxanimate.animate.FlxKeyFrame;
@@ -184,7 +183,7 @@ class FlxAtlasSprite extends FlxAnimate
// Move to the first frame of the animation.
// goToFrameLabel(id);
trace('Playing animation $id');
// trace('Playing animation $id');
if ((id == null || id == "") || this.anim.symbolDictionary.exists(id) || (this.anim.getByName(id) != null))
{
this.anim.play(id, restart, false, startFrame);
@@ -1,8 +1,6 @@
package funkin.graphics.shaders;
import flixel.addons.display.FlxRuntimeShader;
import funkin.Paths;
import openfl.utils.Assets;
class AdjustColorShader extends FlxRuntimeShader
{
@@ -52,4 +50,9 @@ class AdjustColorShader extends FlxRuntimeShader
return this.contrast;
}
public override function toString():String
{
return 'AdjustColorShader(${this.hue}, ${this.saturation}, ${this.brightness}, ${this.contrast})';
}
}
@@ -1,8 +1,6 @@
package funkin.graphics.shaders;
import flixel.addons.display.FlxRuntimeShader;
import funkin.Paths;
import openfl.utils.Assets;
import openfl.display.BitmapData;
import openfl.display.ShaderInput;
@@ -1,8 +1,6 @@
package funkin.graphics.shaders;
import flixel.addons.display.FlxRuntimeShader;
import funkin.Paths;
import openfl.utils.Assets;
/**
* Note... not actually gaussian!
@@ -1,8 +1,6 @@
package funkin.graphics.shaders;
import flixel.addons.display.FlxRuntimeShader;
import funkin.Paths;
import openfl.utils.Assets;
class Grayscale extends FlxRuntimeShader
{
@@ -1,8 +1,6 @@
package funkin.graphics.shaders;
import flixel.addons.display.FlxRuntimeShader;
import funkin.Paths;
import openfl.utils.Assets;
class HSVShader extends FlxRuntimeShader
{
@@ -0,0 +1,23 @@
package funkin.graphics.shaders;
import flixel.addons.display.FlxRuntimeShader;
/**
* Create a little dotting effect.
*/
class InverseDotsShader extends FlxRuntimeShader
{
public var amount:Float;
public function new(amount:Float = 1.0)
{
super(Assets.getText(Paths.frag("InverseDots")));
setAmount(amount);
}
public function setAmount(value:Float):Void
{
this.amount = value;
this.setFloat("_amount", amount);
}
}
@@ -1,8 +1,6 @@
package funkin.graphics.shaders;
import flixel.addons.display.FlxRuntimeShader;
import openfl.utils.Assets;
import funkin.Paths;
import flixel.math.FlxPoint;
class MosaicEffect extends FlxRuntimeShader
@@ -2,7 +2,6 @@ package funkin.graphics.shaders;
import openfl.display.BitmapData;
import openfl.display.BlendMode;
import openfl.utils.Assets;
class RuntimeCustomBlendShader extends RuntimePostEffectShader
{
@@ -5,7 +5,6 @@ import openfl.display.BitmapData;
import openfl.display.ShaderParameter;
import openfl.display.ShaderParameterType;
import flixel.util.FlxColor;
import openfl.utils.Assets;
typedef Light =
{
@@ -0,0 +1,34 @@
package funkin.graphics.video;
#if hxCodec
import hxcodec.flixel.FlxVideoSprite;
/**
* Not to be confused with FlxVideo, this is a hxcodec based video class
* We override it simply to correct/control our volume easier.
*/
class FunkinVideoSprite extends FlxVideoSprite
{
public var volume(default, set):Float = 1;
public function new(x:Float = 0, y:Float = 0)
{
super(x, y);
set_volume(1);
}
override public function update(elapsed:Float):Void
{
super.update(elapsed);
set_volume(volume);
}
function set_volume(value:Float):Float
{
volume = value;
bitmap.volume = Std.int((FlxG.sound.muted ? 0 : 1) * (FlxG.sound.logToLinear(FlxG.sound.volume) * 100) * volume);
return volume;
}
}
#end
+1
View File
@@ -3,6 +3,7 @@ package;
#if !macro
// Only import these when we aren't in a macro.
import funkin.util.Constants;
import funkin.Assets;
import funkin.Paths;
import funkin.Preferences;
import flixel.FlxG; // This one in particular causes a compile error if you're using macros.
+60 -18
View File
@@ -59,7 +59,9 @@ class Controls extends FlxActionSet
var _back = new FunkinAction(Action.BACK);
var _pause = new FunkinAction(Action.PAUSE);
var _reset = new FunkinAction(Action.RESET);
#if FEATURE_SCREENSHOTS
var _window_screenshot = new FunkinAction(Action.WINDOW_SCREENSHOT);
#end
var _window_fullscreen = new FunkinAction(Action.WINDOW_FULLSCREEN);
var _freeplay_favorite = new FunkinAction(Action.FREEPLAY_FAVORITE);
var _freeplay_left = new FunkinAction(Action.FREEPLAY_LEFT);
@@ -67,8 +69,12 @@ class Controls extends FlxActionSet
var _freeplay_char_select = new FunkinAction(Action.FREEPLAY_CHAR_SELECT);
var _cutscene_advance = new FunkinAction(Action.CUTSCENE_ADVANCE);
var _debug_menu = new FunkinAction(Action.DEBUG_MENU);
#if FEATURE_CHART_EDITOR
var _debug_chart = new FunkinAction(Action.DEBUG_CHART);
#end
#if FEATURE_STAGE_EDITOR
var _debug_stage = new FunkinAction(Action.DEBUG_STAGE);
#end
var _volume_up = new FunkinAction(Action.VOLUME_UP);
var _volume_down = new FunkinAction(Action.VOLUME_DOWN);
var _volume_mute = new FunkinAction(Action.VOLUME_MUTE);
@@ -243,10 +249,12 @@ class Controls extends FlxActionSet
inline function get_WINDOW_FULLSCREEN()
return _window_fullscreen.check();
#if FEATURE_SCREENSHOTS
public var WINDOW_SCREENSHOT(get, never):Bool;
inline function get_WINDOW_SCREENSHOT()
return _window_screenshot.check();
#end
public var FREEPLAY_FAVORITE(get, never):Bool;
@@ -278,15 +286,19 @@ class Controls extends FlxActionSet
inline function get_DEBUG_MENU()
return _debug_menu.check();
#if FEATURE_CHART_EDITOR
public var DEBUG_CHART(get, never):Bool;
inline function get_DEBUG_CHART()
return _debug_chart.check();
#end
#if FEATURE_STAGE_EDITOR
public var DEBUG_STAGE(get, never):Bool;
inline function get_DEBUG_STAGE()
return _debug_stage.check();
#end
public var VOLUME_UP(get, never):Bool;
@@ -319,7 +331,7 @@ class Controls extends FlxActionSet
add(_back);
add(_pause);
add(_reset);
add(_window_screenshot);
#if FEATURE_SCREENSHOTS add(_window_screenshot); #end
add(_window_fullscreen);
add(_freeplay_favorite);
add(_freeplay_left);
@@ -327,8 +339,8 @@ class Controls extends FlxActionSet
add(_freeplay_char_select);
add(_cutscene_advance);
add(_debug_menu);
add(_debug_chart);
add(_debug_stage);
#if FEATURE_CHART_EDITOR add(_debug_chart); #end
#if FEATURE_STAGE_EDITOR add(_debug_stage); #end
add(_volume_up);
add(_volume_down);
add(_volume_mute);
@@ -444,7 +456,7 @@ class Controls extends FlxActionSet
case BACK: _back;
case PAUSE: _pause;
case RESET: _reset;
case WINDOW_SCREENSHOT: _window_screenshot;
#if FEATURE_SCREENSHOTS case WINDOW_SCREENSHOT: _window_screenshot; #end
case WINDOW_FULLSCREEN: _window_fullscreen;
case FREEPLAY_FAVORITE: _freeplay_favorite;
case FREEPLAY_LEFT: _freeplay_left;
@@ -452,8 +464,8 @@ class Controls extends FlxActionSet
case FREEPLAY_CHAR_SELECT: _freeplay_char_select;
case CUTSCENE_ADVANCE: _cutscene_advance;
case DEBUG_MENU: _debug_menu;
case DEBUG_CHART: _debug_chart;
case DEBUG_STAGE: _debug_stage;
#if FEATURE_CHART_EDITOR case DEBUG_CHART: _debug_chart; #end
#if FEATURE_STAGE_EDITOR case DEBUG_STAGE: _debug_stage; #end
case VOLUME_UP: _volume_up;
case VOLUME_DOWN: _volume_down;
case VOLUME_MUTE: _volume_mute;
@@ -516,8 +528,10 @@ class Controls extends FlxActionSet
func(_pause, JUST_PRESSED);
case RESET:
func(_reset, JUST_PRESSED);
#if FEATURE_SCREENSHOTS
case WINDOW_SCREENSHOT:
func(_window_screenshot, JUST_PRESSED);
#end
case WINDOW_FULLSCREEN:
func(_window_fullscreen, JUST_PRESSED);
case FREEPLAY_FAVORITE:
@@ -532,10 +546,14 @@ class Controls extends FlxActionSet
func(_cutscene_advance, JUST_PRESSED);
case DEBUG_MENU:
func(_debug_menu, JUST_PRESSED);
#if FEATURE_CHART_EDITOR
case DEBUG_CHART:
func(_debug_chart, JUST_PRESSED);
#end
#if FEATURE_STAGE_EDITOR
case DEBUG_STAGE:
func(_debug_stage, JUST_PRESSED);
#end
case VOLUME_UP:
func(_volume_up, JUST_PRESSED);
case VOLUME_DOWN:
@@ -744,7 +762,9 @@ 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));
#if FEATURE_SCREENSHOTS
bindKeys(Control.WINDOW_SCREENSHOT, getDefaultKeybinds(scheme, Control.WINDOW_SCREENSHOT));
#end
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));
@@ -752,8 +772,12 @@ class Controls extends FlxActionSet
bindKeys(Control.FREEPLAY_CHAR_SELECT, getDefaultKeybinds(scheme, Control.FREEPLAY_CHAR_SELECT));
bindKeys(Control.CUTSCENE_ADVANCE, getDefaultKeybinds(scheme, Control.CUTSCENE_ADVANCE));
bindKeys(Control.DEBUG_MENU, getDefaultKeybinds(scheme, Control.DEBUG_MENU));
#if FEATURE_CHART_EDITOR
bindKeys(Control.DEBUG_CHART, getDefaultKeybinds(scheme, Control.DEBUG_CHART));
#end
#if FEATURE_STAGE_EDITOR
bindKeys(Control.DEBUG_STAGE, getDefaultKeybinds(scheme, Control.DEBUG_STAGE));
#end
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));
@@ -781,15 +805,15 @@ class Controls extends FlxActionSet
case Control.PAUSE: return [P, ENTER, ESCAPE];
case Control.RESET: return [R];
case Control.WINDOW_FULLSCREEN: return [F11]; // We use F for other things LOL.
case Control.WINDOW_SCREENSHOT: return [F3];
#if FEATURE_SCREENSHOTS case Control.WINDOW_SCREENSHOT: return [F3]; #end
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.FREEPLAY_CHAR_SELECT: return [TAB];
case Control.CUTSCENE_ADVANCE: return [Z, ENTER];
case Control.DEBUG_MENU: return [GRAVEACCENT];
case Control.DEBUG_CHART: return [];
case Control.DEBUG_STAGE: return [];
#if FEATURE_CHART_EDITOR case Control.DEBUG_CHART: return []; #end
#if FEATURE_STAGE_EDITOR case Control.DEBUG_STAGE: return []; #end
case Control.VOLUME_UP: return [PLUS, NUMPADPLUS];
case Control.VOLUME_DOWN: return [MINUS, NUMPADMINUS];
case Control.VOLUME_MUTE: return [ZERO, NUMPADZERO];
@@ -809,7 +833,7 @@ class Controls extends FlxActionSet
case Control.BACK: return [H, X];
case Control.PAUSE: return [ONE];
case Control.RESET: return [R];
case Control.WINDOW_SCREENSHOT: return [F3];
#if FEATURE_SCREENSHOTS case Control.WINDOW_SCREENSHOT: return [F3]; #end
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
@@ -817,8 +841,8 @@ class Controls extends FlxActionSet
case Control.FREEPLAY_CHAR_SELECT: return [TAB];
case Control.CUTSCENE_ADVANCE: return [G, Z];
case Control.DEBUG_MENU: return [GRAVEACCENT];
case Control.DEBUG_CHART: return [];
case Control.DEBUG_STAGE: return [];
#if FEATURE_CHART_EDITOR case Control.DEBUG_CHART: return []; #end
#if FEATURE_STAGE_EDITOR case Control.DEBUG_STAGE: return []; #end
case Control.VOLUME_UP: return [PLUS];
case Control.VOLUME_DOWN: return [MINUS];
case Control.VOLUME_MUTE: return [ZERO];
@@ -838,7 +862,7 @@ class Controls extends FlxActionSet
case Control.BACK: return [ESCAPE];
case Control.PAUSE: return [ONE];
case Control.RESET: return [R];
case Control.WINDOW_SCREENSHOT: return [];
#if FEATURE_SCREENSHOTS case Control.WINDOW_SCREENSHOT: return []; #end
case Control.WINDOW_FULLSCREEN: return [];
case Control.FREEPLAY_FAVORITE: return [];
case Control.FREEPLAY_LEFT: return [];
@@ -846,8 +870,8 @@ class Controls extends FlxActionSet
case Control.FREEPLAY_CHAR_SELECT: return [];
case Control.CUTSCENE_ADVANCE: return [ENTER];
case Control.DEBUG_MENU: return [];
case Control.DEBUG_CHART: return [];
case Control.DEBUG_STAGE: return [];
#if FEATURE_CHART_EDITOR case Control.DEBUG_CHART: return []; #end
#if FEATURE_STAGE_EDITOR case Control.DEBUG_STAGE: return []; #end
case Control.VOLUME_UP: return [NUMPADPLUS];
case Control.VOLUME_DOWN: return [NUMPADMINUS];
case Control.VOLUME_MUTE: return [NUMPADZERO];
@@ -952,7 +976,9 @@ class Controls extends FlxActionSet
Control.PAUSE => getDefaultGamepadBinds(Control.PAUSE),
Control.RESET => getDefaultGamepadBinds(Control.RESET),
Control.WINDOW_FULLSCREEN => getDefaultGamepadBinds(Control.WINDOW_FULLSCREEN),
#if FEATURE_SCREENSHOTS
Control.WINDOW_SCREENSHOT => getDefaultGamepadBinds(Control.WINDOW_SCREENSHOT),
#end
Control.CUTSCENE_ADVANCE => getDefaultGamepadBinds(Control.CUTSCENE_ADVANCE),
Control.FREEPLAY_FAVORITE => getDefaultGamepadBinds(Control.FREEPLAY_FAVORITE),
Control.FREEPLAY_LEFT => getDefaultGamepadBinds(Control.FREEPLAY_LEFT),
@@ -961,8 +987,12 @@ class Controls extends FlxActionSet
Control.VOLUME_DOWN => getDefaultGamepadBinds(Control.VOLUME_DOWN),
Control.VOLUME_MUTE => getDefaultGamepadBinds(Control.VOLUME_MUTE),
Control.DEBUG_MENU => getDefaultGamepadBinds(Control.DEBUG_MENU),
#if FEATURE_CHART_EDITOR
Control.DEBUG_CHART => getDefaultGamepadBinds(Control.DEBUG_CHART),
#end
#if FEATURE_STAGE_EDITOR
Control.DEBUG_STAGE => getDefaultGamepadBinds(Control.DEBUG_STAGE),
#end
]);
}
@@ -996,8 +1026,10 @@ class Controls extends FlxActionSet
return [FlxGamepadInputID.BACK]; // Back (i.e. Select)
case Control.WINDOW_FULLSCREEN:
[];
#if FEATURE_SCREENSHOTS
case Control.WINDOW_SCREENSHOT:
[];
#end
case Control.CUTSCENE_ADVANCE:
return [A];
case Control.FREEPLAY_FAVORITE:
@@ -1014,10 +1046,14 @@ class Controls extends FlxActionSet
[];
case Control.DEBUG_MENU:
[];
#if FEATURE_CHART_EDITOR
case Control.DEBUG_CHART:
[];
#end
#if FEATURE_STAGE_EDITOR
case Control.DEBUG_STAGE:
[];
#end
default:
// Fallthrough.
}
@@ -1582,7 +1618,7 @@ enum Control
FREEPLAY_RIGHT;
FREEPLAY_CHAR_SELECT;
// WINDOW
WINDOW_SCREENSHOT;
#if FEATURE_SCREENSHOTS WINDOW_SCREENSHOT; #end
WINDOW_FULLSCREEN;
// VOLUME
VOLUME_UP;
@@ -1590,8 +1626,8 @@ enum Control
VOLUME_MUTE;
// DEBUG
DEBUG_MENU;
DEBUG_CHART;
DEBUG_STAGE;
#if FEATURE_CHART_EDITOR DEBUG_CHART; #end
#if FEATURE_STAGE_EDITOR DEBUG_STAGE; #end
}
enum abstract Action(String) to String from String
@@ -1628,7 +1664,9 @@ enum abstract Action(String) to String from String
var RESET = "reset";
// WINDOW
var WINDOW_FULLSCREEN = "window_fullscreen";
#if FEATURE_SCREENSHOTS
var WINDOW_SCREENSHOT = "window_screenshot";
#end
// CUTSCENE
var CUTSCENE_ADVANCE = "cutscene_advance";
// FREEPLAY
@@ -1642,8 +1680,12 @@ enum abstract Action(String) to String from String
var VOLUME_MUTE = "volume_mute";
// DEBUG
var DEBUG_MENU = "debug_menu";
#if FEATURE_CHART_EDITOR
var DEBUG_CHART = "debug_chart";
#end
#if FEATURE_STAGE_EDITOR
var DEBUG_STAGE = "debug_stage";
#end
}
enum Device
-1
View File
@@ -1,7 +1,6 @@
package funkin.input;
import haxe.ui.backend.flixel.CursorHelper;
import openfl.utils.Assets;
import lime.app.Future;
import openfl.display.BitmapData;
+23 -6
View File
@@ -27,11 +27,18 @@ import polymod.Polymod;
class PolymodHandler
{
/**
* The API version that mods should comply with.
* Indicates which mods are compatible with this version of the game.
* The API version for the current version of the game. Since 0.5.0, we've just made this the game version!
* Minor updates rarely impact mods but major versions often do.
*/
static final API_VERSION:String = "0.5.0"; // Constants.VERSION;
// static final API_VERSION:String = Constants.VERSION;
/**
* The Semantic Versioning rule
* Indicates which mods are compatible with this version of the game.
* Using more complex rules allows mods from older compatible versions to stay functioning,
* while preventing mods made for future versions from being installed.
*/
static final API_VERSION_RULE:String = ">=0.5.0 <0.6.0";
/**
* Where relative to the executable that mods are located.
@@ -131,7 +138,7 @@ class PolymodHandler
// Framework being used to load assets.
framework: OPENFL,
// The current version of our API.
apiVersionRule: API_VERSION,
apiVersionRule: API_VERSION_RULE,
// Call this function any time an error occurs.
errorCallback: PolymodErrorHandler.onPolymodError,
// Enforce semantic version patterns for each mod.
@@ -228,6 +235,8 @@ class PolymodHandler
static function buildImports():Void
{
// Add default imports for common classes.
Polymod.addDefaultImport(funkin.Assets);
Polymod.addDefaultImport(funkin.Paths);
// Add import aliases for certain classes.
// NOTE: Scripted classes are automatically aliased to their parent class.
@@ -258,7 +267,7 @@ class PolymodHandler
Polymod.blacklistImport('cpp.Lib');
// `Unserializer`
// Unserializerr.DEFAULT_RESOLVER.resolveClass() can access blacklisted packages
// Unserializer.DEFAULT_RESOLVER.resolveClass() can access blacklisted packages
Polymod.blacklistImport('Unserializer');
// `lime.system.CFFI`
@@ -273,6 +282,14 @@ class PolymodHandler
// System.load() can load malicious DLLs
Polymod.blacklistImport('lime.system.System');
// `lime.utils.Assets`
// Literally just has a private `resolveClass` function for some reason?
Polymod.blacklistImport('lime.utils.Assets');
Polymod.blacklistImport('openfl.utils.Assets');
Polymod.blacklistImport('openfl.Lib');
Polymod.blacklistImport('openfl.system.ApplicationDomain');
Polymod.blacklistImport('funkin.util.FunkinTypeResolver');
// `openfl.desktop.NativeProcess`
// Can load native processes on the host operating system.
Polymod.blacklistImport('openfl.desktop.NativeProcess');
@@ -336,7 +353,7 @@ class PolymodHandler
var modMetadata:Array<ModMetadata> = Polymod.scan(
{
modRoot: MOD_FOLDER,
apiVersionRule: API_VERSION,
apiVersionRule: API_VERSION_RULE,
fileSystem: modFileSystem,
errorCallback: PolymodErrorHandler.onPolymodError
});
@@ -1,8 +1,8 @@
package funkin.modding.base;
/**
* A script that can be tied to an FlxSprite.
* Create a scripted class that extends FlxSprite to use this.
* A script that can be tied to a FunkinSprite.
* Create a scripted class that extends FunkinSprite to use this.
*/
@:hscriptClass
class ScriptedFunkinSprite extends funkin.graphics.FunkinSprite implements HScriptedClass {}
+1 -1
View File
@@ -103,7 +103,7 @@ class NoteScriptEvent extends ScriptEvent
public var comboCount(default, null):Int;
/**
* Whether to play the record scratch sound (if this eventn type is `NOTE_MISS`).
* Whether to play the record scratch sound (if this event type is `NOTE_MISS`).
*/
public var playSound(default, default):Bool;
@@ -125,7 +125,6 @@ class ModuleHandler
for (key => value in moduleCache)
{
ScriptEventDispatcher.callEvent(value, event);
moduleCache.remove(key);
}
moduleCache.clear();
-1
View File
@@ -11,7 +11,6 @@ import funkin.modding.events.ScriptEvent.CountdownScriptEvent;
import flixel.util.FlxTimer;
import funkin.util.EaseUtil;
import funkin.audio.FunkinSound;
import openfl.utils.Assets;
import funkin.data.notestyle.NoteStyleRegistry;
import funkin.play.notes.notestyle.NoteStyle;
-1
View File
@@ -15,7 +15,6 @@ import funkin.ui.freeplay.FreeplayState;
import funkin.ui.MusicBeatSubState;
import funkin.ui.story.StoryMenuState;
import funkin.util.MathUtil;
import openfl.utils.Assets;
import funkin.effects.RetroCameraFade;
import flixel.math.FlxPoint;
+214 -72
View File
@@ -15,8 +15,8 @@ import flixel.tweens.FlxEase;
import flixel.tweens.FlxTween;
import flixel.ui.FlxBar;
import flixel.util.FlxColor;
import flixel.util.FlxTimer;
import flixel.util.FlxStringUtil;
import flixel.util.FlxTimer;
import funkin.api.newgrounds.NGio;
import funkin.audio.FunkinSound;
import funkin.audio.VoicesGroup;
@@ -44,12 +44,12 @@ import funkin.play.cutscene.dialogue.Conversation;
import funkin.play.cutscene.VanillaCutscenes;
import funkin.play.cutscene.VideoCutscene;
import funkin.play.notes.NoteDirection;
import funkin.play.notes.notekind.NoteKindManager;
import funkin.play.notes.NoteSplash;
import funkin.play.notes.NoteSprite;
import funkin.play.notes.notestyle.NoteStyle;
import funkin.play.notes.Strumline;
import funkin.play.notes.SustainTrail;
import funkin.play.notes.notekind.NoteKindManager;
import funkin.play.scoring.Scoring;
import funkin.play.song.Song;
import funkin.play.stage.Stage;
@@ -68,7 +68,7 @@ import openfl.display.BitmapData;
import openfl.geom.Rectangle;
import openfl.Lib;
#if FEATURE_DISCORD_RPC
import Discord.DiscordClient;
import funkin.api.discord.DiscordClient;
#end
/**
@@ -447,10 +447,8 @@ class PlayState extends MusicBeatSubState
#if FEATURE_DISCORD_RPC
// Discord RPC variables
var storyDifficultyText:String = '';
var iconRPC:String = '';
var detailsText:String = '';
var detailsPausedText:String = '';
var discordRPCAlbum:String = '';
var discordRPCIcon:String = '';
#end
/**
@@ -687,7 +685,11 @@ class PlayState extends MusicBeatSubState
}
Conductor.instance.mapTimeChanges(currentChart.timeChanges);
Conductor.instance.update((Conductor.instance.beatLengthMs * -5) + startTimestamp);
var pre:Float = (Conductor.instance.beatLengthMs * -5) + startTimestamp;
trace('Attempting to start at ' + pre);
Conductor.instance.update(pre);
// The song is now loaded. We can continue to initialize the play state.
initCameras();
@@ -813,6 +815,7 @@ class PlayState extends MusicBeatSubState
}
else
{
this.remove(currentStage);
FlxG.switchState(() -> new MainMenuState());
}
return false;
@@ -857,7 +860,7 @@ class PlayState extends MusicBeatSubState
// Reset music properly.
if (FlxG.sound.music != null)
{
FlxG.sound.music.time = startTimestamp - Conductor.instance.instrumentalOffset;
FlxG.sound.music.time = startTimestamp - Conductor.instance.combinedOffset;
FlxG.sound.music.pitch = playbackRate;
FlxG.sound.music.pause();
}
@@ -874,7 +877,7 @@ class PlayState extends MusicBeatSubState
}
}
vocals.pause();
vocals.time = 0;
vocals.time = 0 - Conductor.instance.combinedOffset;
if (FlxG.sound.music != null) FlxG.sound.music.volume = 1;
vocals.volume = 1;
@@ -915,7 +918,11 @@ class PlayState extends MusicBeatSubState
{
// Do NOT apply offsets at this point, because they already got applied the previous frame!
Conductor.instance.update(Conductor.instance.songPosition + elapsed * 1000, false);
if (Conductor.instance.songPosition >= (startTimestamp)) startSong();
if (Conductor.instance.songPosition >= (startTimestamp + Conductor.instance.combinedOffset))
{
trace("started song at " + Conductor.instance.songPosition);
startSong();
}
}
}
else
@@ -957,6 +964,7 @@ class PlayState extends MusicBeatSubState
// It's a reference to Gitaroo Man, which doesn't let you pause the game.
if (!isSubState && event.gitaroo)
{
this.remove(currentStage);
FlxG.switchState(() -> new GitarooPause(
{
targetSong: currentSong,
@@ -984,7 +992,15 @@ class PlayState extends MusicBeatSubState
}
#if FEATURE_DISCORD_RPC
DiscordClient.changePresence(detailsPausedText, currentSong.song + ' (' + storyDifficultyText + ')', iconRPC);
DiscordClient.instance.setPresence(
{
details: 'Paused - ${buildDiscordRPCDetails()}',
state: buildDiscordRPCState(),
largeImageKey: discordRPCAlbum,
smallImageKey: discordRPCIcon
});
#end
}
}
@@ -1073,8 +1089,14 @@ class PlayState extends MusicBeatSubState
}
#if FEATURE_DISCORD_RPC
// Game Over doesn't get his own variable because it's only used here
DiscordClient.changePresence('Game Over - ' + detailsText, currentSong.song + ' (' + storyDifficultyText + ')', iconRPC);
DiscordClient.instance.setPresence(
{
details: 'Game Over - ${buildDiscordRPCDetails()}',
state: buildDiscordRPCState(),
largeImageKey: discordRPCAlbum,
smallImageKey: discordRPCIcon
});
#end
}
else if (isPlayerDying)
@@ -1285,14 +1307,29 @@ class PlayState extends MusicBeatSubState
Countdown.resumeCountdown();
#if FEATURE_DISCORD_RPC
if (startTimer.finished)
if (Conductor.instance.songPosition > 0)
{
DiscordClient.changePresence(detailsText, '${currentChart.songName} ($storyDifficultyText)', iconRPC, true,
currentSongLengthMs - Conductor.instance.songPosition);
// DiscordClient.changePresence(detailsText, '${currentChart.songName} ($discordRPCDifficulty)', discordRPCIcon, true,
// currentSongLengthMs - Conductor.instance.songPosition);
DiscordClient.instance.setPresence(
{
state: buildDiscordRPCState(),
details: buildDiscordRPCDetails(),
largeImageKey: discordRPCAlbum,
smallImageKey: discordRPCIcon
});
}
else
{
DiscordClient.changePresence(detailsText, '${currentChart.songName} ($storyDifficultyText)', iconRPC);
DiscordClient.instance.setPresence(
{
state: buildDiscordRPCState(),
details: buildDiscordRPCDetails(),
largeImageKey: discordRPCAlbum,
smallImageKey: discordRPCIcon
});
}
#end
@@ -1318,16 +1355,32 @@ class PlayState extends MusicBeatSubState
#end
#if FEATURE_DISCORD_RPC
if (health > Constants.HEALTH_MIN && !paused && FlxG.autoPause)
if (health > Constants.HEALTH_MIN && !isGamePaused && FlxG.autoPause)
{
if (Conductor.instance.songPosition > 0.0) DiscordClient.changePresence(detailsText, currentSong.song
+ ' ('
+ storyDifficultyText
+ ')', iconRPC, true,
currentSongLengthMs
- Conductor.instance.songPosition);
if (Conductor.instance.songPosition > 0.0)
{
DiscordClient.instance.setPresence(
{
state: buildDiscordRPCState(),
details: buildDiscordRPCDetails(),
largeImageKey: discordRPCAlbum,
smallImageKey: discordRPCIcon
});
}
else
DiscordClient.changePresence(detailsText, currentSong.song + ' (' + storyDifficultyText + ')', iconRPC);
{
DiscordClient.instance.setPresence(
{
state: buildDiscordRPCState(),
details: buildDiscordRPCDetails(),
largeImageKey: discordRPCAlbum,
smallImageKey: discordRPCIcon
});
// DiscordClient.changePresence(detailsText, '${currentChart.songName} ($discordRPCDifficulty)', discordRPCIcon, true,
// currentSongLengthMs - Conductor.instance.songPosition);
}
}
#end
@@ -1344,8 +1397,17 @@ class PlayState extends MusicBeatSubState
#end
#if FEATURE_DISCORD_RPC
if (health > Constants.HEALTH_MIN && !paused && FlxG.autoPause) DiscordClient.changePresence(detailsPausedText,
currentSong.song + ' (' + storyDifficultyText + ')', iconRPC);
if (health > Constants.HEALTH_MIN && !isGamePaused && FlxG.autoPause)
{
DiscordClient.instance.setPresence(
{
state: buildDiscordRPCState(),
details: buildDiscordRPCDetails(),
largeImageKey: discordRPCAlbum,
smallImageKey: discordRPCIcon
});
}
#end
super.onFocusLost();
@@ -1358,6 +1420,7 @@ class PlayState extends MusicBeatSubState
{
funkin.modding.PolymodHandler.forceReloadAssets();
lastParams.targetSong = SongRegistry.instance.fetchEntry(currentSong.id);
this.remove(currentStage);
LoadingState.loadPlayState(lastParams);
}
@@ -1391,15 +1454,41 @@ class PlayState extends MusicBeatSubState
// activeNotes.sort(SortUtil.byStrumtime, FlxSort.DESCENDING);
}
if (!startingSong
&& FlxG.sound.music != null
&& (Math.abs(FlxG.sound.music.time - (Conductor.instance.songPosition + Conductor.instance.instrumentalOffset)) > 100
|| Math.abs(vocals.checkSyncError(Conductor.instance.songPosition + Conductor.instance.instrumentalOffset)) > 100))
if (FlxG.sound.music != null)
{
trace("VOCALS NEED RESYNC");
if (vocals != null) trace(vocals.checkSyncError(Conductor.instance.songPosition + Conductor.instance.instrumentalOffset));
trace(FlxG.sound.music.time - (Conductor.instance.songPosition + Conductor.instance.instrumentalOffset));
resyncVocals();
var correctSync:Float = Math.min(FlxG.sound.music.length, Math.max(0, Conductor.instance.songPosition - Conductor.instance.combinedOffset));
var playerVoicesError:Float = 0;
var opponentVoicesError:Float = 0;
if (vocals != null)
{
@:privateAccess // todo: maybe make the groups public :thinking:
{
vocals.playerVoices.forEachAlive(function(voice:FunkinSound) {
var currentRawVoiceTime:Float = voice.time + vocals.playerVoicesOffset;
if (Math.abs(currentRawVoiceTime - correctSync) > Math.abs(playerVoicesError)) playerVoicesError = currentRawVoiceTime - correctSync;
});
vocals.opponentVoices.forEachAlive(function(voice:FunkinSound) {
var currentRawVoiceTime:Float = voice.time + vocals.opponentVoicesOffset;
if (Math.abs(currentRawVoiceTime - correctSync) > Math.abs(opponentVoicesError)) opponentVoicesError = currentRawVoiceTime - correctSync;
});
}
}
if (!startingSong
&& (Math.abs(FlxG.sound.music.time - correctSync) > 5 || Math.abs(playerVoicesError) > 5 || Math.abs(opponentVoicesError) > 5))
{
trace("VOCALS NEED RESYNC");
if (vocals != null)
{
trace(playerVoicesError);
trace(opponentVoicesError);
}
trace(FlxG.sound.music.time);
trace(correctSync);
resyncVocals();
}
}
// Only bop camera if zoom level is below 135%
@@ -1612,7 +1701,7 @@ class PlayState extends MusicBeatSubState
if (girlfriend != null)
{
girlfriend.characterType = CharacterType.GF;
// Don't need to do anything.
}
else if (currentCharacterData.girlfriend != '')
{
@@ -1630,8 +1719,6 @@ class PlayState extends MusicBeatSubState
if (dad != null)
{
dad.characterType = CharacterType.DAD;
//
// OPPONENT HEALTH ICON
//
@@ -1641,6 +1728,11 @@ class PlayState extends MusicBeatSubState
iconP2.zIndex = 850;
add(iconP2);
iconP2.cameras = [camHUD];
#if FEATURE_DISCORD_RPC
discordRPCAlbum = 'album-${currentChart.album}';
discordRPCIcon = 'icon-${currentCharacterData.opponent}';
#end
}
//
@@ -1650,8 +1742,6 @@ class PlayState extends MusicBeatSubState
if (boyfriend != null)
{
boyfriend.characterType = CharacterType.BF;
//
// PLAYER HEALTH ICON
//
@@ -1758,27 +1848,62 @@ class PlayState extends MusicBeatSubState
function initDiscord():Void
{
#if FEATURE_DISCORD_RPC
storyDifficultyText = difficultyString();
iconRPC = currentSong.player2;
// To avoid having duplicate images in Discord assets
switch (iconRPC)
{
case 'senpai-angry':
iconRPC = 'senpai';
case 'monster-christmas':
iconRPC = 'monster';
case 'mom-car':
iconRPC = 'mom';
}
// String that contains the mode defined here so it isn't necessary to call changePresence for each mode
detailsText = isStoryMode ? 'Story Mode: Week $storyWeek' : 'Freeplay';
detailsPausedText = 'Paused - $detailsText';
// Determine the details strings once and reuse them.
// Updating Discord Rich Presence.
DiscordClient.changePresence(detailsText, '${currentChart.songName} ($storyDifficultyText)', iconRPC);
DiscordClient.instance.setPresence(
{
state: buildDiscordRPCState(),
details: buildDiscordRPCDetails(),
largeImageKey: discordRPCAlbum,
smallImageKey: discordRPCIcon
});
#end
#if FEATURE_DISCORD_RPC
// Updating Discord Rich Presence.
DiscordClient.instance.setPresence(
{
state: buildDiscordRPCState(),
details: buildDiscordRPCDetails(),
largeImageKey: discordRPCAlbum,
smallImageKey: discordRPCIcon
});
#end
}
function buildDiscordRPCDetails():String
{
if (PlayStatePlaylist.isStoryMode)
{
return 'Story Mode: ${PlayStatePlaylist.campaignTitle}';
}
else
{
if (isChartingMode)
{
return 'Chart Editor [Playtest]';
}
else if (isPracticeMode)
{
return 'Freeplay [Practice]';
}
else if (isBotPlayMode)
{
return 'Freeplay [Bot Play]';
}
else
{
return 'Freeplay';
}
}
}
function buildDiscordRPCState():String
{
var discordRPCDifficulty = PlayState.instance.currentDifficulty.replace('-', ' ').toTitleCase();
return '${currentChart.songName} [${discordRPCDifficulty}]';
}
function initPreciseInputs():Void
@@ -1956,7 +2081,7 @@ class PlayState extends MusicBeatSubState
};
// A negative instrumental offset means the song skips the first few milliseconds of the track.
// This just gets added into the startTimestamp behavior so we don't need to do anything extra.
FlxG.sound.music.play(true, startTimestamp - Conductor.instance.instrumentalOffset);
FlxG.sound.music.play(true, Math.max(0, startTimestamp - Conductor.instance.combinedOffset));
FlxG.sound.music.pitch = playbackRate;
// Prevent the volume from being wrong.
@@ -1968,16 +2093,27 @@ class PlayState extends MusicBeatSubState
vocals.play();
vocals.volume = 1.0;
vocals.pitch = playbackRate;
vocals.time = FlxG.sound.music.time;
// trace('${FlxG.sound.music.time}');
// trace('${vocals.time}');
resyncVocals();
#if FEATURE_DISCORD_RPC
// Updating Discord Rich Presence (with Time Left)
DiscordClient.changePresence(detailsText, '${currentChart.songName} ($storyDifficultyText)', iconRPC, true, currentSongLengthMs);
DiscordClient.instance.setPresence(
{
state: buildDiscordRPCState(),
details: buildDiscordRPCDetails(),
largeImageKey: discordRPCAlbum,
smallImageKey: discordRPCIcon
});
// DiscordClient.changePresence(detailsText, '${currentChart.songName} ($discordRPCDifficulty)', discordRPCIcon, true, currentSongLengthMs);
#end
if (startTimestamp > 0)
{
// FlxG.sound.music.time = startTimestamp - Conductor.instance.instrumentalOffset;
// FlxG.sound.music.time = startTimestamp - Conductor.instance.combinedOffset;
handleSkippedNotes();
}
@@ -1993,7 +2129,9 @@ class PlayState extends MusicBeatSubState
// Skip this if the music is paused (GameOver, Pause menu, start-of-song offset, etc.)
if (!(FlxG.sound.music?.playing ?? false)) return;
var timeToPlayAt:Float = Conductor.instance.songPosition - Conductor.instance.instrumentalOffset;
var timeToPlayAt:Float = Math.min(FlxG.sound.music.length, Math.max(0, Conductor.instance.songPosition - Conductor.instance.combinedOffset));
trace('Resyncing vocals to ${timeToPlayAt}');
FlxG.sound.music.pause();
vocals.pause();
@@ -2373,9 +2511,9 @@ class PlayState extends MusicBeatSubState
if (targetNote == null) continue;
// Judge and hit the note.
trace('Hit note! ${targetNote.noteData}');
// trace('Hit note! ${targetNote.noteData}');
goodNoteHit(targetNote, input);
trace('Score: ${songScore}');
// trace('Score: ${songScore}');
notesInDirection.remove(targetNote);
@@ -2424,8 +2562,8 @@ class PlayState extends MusicBeatSubState
healthChange = Constants.HEALTH_BAD_BONUS;
isComboBreak = Constants.JUDGEMENT_BAD_COMBO_BREAK;
case 'shit':
isComboBreak = Constants.JUDGEMENT_SHIT_COMBO_BREAK;
healthChange = Constants.HEALTH_SHIT_BONUS;
isComboBreak = Constants.JUDGEMENT_SHIT_COMBO_BREAK;
}
// Send the note hit event.
@@ -2495,8 +2633,6 @@ class PlayState extends MusicBeatSubState
}
vocals.playerVolume = 0;
if (Highscore.tallies.combo != 0) if (Highscore.tallies.combo >= 10) comboPopUps.displayCombo(0);
applyScore(-10, 'miss', healthChange, true);
if (playSound)
@@ -2566,7 +2702,7 @@ class PlayState extends MusicBeatSubState
*/
function debugKeyShit():Void
{
#if FEATURE_CHART_EDITOR
#if FEATURE_STAGE_EDITOR
// Open the stage editor overlaying the current state.
if (controls.DEBUG_STAGE)
{
@@ -2575,7 +2711,9 @@ class PlayState extends MusicBeatSubState
persistentUpdate = false;
openSubState(new StageOffsetSubState());
}
#end
#if FEATURE_CHART_EDITOR
// Redirect to the chart editor playing the current song.
if (controls.DEBUG_CHART)
{
@@ -2583,11 +2721,13 @@ class PlayState extends MusicBeatSubState
persistentUpdate = false;
if (isChartingMode)
{
// Close the playtest substate.
FlxG.sound.music?.pause();
this.close();
}
else
{
this.remove(currentStage);
FlxG.switchState(() -> new ChartEditorState(
{
targetSongId: currentSong.id,
@@ -2711,7 +2851,7 @@ class PlayState extends MusicBeatSubState
}
}
comboPopUps.displayRating(daRating);
if (combo >= 10 || combo == 0) comboPopUps.displayCombo(combo);
if (combo >= 10) comboPopUps.displayCombo(combo);
vocals.playerVolume = 1;
}
@@ -2937,6 +3077,7 @@ class PlayState extends MusicBeatSubState
{
targetVariation = targetSong.getFirstValidVariation(PlayStatePlaylist.campaignDifficulty) ?? Constants.DEFAULT_VARIATION;
}
this.remove(currentStage);
LoadingState.loadPlayState(
{
targetSong: targetSong,
@@ -2954,6 +3095,7 @@ class PlayState extends MusicBeatSubState
{
targetVariation = targetSong.getFirstValidVariation(PlayStatePlaylist.campaignDifficulty) ?? Constants.DEFAULT_VARIATION;
}
this.remove(currentStage);
LoadingState.loadPlayState(
{
targetSong: targetSong,
@@ -3177,7 +3319,7 @@ class PlayState extends MusicBeatSubState
/**
* Resets the camera's zoom level and focus point.
*/
public function resetCamera(?resetZoom:Bool = true, ?cancelTweens:Bool = true):Void
public function resetCamera(?resetZoom:Bool = true, ?cancelTweens:Bool = true, ?snap:Bool = true):Void
{
// Cancel camera tweens if any are active.
if (cancelTweens)
@@ -3194,7 +3336,7 @@ class PlayState extends MusicBeatSubState
}
// Snap the camera to the follow point immediately.
FlxG.camera.focusOn(cameraFollowPoint.getPosition());
if (snap) FlxG.camera.focusOn(cameraFollowPoint.getPosition());
}
/**
+34 -3
View File
@@ -74,6 +74,8 @@ class ResultState extends MusicBeatSubState
var playerCharacterId:Null<String>;
var introMusicAudio:Null<FunkinSound>;
var rankBg:FunkinSprite;
final cameraBG:FunkinCamera;
final cameraScroll:FunkinCamera;
@@ -413,7 +415,8 @@ class ResultState extends MusicBeatSubState
if (Assets.exists(introMusic))
{
// Play the intro music.
FunkinSound.load(introMusic, 1.0, false, true, true, () -> {
introMusicAudio = FunkinSound.load(introMusic, 1.0, false, true, true, () -> {
introMusicAudio = null;
FunkinSound.playMusic(getMusicPath(playerCharacter, rank),
{
startingVolume: 1.0,
@@ -472,9 +475,12 @@ class ResultState extends MusicBeatSubState
{
ease: FlxEase.quartOut,
onUpdate: _ -> {
clearPercentLerp = Math.round(clearPercentLerp);
clearPercentCounter.curNumber = Math.round(clearPercentCounter.curNumber);
// Only play the tick sound if the number increased.
if (clearPercentLerp != clearPercentCounter.curNumber)
{
trace('$clearPercentLerp and ${clearPercentCounter.curNumber}');
clearPercentLerp = clearPercentCounter.curNumber;
FunkinSound.playOnce(Paths.sound('scrollMenu'));
}
@@ -724,9 +730,34 @@ class ResultState extends MusicBeatSubState
if (controls.PAUSE)
{
if (FlxG.sound.music != null)
if (introMusicAudio != null) {
@:nullSafety(Off)
introMusicAudio.onComplete = null;
FlxTween.tween(introMusicAudio, {volume: 0}, 0.8, {
onComplete: _ -> {
if (introMusicAudio != null) {
introMusicAudio.stop();
introMusicAudio.destroy();
introMusicAudio = null;
}
}
});
FlxTween.tween(introMusicAudio, {pitch: 3}, 0.1,
{
onComplete: _ -> {
FlxTween.tween(introMusicAudio, {pitch: 0.5}, 0.4);
}
});
}
else if (FlxG.sound.music != null)
{
FlxTween.tween(FlxG.sound.music, {volume: 0}, 0.8);
FlxTween.tween(FlxG.sound.music, {volume: 0}, 0.8, {
onComplete: _ -> {
FlxG.sound.music.stop();
FlxG.sound.music.destroy();
}
});
FlxTween.tween(FlxG.sound.music, {pitch: 3}, 0.1,
{
onComplete: _ -> {
@@ -147,7 +147,7 @@ class AnimateAtlasCharacter extends BaseCharacter
if (getAnimationData() != null && getAnimationData().looped)
{
playAnimation(prefix, true, false);
playAnimation(currentAnimName, true, false);
}
else
{
+11 -12
View File
@@ -233,15 +233,9 @@ class BaseCharacter extends Bopper
*/
public function resetCharacter(resetCamera:Bool = true):Void
{
// Reset the animation offsets. This will modify x and y to be the absolute position of the character.
// this.animOffsets = [0, 0];
// Now we can set the x and y to be their original values without having to account for animOffsets.
// Set the x and y to be their original values.
this.resetPosition();
// Then reapply animOffsets...
// applyAnimationOffsets(getCurrentAnimation());
this.dance(true); // Force to avoid the old animation playing with the wrong offset at the start of the song.
// Make sure we are playing the idle animation
// ...then update the hitbox so that this.width and this.height are correct.
@@ -305,7 +299,7 @@ class BaseCharacter extends Bopper
{
super.onAnimationFinished(animationName);
trace('${characterId} has finished animation: ${animationName}');
// trace('${characterId} has finished animation: ${animationName}');
if ((animationName.endsWith(Constants.ANIMATION_END_SUFFIX) && !animationName.startsWith('idle') && !animationName.startsWith('dance'))
|| animationName.startsWith('combo')
|| animationName.startsWith('drop'))
@@ -323,6 +317,11 @@ class BaseCharacter extends Bopper
this.cameraFocusPoint = new FlxPoint(charCenterX + _data.cameraOffsets[0], charCenterY + _data.cameraOffsets[1]);
}
public function getHealthIconId():String
{
return _data?.healthIcon?.id ?? Constants.DEFAULT_HEALTH_ICON;
}
public function initHealthIcon(isOpponent:Bool):Void
{
if (!isOpponent)
@@ -332,7 +331,7 @@ class BaseCharacter extends Bopper
trace('[WARN] Player 1 health icon not found!');
return;
}
PlayState.instance.iconP1.configure(_data.healthIcon);
PlayState.instance.iconP1.configure(_data?.healthIcon);
PlayState.instance.iconP1.flipX = !PlayState.instance.iconP1.flipX; // BF is looking the other way.
}
else
@@ -342,7 +341,7 @@ class BaseCharacter extends Bopper
trace('[WARN] Player 2 health icon not found!');
return;
}
PlayState.instance.iconP2.configure(_data.healthIcon);
PlayState.instance.iconP2.configure(_data?.healthIcon);
}
}
@@ -402,7 +401,7 @@ class BaseCharacter extends Bopper
FlxG.watch.addQuick('singTimeSec-${characterId}', singTimeSec);
if (holdTimer > singTimeSec && shouldStopSinging)
{
trace('holdTimer reached ${holdTimer}sec (> ${singTimeSec}), stopping sing animation');
// trace('holdTimer reached ${holdTimer}sec (> ${singTimeSec}), stopping sing animation');
holdTimer = 0;
var currentAnimation:String = getCurrentAnimation();
@@ -636,7 +635,7 @@ class BaseCharacter extends Bopper
var anim:String = 'sing${dir.nameUpper}${miss ? 'miss' : ''}${suffix != '' ? '-${suffix}' : ''}';
// restart even if already playing, because the character might sing the same note twice.
trace('Playing ${anim}...');
// trace('Playing ${anim}...');
playAnimation(anim, true);
}
+58 -21
View File
@@ -11,7 +11,7 @@ import funkin.play.character.ScriptedCharacter.ScriptedSparrowCharacter;
import funkin.util.assets.DataAssets;
import funkin.util.VersionUtil;
import haxe.Json;
import openfl.utils.Assets;
import flixel.graphics.frames.FlxFrame;
class CharacterDataParser
{
@@ -281,41 +281,78 @@ class CharacterDataParser
}
/**
* TODO: Hardcode this.
* Returns the idle frame of a character.
*/
public static function getCharPixelIconAsset(char:String):String
public static function getCharPixelIconAsset(char:String):FlxFrame
{
var icon:String = char;
var charPath:String = "freeplay/icons/";
switch (icon)
// FunkinCrew please dont skin me alive for copying pixelated icon and changing it a tiny bit
switch (char)
{
case "bf-christmas" | "bf-car" | "bf-pixel" | "bf-holding-gf":
icon = "bf";
case "bf-christmas" | "bf-car" | "bf-pixel" | "bf-holding-gf" | "bf-dark":
charPath += "bfpixel";
case "monster-christmas":
icon = "monster";
charPath += "monsterpixel";
case "mom" | "mom-car":
icon = "mommy";
charPath += "mommypixel";
case "pico-blazin" | "pico-playable" | "pico-speaker":
icon = "pico";
case "gf-christmas" | "gf-car" | "gf-pixel" | "gf-tankmen":
icon = "gf";
charPath += "picopixel";
case "gf-christmas" | "gf-car" | "gf-pixel" | "gf-tankmen" | "gf-dark":
charPath += "gfpixel";
case "dad":
icon = "daddy";
charPath += "dadpixel";
case "darnell-blazin":
icon = "darnell";
charPath += "darnellpixel";
case "senpai-angry":
icon = "senpai";
charPath += "senpaipixel";
case "spooky-dark":
icon = "spooky";
charPath += "spookypixel";
case "tankman-atlas":
icon = "tankman";
charPath += "tankmanpixel";
case "pico-christmas" | "pico-dark":
charPath += "picopixel";
default:
charPath += '${char}pixel';
}
var path = Paths.image("freeplay/icons/" + icon + "pixel");
if (Assets.exists(path)) return path;
if (!Assets.exists(Paths.image(charPath)))
{
trace('[WARN] Character ${char} has no freeplay icon.');
return null;
}
// TODO: Hardcode some additional behavior or a fallback.
return null;
var isAnimated = Assets.exists(Paths.file('images/$charPath.xml'));
var frame:FlxFrame = null;
if (isAnimated)
{
var frames = Paths.getSparrowAtlas(charPath);
var idleFrame:FlxFrame = frames.frames.find(function(frame:FlxFrame):Bool {
return frame.name.startsWith('idle');
});
if (idleFrame == null)
{
trace('[WARN] Character ${char} has no idle in their freeplay icon.');
return null;
}
// so, haxe.ui.backend.AssetsImpl uses the parent width and height, which makes the image go crazy when rendered
// so this is a work around so that it uses the actual width and height
var imageGraphic = flixel.graphics.FlxGraphic.fromFrame(idleFrame);
var imageFrame = flixel.graphics.frames.FlxImageFrame.fromImage(imageGraphic);
frame = imageFrame.frame;
}
else
{
var imageFrame = flixel.graphics.frames.FlxImageFrame.fromImage(Paths.image(charPath));
frame = imageFrame.frame;
}
return frame;
}
/**
+9 -21
View File
@@ -5,7 +5,6 @@ import flixel.FlxSprite;
import flixel.math.FlxMath;
import flixel.math.FlxPoint;
import funkin.play.character.CharacterData.CharacterDataParser;
import openfl.utils.Assets;
import funkin.graphics.FunkinSprite;
import funkin.util.MathUtil;
@@ -33,7 +32,7 @@ class HealthIcon extends FunkinSprite
* The character this icon is representing.
* Setting this variable will automatically update the graphic.
*/
public var characterId(default, set):Null<String>;
public var characterId(default, set):String = Constants.DEFAULT_HEALTH_ICON;
/**
* Whether this health icon should automatically update its state based on the character's health.
@@ -116,7 +115,7 @@ class HealthIcon extends FunkinSprite
*/
static final POSITION_OFFSET:Int = 26;
public function new(char:String = 'bf', playerId:Int = 0)
public function new(char:Null<String>, playerId:Int = 0)
{
super(0, 0);
this.playerId = playerId;
@@ -131,7 +130,7 @@ class HealthIcon extends FunkinSprite
snapToTargetSize();
}
function set_characterId(value:Null<String>):Null<String>
function set_characterId(value:Null<String>):String
{
if (value == characterId) return value;
@@ -412,20 +411,9 @@ class HealthIcon extends FunkinSprite
}
}
function correctCharacterId(charId:Null<String>):String
function iconExists(charId:String):Bool
{
if (charId == null)
{
return Constants.DEFAULT_HEALTH_ICON;
}
if (!Assets.exists(Paths.image('icons/icon-$charId')))
{
FlxG.log.warn('No icon for character: $charId : using default placeholder face instead!');
return Constants.DEFAULT_HEALTH_ICON;
}
return charId;
return Assets.exists(Paths.image('icons/icon-$charId'));
}
function isNewSpritesheet(charId:String):Bool
@@ -435,11 +423,11 @@ class HealthIcon extends FunkinSprite
function loadCharacter(charId:Null<String>):Void
{
if (charId == null || correctCharacterId(charId) != charId)
if (charId == null || !iconExists(charId))
{
// This will recursively trigger loadCharacter to be called again.
characterId = correctCharacterId(charId);
return;
FlxG.log.warn('No icon for character: $charId : using default placeholder face instead!');
characterId = Constants.DEFAULT_HEALTH_ICON;
charId = characterId;
}
isLegacyStyle = !isNewSpritesheet(charId);
@@ -8,7 +8,6 @@ import funkin.graphics.FunkinSprite;
import funkin.play.PlayState;
import funkin.util.TimerUtil;
import funkin.util.EaseUtil;
import openfl.utils.Assets;
import funkin.data.notestyle.NoteStyleRegistry;
import funkin.play.notes.notestyle.NoteStyle;
@@ -95,7 +94,6 @@ class PopUpStuff extends FlxTypedGroup<FunkinSprite>
if (numScore == null) continue;
numScore.x = (FlxG.width * 0.507) - (36 * daLoop) - 65;
trace('numScore($daLoop) = ${numScore.x}');
numScore.y = (FlxG.camera.height * 0.44);
numScore.x += offsets[0];
+3 -3
View File
@@ -11,7 +11,7 @@ import flixel.util.FlxTimer;
import funkin.graphics.video.FlxVideo;
#end
#if hxCodec
import hxcodec.flixel.FlxVideoSprite;
import funkin.graphics.video.FunkinVideoSprite;
#end
/**
@@ -26,7 +26,7 @@ class VideoCutscene
static var vid:FlxVideo;
#end
#if hxCodec
static var vid:FlxVideoSprite;
static var vid:FunkinVideoSprite;
#end
/**
@@ -138,7 +138,7 @@ class VideoCutscene
static function playVideoNative(filePath:String):Void
{
// Video displays OVER the FlxState.
vid = new FlxVideoSprite(0, 0);
vid = new FunkinVideoSprite(0, 0);
if (vid != null)
{
@@ -127,7 +127,8 @@ class FocusCameraSongEvent extends SongEvent
switch (ease)
{
case 'CLASSIC': // Old-school. No ease. Just set follow point.
PlayState.instance.resetCamera(false, true);
PlayState.instance.resetCamera(false, false, false);
PlayState.instance.cancelCameraFollowTween();
PlayState.instance.cameraFollowPoint.setPosition(targetX, targetY);
case 'INSTANT': // Instant ease. Duration is automatically 0.
PlayState.instance.tweenCameraToPosition(targetX, targetY, 0);
+33 -11
View File
@@ -2,28 +2,46 @@ package funkin.play.notes;
import funkin.play.notes.notestyle.NoteStyle;
import flixel.graphics.frames.FlxAtlasFrames;
import flixel.FlxSprite;
import funkin.graphics.FunkinSprite;
import funkin.play.notes.NoteSprite;
/**
* The actual receptor that you see on screen.
*/
class StrumlineNote extends FlxSprite
class StrumlineNote extends FunkinSprite
{
/**
* Whether this strumline note is on the player's side or the opponent's side.
*/
public var isPlayer(default, null):Bool;
/**
* The direction which this strumline note is facing.
*/
public var direction(default, set):NoteDirection;
var confirmHoldTimer:Float = -1;
static final CONFIRM_HOLD_TIME:Float = 0.1;
function set_direction(value:NoteDirection):NoteDirection
{
this.direction = value;
return this.direction;
}
/**
* Set this flag to `true` to disable performance optimizations that cause
* the Strumline note sprite to ignore `velocity` and `acceleration`.
*/
public var forceActive:Bool = false;
/**
* How long to continue the hold note animation after a note is pressed.
*/
static final CONFIRM_HOLD_TIME:Float = 0.1;
/**
* How long the hold note animation has been playing after a note is pressed.
*/
var confirmHoldTimer:Float = -1;
public function new(noteStyle:NoteStyle, isPlayer:Bool, direction:NoteDirection)
{
super(0, 0);
@@ -41,7 +59,10 @@ class StrumlineNote extends FlxSprite
this.active = true;
}
function onAnimationFrame(name:String, frameNumber:Int, frameIndex:Int):Void {}
function onAnimationFrame(name:String, frameNumber:Int, frameIndex:Int):Void
{
// Do nothing.
}
function onAnimationFinished(name:String):Void
{
@@ -85,7 +106,8 @@ class StrumlineNote extends FlxSprite
noteStyle.applyStrumlineFrames(this);
noteStyle.applyStrumlineAnimations(this, this.direction);
this.setGraphicSize(Std.int(Strumline.STRUMLINE_SIZE * noteStyle.getStrumlineScale()));
var scale = noteStyle.getStrumlineScale();
this.scale.set(scale, scale);
this.updateHitbox();
noteStyle.applyStrumlineOffsets(this);
@@ -102,19 +124,19 @@ class StrumlineNote extends FlxSprite
public function playStatic():Void
{
this.active = false;
this.active = (forceActive || isAnimationDynamic('static'));
this.playAnimation('static', true);
}
public function playPress():Void
{
this.active = true;
this.active = (forceActive || isAnimationDynamic('press'));
this.playAnimation('press', true);
}
public function playConfirm():Void
{
this.active = true;
this.active = (forceActive || isAnimationDynamic('confirm'));
this.playAnimation('confirm', true);
}
+3 -2
View File
@@ -87,6 +87,7 @@ class SustainTrail extends FlxSprite
public var bottomClip:Float = 0.9;
public var isPixel:Bool;
public var noteStyleOffsets:Array<Float>;
var graphicWidth:Float = 0;
var graphicHeight:Float = 0;
@@ -107,6 +108,7 @@ class SustainTrail extends FlxSprite
this.noteDirection = noteDirection;
setupHoldNoteGraphic(noteStyle);
noteStyleOffsets = noteStyle.getHoldNoteOffsets();
indices = new DrawData<Int>(12, true, TRIANGLE_VERTEX_INDICES);
@@ -137,7 +139,6 @@ class SustainTrail extends FlxSprite
zoom = 1.0;
zoom *= noteStyle.fetchHoldNoteScale();
zoom *= 0.7;
// CALCULATE SIZE
graphicWidth = graphic.width / 8 * zoom; // amount of notes * 2
@@ -202,7 +203,7 @@ class SustainTrail extends FlxSprite
{
width = graphicWidth;
height = graphicHeight;
offset.set(0, 0);
offset.set(noteStyleOffsets[0], noteStyleOffsets[1]);
origin.set(width * 0.5, height * 0.5);
}
+126 -106
View File
@@ -34,7 +34,12 @@ class NoteStyle implements IRegistryEntry<NoteStyleData>
* The note style to use if this one doesn't have a certain asset.
* This can be recursive, ehe.
*/
final fallback:Null<NoteStyle>;
var fallback(get, never):Null<NoteStyle>;
function get_fallback():Null<NoteStyle> {
if (_data == null || _data.fallback == null) return null;
return NoteStyleRegistry.instance.fetchEntry(_data.fallback);
}
/**
* @param id The ID of the JSON file to parse.
@@ -43,9 +48,6 @@ class NoteStyle implements IRegistryEntry<NoteStyleData>
{
this.id = id;
_data = _fetchData(id);
var fallbackID = _data.fallback;
if (fallbackID != null) this.fallback = NoteStyleRegistry.instance.fetchEntry(fallbackID);
}
/**
@@ -93,7 +95,8 @@ class NoteStyle implements IRegistryEntry<NoteStyleData>
buildNoteAnimations(target);
// Set the scale.
target.setGraphicSize(Strumline.STRUMLINE_SIZE * getNoteScale());
var scale = getNoteScale();
target.scale.set(scale, scale);
target.updateHitbox();
}
@@ -102,7 +105,11 @@ class NoteStyle implements IRegistryEntry<NoteStyleData>
function buildNoteFrames(force:Bool = false):Null<FlxAtlasFrames>
{
var noteAssetPath = getNoteAssetPath();
if (noteAssetPath == null) return null;
if (noteAssetPath == null)
{
FlxG.log.warn('Note asset path not found: ${id}');
return null;
}
if (!FunkinSprite.isTextureCached(Paths.image(noteAssetPath)))
{
@@ -135,7 +142,7 @@ class NoteStyle implements IRegistryEntry<NoteStyleData>
if (raw)
{
var rawPath:Null<String> = _data?.assets?.note?.assetPath;
if (rawPath == null && fallback != null) return fallback.getNoteAssetPath(true);
if (rawPath == null) return fallback?.getNoteAssetPath(true);
return rawPath;
}
@@ -173,12 +180,13 @@ class NoteStyle implements IRegistryEntry<NoteStyleData>
public function isNoteAnimated():Bool
{
return _data.assets?.note?.animated ?? false;
// LOL is double ?? bad practice?
return _data.assets?.note?.animated ?? fallback?.isNoteAnimated() ?? false;
}
public function getNoteScale():Float
{
return _data.assets?.note?.scale ?? 1.0;
return _data.assets?.note?.scale ?? fallback?.getNoteScale() ?? 1.0;
}
function fetchNoteAnimationData(dir:NoteDirection):Null<AnimationData>
@@ -191,16 +199,15 @@ class NoteStyle implements IRegistryEntry<NoteStyleData>
case RIGHT: _data.assets?.note?.data?.right?.toNamed();
};
return (result == null && fallback != null) ? fallback.fetchNoteAnimationData(dir) : result;
return result ?? fallback?.fetchNoteAnimationData(dir);
}
public function getHoldNoteAssetPath(raw:Bool = false):Null<String>
{
if (raw)
{
// TODO: figure out why ?. didn't work here
var rawPath:Null<String> = (_data?.assets?.holdNote == null) ? null : _data?.assets?.holdNote?.assetPath;
return (rawPath == null && fallback != null) ? fallback.getHoldNoteAssetPath(true) : rawPath;
var rawPath:Null<String> = _data?.assets?.holdNote?.assetPath;
return rawPath ?? fallback?.getHoldNoteAssetPath(true);
}
// library:path
@@ -212,16 +219,17 @@ class NoteStyle implements IRegistryEntry<NoteStyleData>
public function isHoldNotePixel():Bool
{
var data = _data?.assets?.holdNote;
if (data == null && fallback != null) return fallback.isHoldNotePixel();
return data?.isPixel ?? false;
return _data?.assets?.holdNote?.isPixel ?? fallback?.isHoldNotePixel() ?? false;
}
public function fetchHoldNoteScale():Float
{
var data = _data?.assets?.holdNote;
if (data == null && fallback != null) return fallback.fetchHoldNoteScale();
return data?.scale ?? 1.0;
return _data?.assets?.holdNote?.scale ?? fallback?.fetchHoldNoteScale() ?? 1.0;
}
public function getHoldNoteOffsets():Array<Float>
{
return _data?.assets?.holdNote?.offsets ?? fallback?.getHoldNoteOffsets() ?? [0.0, 0.0];
}
public function applyStrumlineFrames(target:StrumlineNote):Void
@@ -246,9 +254,7 @@ class NoteStyle implements IRegistryEntry<NoteStyleData>
{
if (raw)
{
var rawPath:Null<String> = _data?.assets?.noteStrumline?.assetPath;
if (rawPath == null && fallback != null) return fallback.getStrumlineAssetPath(true);
return rawPath;
return _data?.assets?.noteStrumline?.assetPath ?? fallback?.getStrumlineAssetPath(true);
}
// library:path
@@ -270,11 +276,19 @@ class NoteStyle implements IRegistryEntry<NoteStyleData>
FlxAnimationUtil.addAtlasAnimations(target, getStrumlineAnimationData(dir));
}
/**
* Fetch the animation data for the strumline.
* NOTE: This function only queries the fallback note style if all the animations are missing for a given direction.
*
* @param dir The direction to fetch the animation data for.
* @return The animation data for the strumline in that direction.
*/
function getStrumlineAnimationData(dir:NoteDirection):Array<AnimationData>
{
var result:Array<Null<AnimationData>> = switch (dir)
{
case NoteDirection.LEFT: [
case NoteDirection.LEFT:
[
_data.assets.noteStrumline?.data?.leftStatic?.toNamed('static'),
_data.assets.noteStrumline?.data?.leftPress?.toNamed('press'),
_data.assets.noteStrumline?.data?.leftConfirm?.toNamed('confirm'),
@@ -301,33 +315,39 @@ class NoteStyle implements IRegistryEntry<NoteStyleData>
default: [];
};
return thx.Arrays.filterNull(result);
// New variable so we can change the type.
var filteredResult:Array<AnimationData> = thx.Arrays.filterNull(result);
if (filteredResult.length == 0) return fallback?.getStrumlineAnimationData(dir) ?? [];
return filteredResult;
}
public function getStrumlineOffsets():Array<Float>
{
return _data?.assets?.noteStrumline?.offsets ?? fallback?.getStrumlineOffsets() ?? [0.0, 0.0];
}
public function applyStrumlineOffsets(target:StrumlineNote):Void
{
var offsets = _data?.assets?.noteStrumline?.offsets ?? [0.0, 0.0];
var offsets = getStrumlineOffsets();
target.x += offsets[0];
target.y += offsets[1];
}
public function getStrumlineScale():Float
{
return _data?.assets?.noteStrumline?.scale ?? 1.0;
return _data?.assets?.noteStrumline?.scale ?? fallback?.getStrumlineScale() ?? 1.0;
}
public function isNoteSplashEnabled():Bool
{
var data = _data?.assets?.noteSplash?.data;
if (data == null) return fallback?.isNoteSplashEnabled() ?? false;
return data.enabled ?? false;
return _data?.assets?.noteSplash?.data?.enabled ?? fallback?.isNoteSplashEnabled() ?? false;
}
public function isHoldNoteCoverEnabled():Bool
{
var data = _data?.assets?.holdNoteCover?.data;
if (data == null) return fallback?.isHoldNoteCoverEnabled() ?? false;
return data.enabled ?? false;
return _data?.assets?.holdNoteCover?.data?.enabled ?? fallback?.isHoldNoteCoverEnabled() ?? false;
}
/**
@@ -438,20 +458,20 @@ class NoteStyle implements IRegistryEntry<NoteStyleData>
{
case THREE:
var result = _data.assets.countdownThree?.isPixel;
if (result == null && fallback != null) result = fallback.isCountdownSpritePixel(step);
return result ?? false;
if (result == null) result = fallback?.isCountdownSpritePixel(step) ?? false;
return result;
case TWO:
var result = _data.assets.countdownTwo?.isPixel;
if (result == null && fallback != null) result = fallback.isCountdownSpritePixel(step);
return result ?? false;
if (result == null) result = fallback?.isCountdownSpritePixel(step) ?? false;
return result;
case ONE:
var result = _data.assets.countdownOne?.isPixel;
if (result == null && fallback != null) result = fallback.isCountdownSpritePixel(step);
return result ?? false;
if (result == null) result = fallback?.isCountdownSpritePixel(step) ?? false;
return result;
case GO:
var result = _data.assets.countdownGo?.isPixel;
if (result == null && fallback != null) result = fallback.isCountdownSpritePixel(step);
return result ?? false;
if (result == null) result = fallback?.isCountdownSpritePixel(step) ?? false;
return result;
default:
return false;
}
@@ -463,20 +483,20 @@ class NoteStyle implements IRegistryEntry<NoteStyleData>
{
case THREE:
var result = _data.assets.countdownThree?.offsets;
if (result == null && fallback != null) result = fallback.getCountdownSpriteOffsets(step);
return result ?? [0, 0];
if (result == null) result = fallback?.getCountdownSpriteOffsets(step) ?? [0, 0];
return result;
case TWO:
var result = _data.assets.countdownTwo?.offsets;
if (result == null && fallback != null) result = fallback.getCountdownSpriteOffsets(step);
return result ?? [0, 0];
if (result == null) result = fallback?.getCountdownSpriteOffsets(step) ?? [0, 0];
return result;
case ONE:
var result = _data.assets.countdownOne?.offsets;
if (result == null && fallback != null) result = fallback.getCountdownSpriteOffsets(step);
return result ?? [0, 0];
if (result == null) result = fallback?.getCountdownSpriteOffsets(step) ?? [0, 0];
return result;
case GO:
var result = _data.assets.countdownGo?.offsets;
if (result == null && fallback != null) result = fallback.getCountdownSpriteOffsets(step);
return result ?? [0, 0];
if (result == null) result = fallback?.getCountdownSpriteOffsets(step) ?? [0, 0];
return result;
default:
return [0, 0];
}
@@ -501,7 +521,7 @@ class NoteStyle implements IRegistryEntry<NoteStyleData>
null;
}
return (rawPath == null && fallback != null) ? fallback.getCountdownSoundPath(step, true) : rawPath;
return (rawPath == null) ? fallback?.getCountdownSoundPath(step, true) : rawPath;
}
// library:path
@@ -565,20 +585,20 @@ class NoteStyle implements IRegistryEntry<NoteStyleData>
{
case "sick":
var result = _data.assets.judgementSick?.isPixel;
if (result == null && fallback != null) result = fallback.isJudgementSpritePixel(rating);
return result ?? false;
if (result == null) result = fallback?.isJudgementSpritePixel(rating) ?? false;
return result;
case "good":
var result = _data.assets.judgementGood?.isPixel;
if (result == null && fallback != null) result = fallback.isJudgementSpritePixel(rating);
return result ?? false;
if (result == null) result = fallback?.isJudgementSpritePixel(rating) ?? false;
return result;
case "bad":
var result = _data.assets.judgementBad?.isPixel;
if (result == null && fallback != null) result = fallback.isJudgementSpritePixel(rating);
return result ?? false;
case "GO":
if (result == null) result = fallback?.isJudgementSpritePixel(rating) ?? false;
return result;
case "shit":
var result = _data.assets.judgementShit?.isPixel;
if (result == null && fallback != null) result = fallback.isJudgementSpritePixel(rating);
return result ?? false;
if (result == null) result = fallback?.isJudgementSpritePixel(rating) ?? false;
return result;
default:
return false;
}
@@ -616,20 +636,20 @@ class NoteStyle implements IRegistryEntry<NoteStyleData>
{
case "sick":
var result = _data.assets.judgementSick?.offsets;
if (result == null && fallback != null) result = fallback.getJudgementSpriteOffsets(rating);
return result ?? [0, 0];
if (result == null) result = fallback?.getJudgementSpriteOffsets(rating) ?? [0, 0];
return result;
case "good":
var result = _data.assets.judgementGood?.offsets;
if (result == null && fallback != null) result = fallback.getJudgementSpriteOffsets(rating);
return result ?? [0, 0];
if (result == null) result = fallback?.getJudgementSpriteOffsets(rating) ?? [0, 0];
return result;
case "bad":
var result = _data.assets.judgementBad?.offsets;
if (result == null && fallback != null) result = fallback.getJudgementSpriteOffsets(rating);
return result ?? [0, 0];
if (result == null) result = fallback?.getJudgementSpriteOffsets(rating) ?? [0, 0];
return result;
case "shit":
var result = _data.assets.judgementShit?.offsets;
if (result == null && fallback != null) result = fallback.getJudgementSpriteOffsets(rating);
return result ?? [0, 0];
if (result == null) result = fallback?.getJudgementSpriteOffsets(rating) ?? [0, 0];
return result;
default:
return [0, 0];
}
@@ -730,44 +750,44 @@ class NoteStyle implements IRegistryEntry<NoteStyleData>
{
case 0:
var result = _data.assets.comboNumber0?.isPixel;
if (result == null && fallback != null) result = fallback.isComboNumSpritePixel(digit);
return result ?? false;
if (result == null) result = fallback?.isComboNumSpritePixel(digit) ?? false;
return result;
case 1:
var result = _data.assets.comboNumber1?.isPixel;
if (result == null && fallback != null) result = fallback.isComboNumSpritePixel(digit);
return result ?? false;
if (result == null) result = fallback?.isComboNumSpritePixel(digit) ?? false;
return result;
case 2:
var result = _data.assets.comboNumber2?.isPixel;
if (result == null && fallback != null) result = fallback.isComboNumSpritePixel(digit);
return result ?? false;
if (result == null) result = fallback?.isComboNumSpritePixel(digit) ?? false;
return result;
case 3:
var result = _data.assets.comboNumber3?.isPixel;
if (result == null && fallback != null) result = fallback.isComboNumSpritePixel(digit);
return result ?? false;
if (result == null) result = fallback?.isComboNumSpritePixel(digit) ?? false;
return result;
case 4:
var result = _data.assets.comboNumber4?.isPixel;
if (result == null && fallback != null) result = fallback.isComboNumSpritePixel(digit);
return result ?? false;
if (result == null) result = fallback?.isComboNumSpritePixel(digit) ?? false;
return result;
case 5:
var result = _data.assets.comboNumber5?.isPixel;
if (result == null && fallback != null) result = fallback.isComboNumSpritePixel(digit);
return result ?? false;
if (result == null) result = fallback?.isComboNumSpritePixel(digit) ?? false;
return result;
case 6:
var result = _data.assets.comboNumber6?.isPixel;
if (result == null && fallback != null) result = fallback.isComboNumSpritePixel(digit);
return result ?? false;
if (result == null) result = fallback?.isComboNumSpritePixel(digit) ?? false;
return result;
case 7:
var result = _data.assets.comboNumber7?.isPixel;
if (result == null && fallback != null) result = fallback.isComboNumSpritePixel(digit);
return result ?? false;
if (result == null) result = fallback?.isComboNumSpritePixel(digit) ?? false;
return result;
case 8:
var result = _data.assets.comboNumber8?.isPixel;
if (result == null && fallback != null) result = fallback.isComboNumSpritePixel(digit);
return result ?? false;
if (result == null) result = fallback?.isComboNumSpritePixel(digit) ?? false;
return result;
case 9:
var result = _data.assets.comboNumber9?.isPixel;
if (result == null && fallback != null) result = fallback.isComboNumSpritePixel(digit);
return result ?? false;
if (result == null) result = fallback?.isComboNumSpritePixel(digit) ?? false;
return result;
default:
return false;
}
@@ -817,44 +837,44 @@ class NoteStyle implements IRegistryEntry<NoteStyleData>
{
case 0:
var result = _data.assets.comboNumber0?.offsets;
if (result == null && fallback != null) result = fallback.getComboNumSpriteOffsets(digit);
return result ?? [0, 0];
if (result == null) result = fallback?.getComboNumSpriteOffsets(digit) ?? [0, 0];
return result;
case 1:
var result = _data.assets.comboNumber1?.offsets;
if (result == null && fallback != null) result = fallback.getComboNumSpriteOffsets(digit);
return result ?? [0, 0];
if (result == null) result = fallback?.getComboNumSpriteOffsets(digit) ?? [0, 0];
return result;
case 2:
var result = _data.assets.comboNumber2?.offsets;
if (result == null && fallback != null) result = fallback.getComboNumSpriteOffsets(digit);
return result ?? [0, 0];
if (result == null) result = fallback?.getComboNumSpriteOffsets(digit) ?? [0, 0];
return result;
case 3:
var result = _data.assets.comboNumber3?.offsets;
if (result == null && fallback != null) result = fallback.getComboNumSpriteOffsets(digit);
return result ?? [0, 0];
if (result == null) result = fallback?.getComboNumSpriteOffsets(digit) ?? [0, 0];
return result;
case 4:
var result = _data.assets.comboNumber4?.offsets;
if (result == null && fallback != null) result = fallback.getComboNumSpriteOffsets(digit);
return result ?? [0, 0];
if (result == null) result = fallback?.getComboNumSpriteOffsets(digit) ?? [0, 0];
return result;
case 5:
var result = _data.assets.comboNumber5?.offsets;
if (result == null && fallback != null) result = fallback.getComboNumSpriteOffsets(digit);
return result ?? [0, 0];
if (result == null) result = fallback?.getComboNumSpriteOffsets(digit) ?? [0, 0];
return result;
case 6:
var result = _data.assets.comboNumber6?.offsets;
if (result == null && fallback != null) result = fallback.getComboNumSpriteOffsets(digit);
return result ?? [0, 0];
if (result == null) result = fallback?.getComboNumSpriteOffsets(digit) ?? [0, 0];
return result;
case 7:
var result = _data.assets.comboNumber7?.offsets;
if (result == null && fallback != null) result = fallback.getComboNumSpriteOffsets(digit);
return result ?? [0, 0];
if (result == null) result = fallback?.getComboNumSpriteOffsets(digit) ?? [0, 0];
return result;
case 8:
var result = _data.assets.comboNumber8?.offsets;
if (result == null && fallback != null) result = fallback.getComboNumSpriteOffsets(digit);
return result ?? [0, 0];
if (result == null) result = fallback?.getComboNumSpriteOffsets(digit) ?? [0, 0];
return result;
case 9:
var result = _data.assets.comboNumber9?.offsets;
if (result == null && fallback != null) result = fallback.getComboNumSpriteOffsets(digit);
return result ?? [0, 0];
if (result == null) result = fallback?.getComboNumSpriteOffsets(digit) ?? [0, 0];
return result;
default:
return [0, 0];
}
+117 -45
View File
@@ -15,8 +15,8 @@ import funkin.data.song.SongRegistry;
import funkin.modding.IScriptedClass.IPlayStateScriptedClass;
import funkin.modding.events.ScriptEvent;
import funkin.ui.freeplay.charselect.PlayableCharacter;
import funkin.data.freeplay.player.PlayerRegistry;
import funkin.util.SortUtil;
import openfl.utils.Assets;
/**
* This is a data structure managing information about the current song.
@@ -80,7 +80,12 @@ class Song implements IPlayStateScriptedClass implements IRegistryEntry<SongMeta
// key = variation id, value = metadata
final _metadata:Map<String, SongMetadata>;
final difficulties:Map<String, SongDifficulty>;
/**
* holds the difficulties (as in SongDifficulty) for each variation
* difficulties.get('default').get('easy') would return the easy difficulty for the default variation
*/
final difficulties:Map<String, Map<String, SongDifficulty>>;
/**
* The list of variations a song has.
@@ -93,7 +98,7 @@ class Song implements IPlayStateScriptedClass implements IRegistryEntry<SongMeta
}
// this returns false so that any new song can override this and return true when needed
public function isSongNew(currentDifficulty:String):Bool
public function isSongNew(currentDifficulty:String, currentVariation:String):Bool
{
return false;
}
@@ -147,7 +152,7 @@ class Song implements IPlayStateScriptedClass implements IRegistryEntry<SongMeta
{
this.id = id;
difficulties = new Map<String, SongDifficulty>();
difficulties = new Map<String, Map<String, SongDifficulty>>();
_data = _fetchData(id);
@@ -157,6 +162,12 @@ class Song implements IPlayStateScriptedClass implements IRegistryEntry<SongMeta
{
for (vari in _data.playData.songVariations)
{
if (!validateVariationId(vari))
{
trace(' [WARN] Variation id "$vari" is invalid, skipping...');
continue;
}
var variMeta:Null<SongMetadata> = fetchVariationMetadata(id, vari);
if (variMeta != null)
{
@@ -245,22 +256,39 @@ class Song implements IPlayStateScriptedClass implements IRegistryEntry<SongMeta
* List the album IDs for each variation of the song.
* @return A map of variation IDs to album IDs.
*/
public function listAlbums():Map<String, String>
public function listAlbums(variation:String):Map<String, String>
{
var result:Map<String, String> = new Map<String, String>();
for (difficultyId in difficulties.keys())
for (variationMap in difficulties)
{
var meta:Null<SongDifficulty> = difficulties.get(difficultyId);
if (meta != null && meta.album != null)
for (difficultyId in variationMap.keys())
{
result.set(difficultyId, meta.album);
var meta:Null<SongDifficulty> = variationMap.get(difficultyId);
if (meta != null && meta.album != null)
{
result.set(difficultyId, meta.album);
}
}
}
return result;
}
/**
* Input a difficulty ID and a variation ID, and get the album ID.
* @param diffId
* @param variation
* @return String
*/
public function getAlbumId(diffId:String, variation:String):String
{
var diff:Null<SongDifficulty> = getDifficulty(diffId, variation);
if (diff == null) return '';
return diff.album ?? '';
}
/**
* Populate the difficulty data from the provided metadata.
* Does not load chart data (that is triggered later when we want to play the song).
@@ -281,6 +309,9 @@ class Song implements IPlayStateScriptedClass implements IRegistryEntry<SongMeta
continue;
}
// This resides within difficulties
var difficultyMap:Map<String, SongDifficulty> = new Map<String, SongDifficulty>();
// There may be more difficulties in the chart file than in the metadata,
// (i.e. non-playable charts like the one used for Pico on the speaker in Stress)
// but all the difficulties in the metadata must be in the chart file.
@@ -305,10 +336,9 @@ class Song implements IPlayStateScriptedClass implements IRegistryEntry<SongMeta
difficulty.noteStyle = metadata.playData.noteStyle;
difficulty.characters = metadata.playData.characters;
var variationSuffix = (metadata.variation != Constants.DEFAULT_VARIATION) ? '-${metadata.variation}' : '';
difficulties.set('$diffId$variationSuffix', difficulty);
difficultyMap.set(diffId, difficulty);
}
difficulties.set(metadata.variation, difficultyMap);
}
}
@@ -341,15 +371,18 @@ class Song implements IPlayStateScriptedClass implements IRegistryEntry<SongMeta
for (diffId in chartNotes.keys())
{
// Retrieve the cached difficulty data.
var variationSuffix = (variation != Constants.DEFAULT_VARIATION) ? '-$variation' : '';
var difficulty:Null<SongDifficulty> = difficulties.get('$diffId$variationSuffix');
if (difficulty == null)
// Retrieve the cached difficulty data. This one could potentially be null.
var nullDiff:Null<SongDifficulty> = getDifficulty(diffId, variation);
// if the difficulty doesn't exist, create a new one, and then proceed to fill it with data.
// I mostly do this since I don't wanna throw around ? everywhere for null check lol?
var difficulty:SongDifficulty = nullDiff ?? new SongDifficulty(this, diffId, variation);
if (nullDiff == null)
{
trace('Fabricated new difficulty for $diffId.');
difficulty = new SongDifficulty(this, diffId, variation);
var metadata = _metadata.get(variation);
difficulties.set('$diffId$variationSuffix', difficulty);
difficulties.get(variation)?.set(diffId, difficulty);
if (metadata != null)
{
@@ -392,30 +425,34 @@ class Song implements IPlayStateScriptedClass implements IRegistryEntry<SongMeta
for (currentVariation in variations)
{
var variationSuffix = (currentVariation != Constants.DEFAULT_VARIATION) ? '-$currentVariation' : '';
if (difficulties.exists('$diffId$variationSuffix'))
if (difficulties.get(currentVariation)?.exists(diffId) ?? false)
{
return difficulties.get('$diffId$variationSuffix');
return difficulties.get(currentVariation)?.get(diffId);
}
}
return null;
}
/**
* Returns the first valid variation that matches both the difficulty id, and the current character / possible input variations
* @param diffId
* @param currentCharacter
* @param possibleVariations
* @return Null<String>
*/
public function getFirstValidVariation(?diffId:String, ?currentCharacter:PlayableCharacter, ?possibleVariations:Array<String>):Null<String>
{
if (possibleVariations == null)
{
possibleVariations = getVariationsByCharacter(currentCharacter);
possibleVariations.sort(SortUtil.defaultsThenAlphabetically.bind(Constants.DEFAULT_VARIATION_LIST));
}
if (diffId == null) diffId = listDifficulties(null, possibleVariations)[0];
for (variationId in possibleVariations)
{
var variationSuffix = (variationId != Constants.DEFAULT_VARIATION) ? '-$variationId' : '';
if (difficulties.exists('$diffId$variationSuffix')) return variationId;
if (difficulties.get('$variationId')?.exists(diffId) ?? false) return variationId;
}
return null;
@@ -429,10 +466,14 @@ class Song implements IPlayStateScriptedClass implements IRegistryEntry<SongMeta
*/
public function getVariationsByCharacter(?char:PlayableCharacter):Array<String>
{
if (char == null) return variations;
if (char == null)
{
var result = variations;
result.sort(SortUtil.defaultsThenAlphabetically.bind(Constants.DEFAULT_VARIATION_LIST));
return result;
}
var result = [];
trace('Evaluating variations for ${this.id} ${char.id}: ${this.variations}');
for (variation in variations)
{
var metadata = _metadata.get(variation);
@@ -446,9 +487,24 @@ class Song implements IPlayStateScriptedClass implements IRegistryEntry<SongMeta
}
}
result.sort(SortUtil.defaultsThenAlphabetically.bind(Constants.DEFAULT_VARIATION_LIST));
return result;
}
/**
* Nearly the same thing as getVariationsByCharacter, but takes a character ID instead.
* @param charId
* @return Array<String>
* @see getVariationsByCharacter
*/
public function getVariationsByCharacterId(?charId:String):Array<String>
{
var charPlayer = PlayerRegistry.instance.fetchEntry(charId ?? '');
return getVariationsByCharacter(charPlayer);
}
/**
* List all the difficulties in this song.
*
@@ -466,18 +522,11 @@ class Song implements IPlayStateScriptedClass implements IRegistryEntry<SongMeta
if (variationIds.length == 0) return [];
// The difficulties array contains entries like 'normal', 'nightmare-erect', and 'normal-pico',
// so we have to map it to the actual difficulty names.
// We also filter out difficulties that don't match the variation or that don't exist.
var diffFiltered:Array<String> = difficulties.keys()
.array()
.map(function(diffId:String):Null<String> {
var difficulty:Null<SongDifficulty> = difficulties.get(diffId);
if (difficulty == null) return null;
if (variationIds.length > 0 && !variationIds.contains(difficulty.variation)) return null;
return difficulty.difficulty;
})
var diffFiltered:Array<String> = variationIds.map(function(variationId:String):Array<String> {
var metadata = _metadata.get(variationId);
return metadata?.playData?.difficulties ?? [];
})
.flatten()
.filterNull()
.distinct();
@@ -490,11 +539,16 @@ class Song implements IPlayStateScriptedClass implements IRegistryEntry<SongMeta
return false;
});
diffFiltered.sort(SortUtil.defaultsThenAlphabetically.bind(Constants.DEFAULT_DIFFICULTY_LIST));
diffFiltered.sort(SortUtil.defaultsThenAlphabetically.bind(Constants.DEFAULT_DIFFICULTY_LIST_FULL));
return diffFiltered;
}
/**
* TODO: This line of code makes me sad, but you can't really fix it without a breaking migration.
* @return `easy`, `erect`, `normal-pico`, etc.
* @deprecated This function is deprecated, Funkin no longer uses suffixed difficulties.
*/
public function listSuffixedDifficulties(variationIds:Array<String>, ?showLocked:Bool, ?showHidden:Bool):Array<String>
{
var result = [];
@@ -510,6 +564,8 @@ class Song implements IPlayStateScriptedClass implements IRegistryEntry<SongMeta
}
}
result.sort(SortUtil.defaultsThenAlphabetically.bind(Constants.DEFAULT_DIFFICULTY_LIST_FULL));
return result;
}
@@ -520,8 +576,7 @@ class Song implements IPlayStateScriptedClass implements IRegistryEntry<SongMeta
for (targetVariation in variationIds)
{
var variationSuffix = (targetVariation != Constants.DEFAULT_VARIATION) ? '-$targetVariation' : '';
if (difficulties.exists('$diffId$variationSuffix')) return true;
if (difficulties.get(targetVariation)?.exists(diffId) ?? false) return true;
}
return false;
}
@@ -556,13 +611,16 @@ class Song implements IPlayStateScriptedClass implements IRegistryEntry<SongMeta
}
/**
* Purge the cached chart data for each difficulty of this song.
* Purge the cached chart data for each difficulty/variation of this song.
*/
public function clearCharts():Void
{
for (diff in difficulties)
for (variationMap in difficulties)
{
diff.clearChart();
for (diff in variationMap)
{
diff.clearChart();
}
}
}
@@ -630,6 +688,20 @@ class Song implements IPlayStateScriptedClass implements IRegistryEntry<SongMeta
var meta:Null<SongMetadata> = SongRegistry.instance.parseEntryMetadataWithMigration(id, vari, version);
return meta;
}
static final VARIATION_REGEX = ~/^[a-z][a-z0-9]+$/;
/**
* Validate that the variation ID is valid.
* Auto-accept if it's one of the base game default variations.
* Reject if the ID starts with a number, or contains invalid characters.
*/
static function validateVariationId(variation:String):Bool
{
if (Constants.DEFAULT_VARIATION_LIST.contains(variation)) return true;
return VARIATION_REGEX.match(variation);
}
}
class SongDifficulty
-3
View File
@@ -150,11 +150,8 @@ class Bopper extends StageProp implements IPlayStateScriptedClass
*/
public function resetPosition()
{
var oldAnimOffsets = [animOffsets[0], animOffsets[1]];
animOffsets = [0, 0];
this.x = originalPosition.x;
this.y = originalPosition.y;
animOffsets = oldAnimOffsets;
}
function update_shouldAlternate():Void
+11 -6
View File
@@ -256,8 +256,15 @@ class Stage extends FlxSpriteGroup implements IPlayStateScriptedClass implements
propSprite.scrollFactor.x = dataProp.scroll[0];
propSprite.scrollFactor.y = dataProp.scroll[1];
propSprite.angle = dataProp.angle;
propSprite.color = FlxColor.fromString(dataProp.color);
@:privateAccess if (!isSolidColor) propSprite.blend = BlendMode.fromString(dataProp.blend);
propSprite.zIndex = dataProp.zIndex;
propSprite.flipX = dataProp.flipX;
propSprite.flipY = dataProp.flipY;
switch (dataProp.animType)
{
case 'packer':
@@ -440,12 +447,7 @@ class Stage extends FlxSpriteGroup implements IPlayStateScriptedClass implements
character.x = stageCharData.position[0] - character.characterOrigin.x;
character.y = stageCharData.position[1] - character.characterOrigin.y;
@:privateAccess(funkin.play.stage.Bopper)
{
// Undo animOffsets before saving original position.
character.originalPosition.x = character.x + character.animOffsets[0];
character.originalPosition.y = character.y + character.animOffsets[1];
}
character.originalPosition.set(character.x, character.y);
var finalScale = character.getBaseScale() * stageCharData.scale;
character.setScale(finalScale); // Don't use scale.set for characters!
@@ -464,6 +466,9 @@ class Stage extends FlxSpriteGroup implements IPlayStateScriptedClass implements
#end
}
// Set the characters type
character.characterType = charType;
// Add the character to the scene.
this.add(character);
+193 -15
View File
@@ -10,6 +10,7 @@ import funkin.save.migrator.SaveDataMigrator;
import funkin.save.migrator.SaveDataMigrator;
import funkin.ui.debug.charting.ChartEditorState.ChartEditorLiveInputStyle;
import funkin.ui.debug.charting.ChartEditorState.ChartEditorTheme;
import funkin.ui.debug.stageeditor.StageEditorState.StageEditorTheme;
import funkin.util.SerializerUtil;
import thx.semver.Version;
import thx.semver.Version;
@@ -17,7 +18,7 @@ import thx.semver.Version;
@:nullSafety
class Save
{
public static final SAVE_DATA_VERSION:thx.semver.Version = "2.0.5";
public static final SAVE_DATA_VERSION:thx.semver.Version = "2.0.4";
public static final SAVE_DATA_VERSION_RULE:thx.semver.VersionRule = "2.0.x";
// We load this version's saves from a new save path, to maintain SOME level of backwards compatibility.
@@ -34,19 +35,19 @@ class Save
{
if (_instance == null)
{
_instance = new Save(FlxG.save.data);
return _instance = load();
}
return _instance;
}
var data:RawSaveData;
public static function load():Void
public static function load():Save
{
trace("[SAVE] Loading save...");
// Bind save data.
loadFromSlot(1);
return loadFromSlot(1);
}
/**
@@ -65,7 +66,9 @@ class Save
public static function getDefault():RawSaveData
{
return {
version: Save.SAVE_DATA_VERSION,
// Version number is an abstract(Array) internally.
// This means it copies by reference, so merging save data overides the version number lol.
version: thx.Dynamics.clone(Save.SAVE_DATA_VERSION),
volume: 1.0,
mute: false,
@@ -89,6 +92,7 @@ class Save
options:
{
// Reasonable defaults.
framerate: 60,
naughtyness: true,
downscroll: false,
flashingLights: true,
@@ -143,6 +147,14 @@ class Save
hitsoundVolumeOpponent: 1.0,
themeMusic: true
},
optionsStageEditor:
{
previousFiles: [],
moveStep: "1px",
angleStep: 5,
theme: StageEditorTheme.Light
}
};
}
@@ -425,6 +437,91 @@ class Save
return data.unlocks.oldChar;
}
public var stageEditorPreviousFiles(get, set):Array<String>;
function get_stageEditorPreviousFiles():Array<String>
{
if (data.optionsStageEditor.previousFiles == null) data.optionsStageEditor.previousFiles = [];
return data.optionsStageEditor.previousFiles;
}
function set_stageEditorPreviousFiles(value:Array<String>):Array<String>
{
// Set and apply.
data.optionsStageEditor.previousFiles = value;
flush();
return data.optionsStageEditor.previousFiles;
}
public var stageEditorHasBackup(get, set):Bool;
function get_stageEditorHasBackup():Bool
{
if (data.optionsStageEditor.hasBackup == null) data.optionsStageEditor.hasBackup = false;
return data.optionsStageEditor.hasBackup;
}
function set_stageEditorHasBackup(value:Bool):Bool
{
// Set and apply.
data.optionsStageEditor.hasBackup = value;
flush();
return data.optionsStageEditor.hasBackup;
}
public var stageEditorMoveStep(get, set):String;
function get_stageEditorMoveStep():String
{
if (data.optionsStageEditor.moveStep == null) data.optionsStageEditor.moveStep = "1px";
return data.optionsStageEditor.moveStep;
}
function set_stageEditorMoveStep(value:String):String
{
// Set and apply.
data.optionsStageEditor.moveStep = value;
flush();
return data.optionsStageEditor.moveStep;
}
public var stageEditorAngleStep(get, set):Float;
function get_stageEditorAngleStep():Float
{
if (data.optionsStageEditor.angleStep == null) data.optionsStageEditor.angleStep = 5;
return data.optionsStageEditor.angleStep;
}
function set_stageEditorAngleStep(value:Float):Float
{
// Set and apply.
data.optionsStageEditor.angleStep = value;
flush();
return data.optionsStageEditor.angleStep;
}
public var stageEditorTheme(get, set):StageEditorTheme;
function get_stageEditorTheme():StageEditorTheme
{
if (data.optionsStageEditor.theme == null) data.optionsStageEditor.theme = StageEditorTheme.Light;
return data.optionsStageEditor.theme;
}
function set_stageEditorTheme(value:StageEditorTheme):StageEditorTheme
{
// Set and apply.
data.optionsStageEditor.theme = value;
flush();
return data.optionsStageEditor.theme;
}
/**
* When we've seen a character unlock, add it to the list of characters seen.
* @param character
@@ -433,7 +530,9 @@ class Save
{
if (!data.unlocks.charactersSeen.contains(character))
{
trace('Character seen: ' + character);
data.unlocks.charactersSeen.push(character);
trace('New characters seen list: ' + data.unlocks.charactersSeen);
flush();
}
}
@@ -538,22 +637,34 @@ class Save
*
* @param songId The ID of the song.
* @param difficultyId The difficulty to check.
* @param variation The variation to check. Defaults to empty string. Appended to difficulty with `-`, e.g. `easy-pico`.
* @return A data structure containing score, judgement counts, and accuracy. Returns `null` if no score is saved.
*/
public function getSongScore(songId:String, difficultyId:String = 'normal'):Null<SaveScoreData>
public function getSongScore(songId:String, difficultyId:String = 'normal', ?variation:String):Null<SaveScoreData>
{
var song = data.scores.songs.get(songId);
trace('Getting song score for $songId $difficultyId $variation');
if (song == null)
{
trace('Could not find song data for $songId $difficultyId $variation');
song = [];
data.scores.songs.set(songId, song);
}
// 'default' variations are left with no suffix ('easy', 'normal', 'hard'),
// along with 'erect' variations ('erect', 'nightmare')
// otherwise, we want to add a suffix of our current variation to get the save data.
if (variation != null && variation != '' && variation != 'default' && variation != 'erect')
{
difficultyId = '${difficultyId}-${variation}';
}
return song.get(difficultyId);
}
public function getSongRank(songId:String, difficultyId:String = 'normal'):Null<ScoringRank>
public function getSongRank(songId:String, difficultyId:String = 'normal', ?variation:String):Null<ScoringRank>
{
return Scoring.calculateRank(getSongScore(songId, difficultyId));
return Scoring.calculateRank(getSongScore(songId, difficultyId, variation));
}
/**
@@ -598,11 +709,14 @@ class Save
return;
}
var newCompletion = (newScoreData.tallies.sick + newScoreData.tallies.good) / newScoreData.tallies.totalNotes;
var previousCompletion = (previousScoreData.tallies.sick + previousScoreData.tallies.good) / previousScoreData.tallies.totalNotes;
// 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
tallies: (previousRank > newRank || previousCompletion > newCompletion) ? previousScoreData.tallies : newScoreData.tallies
};
song.set(difficultyId, newScore);
@@ -670,18 +784,31 @@ class Save
/**
* Has the provided song been beaten on one of the listed difficulties?
* Note: This function can still take in the 'difficulty-variation' format for the difficultyList parameter
* as it is used in the old save data format. However inputting a variation will append it to the difficulty
* so you can do `hasBeatenSong('dadbattle', ['easy-pico'])` to check if you've beaten the Pico mix on easy.
* or you can do `hasBeatenSong('dadbattle', ['easy'], 'pico')` to check if you've beaten the Pico mix on easy.
* however you should not mix the two as it will append '-pico' to the 'easy-pico' if it's inputted into the array.
* @param songId The song ID to check.
* @param difficultyList The difficulties to check. Defaults to `easy`, `normal`, and `hard`.
* @param variation The variation to check. Defaults to empty string. Appended to difficulty list with `-`, e.g. `easy-pico`.
* This is our old format for getting difficulty/variation information, however we don't want to mess around with
* save migration just yet.
* @return Whether the song has been beaten on any of the listed difficulties.
*/
public function hasBeatenSong(songId:String, ?difficultyList:Array<String>):Bool
public function hasBeatenSong(songId:String, ?difficultyList:Array<String>, ?variation:String):Bool
{
if (difficultyList == null)
{
difficultyList = ['easy', 'normal', 'hard'];
}
if (variation == null) variation = '';
for (difficulty in difficultyList)
{
if (variation != '') difficulty = '${difficulty}-${variation}';
var score:Null<SaveScoreData> = getSongScore(songId, difficulty);
if (score != null)
{
@@ -832,7 +959,7 @@ class Save
* If you set slot to `2`, it will load an independe
* @param slot
*/
static function loadFromSlot(slot:Int):Void
static function loadFromSlot(slot:Int):Save
{
trace("[SAVE] Loading save from slot " + slot + "...");
@@ -850,12 +977,14 @@ class Save
trace('[SAVE] Found legacy save data, converting...');
var gameSave = SaveDataMigrator.migrateFromLegacy(legacySaveData);
FlxG.save.mergeData(gameSave.data, true);
return gameSave;
}
else
{
trace('[SAVE] No legacy save data found.');
var gameSave = new Save();
FlxG.save.mergeData(gameSave.data, true);
return gameSave;
}
}
else
@@ -863,6 +992,8 @@ class Save
trace('[SAVE] Found existing save data.');
var gameSave = SaveDataMigrator.migrate(FlxG.save.data);
FlxG.save.mergeData(gameSave.data, true);
return gameSave;
}
}
@@ -1031,6 +1162,11 @@ typedef RawSaveData =
* The user's preferences specific to the Chart Editor.
*/
var optionsChartEditor:SaveDataChartEditorOptions;
/**
* The user's preferences specific to the Stage Editor.
*/
var optionsStageEditor:SaveDataStageEditorOptions;
};
typedef SaveApiData =
@@ -1134,7 +1270,13 @@ typedef SaveScoreTallyData =
typedef SaveDataOptions =
{
/**
* Whether some particularly fowl language is displayed.
* FPS
* @default `60`
*/
var framerate:Int;
/**
* Whether some particularly foul language is displayed.
* @default `true`
*/
var naughtyness:Bool;
@@ -1170,20 +1312,20 @@ typedef SaveDataOptions =
var autoPause:Bool;
/**
* Offset the users inputs by this many ms.
* Offset the user's inputs by this many ms.
* @default `0`
*/
var inputOffset:Int;
/**
* Affects the delay between the audio and the visuals during gameplay
* Affects the delay between the audio and the visuals during gameplay.
* @default `0`
*/
var audioVisualOffset:Int;
/**
* If we want the framerate to be unlocked on HTML5.
* @default `false
* @default `false`
*/
var unlockedFramerate:Bool;
@@ -1398,3 +1540,39 @@ typedef SaveDataChartEditorOptions =
*/
var ?playbackSpeed:Float;
};
typedef SaveDataStageEditorOptions =
{
// a lot of these things were copied from savedatacharteditoroptions
/**
* Whether the Stage Editor created a backup the last time it closed.
* Prompt the user to load it, then set this back to `false`.
* @default `false`
*/
var ?hasBackup:Bool;
/**
* Previous files opened in the Stage Editor.
* @default `[]`
*/
var ?previousFiles:Array<String>;
/**
* The Step at which an Object or Character is moved.
* @default `1px`
*/
var ?moveStep:String;
/**
* The Step at which an Object is rotated.
* @default `5`
*/
var ?angleStep:Float;
/**
* Theme in the Stage Editor.
* @default `StageEditorTheme.Light`
*/
var ?theme:StageEditorTheme;
};
+6
View File
@@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [2.0.4] - 2024-09-12
Note to self: Only update to 2.1.0 when migration is needed.
### Added
- `unlocks.charactersSeen:Array<String>` to `Save`
- `unlocks.oldChar:Bool` to `Save`
## [2.0.5] - 2024-05-21
### Fixed
- Resolved an issue where HTML5 wouldn't store the semantic version properly, causing the game to fail to load the save.
+14 -6
View File
@@ -37,17 +37,25 @@ class MusicBeatSubState extends FlxSubState implements IEventHandler
return _conductorInUse = value;
}
public function new(bgColor:FlxColor = FlxColor.TRANSPARENT)
{
super();
this.bgColor = bgColor;
}
var controls(get, never):Controls;
inline function get_controls():Controls
return PlayerSettings.player1.controls;
public function new(bgColor:FlxColor = FlxColor.TRANSPARENT)
{
super();
this.bgColor = bgColor;
initCallbacks();
}
function initCallbacks()
{
subStateOpened.add(onOpenSubStateComplete);
subStateClosed.add(onCloseSubStateComplete);
}
override function create():Void
{
super.create();
+5
View File
@@ -50,8 +50,13 @@ class PixelatedIcon extends FlxFilteredSprite
if (!openfl.utils.Assets.exists(Paths.image(charPath)))
{
trace('[WARN] Character ${char} has no freeplay icon.');
this.visible = false;
return;
}
else
{
this.visible = true;
}
var isAnimated = openfl.utils.Assets.exists(Paths.file('images/$charPath.xml'));
+24 -23
View File
@@ -11,6 +11,7 @@ import funkin.modding.IScriptedClass.IBPMSyncedScriptedClass;
import flixel.math.FlxMath;
import funkin.modding.events.ScriptEvent;
import funkin.vis.dsp.SpectralAnalyzer;
import funkin.data.freeplay.player.PlayerRegistry;
class CharSelectGF extends FlxAtlasSprite implements IBPMSyncedScriptedClass
{
@@ -27,7 +28,8 @@ class CharSelectGF extends FlxAtlasSprite implements IBPMSyncedScriptedClass
var analyzer:SpectralAnalyzer;
var curGF:GFChar = GF;
var currentGFPath:Null<String>;
var enableVisualizer:Bool = false;
public function new()
{
@@ -97,7 +99,7 @@ class CharSelectGF extends FlxAtlasSprite implements IBPMSyncedScriptedClass
function drawFFT()
{
if (curGF == NENE)
if (enableVisualizer)
{
var levels = analyzer.getLevels();
var frame = anim.curSymbol.timeline.get("VIZ_bars").get(anim.curFrame);
@@ -172,28 +174,33 @@ class CharSelectGF extends FlxAtlasSprite implements IBPMSyncedScriptedClass
*/
public function switchGF(bf:String):Void
{
var prevGF:GFChar = curGF;
switch (bf)
{
case "pico":
curGF = NENE;
case "bf":
curGF = GF;
default:
curGF = GF;
}
var previousGFPath = currentGFPath;
var bfObj = PlayerRegistry.instance.fetchEntry(bf);
var gfData = bfObj?.getCharSelectData()?.gf;
currentGFPath = gfData?.assetPath != null ? Paths.animateAtlas(gfData?.assetPath) : null;
// We don't need to update any anims if we didn't change GF
if (prevGF != curGF)
trace('currentGFPath(${currentGFPath})');
if (currentGFPath == null)
{
loadAtlas(Paths.animateAtlas("charSelect/" + curGF + "Chill"));
this.visible = false;
return;
}
else if (previousGFPath != currentGFPath)
{
this.visible = true;
loadAtlas(currentGFPath);
animInInfo = FramesJSFLParser.parse(Paths.file("images/charSelect/" + curGF + "AnimInfo/" + curGF + "In.txt"));
animOutInfo = FramesJSFLParser.parse(Paths.file("images/charSelect/" + curGF + "AnimInfo/" + curGF + "Out.txt"));
enableVisualizer = gfData?.visualizer ?? false;
var animInfoPath = Paths.file('images/${gfData?.animInfoPath}');
animInInfo = FramesJSFLParser.parse(animInfoPath + '/In.txt');
animOutInfo = FramesJSFLParser.parse(animInfoPath + '/Out.txt');
}
playAnimation("idle", true, false, false);
// addFrameCallback(getNextFrameLabel("idle"), () -> playAnimation("idle", true, false, false));
updateHitbox();
}
@@ -213,9 +220,3 @@ enum FadeStatus
FADE_OUT;
FADE_IN;
}
enum abstract GFChar(String) from String to String
{
var GF = "gf";
var NENE = "nene";
}
@@ -47,7 +47,6 @@ class CharSelectPlayer extends FlxAtlasSprite implements IBPMSyncedScriptedClass
//
if (getCurrentAnimation() == "idle")
{
trace('Player beat hit');
playAnimation("idle", true, false, false);
}
};
@@ -71,6 +71,7 @@ class CharSelectSubState extends MusicBeatSubState
var availableChars:Map<Int, String> = new Map<Int, String>();
var pressedSelect:Bool = false;
var selectTimer:FlxTimer = new FlxTimer();
var allowInput:Bool = false;
var selectSound:FunkinSound;
var unlockSound:FunkinSound;
@@ -174,6 +175,7 @@ class CharSelectSubState extends MusicBeatSubState
playerChillOut = new CharSelectPlayer(0, 0);
playerChillOut.switchChar("bf");
playerChillOut.visible = false;
add(playerChillOut);
playerChill = new CharSelectPlayer(0, 0);
@@ -430,6 +432,8 @@ class CharSelectSubState extends MusicBeatSubState
overrideExisting: true,
restartTrack: true,
onLoad: function() {
allowInput = true;
@:privateAccess
gfChill.analyzer = new SpectralAnalyzer(FlxG.sound.music._channel.__audioSource, 7, 0.1);
#if desktop
@@ -540,6 +544,7 @@ class CharSelectSubState extends MusicBeatSubState
nametag.switchChar(char);
gfChill.switchGF(char);
gfChill.visible = true;
var icon = new PixelatedIcon(0, 0);
icon.setCharacter(char);
@@ -573,6 +578,8 @@ class CharSelectSubState extends MusicBeatSubState
overrideExisting: true,
restartTrack: true,
onLoad: function() {
allowInput = true;
@:privateAccess
gfChill.analyzer = new SpectralAnalyzer(FlxG.sound.music._channel.__audioSource, 7, 0.1);
#if desktop
@@ -642,6 +649,7 @@ class CharSelectSubState extends MusicBeatSubState
function goToFreeplay():Void
{
allowInput = false;
autoFollow = false;
FlxTween.tween(cursor, {alpha: 0}, 0.8, {ease: FlxEase.expoOut});
@@ -695,7 +703,7 @@ class CharSelectSubState extends MusicBeatSubState
syncAudio(elapsed);
if (!pressedSelect)
if (allowInput && !pressedSelect)
{
if (controls.UI_UP) holdTmrUp += elapsed;
if (controls.UI_UP_R)
@@ -782,18 +790,18 @@ class CharSelectSubState extends MusicBeatSubState
cursorY = -1;
}
if (autoFollow
&& availableChars.exists(getCurrentSelected())
&& Save.instance.charactersSeen.contains(availableChars[getCurrentSelected()]))
if (availableChars.exists(getCurrentSelected()) && Save.instance.charactersSeen.contains(availableChars[getCurrentSelected()]))
{
gfChill.visible = true;
curChar = availableChars.get(getCurrentSelected());
if (!pressedSelect && controls.ACCEPT)
if (allowInput && !pressedSelect && controls.ACCEPT)
{
spamUp = false;
spamDown = false;
spamLeft = false;
spamRight = false;
cursorConfirmed.visible = true;
cursorConfirmed.x = cursor.x - 2;
cursorConfirmed.y = cursor.y - 4;
cursorConfirmed.animation.play("idle", true);
grpCursors.visible = false;
@@ -817,7 +825,7 @@ class CharSelectSubState extends MusicBeatSubState
});
}
if (pressedSelect && controls.BACK)
if (allowInput && pressedSelect && controls.BACK)
{
cursorConfirmed.visible = false;
grpCursors.visible = true;
@@ -841,17 +849,15 @@ class CharSelectSubState extends MusicBeatSubState
selectTimer.cancel();
}
}
else if (autoFollow)
else
{
curChar = "locked";
gfChill.visible = false;
if (controls.ACCEPT)
if (allowInput && controls.ACCEPT)
{
cursorDenied.visible = true;
cursorDenied.x = cursor.x - 2;
cursorDenied.y = cursor.y - 4;
playerChill.playAnimation("cannot select Label", true);
@@ -879,14 +885,20 @@ class CharSelectSubState extends MusicBeatSubState
cursorLocIntended.x += cursorOffsetX;
cursorLocIntended.y += cursorOffsetY;
cursor.x = MathUtil.coolLerp(cursor.x, cursorLocIntended.x, lerpAmnt);
cursor.y = MathUtil.coolLerp(cursor.y, cursorLocIntended.y, lerpAmnt);
cursor.x = MathUtil.smoothLerp(cursor.x, cursorLocIntended.x, elapsed, 0.1);
cursor.y = MathUtil.smoothLerp(cursor.y, cursorLocIntended.y, elapsed, 0.1);
cursorBlue.x = MathUtil.coolLerp(cursorBlue.x, cursor.x, lerpAmnt * 0.4);
cursorBlue.y = MathUtil.coolLerp(cursorBlue.y, cursor.y, lerpAmnt * 0.4);
cursorDarkBlue.x = MathUtil.coolLerp(cursorDarkBlue.x, cursorLocIntended.x, lerpAmnt * 0.2);
cursorDarkBlue.y = MathUtil.coolLerp(cursorDarkBlue.y, cursorLocIntended.y, lerpAmnt * 0.2);
cursorConfirmed.x = cursor.x - 2;
cursorConfirmed.y = cursor.y - 4;
cursorDenied.x = cursor.x - 2;
cursorDenied.y = cursor.y - 4;
}
var bopTimer:Float = 0;
@@ -1051,18 +1063,21 @@ class CharSelectSubState extends MusicBeatSubState
staticSound.stop();
nametag.switchChar(value);
gfChill.visible = false;
playerChill.visible = false;
playerChillOut.visible = true;
playerChillOut.playAnimation("slideout");
var index = playerChillOut.anim.getFrameLabel("slideout").index;
playerChillOut.onAnimationFrame.removeAll();
playerChillOut.onAnimationFrame.add((_, frame:Int) -> {
if (frame == index + 1)
if (frame >= index + 1)
{
playerChill.visible = true;
playerChill.switchChar(value);
gfChill.switchGF(value);
gfChill.visible = true;
}
if (frame == index + 2)
if (frame >= index + 2)
{
playerChillOut.switchChar(value);
playerChillOut.visible = false;
+3 -3
View File
@@ -4,7 +4,7 @@ package funkin.ui.charSelect;
import funkin.graphics.video.FlxVideo;
#end
#if hxCodec
import hxcodec.flixel.FlxVideoSprite;
import funkin.graphics.video.FunkinVideoSprite;
#end
import funkin.ui.MusicBeatSubState;
import funkin.audio.FunkinSound;
@@ -72,12 +72,12 @@ class IntroSubState extends MusicBeatSubState
#end
#if hxCodec
var vid:FlxVideoSprite;
var vid:FunkinVideoSprite;
function playVideoNative(filePath:String):Void
{
// Video displays OVER the FlxState.
vid = new FlxVideoSprite(0, 0);
vid = new FunkinVideoSprite(0, 0);
vid.scrollFactor.set();
+2 -1
View File
@@ -60,7 +60,7 @@ class DebugMenuSubState extends MusicBeatSubState
// createItem("Input Offset Testing", openInputOffsetTesting);
createItem("CHARACTER SELECT", openCharSelect, true);
createItem("ANIMATION EDITOR", openAnimationEditor);
// createItem("STAGE EDITOR", openStageEditor);
createItem("STAGE EDITOR", openStageEditor);
// createItem("TEST STICKERS", testStickers);
#if sys
createItem("OPEN CRASH LOG FOLDER", openLogFolder);
@@ -125,6 +125,7 @@ class DebugMenuSubState extends MusicBeatSubState
function openStageEditor()
{
trace('Stage Editor');
FlxG.switchState(() -> new funkin.ui.debug.stageeditor.StageEditorState());
}
#if sys
@@ -24,7 +24,6 @@ import haxe.ui.core.Screen;
import haxe.ui.events.UIEvent;
import haxe.ui.RuntimeComponentBuilder;
import lime.utils.Assets as LimeAssets;
import openfl.Assets;
import openfl.events.Event;
import openfl.events.IOErrorEvent;
import openfl.geom.Rectangle;
@@ -110,9 +109,11 @@ class DebugBoundingState extends FlxState
offsetEditorDialog.cameras = [hudCam];
add(offsetEditorDialog);
offsetEditorDialog.showDialog(false);
// Anchor to the right side by default
// offsetEditorDialog.x = FlxG.width - offsetEditorDialog.width;
// Anchor to the left side by default
offsetEditorDialog.x = 16;
offsetEditorDialog.y = 16;
// sets the default camera back to FlxG.camera, since we set it to hudCamera for haxeui stuf
FlxG.cameras.setDefaultDrawTarget(FlxG.camera, true);
@@ -239,6 +240,11 @@ class DebugBoundingState extends FlxState
{
movingCharacter = false;
}
if (FlxG.mouse.justReleased)
{
movingCharacter = false;
}
}
}
@@ -79,7 +79,6 @@ import funkin.ui.debug.charting.commands.SetItemSelectionCommand;
import funkin.ui.debug.charting.components.ChartEditorEventSprite;
import funkin.ui.debug.charting.components.ChartEditorHoldNoteSprite;
import funkin.ui.debug.charting.components.ChartEditorMeasureTicks;
import funkin.ui.debug.charting.components.ChartEditorMeasureTicks;
import funkin.ui.debug.charting.components.ChartEditorNotePreview;
import funkin.ui.debug.charting.components.ChartEditorNoteSprite;
import funkin.ui.debug.charting.components.ChartEditorPlaybarHead;
@@ -700,7 +699,7 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
function get_isCursorOverHaxeUI():Bool
{
return Screen.instance.hasSolidComponentUnderPoint(FlxG.mouse.screenX, FlxG.mouse.screenY);
return Screen.instance.hasSolidComponentUnderPoint(FlxG.mouse.viewX, FlxG.mouse.viewY);
}
/**
@@ -2274,8 +2273,25 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
this.openBackupAvailableDialog(welcomeDialog);
}
}
#if FEATURE_DISCORD_RPC
updateDiscordRPC();
#end
}
#if FEATURE_DISCORD_RPC
function updateDiscordRPC():Void
{
funkin.api.discord.DiscordClient.instance.setPresence(
{
// TODO: Make this display the song name and update when it changes.
// state: '${currentSongName} [${selectedDifficulty}]',
state: null,
details: 'Chart Editor [Charting]'
});
}
#end
function setupWelcomeMusic()
{
this.welcomeMusic.loadEmbedded(Paths.music('chartEditorLoop/chartEditorLoop'));
@@ -3840,7 +3856,7 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
// Handle scroll anchor
if (scrollAnchorScreenPos != null)
{
var currentScreenPos = new FlxPoint(FlxG.mouse.screenX, FlxG.mouse.screenY);
var currentScreenPos = new FlxPoint(FlxG.mouse.viewX, FlxG.mouse.viewX);
var distance = currentScreenPos - scrollAnchorScreenPos;
var verticalDistance = distance.y;
@@ -4121,8 +4137,8 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
var overlapsRenderedEvents:Bool = FlxG.mouse.overlaps(renderedEvents);
// Cursor position relative to the grid.
var cursorX:Float = FlxG.mouse.screenX - gridTiledSprite.x;
var cursorY:Float = FlxG.mouse.screenY - gridTiledSprite.y;
var cursorX:Float = FlxG.mouse.viewX - gridTiledSprite.x;
var cursorY:Float = FlxG.mouse.viewY - gridTiledSprite.y;
var overlapsSelectionBorder:Bool = overlapsGrid
&& ((cursorX % 40) < (GRID_SELECTION_BORDER_WIDTH / 2)
@@ -4137,7 +4153,7 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
{
if (scrollAnchorScreenPos == null)
{
scrollAnchorScreenPos = new FlxPoint(FlxG.mouse.screenX, FlxG.mouse.screenY);
scrollAnchorScreenPos = new FlxPoint(FlxG.mouse.viewX, FlxG.mouse.viewY);
selectionBoxStartPos = null;
}
else
@@ -4159,11 +4175,11 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
else if (notePreview != null && FlxG.mouse.overlaps(notePreview) && !isCursorOverHaxeUI)
{
// Clicked note preview
notePreviewScrollAreaStartPos = new FlxPoint(FlxG.mouse.screenX, FlxG.mouse.screenY);
notePreviewScrollAreaStartPos = new FlxPoint(FlxG.mouse.viewX, FlxG.mouse.viewY);
}
else if (!isCursorOverHaxeUI && (!overlapsGrid || overlapsSelectionBorder))
{
selectionBoxStartPos = new FlxPoint(FlxG.mouse.screenX, FlxG.mouse.screenY);
selectionBoxStartPos = new FlxPoint(FlxG.mouse.viewX, FlxG.mouse.viewY);
// Drawing selection box.
targetCursorMode = Crosshair;
}
@@ -4188,7 +4204,7 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
{
// Clicked on the playhead scroll area.
// Move the playhead to the cursor position.
this.playheadPositionInPixels = FlxG.mouse.screenY - (GRID_INITIAL_Y_POS);
this.playheadPositionInPixels = FlxG.mouse.viewY - (GRID_INITIAL_Y_POS);
moveSongToScrollPosition();
// Cursor should be a grabby hand.
@@ -4251,8 +4267,8 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
}
else
{
// Minimum of 0.
return 0;
// Minimum of -1.
return -1;
}
});
@@ -4313,27 +4329,27 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
// Clicking and dragging.
// Scroll the screen if the mouse is above or below the grid.
if (FlxG.mouse.screenY < MENU_BAR_HEIGHT)
if (FlxG.mouse.viewY < MENU_BAR_HEIGHT)
{
// Scroll up.
var diff:Float = MENU_BAR_HEIGHT - FlxG.mouse.screenY;
var diff:Float = MENU_BAR_HEIGHT - FlxG.mouse.viewY;
scrollPositionInPixels -= diff * 0.5; // Too fast!
moveSongToScrollPosition();
}
else if (FlxG.mouse.screenY > (playbarHeadLayout?.y ?? 0.0))
else if (FlxG.mouse.viewY > (playbarHeadLayout?.y ?? 0.0))
{
// Scroll down.
var diff:Float = FlxG.mouse.screenY - (playbarHeadLayout?.y ?? 0.0);
var diff:Float = FlxG.mouse.viewY - (playbarHeadLayout?.y ?? 0.0);
scrollPositionInPixels += diff * 0.5; // Too fast!
moveSongToScrollPosition();
}
// Render the selection box.
var selectionRect:FlxRect = new FlxRect();
selectionRect.x = Math.min(FlxG.mouse.screenX, selectionBoxStartPos.x);
selectionRect.y = Math.min(FlxG.mouse.screenY, selectionBoxStartPos.y);
selectionRect.width = Math.abs(FlxG.mouse.screenX - selectionBoxStartPos.x);
selectionRect.height = Math.abs(FlxG.mouse.screenY - selectionBoxStartPos.y);
selectionRect.x = Math.min(FlxG.mouse.viewX, selectionBoxStartPos.x);
selectionRect.y = Math.min(FlxG.mouse.viewY, selectionBoxStartPos.y);
selectionRect.width = Math.abs(FlxG.mouse.viewX - selectionBoxStartPos.x);
selectionRect.height = Math.abs(FlxG.mouse.viewY - selectionBoxStartPos.y);
setSelectionBoxBounds(selectionRect);
targetCursorMode = Crosshair;
@@ -4461,8 +4477,8 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
// Player is clicking and holding on note preview to scrub around.
targetCursorMode = Grabbing;
var clickedPosInPixels:Float = FlxMath.remapToRange(FlxG.mouse.screenY, (notePreview?.y ?? 0.0),
(notePreview?.y ?? 0.0) + (notePreview?.height ?? 0.0), 0, songLengthInPixels);
var clickedPosInPixels:Float = FlxMath.remapToRange(FlxG.mouse.viewY, (notePreview?.y ?? 0.0), (notePreview?.y ?? 0.0) + (notePreview?.height ?? 0.0),
0, songLengthInPixels);
scrollPositionInPixels = clickedPosInPixels;
moveSongToScrollPosition();
@@ -4520,17 +4536,17 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
targetCursorMode = Grabbing;
// Scroll the screen if the mouse is above or below the grid.
if (FlxG.mouse.screenY < MENU_BAR_HEIGHT)
if (FlxG.mouse.viewY < MENU_BAR_HEIGHT)
{
// Scroll up.
var diff:Float = MENU_BAR_HEIGHT - FlxG.mouse.screenY;
var diff:Float = MENU_BAR_HEIGHT - FlxG.mouse.viewY;
scrollPositionInPixels -= diff * 0.5; // Too fast!
moveSongToScrollPosition();
}
else if (FlxG.mouse.screenY > (playbarHeadLayout?.y ?? 0.0))
else if (FlxG.mouse.viewY > (playbarHeadLayout?.y ?? 0.0))
{
// Scroll down.
var diff:Float = FlxG.mouse.screenY - (playbarHeadLayout?.y ?? 0.0);
var diff:Float = FlxG.mouse.viewY - (playbarHeadLayout?.y ?? 0.0);
scrollPositionInPixels += diff * 0.5; // Too fast!
moveSongToScrollPosition();
}
@@ -4811,11 +4827,11 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
// Show the context menu connected to the note.
if (useSingleNoteContextMenu)
{
this.openNoteContextMenu(FlxG.mouse.screenX, FlxG.mouse.screenY, highlightedNote.noteData);
this.openNoteContextMenu(FlxG.mouse.viewX, FlxG.mouse.viewY, highlightedNote.noteData);
}
else
{
this.openSelectionContextMenu(FlxG.mouse.screenX, FlxG.mouse.screenY);
this.openSelectionContextMenu(FlxG.mouse.viewX, FlxG.mouse.viewY);
}
}
else
@@ -4835,11 +4851,11 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
|| (isHighlightedEventSelected && currentEventSelection.length == 1);
if (useSingleEventContextMenu)
{
this.openEventContextMenu(FlxG.mouse.screenX, FlxG.mouse.screenY, highlightedEvent.eventData);
this.openEventContextMenu(FlxG.mouse.viewX, FlxG.mouse.viewY, highlightedEvent.eventData);
}
else
{
this.openSelectionContextMenu(FlxG.mouse.screenX, FlxG.mouse.screenY);
this.openSelectionContextMenu(FlxG.mouse.viewX, FlxG.mouse.viewY);
}
}
else
@@ -4860,11 +4876,11 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
// Show the context menu connected to the note.
if (useSingleNoteContextMenu)
{
this.openHoldNoteContextMenu(FlxG.mouse.screenX, FlxG.mouse.screenY, highlightedHoldNote.noteData);
this.openHoldNoteContextMenu(FlxG.mouse.viewX, FlxG.mouse.viewY, highlightedHoldNote.noteData);
}
else
{
this.openSelectionContextMenu(FlxG.mouse.screenX, FlxG.mouse.screenY);
this.openSelectionContextMenu(FlxG.mouse.viewX, FlxG.mouse.viewY);
}
}
else
@@ -5139,10 +5155,11 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
}
var songPos:Float = Conductor.instance.songPosition + Conductor.instance.instrumentalOffset;
var songPosMilliseconds:String = Std.string(Math.floor(Math.abs(songPos) % 1000)).lpad('0', 2).substr(0, 2);
var songPosSeconds:String = Std.string(Math.floor((Math.abs(songPos) / 1000) % 60)).lpad('0', 2);
var songPosMinutes:String = Std.string(Math.floor((Math.abs(songPos) / 1000) / 60)).lpad('0', 2);
if (songPos < 0) songPosMinutes = '-' + songPosMinutes;
var songPosString:String = '${songPosMinutes}:${songPosSeconds}';
var songPosString:String = '${songPosMinutes}:${songPosSeconds}.${songPosMilliseconds}';
if (playbarSongPos.value != songPosString) playbarSongPos.value = songPosString;
@@ -5614,7 +5631,7 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
}
else
{
trace('Ignoring keybinds for View menu items because we are in live input mode (${currentLiveInputStyle}).');
// trace('Ignoring keybinds for View menu items because we are in live input mode (${currentLiveInputStyle}).');
}
}
@@ -5637,7 +5654,9 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
function handleHelpKeybinds():Void
{
// F1 = Open Help
if (FlxG.keys.justPressed.F1) this.openUserGuideDialog();
if (FlxG.keys.justPressed.F1 && !isHaxeUIDialogOpen) {
this.openUserGuideDialog();
}
}
function handleQuickWatch():Void
@@ -3,7 +3,6 @@ package funkin.ui.debug.charting.components;
import funkin.data.event.SongEventRegistry;
import flixel.graphics.frames.FlxAtlasFrames;
import openfl.display.BitmapData;
import openfl.utils.Assets;
import flixel.FlxObject;
import flixel.FlxBasic;
import flixel.FlxSprite;
@@ -95,7 +95,7 @@ class ChartEditorCharacterIconSelectorMenu extends ChartEditorBaseMenu
}
var LIMIT = 6;
charButton.icon = CharacterDataParser.getCharPixelIconAsset(charId);
charButton.icon = haxe.ui.util.Variant.fromImageData(CharacterDataParser.getCharPixelIconAsset(charId));
charButton.text = charData.name.length > LIMIT ? '${charData.name.substr(0, LIMIT)}.' : '${charData.name}';
charButton.onClick = _ -> {
@@ -13,7 +13,6 @@ import funkin.audio.waveform.WaveformSprite;
import flixel.util.FlxColor;
import haxe.io.Bytes;
import haxe.io.Path;
import openfl.utils.Assets;
/**
* Functions for loading audio for the chart editor.
@@ -221,7 +221,7 @@ class ChartEditorMetadataToolbox extends ChartEditorBaseToolbox
var charDataOpponent:Null<CharacterData> = CharacterDataParser.fetchCharacterData(chartEditorState.currentSongMetadata.playData.characters.opponent);
if (charDataOpponent != null)
{
buttonCharacterOpponent.icon = CharacterDataParser.getCharPixelIconAsset(chartEditorState.currentSongMetadata.playData.characters.opponent);
buttonCharacterOpponent.icon = haxe.ui.util.Variant.fromImageData(CharacterDataParser.getCharPixelIconAsset(chartEditorState.currentSongMetadata.playData.characters.opponent));
buttonCharacterOpponent.text = charDataOpponent.name.length > LIMIT ? '${charDataOpponent.name.substr(0, LIMIT)}.' : '${charDataOpponent.name}';
}
else
@@ -233,7 +233,7 @@ class ChartEditorMetadataToolbox extends ChartEditorBaseToolbox
var charDataGirlfriend:Null<CharacterData> = CharacterDataParser.fetchCharacterData(chartEditorState.currentSongMetadata.playData.characters.girlfriend);
if (charDataGirlfriend != null)
{
buttonCharacterGirlfriend.icon = CharacterDataParser.getCharPixelIconAsset(chartEditorState.currentSongMetadata.playData.characters.girlfriend);
buttonCharacterGirlfriend.icon = haxe.ui.util.Variant.fromImageData(CharacterDataParser.getCharPixelIconAsset(chartEditorState.currentSongMetadata.playData.characters.girlfriend));
buttonCharacterGirlfriend.text = charDataGirlfriend.name.length > LIMIT ? '${charDataGirlfriend.name.substr(0, LIMIT)}.' : '${charDataGirlfriend.name}';
}
else
@@ -245,7 +245,7 @@ class ChartEditorMetadataToolbox extends ChartEditorBaseToolbox
var charDataPlayer:Null<CharacterData> = CharacterDataParser.fetchCharacterData(chartEditorState.currentSongMetadata.playData.characters.player);
if (charDataPlayer != null)
{
buttonCharacterPlayer.icon = CharacterDataParser.getCharPixelIconAsset(chartEditorState.currentSongMetadata.playData.characters.player);
buttonCharacterPlayer.icon = haxe.ui.util.Variant.fromImageData(CharacterDataParser.getCharPixelIconAsset(chartEditorState.currentSongMetadata.playData.characters.player));
buttonCharacterPlayer.text = charDataPlayer.name.length > LIMIT ? '${charDataPlayer.name.substr(0, LIMIT)}.' : '${charDataPlayer.name}';
}
else
+15 -3
View File
@@ -16,6 +16,7 @@ import funkin.ui.debug.latency.CoolStatsGraph;
import openfl.events.KeyboardEvent;
import funkin.input.PreciseInputManager;
import funkin.play.notes.Strumline;
import funkin.ui.mainmenu.MainMenuState;
import funkin.play.notes.notestyle.NoteStyle;
import funkin.data.notestyle.NoteStyleData;
import funkin.data.notestyle.NoteStyleRegistry;
@@ -188,11 +189,21 @@ class LatencyState extends MusicBeatSubState
}
override public function close():Void
{
cleanup();
super.close();
}
function cleanup():Void
{
PreciseInputManager.instance.onInputPressed.remove(preciseInputPressed);
PreciseInputManager.instance.onInputReleased.remove(preciseInputReleased);
FlxG.sound.music.volume = previousVolume;
if (FlxG.sound.music != null)
{
FlxG.sound.music.volume = previousVolume;
}
swagSong.stop();
FlxG.sound.list.remove(swagSong);
@@ -200,7 +211,6 @@ class LatencyState extends MusicBeatSubState
FlxG.state.persistentDraw = prevPersistentDraw;
FlxG.state.persistentUpdate = prevPersistentUpdate;
super.close();
}
function regenNoteData()
@@ -311,7 +321,9 @@ class LatencyState extends MusicBeatSubState
if (controls.BACK)
{
close();
// close();
cleanup();
FlxG.switchState(() -> new MainMenuState());
}
super.update(elapsed);
@@ -0,0 +1,125 @@
package funkin.ui.debug.stageeditor;
import funkin.data.animation.AnimationData;
import funkin.graphics.FunkinSprite;
import funkin.modding.events.ScriptEvent;
import funkin.graphics.shaders.InverseDotsShader;
/**
* Contains all the Logic needed for Stage Editor. Only for Stage Editor, as in the gameplay StageProps and Boppers will be used.
*/
class StageEditorObject extends FunkinSprite
{
/**
* The internal Name of the Object.
*/
public var name:String = "Unnamed";
public var selectedShader:InverseDotsShader;
/**
* What animation to play upon starting.
*/
public var startingAnimation:String = "";
public var animDatas:Map<String, AnimationData> = [];
override public function new()
{
super();
selectedShader = new InverseDotsShader(0);
shader = selectedShader;
}
/**
* Whether the Object is currently being modified in the Stage Editor.
*/
public var isDebugged(default, set):Bool = true;
function set_isDebugged(value:Bool):Bool
{
this.isDebugged = value;
if (value == false) // plays upon starting yippee!!!
playAnim(startingAnimation, true);
else
{
if (animation.curAnim != null)
{
animation.stop();
offset.set();
updateHitbox();
}
}
return value;
}
public function playAnim(name:String, restart:Bool = false, reversed:Bool = false):Void
{
if (!animation.getNameList().contains(name)) return;
animation.play(name, restart, reversed, 0);
if (animDatas.exists(name)) offset.set(animDatas[name].offsets[0], animDatas[name].offsets[1]);
else
offset.set();
}
/**
* On which beat should it dance?
*/
public var danceEvery:Float = 0;
/**
* Internal, handles danceLeft and danceRight.
*/
var _danced:Bool = true;
public function dance(restart:Bool = false):Void
{
if (isDebugged) return;
var idle = animation.getNameList().contains("idle");
var dancing = animation.getNameList().contains("danceLeft") && animation.getNameList().contains("danceRight");
if (!idle && !dancing) return;
if (dancing)
{
if (_danced) playAnim("danceRight", restart);
else
playAnim("danceLeft", restart);
_danced = !_danced;
}
else if (idle)
{
playAnim("idle", restart);
}
}
public function addAnim(name:String, prefix:String, offsets:Array<Float>, indices:Array<Int>, frameRate:Int = 24, looped:Bool = true, flipX:Bool = false,
flipY:Bool = false)
{
if (indices.length > 0) animation.addByIndices(name, prefix, indices, "", frameRate, looped, flipX, flipY);
else
animation.addByPrefix(name, prefix, frameRate, looped, flipX, flipY);
if (animation.getNameList().contains(name)) // sometimes the animation doesnt add
{
animDatas.set(name,
{
name: name,
prefix: prefix,
offsets: offsets,
looped: looped,
frameRate: frameRate,
flipX: flipX,
flipY: flipY,
frameIndices: indices
});
}
}
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,6 @@
package funkin.ui.debug.stageeditor.components;
import haxe.ui.containers.dialogs.Dialog;
@:build(haxe.ui.macros.ComponentMacros.build("assets/exclude/data/ui/stage-editor/dialogs/about.xml"))
class AboutDialog extends Dialog {}
@@ -0,0 +1,80 @@
package funkin.ui.debug.stageeditor.components;
import haxe.ui.containers.dialogs.Dialog;
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;
@:xml('
<dialog id="backupAvailableDialog" width="475" height="150" title="Hey! Listen!">
<vbox width="100%" height="100%">
<label text="There is a chart backup available, would you like to open it?\n" width="100%" textAlign="center" />
<spacer height="6" />
<label id="backupTimeLabel" text="Jan 1, 1970 0:00" width="100%" textAlign="center" />
<spacer height="100%" />
<hbox width="100%">
<button text="No Thanks" id="dialogCancel" />
<spacer width="100%" />
<button text="Take Me There" id="buttonGoToFolder" />
<spacer width="100%" />
<button text="Open It" id="buttonOpenBackup" />
</hbox>
</vbox>
</dialog>
')
class BackupAvailableDialog extends Dialog
{
override public function new(state:StageEditorState, filePath:String)
{
super();
if (!FileUtil.doesFileExist(filePath)) return;
// time text
var fileDate = Path.withoutExtension(Path.withoutDirectory(filePath));
var dateParts = fileDate.split("-");
while (dateParts.length < 8)
dateParts.push("0");
var year:Int = Std.parseInt(dateParts[2]) ?? 0; // copied parts from ChartEditorImportExportHandler.hx
var month:Int = Std.parseInt(dateParts[3]) ?? 1;
var day:Int = Std.parseInt(dateParts[4]) ?? 0;
var hour:Int = Std.parseInt(dateParts[5]) ?? 0;
var minute:Int = Std.parseInt(dateParts[6]) ?? 0;
var second:Int = Std.parseInt(dateParts[7]) ?? 0;
backupTimeLabel.text = DateUtil.generateCleanTimestamp(new Date(year, month - 1, day, hour, minute, second));
// button callbacks
dialogCancel.onClick = function(_) hideDialog(DialogButton.CANCEL);
buttonGoToFolder.onClick = function(_) {
// :[
#if sys
var absoluteBackupsPath:String = Path.join([Sys.getCwd(), StageEditorState.BACKUPS_PATH]);
WindowUtil.openFolder(absoluteBackupsPath);
#end
}
buttonOpenBackup.onClick = function(_) {
if (FileUtil.doesFileExist(filePath) && state.welcomeDialog != null) // doing a check in case a sleezy FUCK decides to delete the backup file AFTER dialog opens
{
state.welcomeDialog.loadFromFilePath(filePath);
}
hideDialog(DialogButton.APPLY);
}
// uhhh
onDialogClosed = function(event) {
if (event.button == DialogButton.APPLY)
{
if (state.welcomeDialog != null) state.welcomeDialog.hideDialog(DialogButton.APPLY);
}
};
}
}
@@ -0,0 +1,31 @@
package funkin.ui.debug.stageeditor.components;
import haxe.ui.containers.dialogs.Dialog;
@:build(haxe.ui.macros.ComponentMacros.build("assets/exclude/data/ui/stage-editor/dialogs/exit-confirm.xml"))
class ExitConfirmDialog extends Dialog
{
var onComplete:Void->Void = null;
override public function new(onComp:Void->Void)
{
super();
onComplete = onComp;
buttons = DialogButton.CANCEL | "{{Proceed}}";
defaultButton = "{{Proceed}}";
destroyOnClose = true;
}
public override function validateDialog(button:DialogButton, fn:Bool->Void)
{
if (button == "{{Proceed}}" && onComplete != null)
{
onComplete();
}
fn(true);
}
}
@@ -0,0 +1,105 @@
package funkin.ui.debug.stageeditor.components;
import haxe.ui.containers.dialogs.Dialog;
import funkin.play.stage.StageProp;
import funkin.ui.debug.stageeditor.handlers.AssetDataHandler;
import haxe.ui.components.TextField;
import haxe.ui.components.CheckBox;
@:build(haxe.ui.macros.ComponentMacros.build("assets/exclude/data/ui/stage-editor/dialogs/find-object.xml"))
class FindObjDialog extends Dialog
{
var stageEditorState:StageEditorState;
var assets:Array<StageEditorObject> = [];
var curSelected:Int = 0;
var field:TextField;
var checkWord:CheckBox;
var checkCaps:CheckBox;
override public function new(state:StageEditorState, searchFor:String = "")
{
super();
stageEditorState = state;
nameField.text = searchFor;
this.field = nameField;
this.checkWord = wordCheck;
this.checkCaps = capsCheck;
field.onChange = function(_) updateIndicator();
indicator.hide();
top = 20;
left = FlxG.width - width - 20;
buttons = DialogButton.CANCEL | "{{Find Next}}";
defaultButton = "{{Find Next}}";
}
public function updateIndicator()
{
var prevObjCheck = assets[curSelected];
assets = [];
for (ass in stageEditorState.spriteArray)
{
var name = ass.name;
var checkFor = field.text;
if (!checkCaps.selected)
{
name = name.toLowerCase();
checkFor = checkFor.toLowerCase();
}
if (((name.contains(checkFor) && !checkWord.selected) || (name == checkFor && checkWord.selected)) && ass.visible) assets.push(ass);
}
if (assets.length > 0 && prevObjCheck == null)
{
stageEditorState.selectedSprite = assets[0];
}
if (assets.length > 0)
{
indicator.text = "Selected: " + (assets.indexOf(stageEditorState.selectedSprite) + 1) + " / " + assets.length;
}
else
{
indicator.text = "No Matches Found";
}
if (field.text != "" && field.text != null) indicator.show();
else
indicator.hide();
}
public override function validateDialog(button:DialogButton, fn:Bool->Void)
{
var done = true;
if (button == "{{Find Next}}")
{
done = false;
if (assets.length > 0)
{
curSelected = assets.indexOf(stageEditorState.selectedSprite);
curSelected++;
if (curSelected >= assets.length) curSelected = 0;
stageEditorState.selectedSprite = assets[curSelected];
indicator.text = "Selected: " + (assets.indexOf(stageEditorState.selectedSprite) + 1) + " / " + assets.length;
stageEditorState.camFollow.x = assets[curSelected].getMidpoint().x;
stageEditorState.camFollow.y = assets[curSelected].getMidpoint().y;
}
}
fn(done);
}
}
@@ -0,0 +1,70 @@
package funkin.ui.debug.stageeditor.components;
import haxe.ui.containers.dialogs.Dialog;
import lime.utils.Bytes;
import haxe.ui.components.TextField;
import openfl.net.URLLoader;
import openfl.net.URLRequest;
import openfl.events.Event;
import openfl.events.IOErrorEvent;
import openfl.events.ProgressEvent;
import openfl.events.SecurityErrorEvent;
import openfl.utils.ByteArray;
@:build(haxe.ui.macros.ComponentMacros.build("assets/exclude/data/ui/stage-editor/dialogs/load-url.xml"))
class LoadFromUrlDialog extends Dialog
{
var urlField:TextField;
var loader:URLLoader;
override public function new(successCallback:Bytes->Void = null, failCallback:String->Void = null)
{
super();
destroyOnClose = true;
loader = new URLLoader();
loader.dataFormat = BINARY;
urlField.text = "";
loader.addEventListener(Event.COMPLETE, function(event:Event) {
var bytes:Bytes = cast(loader.data, ByteArray);
if (successCallback != null) successCallback(bytes);
trace("loaded the image and did success callback");
@:privateAccess
loader.__removeAllListeners();
hideDialog(DialogButton.CANCEL);
});
loader.addEventListener(IOErrorEvent.IO_ERROR, function(event:IOErrorEvent) {
if (failCallback != null) failCallback(urlField.text);
trace("error with this shit");
});
loader.addEventListener(SecurityErrorEvent.SECURITY_ERROR, function(event:SecurityErrorEvent) {
if (failCallback != null) failCallback(urlField.text);
trace("error with this shit");
});
buttons = DialogButton.CANCEL | "{{Load}}";
defaultButton = "{{Load}}";
}
override public function validateDialog(button:DialogButton, fn:Bool->Void)
{
if (button == DialogButton.CANCEL)
{
fn(true);
}
else
{
loader.load(new URLRequest(urlField.text));
}
}
}

Some files were not shown because too many files have changed in this diff Show More