Compare commits

...
710 Commits
Author SHA1 Message Date
EliteMasterEric d59594ee45 Fix animations not looping on Char Select
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-12 22:02:05 -04:00
Cameron Taylor d3d998d994 saru fixies 2024-09-12 21:57:48 -04:00
Cameron Taylor 247b86ea1d Merge branch 'bugfix/blazin-offsets' into rewrite/master 2024-09-12 21:53:54 -04:00
Cameron Taylor 80868ccbba assets submod 2024-09-12 21:53:38 -04:00
EliteMasterEric 0e225c9bae Update eggnog vocals again 2024-09-12 20:51:02 -04:00
EliteMasterEric c9d6c19420 Update fresh audio 2024-09-12 20:35:13 -04:00
EliteMasterEric c6bdd36959 Fix blazin offsets 2024-09-12 20:32:19 -04:00
Cameron Taylor cae7db6254 Merge branch 'vp9-cutscene' into rewrite/master 2024-09-12 20:26:05 -04:00
Cameron Taylor af31be5436 makeship linky 2024-09-12 20:14:48 -04:00
Cameron Taylor 172c90b1bd assets submod 2024-09-12 20:12:20 -04:00
Cameron Taylor a4cd2eb169 Merge branch 'pico-christmas-offsets' into rewrite/master 2024-09-12 20:05:42 -04:00
Cameron Taylor 0aa2ccd1cd assets submod 2024-09-12 20:05:14 -04:00
Cameron Taylor e2a51def65 Merge branch 'rewrite/master' into pico-cutscene-tweaks 2024-09-12 20:04:02 -04:00
Cameron Taylor 47f3c6f00a vid sizing 2024-09-12 19:56:04 -04:00
Cameron Taylor d826f2a7bc Merge branch 'rewrite/master' into char-unlock-tinkers 2024-09-12 19:55:35 -04:00
FabsTheFabs fdc5bc6b79 assets submod... 2024-09-13 00:37:47 +01:00
Cameron TaylorandGitHub 3103768d91 Merge pull request #747 from FunkinCrew/charselect-fade-fix
Fix transition out of character select
2024-09-12 19:14:34 -04:00
Cameron Taylor 10dfc96cf4 Merge branch 'freeplay-charselect-hint' into rewrite/master 2024-09-12 19:11:42 -04:00
Cameron Taylor 2dc4e13b00 assets submod 2024-09-12 19:08:13 -04:00
CheemsAndFriends 1e9c6f0c4c Add Char Select stuff 2024-09-13 00:31:52 +02:00
FabsTheFabs f96532f104 assets submod 2024-09-12 22:47:58 +01:00
FabsTheFabs bc86f1f459 character select hint text 2024-09-12 22:44:40 +01:00
FabsTheFabs 5f60be6d75 allow controls to get dialouge name from control + ignore brackets 2024-09-12 22:44:22 +01:00
FabsTheFabs 703e899288 apply shader filter 2024-09-12 22:43:12 +01:00
CheemsAndFriends 34d1c568ea locked fixin 2024-09-12 23:22:20 +02:00
EliteMasterEric ae6f431b6a Update credits 2024-09-12 17:13:46 -04:00
EliteMasterEric a4bdeeaf5f Update polymod to fix a crash on missing imports 2024-09-12 17:13:40 -04:00
CheemsAndFriends 6dca858fd7 Introbizz 2024-09-12 23:13:30 +02:00
CheemsAndFriends 2a9814e030 port SAVE from develop 2024-09-12 22:58:31 +02:00
CheemsAndFriends f0ac09f949 Art master bizz 2024-09-12 22:53:11 +02:00
CheemsAndFriends 395de4ee95 Char select subs stuff 2024-09-12 22:53:01 +02:00
Cameron Taylor 89f4703977 Merge branch 'framerate-pref' into rewrite/master 2024-09-12 16:47:13 -04:00
Cameron Taylor dab41091af Merge branch 'update-final-charts' into rewrite/master 2024-09-12 16:45:28 -04:00
Cameron Taylor a4e977f60f assets submod 2024-09-12 16:45:20 -04:00
Cameron Taylor 1ee351c83d art submod 2024-09-12 16:42:57 -04:00
Cameron Taylor 33df8936b1 assets submod 2024-09-12 16:41:14 -04:00
FabsTheFabs f7f311d6f2 assets submod....... 2024-09-12 21:07:40 +01:00
EliteMasterEric a9667c54f3 Fix FlxAtlasSprite completion handling and music looping 2024-09-12 15:48:41 -04:00
EliteMasterEric 3970189fe9 Ensure save data gets flushed when you see a character 2024-09-12 15:43:40 -04:00
Cameron Taylor 721cecd271 add preference option for framerate capping 2024-09-12 15:38:44 -04:00
EliteMasterEric e5673549cf Fix issues with the difficulty selector showing non-existant difficulties in Freeplay 2024-09-12 15:38:20 -04:00
EliteMasterEric 386dc22d7b Debug hotkey properly resets char select cutscene 2024-09-12 15:34:16 -04:00
EliteMasterEric b2b16ff2d3 Update vocal delay again 2024-09-12 15:31:58 -04:00
EliteMasterEric cdd78818a7 Update assets submodule and changelog 2024-09-12 15:20:12 -04:00
Cameron Taylor bfb19cc67e lastTime error fix 2024-09-12 14:46:29 -04:00
Cameron Taylor 9eb56b4e76 Merge branch 'pico-bf-censor-anims' into rewrite/master 2024-09-12 14:38:55 -04:00
Cameron Taylor 07c5c5d5a7 assets submod 2024-09-12 14:38:29 -04:00
Cameron Taylor 7daedd19fc Merge branch 'tankman-pico-anims' into rewrite/master 2024-09-12 14:35:45 -04:00
Cameron Taylor 260946f44f assets submod 2024-09-12 14:35:19 -04:00
Cameron Taylor 3de7047d22 Merge branch 'master-bugs' into rewrite/master 2024-09-12 14:34:21 -04:00
Cameron Taylor 0b13e0fdd5 art submod (char select stuff) 2024-09-12 14:33:31 -04:00
Cameron Taylor 96f306471c assets submod 2024-09-12 14:31:56 -04:00
Cameron Taylor 9f6d29cf66 Merge branch 'feature/final-results-anims' into rewrite/master 2024-09-12 14:30:38 -04:00
Cameron Taylor 19f332ea7e assets submod 2024-09-12 14:30:14 -04:00
Cameron Taylor 8fdf04796c Merge branch 'bugfix/vocal-loop' into rewrite/master 2024-09-12 14:29:20 -04:00
Cameron Taylor d3e8938888 assets submod 2024-09-12 14:28:51 -04:00
Cameron Taylor 2c80701855 assets submod 2024-09-12 14:26:11 -04:00
FabsTheFabs b7fb6105a7 assets submod 2024-09-12 17:50:46 +01:00
FabsTheFabs e12ed47162 assets submod 2024-09-12 09:25:42 +01:00
EliteMasterEric bfcbc54ced Update assets submodule 2024-09-11 20:39:31 -04:00
CheemsAndFriends 3553d008cf tinkering shit 2024-09-12 01:37:32 +02:00
EliteMasterEric e32dd0e504 Update assets submodule 2024-09-11 17:09:45 -04:00
EliteMasterEric fded5892c5 Update audio compression (via Saru) 2024-09-11 15:55:38 -04:00
CheemsAndFriends 70ab000be4 Readd CharSelectSubState from char unlock 2024-09-11 21:16:02 +02:00
CheemsAndFriends cfcfc773da readd Save from char unlock 2024-09-11 20:53:05 +02:00
CheemsAndFriends 9f5c154b1d readd IntroSubState from char unlock 2024-09-11 20:49:55 +02:00
CheemsAndFriends bea23c37a8 readd FlxAtlasSprite from char unlock branch 2024-09-11 20:47:45 +02:00
CheemsAndFriends c81f041695 Tinkering with atlassprite 2024-09-11 20:05:39 +02:00
CheemsAndFriends 17a48bfc2b D'oh! 2024-09-11 19:26:38 +02:00
CheemsAndFriends 68d87a0837 Add one more conditional in atlas + add ignoreExclusions in Bopper/BaseCharacter 2024-09-11 19:24:21 +02:00
CheemsAndFriends 6349ba3a5a Fix GF not appearing on screen 2024-09-11 18:30:11 +02:00
CheemsAndFriends 5c1766a00f Fix char select substate crash 2024-09-11 18:29:47 +02:00
CheemsAndFriends 0dc286e1d3 Fix Eggnog santa not playing plus Ugh fix 2024-09-11 18:29:31 +02:00
CheemsAndFriends 2aa9e58f67 Fix titlestate reentering crash 2024-09-11 18:29:00 +02:00
CheemsAndFriends 07d9ce2d5a Submodule thing 2024-09-11 17:15:31 +02:00
EliteMasterEric c3fcc707f1 Update compilation guide 2024-09-11 06:52:46 -04:00
EliteMasterEric 94856a6c32 Fix a bug where you could select Pico inst on erect difficulty 2024-09-11 06:18:31 -04:00
EliteMasterEric 0956b692d7 Add a debug hotkey to set characters as not seen. 2024-09-11 06:18:16 -04:00
EliteMasterEric c63feaafbd BF force plays the unlock animation even when he would fist pump 2024-09-11 06:00:06 -04:00
EliteMasterEric d1622040b6 Fix a bug where vocals would restart after a song ends 2024-09-11 04:22:33 -04:00
Cameron Taylor 4cbea7d486 get rid of submodules that appeared for some reason 2024-09-11 00:07:52 -04:00
Cameron Taylor 22b1a5d9c0 Merge branch 'rewrite/master' into feature/char-unlock-merging 2024-09-10 23:52:52 -04:00
Cameron Taylor 9891dc7309 Merge branch 'rewrite/master' into bugfix/web-fixes 2024-09-10 23:43:26 -04:00
Cameron Taylor e5a788de7d change xargs input 2024-09-10 20:22:44 -04:00
EliteMasterEric 59fac5a809 Enable New labels for character mixes 2024-09-10 19:32:19 -04:00
EliteMasterEric 9a242c5d00 Fix an issue where New labels wouldn't show on character mixes 2024-09-10 19:32:10 -04:00
EliteMasterEric a530d91a76 Fix a bug where StickerSubState was being loaded as a state and not a substate, breaking some transitions 2024-09-10 19:16:48 -04:00
CheemsAndFriends f74365f230 Add Changes 2024-09-11 00:55:14 +02:00
EliteMasterEric 0ec22bcc85 Update assets submodule 2024-09-10 17:40:27 -04:00
EliteMasterEric 7aa20223b9 Update art submodule 2024-09-10 17:35:52 -04:00
EliteMasterEric c678cabbf2 Fix issue where difficulty names wouldn't show up properly sometimes. 2024-09-10 17:30:33 -04:00
EliteMasterEric 5021b49915 Enable the New Character backing card 2024-09-10 17:27:04 -04:00
EliteMasterEric 7063fafd33 Fix web builds using disgusting amounts of bandwidth 2024-09-10 17:26:33 -04:00
Cameron Taylor 9c8142b769 Merge branch 'html5-fps' into rewrite/master 2024-09-10 15:40:30 -04:00
Cameron Taylor 96657e9e41 Merge branch 'rewrite/master' into week2-erect-bg-fixes 2024-09-10 07:38:38 -04:00
FabsTheFabs ee78178b20 assets submod 2024-09-10 07:30:24 +01:00
FabsTheFabs 03d9416ab1 texture swap shader 2024-09-10 07:26:15 +01:00
FabsTheFabs 34e93fa95a color util (with just one function lol) 2024-09-10 07:25:11 +01:00
EliteMasterEric f6bd203786 Fix an issue where base inst wouldn't be chosen properly on remixes 2024-09-10 01:33:15 -04:00
Cameron Taylor 06389cb5cd Merge branch 'rewrite/master' into bugfix/doppel-random 2024-09-09 23:50:00 -04:00
Cameron Taylor 030afe1355 Merge branch 'bugfix/instrumental-selector' into rewrite/master 2024-09-09 23:49:02 -04:00
Cameron Taylor adb4bc96ca flxanimate version bump 2024-09-09 23:47:17 -04:00
EliteMasterEric 4c1b4859e7 Fix a bug where the random event in Week 3 would always trigger 2024-09-09 22:35:02 -04:00
EliteMasterEric 877d64c32b Fixed a bug where the instrumental selector would be ignored sometimes 2024-09-09 21:21:50 -04:00
CheemsAndFriends af8fe0c0d2 Remove onAnimationLoopComplete 2024-09-10 01:11:41 +02:00
CheemsAndFriends 8d27a45d17 change lock a bit 2024-09-09 21:39:38 +02:00
Cameron Taylor e2c287e112 logarithmic volume control 2024-09-09 13:01:19 -04:00
Cameron Taylor 591d4a29f4 gameover positioning fixes 2024-09-09 12:34:55 -04:00
Cameron Taylor d9a3604880 Merge branch 'pico-doppleganger-cutscene' into rewrite/master 2024-09-09 11:45:57 -04:00
Cameron Taylor 7220fd7e95 assets submod 2024-09-09 11:45:37 -04:00
Cameron Taylor c2ebd4ead6 Merge branch 'weekend1-alt-bg-tweaks' into rewrite/master 2024-09-09 11:44:49 -04:00
Cameron Taylor 5a4795eea2 assets submod 2024-09-09 11:44:27 -04:00
Cameron Taylor e2d25b2721 Merge branch 'feature/pico-excellent-music' into rewrite/master 2024-09-09 11:43:27 -04:00
CheemsAndFriends 35af057f88 Fix scaleY not parsing 2024-09-09 17:41:25 +02:00
Cameron Taylor d61357b80d hmm flxanimate bump 2024-09-09 11:40:17 -04:00
FabsTheFabs b9b8490243 assets submod 2024-09-09 08:09:40 +01:00
FabsTheFabs 50d2a8fd9d assets submod 2024-09-09 08:06:11 +01:00
FabsTheFabs f8a2709482 assets submod 2024-09-09 08:03:06 +01:00
CheemsAndFriends 6961e6cc63 Add a buncho Gizmos 2024-09-09 08:23:46 +02:00
EliteMasterEric 4f1423870c Update assets submodule 2024-09-08 14:44:22 -04:00
Cameron Taylor 51e5eb929c add hxjsonast to hmm.json to fix builds? 2024-09-08 11:22:24 -04:00
Cameron Taylor fbcf553bd9 Merge branch 'rewrite/master' into week5-alt-bg 2024-09-06 20:23:21 -04:00
CheemsAndFriends f3722e5da2 Add hmm flxanimate, new conditional for Cheems' PC sake and more wip char select animation 2024-09-07 02:07:00 +02:00
FabsTheFabs 40b5ad7c2a assets submod 2024-09-07 00:54:21 +01:00
FabsTheFabs e0a4818e5a registry updates 2024-09-07 00:52:38 +01:00
Cameron Taylor b1e68c27fd Merge branch 'rewrite/master' into feature/pico-results-perfect 2024-09-06 19:46:39 -04:00
Cameron Taylor a623ec77f7 Merge branch 'feature/char-unlock-notif' into rewrite/master 2024-09-06 19:44:58 -04:00
Cameron Taylor 89e1cb8258 small null fix for if we're not playing music 2024-09-06 19:44:33 -04:00
Cameron Taylor 55c5e01bd5 Merge branch 'camera-helpies' into rewrite/master 2024-09-06 19:12:59 -04:00
Cameron Taylor 4f666e4855 creds merge 2024-09-06 19:12:36 -04:00
Cameron Taylor e185eef7ea Merge branch 'feature/album-titles-and-results-themes' into rewrite/master 2024-09-06 19:11:50 -04:00
Cameron Taylor c45fa93786 update lime (ndlls) 2024-09-06 16:46:11 -04:00
CheemsAndFriends a901677853 Merge branch 'feature/char-unlock' of https://github.com/FunkinCrew/Funkin-secret into feature/char-unlock 2024-09-06 06:33:01 +02:00
CheemsAndFriends a61f40571d add wip bizz 2024-09-06 06:28:08 +02:00
EliteMasterEric 313dba6985 Update assets submodule 2024-09-06 00:24:07 -04:00
CheemsAndFriendsandEliteMasterEric 1021f5c2ee wip sequence 2024-09-05 22:44:05 -04:00
CheemsAndFriendsandEliteMasterEric 4cad56705a Add lock bizz 2024-09-05 22:40:27 -04:00
CheemsAndFriends 677357ba37 wip sequence 2024-09-06 02:55:47 +02:00
EliteMasterEric 34d13c61de Cleanup character unlock impl and queue it for after Story Mode is completed. 2024-09-05 17:54:03 -04:00
EliteMasterEric 239b9b0419 Update assets submodule 2024-09-05 02:10:51 -04:00
Cameron Taylor 33aaabe190 lil console command helper for camera zoom 2024-09-05 01:22:45 -04:00
Cameron Taylor 0e37cb9540 Merge branch 'rewrite/master' into bugfix/blazin-flxanimate-fixes 2024-09-05 00:31:47 -04:00
Cameron Taylor 5c44e61ce1 assets submod 2024-09-05 00:20:55 -04:00
CheemsAndFriends def2b64a41 Add lock bizz 2024-09-04 20:08:38 +02:00
EliteMasterEric 24096bd319 Fixed positioning in Blazin'. 2024-09-04 10:58:18 -04:00
EliteMasterEric 3a2ca6b525 Code changes to fix Blazin' 2024-09-04 09:58:04 -04:00
EliteMasterEric 0a6350113e Fix some issues with Blazin 2024-09-04 09:58:00 -04:00
Cameron Taylor b37ebf1aac assets submod 2024-09-03 23:57:01 -04:00
Cameron Taylor 788f0ee026 Merge branch 'bugfix/labor-daybor' into rewrite/master 2024-09-03 23:56:45 -04:00
Cameron Taylor bd144d6adb Merge branch 'rewrite/master' into bugfix/friday-fixes 2024-09-03 23:42:51 -04:00
EliteMasterEric 36505f75c1 The actual code for custom freeplay music LOL 2024-09-03 21:14:57 -04:00
FabsTheFabs f16bffb3fc assets submod..................... 2024-09-03 19:19:25 +01:00
FabsTheFabs b58bd07fd2 rain shader recolor support 2024-09-03 19:16:58 +01:00
FabsTheFabs d049478c65 registry updates 2024-09-03 19:16:46 +01:00
Cameron Taylor 930f5ff5a6 Merge branch 'feature/instrumental-select-hud' into rewrite/master 2024-09-03 11:25:34 -04:00
EliteMasterEric 2f59363432 Merge branch 'bugfix/assets-cleanup' into develop-2 2024-09-03 00:21:25 -04:00
Cameron Taylor 498cd4a830 Merge branch 'cards-and-char-select' into rewrite/master 2024-09-01 17:56:12 -04:00
Cameron Taylor 33d1112095 Merge branch 'bugfix/assets-cleanup' into rewrite/master 2024-09-01 17:20:03 -04:00
Cameron Taylor cdc3883173 assets submod 2024-09-01 17:19:39 -04:00
EliteMasterEric 7511de1e7a A bunch of Freeplay visual fixes 2024-09-01 03:28:56 -04:00
EliteMasterEric 21d5bb6112 Update assets submodule 2024-08-29 22:10:27 -04:00
FabsTheFabs 71da847158 forgot to change these back 2024-08-30 01:12:26 +01:00
FabsTheFabs 4f562e3d6c assets submod 2024-08-30 01:08:47 +01:00
FabsTheFabs 27970e4c2d freeplay style changelog oops 2024-08-30 01:04:51 +01:00
FabsTheFabs 60c10aae99 char select to freeplay transition, backing card implementation, beatHit for backing cards 2024-08-30 01:04:30 +01:00
FabsTheFabs 0c809c828e color tint for angle mask shader 2024-08-30 01:03:11 +01:00
FabsTheFabs de03da7e6f backing card classes 2024-08-30 01:02:32 +01:00
FabsTheFabs e7448cb8f7 style support 2024-08-30 00:58:19 +01:00
FabsTheFabs a4f3c2cb84 freeplay style code 2024-08-30 00:55:24 +01:00
Cameron TaylorandGitHub 78fb6e1188 Merge pull request #712 from FunkinCrew/menu-music-fix
FUNK-525 stop main menu music from playing when entering freeplay from pausemenu
2024-08-29 18:28:00 -04:00
Cameron Taylor ecd6100cf9 assets submod 2024-08-29 18:26:04 -04:00
Cameron Taylor 3e339916d2 flxanimate bump 2024-08-29 18:11:51 -04:00
Cameron Taylor 737a679196 merge conflict fixins 2024-08-29 15:26:35 -04:00
Cameron Taylor 825327e1c8 Merge branch 'rewrite/master' into feature/charSelect 2024-08-29 15:13:58 -04:00
Cameron Taylor 364a5d5a55 hmm flxanimate version fix 2024-08-29 15:06:11 -04:00
Cameron Taylor 0392eddba6 gf/nene char select mini optimization 2024-08-29 14:32:10 -04:00
Cameron Taylor b27aa4c94d Merge branch 'rewrite/master' into feature/pico-playable-christmas 2024-08-29 13:40:56 -04:00
Cameron Taylor 0a316c815f stop main menu music from playing when entering freeplay from pausemenu 2024-08-29 13:22:56 -04:00
EliteMasterEric 560badd6b5 File optimization and Expansion 2 album art 2024-08-29 06:59:10 -04:00
Cameron Taylor 1fbca9ab6a Merge branch 'bugfix/various-develop-fixes' into rewrite/master 2024-08-28 16:32:50 -04:00
Cameron Taylor 5d590654f4 assets submod 2024-08-28 16:32:41 -04:00
Cameron Taylor 2effd977f4 Merge branch 'feature/cory-chart-revisions' into rewrite/master 2024-08-28 16:31:07 -04:00
Cameron TaylorandGitHub 8385c2b8ca Merge pull request #707 from FunkinCrew/flixel-bump
bump flixel to latest
2024-08-28 16:30:33 -04:00
EliteMasterEric 452747139e Updated Pico and Erect charts, sent on August 27th 2024-08-28 09:41:58 -04:00
EliteMasterEric 6cff1efc72 Fix several compile errors, and update assets submodule. 2024-08-28 06:45:18 -04:00
EliteMasterEric e7fca119f8 Logic + animations for new unlocks 2024-08-28 06:11:01 -04:00
EliteMasterEric 1fb5c31c22 Don't apply global offset twice (NOTE: this may break Nene again!) 2024-08-28 06:09:34 -04:00
EliteMasterEric 7e39687994 Data driven char select grid positions 2024-08-28 06:09:14 -04:00
EliteMasterEric 16a6dba9df Pico Fist Pump animation (with loss animation) 2024-08-28 06:08:30 -04:00
EliteMasterEric 2e7eabc494 Remember character ID between visits to Freeplay, plus some fixes to prevent spamming keys 2024-08-28 06:05:28 -04:00
EliteMasterEric 570e672296 Fix magenta flicker on the main menu. 2024-08-28 06:03:26 -04:00
EliteMasterEric 152820f2e1 Fix some warnings with props in StoryMenu 2024-08-28 06:03:12 -04:00
EliteMasterEric 89402f8bb8 Fix a bug where Bot Play could miss (via lag or the player mashing) and lose the song. 2024-08-28 05:47:34 -04:00
EliteMasterEric ccabded2cc Fix warning related to bad asset caching for judgements. 2024-08-28 05:43:41 -04:00
EliteMasterEric af93da6cd4 Fixes to Chart Editor toolboxes 2024-08-28 05:43:23 -04:00
EliteMasterEric b0f04779dc Fix to Spooky icon in Freeplay menu 2024-08-28 05:43:01 -04:00
EliteMasterEric 382af3b485 Reimplement ghost tapping (disabled via compile define) 2024-08-28 05:42:14 -04:00
EliteMasterEric 469ff6690f Fix a crash when skipping in the song before it started. 2024-08-28 05:40:50 -04:00
CheemsAndFriends 353aa42f5b Fixes for the atlasSprite bizz 2024-08-28 02:48:56 +02:00
Cameron Taylor 9b712ce2aa bump flixel 2024-08-27 16:13:52 -04:00
Cameron Taylor 71ecc8f651 Merge branch 'art-repo-update' into rewrite/master 2024-08-27 15:25:42 -04:00
Cameron Taylor 861b869b2d fonts fix for mac 2024-08-27 15:23:27 -04:00
Cameron Taylor ce62c240fa Merge branch 'rewrite/master' into bugfix/nene-pico-offsets 2024-08-27 14:40:56 -04:00
Cameron TaylorandGitHub f10ff1d80a Merge pull request #706 from FunkinCrew/EliteMasterEric-patch-1
Display syntax formatting in project.hxp on Github.com
2024-08-27 14:26:38 -04:00
Cameron TaylorandGitHub a7334d8ff9 Merge pull request #705 from FunkinCrew/bugfix/week-4-boppers
Fix a bug where stage props would receive events twice
2024-08-27 14:26:19 -04:00
EricandGitHub 82496299e7 Display syntax formatting in project.hxp on Github.com 2024-08-27 14:21:40 -04:00
Cameron TaylorandGitHub 4990ac03a4 Merge pull request #703 from FunkinCrew/feature/project-hxp
Rework project to use HXP
2024-08-27 11:26:39 -04:00
Cameron TaylorandGitHub fd5d8aa196 Merge branch 'rewrite/master' into feature/project-hxp 2024-08-27 11:26:29 -04:00
EliteMasterEric d02f632c0e Fix a bug where stage props would receive events twice 2024-08-27 04:54:02 -04:00
EliteMasterEric df42ac7531 Fixed issues with Nene offsets in Pico mode 2024-08-27 04:20:49 -04:00
EliteMasterEric 5caba54e19 Update HScript to use the organization's fork 2024-08-27 02:33:17 -04:00
Cameron Taylor dff87babe6 Merge branch 'rewrite/master' of github.com:FunkinCrew/Funkin-secret into rewrite/master 2024-08-26 21:58:39 -04:00
Cameron Taylor 91e4043ce9 small hmm updates 2024-08-26 21:58:35 -04:00
Cameron TaylorandGitHub 475a20ece8 Merge pull request #700 from FunkinCrew/bugfix/builds-2024-08
ci build maintenance, august 2024 edition
2024-08-26 18:11:05 -04:00
EliteMasterEric 200b3c963b Updated compile defines to use feature flag system 2024-08-26 18:01:36 -04:00
EliteMasterEric 6b9bdb5f2a Upgraded project file to HXP 2024-08-26 18:01:23 -04:00
EliteMasterEric 269f3ecfbe Updated haxelibs 2024-08-26 18:01:06 -04:00
EliteMasterEric f2433bfdcc Updated CHANGELOG 2024-08-26 18:00:59 -04:00
EliteMasterEric b51ba61d07 Update art submodule 2024-08-26 17:14:15 -04:00
mintandember / mint 3c208ee143 git cleanup crew 2024-08-26 21:32:21 +02:00
mintandember / mint a778555a97 more debug info 2024-08-26 21:32:21 +02:00
mintandember / mint 266bf939a9 haxelib 2024-08-26 21:32:21 +02:00
mintandember / mint 514aa576ea haxelib 2024-08-26 21:32:21 +02:00
mintandember / mint 8010441bef haxelib 2024-08-26 21:32:21 +02:00
mintandember / mint 0193bde700 hm, pain 2024-08-26 21:32:21 +02:00
mintandember / mint 7cac3c95ee config the haxelib 👁️ 2024-08-26 21:32:21 +02:00
mintandember / mint 1089764ab6 suppress useless git warnings 2024-08-26 21:32:21 +02:00
mintandember / mint 86f61b4fdd pulseaudio 2024-08-26 21:32:21 +02:00
mintandember / mint a1714711e3 swap docker image deps 2024-08-26 21:32:21 +02:00
CheemsAndFriends 0b19b4bc25 add the maskTest Bizz 2024-08-26 20:34:14 +02:00
Cameron Taylor f4c45f082f Merge branch 'rewrite/master' of github.com:FunkinCrew/Funkin-secret into rewrite/master 2024-08-26 13:18:09 -04:00
Cameron Taylor 025c186ddc assets submod 2024-08-26 13:18:05 -04:00
Cameron TaylorandGitHub 7940b19dbf Merge pull request #696 from FunkinCrew/funk-vis-pr
update funkin.vis
2024-08-26 13:16:41 -04:00
Cameron TaylorandGitHub fd06e6800c Merge pull request #698 from FunkinCrew/completion-server-null-fix
completion server null fix
2024-08-26 13:16:05 -04:00
FabsTheFabs 9e1d328a0f assets submod 2024-08-23 13:37:50 +01:00
FabsTheFabs 55dd1857c9 freeplay transition + wip card classes 2024-08-23 13:36:35 +01:00
FabsTheFabs e37330f288 character select transition 2024-08-23 13:36:00 +01:00
FabsTheFabs 0d3fa41b29 blue fade shader 2024-08-23 13:35:50 +01:00
CheemsAndFriends 7f0f0efe46 initial Commit 2024-08-22 23:36:43 +02:00
Cameron Taylor 5756eff7cf dont need null check, we just need to declare string type 2024-08-21 16:39:34 -04:00
Cameron Taylor e1d8e758bb completion server fixin? 2024-08-21 16:31:10 -04:00
Cameron TaylorandGitHub cee5d53deb Merge pull request #686 from FunkinCrew/applehair/freeplay-stack-overflow
[PUBLIC PR] Fix a stack overflow for songs with no "Normal" difficulty
2024-08-20 15:09:36 -04:00
Cameron Taylor df588f86af Merge branch 'rewrite/master' into applehair/storymode-valid-variation 2024-08-20 15:06:07 -04:00
Cameron Taylor 78d299db4e Merge branch 'gamerbross/animation-editor' into rewrite/master 2024-08-20 15:03:42 -04:00
Cameron Taylor 76edf2e4e9 remove unused imports 2024-08-20 14:44:53 -04:00
Cameron Taylor 6e3fba4d3d Merge branch 'rewrite/master' into gamerbross/animation-editor 2024-08-20 14:29:43 -04:00
Cameron TaylorandGitHub af8c52a489 Merge pull request #685 from FunkinCrew/70ltan/char-path-fix
[PUBLIC PR] Fix an issue with character paths
2024-08-20 14:21:58 -04:00
Cameron TaylorandGitHub 1b309e33ef Merge branch 'rewrite/master' into 70ltan/char-path-fix 2024-08-20 14:21:36 -04:00
Cameron Taylor f8b63c9968 update funkin.vis PR 2024-08-20 14:19:04 -04:00
CheemsAndFriends 94a08ff528 asset stuff 2024-08-20 01:28:03 +02:00
CheemsAndFriends a6f8cf0141 Setting a simple mask test 2024-08-20 01:20:13 +02:00
Cameron Taylor 7d3d83b23c Merge branch 'week1-stage-erect' into rewrite/master 2024-08-19 19:06:24 -04:00
Cameron Taylor ec07a476c1 assets submod 2024-08-19 19:06:07 -04:00
Cameron Taylor 0aa9c41c5b assets submod 2024-08-19 18:59:08 -04:00
CheemsAndFriends 82eea221d8 Can't seem to understand AtlasSprite 2024-08-19 14:41:20 +02:00
CheemsAndFriends 8a2d8a9941 Committing all the additional stuff (Lowering FPS
For my PC lol)
2024-08-19 13:41:29 +02:00
CheemsAndFriends 4dad17d241 Prepare the FlxAnimate bizz 2024-08-19 13:40:58 +02:00
FabsTheFabs 8a03cc7b2a assets submod 2024-08-19 04:29:28 +01:00
FabsTheFabs 9d85d423c6 add stage to registry and chart editor 2024-08-19 04:29:22 +01:00
Cameron Taylor eb5bf449a4 assets submod 2024-08-17 15:06:10 -04:00
Cameron Taylor 0270df6b23 assets submod 2024-08-17 14:58:42 -04:00
Cameron Taylor 0e46f91a60 Merge branch 'rewrite/master' into feature/album-art-swap 2024-08-16 20:21:51 -04:00
Cameron Taylor b1fe983c21 Merge branch '2-erect-songs' into rewrite/master 2024-08-15 15:15:08 -04:00
Cameron Taylor 6679ec5519 assets submod 2024-08-15 15:14:41 -04:00
Cameron TaylorandGitHub 0d33cd29a9 Merge pull request #692 from FunkinCrew/feature/more-pico-songs
Add a bunch of Pico remixes
2024-08-15 15:13:37 -04:00
EliteMasterEric 988e819e9b Add a bunch of remixes 2024-08-14 15:10:47 -04:00
EliteMasterEric c209e0e192 Ugh Erect and Cocoa Erect 2024-08-14 10:57:44 -04:00
EricandGitHub f4e42375d1 Merge branch 'rewrite/master' into applehair/freeplay-stack-overflow 2024-08-12 14:37:18 -04:00
EricandGitHub 6e1ff4a6b1 Merge branch 'rewrite/master' into 70ltan/char-path-fix 2024-08-12 14:37:16 -04:00
EricandGitHub f5826e3a35 Merge branch 'rewrite/master' into applehair/storymode-valid-variation 2024-08-12 14:37:15 -04:00
Cameron TaylorandGitHub ce559106f6 Merge pull request #691 from FunkinCrew/runners-fixins
Windows + Mac quick runners fix
2024-08-10 15:30:35 -04:00
Cameron Taylor a0047a482f use --always when installing funkin-patches versions of haxelib and hmm 2024-08-09 23:31:40 -04:00
Cameron Taylor b47c695cb7 perhaps use funkin versions of haxelib and hmm? 2024-08-09 23:09:23 -04:00
Cameron Taylor 78d9d2ad21 Merge branch 'ninjamuffin99/funk-605' into rewrite/master 2024-08-09 23:03:23 -04:00
Cameron Taylor 9ff3e0435a assets submod 2024-08-09 23:02:46 -04:00
Cameron Taylor 21fe5f12be Merge branch 'ninjamuffin99/funk-644' into rewrite/master 2024-08-09 23:02:02 -04:00
Cameron Taylor e105f933ac Merge branch 'rewrite/master' into anysad/custom-countdowns 2024-08-09 23:00:03 -04:00
Cameron TaylorandGitHub 09fe8c1196 Merge pull request #687 from FunkinCrew/feature/erect-stages
Erect stages for weeks 2,3,4 + unfinished pico shit
2024-08-09 22:27:05 -04:00
Cameron Taylor cce6434570 Merge branch 'rewrite/master' into feature/erect-stages 2024-08-07 19:43:37 -04:00
Cameron Taylor c3d497a9d9 hxcpp bump 2024-08-07 19:01:46 -04:00
Cameron Taylor ae648418c2 assets submod senpai fix 2024-08-06 14:03:25 -04:00
Cameron Taylor 62d0b33689 Fix for switching to old icon on isPixel levels 2024-08-06 13:44:02 -04:00
Cameron TaylorandGitHub 960c151985 Merge pull request #682 from FunkinCrew/haxelib-updates
Update OpenFL to latest
2024-08-05 10:48:12 -04:00
Cameron Taylor f4968b0ae5 openfl hmm commit to dev-funkin 2024-08-05 10:47:59 -04:00
FabsTheFabs 8200a08152 assets submod 2024-07-31 14:36:34 +01:00
FabsTheFabs 270748d108 fuck these decimals messing up my compiling 2024-07-31 14:36:24 +01:00
FabsTheFabs 3b7e656793 add stage names to registry + chart editor 2024-07-31 14:36:06 +01:00
Cameron TaylorandGitHub 3c814dacf0 Merge pull request #672 from FunkinCrew/bugfix/character-offset-fixes
[PUBLIC PR] Fix some bugs with how character positions are handled.
2024-07-29 21:27:04 -04:00
Cameron Taylor c9c81fae51 assets submod? 2024-07-29 21:26:02 -04:00
Cameron Taylor f4a2ac4dde Merge branch 'rewrite/master' into bugfix/character-offset-fixes 2024-07-29 21:25:33 -04:00
AppleHairandEliteMasterEric cb02ea7da5 Updated to extend #2712 2024-07-29 19:03:54 -04:00
AppleHairandEliteMasterEric c8322c479c Added a comment 2024-07-29 19:03:52 -04:00
AppleHairandEliteMasterEric 4f46a8e4d0 [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-29 19:03:37 -04:00
7oltanandEliteMasterEric e2297af1cd FIX CHARACTER PATHS ISSUE 2024-07-29 18:54:26 -04:00
AppleHairandEliteMasterEric eb78b754f8 A fix requested by Eric 2024-07-29 18:34:59 -04:00
AppleHairandEliteMasterEric bef2e98222 [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-29 18:34:59 -04:00
EliteMasterEric 68b7610225 Update OpenFL to latest (requires a few fixes) 2024-07-29 17:26:49 -04:00
EricandGitHub 9de51fd7d1 Merge pull request #674 from FunkinCrew/arm64-mac
lime updates for arm64 mac
2024-07-29 16:53:09 -04:00
EliteMasterEric e4e4c66c6c Update Lime version 2024-07-29 16:24:29 -04:00
Cameron TaylorandEliteMasterEric 5e04628480 lime shallow cairo 2024-07-29 16:24:29 -04:00
Cameron TaylorandEliteMasterEric 195010c7ed hxcpp and lime hmm updates for arm64 mac 2024-07-29 16:24:24 -04:00
Cameron Taylor f1af005cf3 Merge branch 'rewrite/master' into burgerballs/song-resync-tweaks 2024-07-29 14:04:41 -04:00
Cameron Taylor ee584d780c Merge branch 'rewrite/master' into flooferland/new-settings-types 2024-07-29 13:44:01 -04:00
EliteMasterEric 41bd0246ac Custom coutndown, judgements, and combo count now use the note style file instead of hardcoded paths. 2024-07-28 17:10:32 -04:00
anysadandEliteMasterEric d07564cdc2 hopefully final polish? 2024-07-28 02:44:16 -04:00
anysadandEliteMasterEric 82a6ca5916 welcome fallback note styles! 2024-07-28 02:43:02 -04:00
anysadandEliteMasterEric d3209e57b7 goodbye scripts, hello notestyles! 2024-07-28 02:34:12 -04:00
anysadandEliteMasterEric d5a53855d3 how the hell did I miss these? 2024-07-28 02:31:25 -04:00
anysadandEliteMasterEric dc9dbe84fa cache textures at their new locations! 2024-07-28 02:31:25 -04:00
anysadandEliteMasterEric bf1d4031af remove trace 2024-07-28 02:31:20 -04:00
anysadandEliteMasterEric 0e7fad090b custom popups and countdowns yay!!! 2024-07-28 02:31:01 -04:00
EliteMasterEric f3624f7e76 Fixes for scripted song events, define vocal tracks per variation, display suffixed difficulties properly. 2024-07-28 01:42:09 -04:00
EliteMasterEric 3db0cf3e0a Update Polymod to support applying JSON patches in the _merge folder of mods. 2024-07-26 00:22:36 -04:00
EricandGitHub f07777116d Merge pull request #676 from FunkinCrew/haxelib/hxcpp
update hxcpp haxelib
2024-07-25 07:46:54 -04:00
EricandGitHub 1f1d467156 Merge branch 'rewrite/master' into haxelib/hxcpp 2024-07-25 07:46:45 -04:00
Cameron TaylorandEliteMasterEric 4dfb469552 update hxcpp haxelib 2024-07-25 06:39:12 -04:00
Cameron TaylorandEliteMasterEric a15695c3dc compile dev version of hxcpp 2024-07-25 06:39:12 -04:00
EricandGitHub 35c8b2c818 Merge pull request #634 from FunkinCrew/haxelib/flixels
flixel haxelib updates
2024-07-25 06:38:28 -04:00
EricandGitHub a2838fffd0 Merge branch 'rewrite/master' into haxelib/flixels 2024-07-25 06:38:18 -04:00
Cameron TaylorandEliteMasterEric aaab24850d flixel haxelib updates 2024-07-25 06:34:35 -04:00
BurgerballsandEliteMasterEric 1831daac38 Update PlayState.hx 2024-07-25 03:34:59 -04:00
BurgerballsandEliteMasterEric 6e301bf648 Update PlayState.hx 2024-07-25 03:34:58 -04:00
Cameron TaylorandGitHub c60299e51a Merge pull request #671 from FunkinCrew/lemz1/note-kind-scripts
[PUBLIC PR] Note Kind Scripts
2024-07-22 22:21:14 -04:00
Cameron Taylor 4164329ca9 Merge branch 'rewrite/master' into lemz1/note-kind-scripts 2024-07-22 22:20:58 -04:00
Cameron Taylor 9b8961d4b5 assets submod 2024-07-22 22:20:51 -04:00
EliteMasterEric 04c88baff0 CI fix? 2024-07-22 20:53:34 -04:00
EliteMasterEric a071e90746 Added alt vocal offsets feature, disabled alt instrumentals on Pico mix (for now?) 2024-07-22 20:52:03 -04:00
EliteMasterEric 1515719a0f Implemented instrumental select (you need to beat the song as Pico first)! 2024-07-22 18:38:22 -04:00
EliteMasterEric 0110936a3e Update assets submodule 2024-07-20 02:19:34 -04:00
Cameron TaylorandGitHub bfa0bafc6f Merge pull request #675 from FunkinCrew/bugfix/hud-hiding
Several tiny bug fixes
2024-07-19 19:10:28 -04:00
EliteMasterEric 7547875535 Allow hiding HUD on launcher builds. 2024-07-18 23:27:41 -04:00
EliteMasterEric 729745899e Blacklist haxe.Unserializer in scripts. 2024-07-18 23:27:24 -04:00
EliteMasterEric 558ec53532 Switch songs with no difficulties from an error to a warning. 2024-07-18 23:27:12 -04:00
Cameron TaylorandGitHub 3f242eb96c Merge pull request #666 from FunkinCrew/anysad/tutorial-hey-events
[PUBLIC PR] Un-hardcode animation events from Tutorial.
2024-07-18 15:12:15 -04:00
Cameron TaylorandGitHub f90c2bda99 Merge branch 'rewrite/master' into anysad/tutorial-hey-events 2024-07-18 15:08:10 -04:00
Cameron TaylorandGitHub b0a842c2c7 Merge pull request #664 from FunkinCrew/gamerbross/chart-reload-f5
[PUBLIC PR] Pressing F5 in play state now reloads the chart data from your assets folder
2024-07-18 15:07:52 -04:00
Cameron TaylorandGitHub 8d9071d4fd Merge pull request #669 from FunkinCrew/gamerbross/pause-sticker-zoom
[PUBLIC PR] Fix a bug where pausing during a camera zoom would break the HUD funk-612
2024-07-18 15:00:09 -04:00
Cameron TaylorandGitHub e26a99d128 Merge pull request #668 from FunkinCrew/gamerbross/chart-editor-live-inputs
[PUBLIC PR] Cleanup chart editor live inputs
2024-07-18 14:56:41 -04:00
FabsTheFabs 563905ebd4 assets submod 2024-07-18 06:04:32 +01:00
FabsTheFabs a0ab216617 merged rain shader stuff from 'feature/week2-erect-bg-rain' 2024-07-18 06:04:19 +01:00
FabsTheFabs 4bcfbc957f assets submod 2024-07-18 05:24:15 +01:00
FabsTheFabs ad93706b1d adjust color shader 2024-07-18 05:23:37 +01:00
FabsTheFabs 73fc855f8e new stage names 2024-07-18 05:23:31 +01:00
Cameron Taylor 35ba5663a1 uncapped framerate on web 2024-07-15 23:10:08 -04:00
Cameron TaylorandGitHub fbe224731a Merge branch 'rewrite/master' into lemz1/note-kind-scripts 2024-07-15 12:54:06 -04:00
Cameron TaylorandGitHub d7794374d9 Merge branch 'rewrite/master' into gamerbross/chart-editor-live-inputs 2024-07-15 12:53:59 -04:00
Cameron TaylorandGitHub b6a8b62950 Merge branch 'rewrite/master' into gamerbross/pause-sticker-zoom 2024-07-15 12:53:50 -04:00
Cameron TaylorandGitHub 66ef6a6290 Merge branch 'rewrite/master' into gamerbross/animation-editor 2024-07-15 12:53:42 -04:00
Cameron TaylorandGitHub 894ea5cc6b Merge branch 'rewrite/master' into bugfix/character-offset-fixes 2024-07-15 12:53:34 -04:00
Cameron TaylorandGitHub 6f66488a04 Merge pull request #665 from FunkinCrew/public-release/develop
Documentation changes from `public/develop`
2024-07-15 12:49:48 -04:00
EliteMasterEric 416d60000f Implement Nene Christmas, and fix Nene offsets on other stages. 2024-07-15 06:30:10 -04:00
EliteMasterEric 6116ec3639 Some more fixes for offsets handling and stuffs 2024-07-12 22:31:04 -04:00
EliteMasterEric 492874ce32 Merge branch 'sword352/indirect-anim-offsets' into bugfix/character-offset-fixes 2024-07-12 21:41:25 -04:00
EliteMasterEric d4cbe74939 Smaller fixes tied to note kinds 2024-07-12 21:40:46 -04:00
EliteMasterEric ace762413e Fix an issue where display would break on invalid note styles. 2024-07-12 16:39:42 -04:00
EliteMasterEric f76309c91e Update rendering for custom note styles 2024-07-12 04:13:20 -04:00
lemzandEliteMasterEric 1fe44fa368 add from 2024-07-12 02:13:23 -04:00
lemzandEliteMasterEric 4746c1da0e checking empty suffix is stupid 2024-07-12 02:13:22 -04:00
lemzandEliteMasterEric f9bccb057a use suffixes instead of pixel boolean 2024-07-12 02:13:22 -04:00
lemzandEliteMasterEric 492af8add4 String works now 2024-07-12 02:13:21 -04:00
lemzandEliteMasterEric 44d9785317 editing them works now
still need to implement String and do some testing
2024-07-12 02:13:21 -04:00
lemzandEliteMasterEric c41d846df5 store params in chart
chart editor still doesnt fully work
2024-07-12 02:13:20 -04:00
lemzandEliteMasterEric 764cdee63d add more options 2024-07-12 02:13:20 -04:00
lemzandEliteMasterEric 0fe726cefa fix min, max 2024-07-12 02:13:20 -04:00
lemzandEliteMasterEric 437cc68ba7 adapt to minimize problem 2024-07-12 02:13:19 -04:00
lemzandEliteMasterEric 93475ae8aa minimized check 2024-07-12 02:13:19 -04:00
lemzandEliteMasterEric d9b9854d91 add params to toolbox
not completely finished
2024-07-12 02:13:18 -04:00
lemzandEliteMasterEric 9a563ec46b switch seemingly doesnt work 2024-07-12 02:13:18 -04:00
lemzandEliteMasterEric 94fe4a06b9 Update NoteKind.hx 2024-07-12 02:13:18 -04:00
lemzandEliteMasterEric c8d019da2f Update NoteKind.hx 2024-07-12 02:13:17 -04:00
lemzandEliteMasterEric acd8912d16 Add Custom Params For NoteKind
still need to implement the chart editor stuff
2024-07-12 02:13:17 -04:00
lemzandEliteMasterEric fbcc73dcee unhardcode notestyledropdown 2024-07-12 02:13:17 -04:00
lemzandEliteMasterEric 7a0c7ade35 Update ChartEditorDropdowns.hx 2024-07-12 02:13:16 -04:00
lemzandEliteMasterEric 928de7b8eb check for pixel style if necessary 2024-07-12 02:13:16 -04:00
lemzandEliteMasterEric c4855c0ca8 fix hold note 2024-07-12 02:13:15 -04:00
lemzandEliteMasterEric 49d302be95 make code a bit simpler 2024-07-12 02:13:15 -04:00
lemzandEliteMasterEric bb97549171 fixed a bit 2024-07-12 02:13:14 -04:00
lemzandEliteMasterEric 040fc85a62 change note style on change 2024-07-12 02:13:14 -04:00
lemzandEliteMasterEric ca2cbb44f5 display custom note style in chart editor 2024-07-12 02:13:14 -04:00
lemzandEliteMasterEric 9d7846a0d5 loop through all note style entries 2024-07-12 02:13:13 -04:00
lemzandEliteMasterEric ca69e7b850 custom note styles in chart editor 2024-07-12 02:13:13 -04:00
lemzandEliteMasterEric 328e590f92 hold assets are updated aswell 2024-07-12 02:13:13 -04:00
lemzandEliteMasterEric b6eda8e498 remove note kind logic from playstate 2024-07-12 02:13:12 -04:00
lemzandEliteMasterEric 14771e72de no more note getter 2024-07-12 02:13:12 -04:00
lemzandEliteMasterEric 3f39d9509c make custom note style less clunky 2024-07-12 02:13:12 -04:00
lemzandEliteMasterEric e3e4e9fac0 helper function 2024-07-12 02:13:11 -04:00
lemzandEliteMasterEric c83e505f5b onUpdate, etc. works now too 2024-07-12 02:13:11 -04:00
lemzandEliteMasterEric 606d9d4af4 Update NoteKindManager.hx 2024-07-12 02:13:11 -04:00
lemzandEliteMasterEric 134b467876 rename stuff 2024-07-12 02:13:10 -04:00
lemzandEliteMasterEric a7482410b9 add note kind scripts 2024-07-12 02:13:10 -04:00
EliteMasterEric 03d1f858ec Remove flixel-ui and add a new dropdown to the animation offset editor 2024-07-12 00:57:08 -04:00
gamerbrossandEliteMasterEric c3f8075b5f Few animation editor bugfixes 2024-07-11 23:11:58 -04:00
gamerbrossandEliteMasterEric e6c9767800 Revert camCutscene rename 2024-07-11 22:48:21 -04:00
gamerbrossandEliteMasterEric e23e6c160d Fix references to camCutscene 2024-07-11 22:48:20 -04:00
gamerbrossandEliteMasterEric 17f5a06256 Add camOther to fix zooms on pause and stickers 2024-07-11 22:48:20 -04:00
gamerbrossandEliteMasterEric 90155bcfbf ChartEditor Live Input Code Refactor + 6 key fix 2024-07-11 22:24:38 -04:00
EliteMasterEric 4a7545a0db Remove empty function. 2024-07-11 21:45:06 -04:00
anysadandEliteMasterEric 305ab3146f Add HEY! song events to Tutorial 2024-07-11 21:42:24 -04:00
anysadandEliteMasterEric 18b795d4f7 Add HEY! song events to Tutorial 2024-07-11 21:39:20 -04:00
EliteMasterEric 50b587e3b8 Merge remote-tracking branch 'public/develop' into rewrite/master 2024-07-11 20:58:42 -04:00
EliteMasterEric 3721fb688f Merge branch 'main' into develop 2024-07-11 20:38:45 -04:00
Cameron TaylorandGitHub 5a26ece9d6 Merge branch 'rewrite/master' into gamerbross/chart-reload-f5 2024-07-11 19:59:15 -04:00
Cameron TaylorandGitHub 7cd19a0135 Merge pull request #656 from FunkinCrew/feature/nene-combo-anims
Implement combo animations for Nene + other changes
2024-07-11 19:52:01 -04:00
Cameron Taylor 966fce3426 Merge branch 'rewrite/master' into feature/nene-combo-anims 2024-07-11 19:51:13 -04:00
Cameron Taylor 261d68c410 assets submod 2024-07-11 19:51:00 -04:00
Cameron TaylorandGitHub d423753de0 Merge branch 'rewrite/master' into flooferland/new-settings-types 2024-07-11 19:48:51 -04:00
Cameron TaylorandGitHub cffe41985d Merge pull request #663 from FunkinCrew/gamerbross/hold-note-forced-alpha
[PUBLIC PR] Fix a bug where mods can't change the transparency of hold notes
2024-07-11 19:48:35 -04:00
Cameron Taylor 068a660a91 Merge branch 'rewrite/master' of github.com:FunkinCrew/Funkin-secret into rewrite/master 2024-07-11 19:46:40 -04:00
Cameron Taylor 19fd8b5e4e Merge branch 'gamerbross/chart-editor-key' into rewrite/master 2024-07-11 19:45:10 -04:00
71947c581e [PUBLIC PR] Fix a bug where the memory counter would overflow into the negatives (#662)
* get Float instead of Int in cpp (Float is 64-bit in so it works easier than Int64)

* use Math.fround instead of Math.round

---------

Co-authored-by: Karim Akra <144803230+KarimAkra@users.noreply.github.com>
2024-07-11 19:35:41 -04:00
66b103c650 [PUBLIC PR] Remove 5 duplicate audio files from the DadBattle folder. (#657)
* Remove 5 duplicate audio files from the DadBattle folder.

* assets submod merge

---------

Co-authored-by: Cameron Taylor <cameron.taylor.ninja@gmail.com>
2024-07-11 19:34:34 -04:00
Cameron TaylorandGitHub 411484351a Merge pull request #655 from FunkinCrew/doggogit/pico-death-fix
[PUBLIC PR] Fix an issue with Pico's death animation spritesheet
2024-07-11 18:39:23 -04:00
Cameron Taylor ddec0070e3 Merge branch 'rewrite/master' into doggogit/pico-death-fix 2024-07-11 18:39:04 -04:00
Cameron Taylor cfb2cf36de assets submod merge 2024-07-11 18:38:29 -04:00
Cameron TaylorandGitHub 93148e97e8 Merge pull request #658 from FunkinCrew/bugfix/song-title-fixes
Song title fixes.
2024-07-11 18:37:31 -04:00
Cameron TaylorandGitHub dd3f41ab1b Merge pull request #659 from FunkinCrew/feature/commas-in-score
Add commas to the score to make it more readable
2024-07-11 18:36:35 -04:00
Cameron TaylorandGitHub 69859b80ee Merge pull request #661 from FunkinCrew/applehair/menu-back-sounds
[PUBLIC PR] Fixed back sound not playing in Story and Options menus
2024-07-11 18:36:23 -04:00
EricandGitHub 1a44853c88 Merge pull request #2452 from eltociear/patch-1
Update ScriptEventType.hx
2024-07-11 03:56:07 -04:00
EricandGitHub 9b483de1da Merge pull request #3003 from Hundrec/issue-templates
New Issue and PR templates tweaks
2024-07-11 03:49:11 -04:00
gamerbrossandEliteMasterEric 7b9e4a0542 Fix F5 chart not reloading 2024-07-11 03:41:51 -04:00
EliteMasterEric 3f63bc35a4 Add change counts labels to Actions labeler 2024-07-11 03:41:51 -04:00
Eric 6e65996180 Make downloading the assets submodule a separate step. 2024-07-11 03:41:50 -04:00
HundrecandEliteMasterEric 562136ed55 Add ZIP button warning and restructured sentences
Each step should be easier to follow with this structure
2024-07-11 03:41:50 -04:00
HundrecandEliteMasterEric 4044a7d936 Reorder download Git step in compiling guide
Moved “download Git” from the middle of the guide to the setup step
Should prevent errors with Git before installing Git
2024-07-11 03:41:50 -04:00
HundrecandGitHub 25a90d8419 Reword in crash report 2024-07-10 20:33:12 -07:00
HundrecandGitHub 6698ee6770 . 2024-07-10 20:31:06 -07:00
HundrecandGitHub ffadce45e0 More crash report tweaks 2024-07-10 18:50:12 -07:00
HundrecandGitHub ca5e08f967 Specify crash log location 2024-07-10 18:47:34 -07:00
HundrecandGitHub 0f35618a15 PR template tweak 2024-07-10 18:43:15 -07:00
HundrecandGitHub ce24a6f7a3 Tweak Enhancement Template 2024-07-10 18:42:25 -07:00
HundrecandGitHub ac11e5238d Tweak Crash Report Template 2024-07-10 18:40:38 -07:00
HundrecandGitHub 88b35ce8c2 Tweak Bug Report Template 2024-07-10 18:37:19 -07:00
HundrecandGitHub 7353747ca5 Simplify PR template 2024-07-10 18:25:32 -07:00
HundrecandGitHub fd37e2121c PR template rename 2024-07-10 18:13:27 -07:00
EricandGitHub 712792c385 Merge pull request #2717 from tposejank/better-templates
[FEATURE] Better issue and pull request templates
2024-07-10 20:48:10 -04:00
tposejank 2915fd7717 efgh 2024-07-10 20:42:08 -04:00
tposejank 738a21eeb6 abcd 2024-07-10 20:41:40 -04:00
tposejank a27e743c5f Merge remote-tracking branch 'upstream/main' into better-templates 2024-07-10 20:37:31 -04:00
EricandGitHub dd763c4b64 Merge pull request #2996 from Hundrec/issue-templates
[DOCS] Automatically assign 'status: pending triage' label to all new issues
2024-07-10 20:21:49 -04:00
gamerbrossandEliteMasterEric 8107d1a290 Remove SustainTrail forced alpha 2024-07-10 20:18:29 -04:00
EliteMasterEric 49b7876b5a Add change counts labels to Actions labeler 2024-07-10 20:18:28 -04:00
Eric abf898ff01 Make downloading the assets submodule a separate step. 2024-07-10 20:18:28 -04:00
HundrecandEliteMasterEric 33bfe34f09 Add ZIP button warning and restructured sentences
Each step should be easier to follow with this structure
2024-07-10 20:18:28 -04:00
HundrecandEliteMasterEric 2d5be92882 Reorder download Git step in compiling guide
Moved “download Git” from the middle of the guide to the setup step
Should prevent errors with Git before installing Git
2024-07-10 20:18:28 -04:00
HundrecandGitHub db0bb4d9c2 Final bug template polish 2024-07-10 16:14:29 -07:00
HundrecandGitHub 56948507e8 Capitalize C in "context" 2024-07-10 16:04:21 -07:00
HundrecandGitHub 5a534e210b Wrong quote whoops 2024-07-10 16:02:18 -07:00
HundrecandGitHub fd7cdca333 Add triage label to PR enhancement template 2024-07-10 16:01:52 -07:00
HundrecandGitHub 2ba71e78bb Add triage label to PR bugfix template 2024-07-10 16:00:28 -07:00
HundrecandGitHub 6b2ab64e97 Add triage label to enhancement template 2024-07-10 15:58:42 -07:00
HundrecandGitHub 2a5a24af70 Polish and add triage label to bug template 2024-07-10 15:54:54 -07:00
EricandGitHub f1e1b99b97 Merge pull request #2984 from Hundrec/patch-5
[DOCS] Add common troubleshooting steps to compiling guide
2024-07-10 18:15:56 -04:00
AppleHairandEliteMasterEric 34a19ef583 [BUGFIX] Fixed cancelMenu sound not playing after switching state. 2024-07-10 18:08:55 -04:00
EliteMasterEric 242ab6e922 Add change counts labels to Actions labeler 2024-07-10 18:08:54 -04:00
Eric 87d8d4043e Make downloading the assets submodule a separate step. 2024-07-10 18:08:54 -04:00
HundrecandEliteMasterEric 9f17478a3a Add ZIP button warning and restructured sentences
Each step should be easier to follow with this structure
2024-07-10 18:08:54 -04:00
HundrecandEliteMasterEric 81680694e3 Reorder download Git step in compiling guide
Moved “download Git” from the middle of the guide to the setup step
Should prevent errors with Git before installing Git
2024-07-10 18:08:54 -04:00
EliteMasterEric 2ae6882241 Swappable album art and updated FlxAnimate 2024-07-10 17:25:52 -04:00
EliteMasterEric d8572cd323 Thank you loggo 2024-07-10 14:23:50 -04:00
EliteMasterEric a93af43d63 Song title fixes. 2024-07-09 19:37:06 -04:00
HundrecandGitHub 6c077cad5f Add second cd step after cloning 2024-07-09 16:22:43 -07:00
HundrecandGitHub ff770d6948 Wrong slashes lol 2024-07-09 12:55:04 -07:00
HundrecandGitHub 2d1d6eb19e Add cd step for improved clarity 2024-07-09 12:54:29 -07:00
HundrecandGitHub 39a774709e [DOCS] Add common troubleshooting steps to compiling guide
Makes compiling easier for everyone
2024-07-09 02:10:55 -07:00
EliteMasterEric 98ed4bd843 Implement Nene/GFXmas combo anims 2024-07-09 04:21:14 -04:00
EliteMasterEric cb4620d33a Fix background props not bopping on Week 5 2024-07-09 04:20:42 -04:00
EliteMasterEric ae03537676 Fix an issue with Pico's death animation spritesheet 2024-07-09 03:20:51 -04:00
Cameron TaylorandGitHub 7a653707a8 Merge pull request #641 from FunkinCrew/maybemaru/pixels-per-ms
[PUBLIC PR] Make use of Constants.PIXELS_PER_MS consistent.
2024-07-08 22:12:18 -04:00
Cameron Taylor fdf52efdd1 Merge branch 'rewrite/master' of github.com:FunkinCrew/Funkin-secret into rewrite/master 2024-07-08 22:10:52 -04:00
Cameron Taylor b4acfe8d95 assets submod 2024-07-08 22:10:40 -04:00
Cameron Taylor 51a156eec9 Merge branch 'char-select-cherrypick' into rewrite/master 2024-07-08 22:10:17 -04:00
Cameron TaylorandGitHub d9d0facfca Merge pull request #653 from FunkinCrew/feature/playable-pico-results
Feature/playable pico results
2024-07-08 21:52:23 -04:00
Cameron Taylor 6e5c6a8f6d assets submod 2024-07-08 21:51:44 -04:00
Cameron Taylor 96aa0b3a59 assets submod 2024-07-08 21:51:27 -04:00
Cameron TaylorandGitHub b338dfe8f0 Merge pull request #649 from FunkinCrew/jvnpixels/story-menu-scrolling
[PUBLIC PR] Scroll wheel in Story Menu
2024-07-08 17:39:30 -04:00
Cameron Taylor 3a37b79a55 add TAB to controls stuff 2024-07-08 16:40:10 -04:00
Cameron Taylor 57c995e19d char select screen controls stuff 2024-07-08 16:30:17 -04:00
Cameron Taylor a92334d5ae Merge branch 'rewrite/master' into char-select-cherrypick 2024-07-08 16:23:32 -04:00
Cameron Taylor d7105e8b8e change debug menu and add key for freeplay 2024-07-08 16:22:38 -04:00
EricandGitHub d1a1f2a32f Merge pull request #2962 from Punkinator7/main
[Minor Fix] Remove duplicate lines in CHANGELOG.md for Version 4.0
2024-07-07 04:14:50 -04:00
EliteMasterEric a9aa142b8d Added more pico results + charts 2024-07-07 04:10:37 -04:00
Cameron Taylor c9c94a5fda note fadein fix 2024-07-04 15:55:19 -04:00
Cameron TaylorandGitHub 6593ddbbc8 Merge pull request #646 from FunkinCrew/gamerbross/playonce-returns
[PUBLIC PR] FunkinSound.playOnce now returns the created sound
2024-07-04 15:10:20 -04:00
Cameron TaylorandGitHub 4d9b506380 Merge pull request #645 from FunkinCrew/gamerbross/char-danceevery
[PUBLIC PR + CHANGES] Fix danceEvery for characters
2024-07-04 15:08:51 -04:00
Cameron TaylorandGitHub 214f68c4c1 Merge pull request #643 from FunkinCrew/feature/character-anim-fixes
Enable GF combo animations, several character animation issues
2024-07-04 15:07:25 -04:00
Cameron Taylor 67b1c3864e Merge branch 'rewrite/master' into feature/character-anim-fixes 2024-07-04 15:07:07 -04:00
Cameron Taylor 130440fd6e assets submod 2024-07-04 15:06:04 -04:00
Cameron TaylorandGitHub eddfa23955 Merge pull request #644 from FunkinCrew/abnormalpoof/cutscene-auto-pause
[PUBLIC PR] Automatically pause video cutscenes when tabbing away from the game
2024-07-04 14:52:46 -04:00
Cameron TaylorandGitHub 11eefc4f6d Merge pull request #626 from FunkinCrew/feature/playable-pico-mode
Playable Pico Mode
2024-07-04 14:51:00 -04:00
Cameron Taylor 1eb12a3e3f assets submod 2024-07-04 14:49:35 -04:00
Cameron Taylor a7cfae8545 mer 2024-07-04 14:48:24 -04:00
EliteMasterEric 7fbc765403 Implement Pico results (good animation) 2024-07-04 03:32:50 -04:00
EliteMasterEric e32fcee77c Migrate results animations to JSON data so we can implement them per-character 2024-07-03 22:50:39 -04:00
Punkinator7andGitHub f31d2f7bfc Rename changelog.md to CHANGELOG.md
replace the old one with the fixed version
2024-07-03 20:57:01 -04:00
Punkinator7andGitHub cd9400e898 Delete CHANGELOG.md 2024-07-03 20:56:19 -04:00
Punkinator7andGitHub 05b57c88d3 Add fixed Changelog
There were several duplicate lines in the V4.0 Changelog, so I removed them
2024-07-03 20:55:15 -04:00
AppleHairandEliteMasterEric bd17d965f5 [BUGFIX] Fixed Ranks not appearing in freeplay for custom variations
Freeplay tries to access a song's rank using the current difficulty name alone, but custom variation ranks are being saved with a variation prefix. This PR makes freeplay look for the variation prefix when necessary.
2024-07-03 18:03:46 -04:00
EliteMasterEric ad57e64994 Working Pico DJ 2024-07-03 18:03:31 -04:00
EliteMasterEric 5c2bad888d Make Boyfriend DJ animations data driven 2024-07-03 18:02:16 -04:00
EliteMasterEric 72a00b9ae2 Implemented playable character registry, added Freeplay character filtering, added alt instrumental support 2024-07-03 18:01:49 -04:00
AppleHairandEliteMasterEric b1021530d8 now using getVariationsByCharId instead 2024-07-03 18:00:59 -04:00
AppleHairandEliteMasterEric 837efcea36 [BUGFIX] Made freeplay use the metadata to get the instrumental suffix
Song previews in freeplay will now use the instrumental suffix from the current difficulty's corresponding song variation metadata instead of using the variation id as an instrumental suffix and checking only the "erect" variation.
2024-07-03 18:00:58 -04:00
Cameron Taylor 105e3dccba spritesheet fixins for char select 2024-07-02 21:26:16 -04:00
FabsTheFabsandCameron Taylor 3fa9b2a635 new music 2024-07-01 22:18:04 -04:00
Cameron Taylor 8dfd36d227 menu spam fixie 2024-07-01 22:18:03 -04:00
FabsTheFabsandCameron Taylor b1b7a032be music updates 2024-07-01 22:17:55 -04:00
FabsTheFabsandCameron Taylor 28068b1a86 updating more stuff 2024-07-01 22:17:55 -04:00
FabsTheFabsandCameron Taylor be4ca0f47d assets..... submod... 2024-07-01 22:17:54 -04:00
FabsTheFabsandCameron Taylor d686890f76 most of the old code 2024-07-01 22:16:56 -04:00
Cameron Taylor bcaeae27f1 xml fix derp 2024-07-01 22:07:50 -04:00
Cameron TaylorandGitHub 043c8e8ade Merge pull request #638 from FunkinCrew/cyn0x8/flash-fix
[PUBLIC PR] Make flashing effects look more consistent
2024-07-01 20:23:16 -04:00
Cameron TaylorandGitHub 5134547071 Merge pull request #648 from FunkinCrew/gamerbross/freeplay-stack-overflow
[PUBLIC PR] Fix Stack Overflow if song doesn't have "normal" difficulty
2024-07-01 20:20:38 -04:00
Cameron TaylorandGitHub bb1fc64754 Merge pull request #647 from FunkinCrew/gamerbross/stickers-f5-screen
[PUBLIC PR] Fix crash after pressing F5 and coming back from stickers
2024-07-01 20:19:09 -04:00
Cameron TaylorandGitHub 88263b9ffd Merge pull request #640 from FunkinCrew/nothyper-474/loading-state-trace
[PUBLIC PR] Fix broken trace call in LoadingState
2024-07-01 16:53:07 -04:00
Cameron TaylorandGitHub 61fad2325d Merge pull request #642 from FunkinCrew/feature/freeplay-pixel-icons
Animated pixel icons for Freeplay
2024-07-01 16:52:46 -04:00
EliteMasterEricandCameron Taylor 432c709075 Animated pixel icons for freeplay
mend
2024-07-01 16:51:54 -04:00
FlooferLand!andEliteMasterEric cd08116aed Added getWidth 2024-07-01 15:41:08 -04:00
FlooferLand!andEliteMasterEric fbc78adb65 Added new settings items 2024-07-01 15:41:08 -04:00
EliteMasterEric 8a4f19d603 Add change counts labels to Actions labeler 2024-07-01 15:41:08 -04:00
Eric 841a61408c Make downloading the assets submodule a separate step. 2024-07-01 15:41:08 -04:00
HundrecandEliteMasterEric 9fb4a8719a Add ZIP button warning and restructured sentences
Each step should be easier to follow with this structure
2024-07-01 15:41:08 -04:00
HundrecandEliteMasterEric 2916bd6ff7 Reorder download Git step in compiling guide
Moved “download Git” from the middle of the guide to the setup step
Should prevent errors with Git before installing Git
2024-07-01 15:41:07 -04:00
PixelandEliteMasterEric a9c6b9ff8a Extra newline removal.
Removes the extra line in code.
2024-06-29 01:15:48 -04:00
90f3a8f285 Update source/funkin/ui/story/StoryMenuState.hx
Co-authored-by: gamerbross <55158797+gamerbross@users.noreply.github.com>
2024-06-29 01:15:48 -04:00
PixelandEliteMasterEric 55d02d49c2 Update StoryMenuState.hx 2024-06-29 01:15:47 -04:00
gamerbrossandEliteMasterEric 7e6ef61169 Fix Stack Overflow if song doesn't have "normal" difficulty 2024-06-29 00:35:01 -04:00
gamerbrossandEliteMasterEric 32deb8d190 Fix crash after pressing F5 and coming back from stickers 2024-06-29 00:29:23 -04:00
EliteMasterEric 62501a1ded Fix null safety error. 2024-06-29 00:03:28 -04:00
gamerbrossandEliteMasterEric 03eab140f1 FunkinSound.playOnce return sound 2024-06-28 23:29:23 -04:00
EliteMasterEric b022581e23 Make danceEvery a float precise up to 0.25 beats (1 step) 2024-06-28 23:25:59 -04:00
gamerbrossandEliteMasterEric 6bf28a5416 Implement danceEvery for Characters 2024-06-28 22:57:44 -04:00
AbnormalPoofandEliteMasterEric 9d9d7a853c video cutscene autopause magic 2024-06-28 22:36:01 -04:00
EliteMasterEric 84dd1cd3b9 Fix several character animation issues 2024-06-28 22:29:59 -04:00
EliteMasterEric fbfd8259a6 Merge branch 'applehair/ranks-for-custom-variations' into feature/playable-pico-mode 2024-06-27 04:06:10 -04:00
MaybeMaruandEliteMasterEric 16d64991ed Add missing constants 2024-06-27 03:56:41 -04:00
NotHyper-474andEliteMasterEric 6f26fbba5f Fix trace 2024-06-26 20:57:01 -04:00
gamerbrossandEliteMasterEric a7bdf23832 Fix chart reset when charting and pressing chart key 2024-06-26 20:52:32 -04:00
Cameron TaylorandGitHub 27bf88c11e Merge pull request #2914 from FunkinCrew/docs/changed-lines-count-labeler
Add change counts labels to Actions labeler
2024-06-26 20:43:59 -04:00
Cameron TaylorandGitHub dd30012d80 Merge pull request #637 from FunkinCrew/hundrec/tankman-chart-editor-fix
[PUBLIC PR] Fix tankmanpixel icon in Chart Editor
2024-06-26 20:41:24 -04:00
cynandEliteMasterEric dad8b0815d flash fix 2024-06-26 20:36:53 -04:00
EliteMasterEric 4a73d7e1ce Add change counts labels to Actions labeler 2024-06-25 18:22:30 -04:00
HundrecandGitHub 08d35eb00d Fix tankmanpixel icon in Chart Editor 2024-06-25 18:07:09 -04:00
Cameron Taylor 69a9a45131 Merge branch 'rewrite/master' into haxelib/thx 2024-06-25 13:58:04 -04:00
Cameron Taylor e7f39ea081 hxp hmm update 2024-06-25 13:57:26 -04:00
Cameron Taylor ef7612d1c2 discord RPC haxelib 2024-06-25 13:57:26 -04:00
Cameron Taylor e7dd724be6 assets 2024-06-25 13:56:42 -04:00
Cameron Taylor 8a144352a0 remove bopper trace 2024-06-25 13:56:31 -04:00
Cameron Taylor 1757532097 more retro week 6 stuff 2024-06-25 13:56:31 -04:00
Cameron Taylor ab2f949d7e fix for heart icons being on the wrong frames 2024-06-25 13:56:31 -04:00
Cameron Taylor 5751430261 fix the camera not panning when opening then closing the debug menu during transition 2024-06-25 13:56:31 -04:00
Cameron Taylor 39c3af58f2 fix: bf v pose playing during a gameover 2024-06-25 13:56:31 -04:00
Cameron Taylor 9b4f9db73e update thx related haxelibs 2024-06-25 13:53:55 -04:00
Cameron Taylor 458e51c327 haxeui 2024-06-25 13:53:47 -04:00
Cameron TaylorandGitHub 4bd78f4696 Merge pull request #628 from FunkinCrew/remove-traces
remove bopper trace (FUNK-520)
2024-06-25 13:48:44 -04:00
Cameron TaylorandGitHub 9b64d08944 Merge pull request #627 from FunkinCrew/pixel-perfect
more retro week 6 stuff
2024-06-25 13:48:29 -04:00
Cameron TaylorandGitHub 153590b8fc Merge pull request #629 from FunkinCrew/ninjamuffin99/funk-195
fix: bf v pose playing during a gameover
2024-06-25 13:48:18 -04:00
Cameron TaylorandGitHub e862963c16 Merge branch 'rewrite/master' into ninjamuffin99/funk-195 2024-06-25 13:48:06 -04:00
Cameron Taylor da834dab8d fix for heart icons being on the wrong frames 2024-06-25 13:47:40 -04:00
Cameron Taylor bdbc136497 fix the camera not panning when opening then closing the debug menu during transition 2024-06-25 13:47:27 -04:00
Cameron Taylor a5442b407e haxeui 2024-06-24 21:53:56 -04:00
Cameron Taylor 47b7aa702a submod 2024-06-24 14:46:09 -04:00
Cameron Taylor de6ba0c741 flxpartialsound hmm update 2024-06-24 14:40:55 -04:00
Cameron Taylor 93aa02868e submod 2024-06-24 14:40:55 -04:00
Cameron Taylor 92917e17c6 submod 2024-06-24 14:40:55 -04:00
Cameron Taylor 0f972cb11c submoduel 2024-06-24 14:40:55 -04:00
EliteMasterEricandCameron Taylor 4e65c49e0e Get rid of a warning about missing BPM info 2024-06-24 14:40:55 -04:00
Karim AkraandCameron Taylor 983d241e47 remove the library strip 2024-06-24 14:40:55 -04:00
EliteMasterEricandCameron Taylor d44275c2c7 Fix a bug where songs with no notes would crash the results screen. 2024-06-24 14:40:55 -04:00
Cameron Taylor 81cada675c fix for release, no bf printing directly to stdout! 2024-06-24 14:40:55 -04:00
Cameron Taylor aa3e3eb9b6 fix: bf v pose playing during a gameover 2024-06-24 14:13:30 -04:00
Cameron Taylor aa24dc4aa0 remove bopper trace 2024-06-24 13:34:33 -04:00
EliteMasterEric 9b3a748f37 Working Pico DJ 2024-06-20 16:17:53 -04:00
Cameron Taylor dd413d42ab more retro week 6 stuff 2024-06-19 23:47:11 -04:00
EliteMasterEric 263039f52c Make Boyfriend DJ animations data driven 2024-06-18 20:07:27 -04:00
EliteMasterEric 60e741434c Implemented playable character registry, added Freeplay character filtering, added alt instrumental support 2024-06-18 17:56:24 -04:00
EliteMasterEric 6f2f2a9aa4 Merge branch 'applehair/preview-inst-suffix' into feature/playable-pico-mode 2024-06-18 15:40:51 -04:00
Cameron Taylor 78bbf5a7aa submod 2024-06-18 13:13:47 -04:00
Cameron Taylor cf44774b21 submod 2024-06-18 13:13:47 -04:00
Cameron Taylor 0ed103b2f0 submoduel 2024-06-18 13:13:47 -04:00
EliteMasterEricandCameron Taylor e2be19039c Get rid of a warning about missing BPM info 2024-06-18 13:11:16 -04:00
Karim AkraandCameron Taylor 42192dfe97 remove the library strip 2024-06-18 13:11:16 -04:00
EliteMasterEricandCameron Taylor 24bdf2db64 Fix a bug where songs with no notes would crash the results screen. 2024-06-18 13:10:50 -04:00
tposejank 37b8c881a8 Fulfill requests & new crash template 2024-06-17 01:06:14 -04:00
tposejankandGitHub b5c4a8589a Delete 2024-06-17 00:49:09 -04:00
tposejankandGitHub 2cc41c23a8 Merge branch 'develop' into better-templates 2024-06-17 00:48:32 -04:00
tposejank 3c81f93ca2 will you 2024-06-17 00:47:46 -04:00
Cameron Taylorandtposejank 60f6e5ec50 simplified the bug template to have less clutter 2024-06-17 00:47:05 -04:00
tposejankandGitHub ac08f5518d Thanks, Git! 2024-06-17 00:45:00 -04:00
Cameron Taylorandtposejank 4b354f6f32 simplified the bug template to have less clutter 2024-06-17 00:44:01 -04:00
Cameron Taylorandtposejank 5cde06bc86 simplified the bug template to have less clutter 2024-06-17 00:43:06 -04:00
EricandGitHub 9bd09e3791 Make downloading the assets submodule a separate step. 2024-06-16 18:48:01 -04:00
EricandGitHub 504766a081 Merge pull request #2813 from Hundrec/patch-3
[DOCS] Make compiling guide more user friendly
2024-06-16 18:43:37 -04:00
EricandGitHub 5b40900066 Merge branch 'main' into patch-3 2024-06-16 18:41:39 -04:00
HundrecandGitHub 32ad9d159e Add ZIP button warning and restructured sentences
Each step should be easier to follow with this structure
2024-06-15 13:37:21 -04:00
HundrecandGitHub b8c9717864 Reorder download Git step in compiling guide
Moved “download Git” from the middle of the guide to the setup step
Should prevent errors with Git before installing Git
2024-06-14 21:52:52 -07:00
AppleHairandGitHub 1f1fe62a06 [BUGFIX] Fixed Ranks not appearing in freeplay for custom variations
Freeplay tries to access a song's rank using the current difficulty name alone, but custom variation ranks are being saved with a variation prefix. This PR makes freeplay look for the variation prefix when necessary.
2024-06-14 16:53:33 +03:00
Cameron Taylor 49155b06b3 Merge branch 'rewrite/master' 2024-06-12 20:31:57 -04:00
Cameron Taylor a63b60d458 fix for release, no bf printing directly to stdout! 2024-06-12 20:31:27 -04:00
Cameron Taylor 1c45c9b03b git modules 2024-06-12 15:50:59 -04:00
Cameron Taylor 80981eee37 inputs null fix 2024-06-12 15:41:42 -04:00
Cameron Taylor 7a2b023f30 gitmodules for dev repo 2024-06-12 15:29:44 -04:00
Cameron Taylor 9908f973cf someone pls tell me how to use two different git submodules
Create and publish Docker image / build-and-push-image (push) Canceled after 0s
Build and Upload nightly game builds / build-game-on-host (macos) (push) Canceled after 0s
Build and Upload nightly game builds / build-game-on-host (windows) (push) Canceled after 0s
Build and Upload nightly game builds / build-game-in-container (html5) (push) Canceled after 0s
Build and Upload nightly game builds / build-game-in-container (linux) (push) Canceled after 0s
2024-06-12 15:27:56 -04:00
Cameron Taylor ead37894cd Merge branch 'rewrite/master' 2024-06-12 15:26:40 -04:00
Cameron Taylor cce2ab7fff update project.xml for 0.4.1 lol 2024-06-12 15:05:32 -04:00
EricandCameron Taylor 48653ababd Update CHANGELOG.md 2024-06-12 15:01:27 -04:00
EricandCameron Taylor 7ce0544b18 Update CHANGELOG.md 2024-06-12 14:54:41 -04:00
Cameron Taylor f8ecddc5b3 added eric code to changelog 2024-06-12 14:54:41 -04:00
Cameron Taylor 1ebcae79fe changelog for 0.4.1 2024-06-12 14:54:41 -04:00
EliteMasterEric 47f885ae97 Charter credits for Eggnog Erect 2024-06-12 13:33:19 -04:00
AppleHairandGitHub c4d6e18885 now using getVariationsByCharId instead 2024-06-12 11:23:45 +03:00
Cameron TaylorandGitHub 47d5c4d141 Merge pull request #619 from FunkinCrew/freeplay-dad-smoother
freeplay bg nicer AA and proper sizing
2024-06-11 16:16:13 -04:00
Cameron TaylorandGitHub c325fdaa1b Merge pull request #618 from FunkinCrew/speaker-volume-desktop
[funk-378] reactive speaker to gamevolume on desktop
2024-06-11 16:16:02 -04:00
Cameron TaylorandGitHub b64af80eba Merge pull request #608 from FunkinCrew/bugfix/instrumental-id
Play song IDs based on the chart file's "instrumental" field, not the variation ID.
2024-06-11 16:15:24 -04:00
Cameron Taylor c05f053fe3 Merge branch 'rewrite/master' into bugfix/instrumental-id 2024-06-11 16:12:39 -04:00
Cameron Taylor 1e3ef61fc9 freeplay bg nicer AA and proper sizing 2024-06-11 15:57:45 -04:00
Cameron Taylor 37a15e0a0f reactive speaker to gamevolume on desktop 2024-06-11 12:13:10 -04:00
Cameron TaylorandGitHub 817c216d06 Merge pull request #617 from FunkinCrew/bugfix/save-highest-rank
[FUNK-387] Save high scores and high ranks separately.
2024-06-11 12:04:38 -04:00
Cameron TaylorandGitHub 381e0104e9 Merge pull request #616 from FunkinCrew/feature/freeplay-keybinds
[FUNK-391] Rebindable controls for the Freeplay menu
2024-06-11 11:49:24 -04:00
Cameron Taylor 5686bfcd6b ### Changed
- Tweaked the chart for Lit Up some more to fix some offset notes.Merge branch 'bugfix/spaz-charts' into rewrite/master
2024-06-11 11:27:57 -04:00
Cameron Taylor 93c0bd0b63 assets submod 2024-06-11 11:25:43 -04:00
tposejankandGitHub f48a65e9ce Remove question & compiling help 2024-06-11 02:09:56 -04:00
EliteMasterEric b30faad7d9 Save high scores and high ranks separately. 2024-06-11 00:40:43 -04:00
EliteMasterEric c0a7e4f728 Readd camera events to Roses 2024-06-10 19:32:53 -04:00
Cameron Taylor 00021523bc lower volume on freeplay easter egg 2024-06-10 17:35:49 -04:00
Ikko Eltociear AshimineandCameron Taylor e8f8a0c181 chore: update MenuList.hx
lenth -> length
2024-06-10 16:45:22 -04:00
Cameron Taylor 13d49017ac removed compiling help and question templates 2024-06-10 16:45:22 -04:00
Cameron Taylor f91f4b2ddb simplified the bug template to have less clutter 2024-06-10 16:45:22 -04:00
DM-kunandCameron Taylor da61b72c48 crash fix 2024-06-10 16:21:41 -04:00
Cameron Taylor f31ea8fb73 add sound for changing sorting 2024-06-10 16:13:32 -04:00
gamerbrossandCameron Taylor 8f44d9606d Remove unnecessary scrollMenu sounds + adjust volume 2024-06-10 13:17:38 -04:00
AppleHairandGitHub 9fa603363c [BUGFIX] Made freeplay use the metadata to get the instrumental suffix
Song previews in freeplay will now use the instrumental suffix from the current difficulty's corresponding song variation metadata instead of using the variation id as an instrumental suffix and checking only the "erect" variation.
2024-06-10 19:42:27 +03:00
Cameron Taylor 4691e3d249 Merge branch 'bugfix/chart-editor-event-toolbox-crash' into rewrite/master 2024-06-10 12:26:47 -04:00
Cameron Taylor cd2bbcb43b Merge branch 'ninjamuffin99/funk-292' into rewrite/master 2024-06-10 12:05:08 -04:00
Cameron Taylor b7d25bf04f Merge branch 'escape-quit' into rewrite/master 2024-06-10 12:04:30 -04:00
Cameron Taylor 5dcd3eb946 Merge branch 'heart-capsule-pos' into rewrite/master 2024-06-10 12:04:09 -04:00
Cameron Taylor b811aeec80 fix for pico explo 2024-06-09 16:15:33 -04:00
Cameron Taylor 55edb9ea14 pressing escape on title screen exits game 2024-06-09 15:38:22 -04:00
Cameron Taylor d974f12c72 Merge branch 'develop' into rewrite/master 2024-06-09 15:30:14 -04:00
Cameron Taylor f2d5a80bd1 completes funk-305 2024-06-09 15:06:45 -04:00
tposejank 6962088d16 Merge branch 'develop' into better-templates 2024-06-09 14:59:33 -04:00
tposejank db10257993 Merge remote-tracking branch 'upstream/main' into better-templates 2024-06-09 14:45:36 -04:00
Cameron TaylorandGitHub 9a26837374 Merge pull request #2730 from eltociear/patch-2
chore: update MenuList.hx
2024-06-09 14:19:37 -04:00
Ikko Eltociear AshimineandGitHub bdaadfbfdd chore: update MenuList.hx
lenth -> length
2024-06-10 02:26:55 +09:00
Cameron Taylor 9f960f5c28 removed compiling help and question templates 2024-06-09 12:43:43 -04:00
Cameron Taylor 9455b6eadc simplified the bug template to have less clutter 2024-06-09 12:41:00 -04:00
Cameron TaylorandGitHub eb979a8625 Merge pull request #2701 from zacksgamerz/develop
Fixed that one mistake in .github/ISSUE_TEMPLATE/bug.md
2024-06-09 12:21:45 -04:00
EliteMasterEric 839d6a0841 A couple chart fixes 2024-06-09 02:27:36 -04:00
EliteMasterEric 09aa8fbf52 Rebindable controls for the Freeplay menu 2024-06-09 02:22:03 -04:00
tposejankandGitHub 075989ce9c Update and rename enhancement.md to enhancement.yml 2024-06-08 23:00:24 -04:00
tposejankandGitHub 19ef15dbc8 Update and rename bug.md to bug.yml 2024-06-08 22:59:17 -04:00
tposejankandGitHub 347f487358 Create config.yml 2024-06-08 22:54:44 -04:00
tposejankandGitHub 0808469a62 Update and rename question.md to question.yml 2024-06-08 22:52:37 -04:00
tposejankandGitHub 3f77d1d7ca Update and rename enhancement.md to enhancement.yml 2024-06-08 22:50:44 -04:00
tposejankandGitHub c1da4d336c Update and rename compiling.md to compiling.yml 2024-06-08 22:48:05 -04:00
tposejankandGitHub 6b74befb5f Run it through prettier 2024-06-08 22:42:50 -04:00
tposejankandGitHub 3334cc3563 Update and rename bug.md to bug.yml 2024-06-08 22:40:09 -04:00
zacksgamerzandGitHub bc80e39a85 you're to your 2024-06-08 19:07:22 +07:00
Cameron Taylor 45b43108d1 lower fft amount on desktop 2024-06-07 22:36:25 -04:00
EricandGitHub 9a78060329 Merge pull request #2451 from nebulazorua/abstract-optionname
abstract enum pagename
2024-06-07 22:02:18 -04:00
EricandGitHub 4169116129 Merge branch 'develop' into abstract-optionname 2024-06-07 21:44:28 -04:00
EricandGitHub 5bd9ff8c21 Merge pull request #2551 from gamerbross/bugfix/fast-enter-options
[BUGFIX] Options Menu not enabled in transIn
2024-06-07 21:36:21 -04:00
EricandGitHub f38f5a268b Merge branch 'develop' into bugfix/fast-enter-options 2024-06-07 21:35:56 -04:00
gamerbrossandEliteMasterEric 1172949a04 Fix Options Menu not enabled in transIn 2024-06-07 21:31:53 -04:00
EliteMasterEric d19e9e62fa Merge branch 'richtrash21/freeplay-camera-optimization' into develop 2024-06-07 21:21:11 -04:00
EliteMasterEric 2e4b94d528 Fix additional merge conflicts 2024-06-07 21:20:04 -04:00
EliteMasterEric 4382b3e16e Merge branch 'develop' into richtrash21/freeplay-camera-optimization 2024-06-07 21:13:13 -04:00
EricandGitHub 195663638e Merge pull request #2683 from Hundrec/patch-1
Fix botplay sustain release bug
2024-06-07 21:08:19 -04:00
EricandGitHub 9a8ba4183e Merge branch 'develop' into patch-1 2024-06-07 21:08:09 -04:00
EricandGitHub aace5e2326 Merge pull request #2684 from gamerbross/bugfix/camfollow-pause-game
[BUGFIX] Pause Camera Follow when pausing
2024-06-07 20:56:01 -04:00
gamerbross cd485213db Pause Camera Follow when pausing 2024-06-08 02:26:17 +02:00
gamerbross ee6c4478a9 Use FlxG.camera instead of camGame 2024-06-08 02:02:54 +02:00
HundrecandGitHub 393355b512 Fix botplay sustain release bug
Copied opponent's holdTimer code to the player's side
2024-06-07 19:59:02 -04:00
EliteMasterEric d39f3dc1e8 Merge branch 'main' into develop 2024-06-07 19:54:30 -04:00
Cameron Taylor 7b90a3cee3 lil changelog in progres 2024-06-07 14:36:14 -04:00
Cameron TaylorandGitHub 1d6315fe0e Merge pull request #610 from FunkinCrew/2hot-freeplay
regexp for numbers
2024-06-07 14:33:56 -04:00
Cameron Taylor 34c91dae76 dadbattle hard/erect fix 2024-06-07 14:24:57 -04:00
Cameron Taylor a0adbc72b3 regexp for numbers 2024-06-07 13:04:45 -04:00
Cameron TaylorandGitHub 7dfd682148 Merge pull request #2661 from Hundrec/patch-1
README grammar fix
2024-06-07 11:40:16 -04:00
Cameron TaylorandGitHub 0242a6b64f Merge pull request #2662 from An-enderman/patch-2
Update COMPILING, adding one step
2024-06-07 11:40:09 -04:00
Cameron TaylorandGitHub 62091523d2 Merge branch 'main' into patch-2 2024-06-07 11:40:02 -04:00
Cameron Taylor 6fd030cb30 Merge branch 'patch-1' into rewrite/master 2024-06-07 11:38:57 -04:00
Cameron Taylor 1e63998c74 Merge branch 'patch-2' into rewrite/master 2024-06-07 11:37:37 -04:00
An-endermanandGitHub d4a524bbcb Update COMPILING, adding one step
I added the step that says to download Git, because the command "hmm install" requires Git to work.
2024-06-07 16:40:37 +02:00
HundrecandGitHub 03cf3dcf99 README grammar fix 2024-06-07 03:29:58 -04:00
EliteMasterEric ca345e6c4f Play song IDs based on the chart file's "instrumental" field, not the variation ID. 2024-06-06 21:38:00 -04:00
EliteMasterEric 266049df65 Update assets submodule 2024-06-06 20:10:28 -04:00
EliteMasterEric fe5f1eb6ea Fix merge conflict 2024-06-06 17:11:30 -04:00
EliteMasterEric 70f027cc3f Fix another crash with the chart editor event toolbox 2024-06-06 16:44:47 -04:00
EliteMasterEric a81b6b2d6e Fix issue with rendering the grid in 3/4 time signature 2024-06-06 16:44:20 -04:00
EliteMasterEric 6fb19dc4d3 Update chart editor dropdowns to be searchable 2024-06-05 20:09:26 -04:00
EliteMasterEric 6d133f007d Fix a bug where the event data toolbox wouldn't rebuild, and it would crash. 2024-06-05 19:25:53 -04:00
EricandGitHub 3b74a14a0d Merge pull request #2610 from PurSnake/fixing
[BUGFIX] Correct characters scaling on stage
2024-05-30 23:54:38 -04:00
EricandGitHub 2380058820 Merge pull request #2328 from nebulazorua/new-judge-applying
New judge application logic
2024-05-30 16:10:17 -04:00
EricandGitHub 6cc9c3d968 Merge pull request #2409 from Burgerballs/scroll-speed-fix
[FEATURE] Scroll Speed Event
2024-05-29 23:22:03 -04:00
EricandGitHub 0388f887b5 Merge pull request #2565 from gamerbross/bugfix/charting-sustain-trails
[BUGFIX] Charting Editor Sustain Trails (2 bugs)
2024-05-29 22:54:49 -04:00
EricandGitHub b487adb169 Merge pull request #2629 from NotHyper-474/bugfix/cwd-preloader-issue
[BUGFIX?] Reset CWD before Preloader
2024-05-29 22:52:17 -04:00
richTrash21 4ca30a571d safety 2024-05-23 21:52:28 +04:00
richTrash21 1c352e4e11 simplify freeplay camera 2024-05-23 21:50:11 +04:00
gamerbross a73d65757c Fix Options Menu not enabled in transIn 2024-05-19 00:23:51 +02:00
nebulazorua e462b04b59 does notesplash 2024-05-15 20:46:08 +08:00
richandGitHub 7a19bd4b50 Merge branch 'FunkinCrew:main' into debelop-freeplay-patch 2024-05-15 16:31:57 +04:00
richandGitHub 59e409f8e6 ensure that only freeplay camera gets destroyed 2024-05-14 04:30:36 +04:00
richandGitHub 3810662f9f freeplay optimization 2024-05-14 04:20:23 +04:00
Ikko Eltociear AshimineandGitHub 6a52efe8a4 Update ScriptEventType.hx
relevent -> relevant
2024-05-11 18:10:15 +09:00
nebulazorua fa4fa8116c abstract enum pagename
should make adding modded optionspages better and easier
makes it so you dont have to leech off an unused PageName or write your own code for making modded options, helping with compatibility between mods.
2024-05-11 16:51:27 +08:00
Sword352 f6334fb30b Use animOffsets directly. 2024-05-08 22:18:41 +02:00
nebulazorua 4b500f78e1 Revert change because i forgot to do it in a new branch oriignally lol 2024-05-08 20:30:47 +08:00
nebulazorua 2eaea3cdc5 Apply judgements through a seperate function to applyScore
Also adds more to the HitNoteScriptEvent, such as the noteDiff and also isComboBreak.
noteDiff is important as it lets you create stuff like notes with reduced hitboxes (i.e mines/"hurt notes") or millisecond hit displays. isComboBreak lets you set whether the judge combo broke, so you could in theory create custom judgements in scripts now with these changes (killer reimplementation in scripts? more likely than you'd think!)
2024-05-08 20:26:17 +08:00
Sword352 dd86934712 did the requested changes 2024-05-08 09:22:49 +02:00
Sword352 7ce3eabd17 Better character animation offsets handling. 2024-05-08 07:35:46 +02:00
182 changed files with 13310 additions and 3524 deletions
+3 -1
View File
@@ -1 +1,3 @@
* text=auto eol=lf
* text=auto eol=lf
*.hxc linguist-language=Haxe
*.hxp linguist-language=Haxe
-44
View File
@@ -1,44 +0,0 @@
---
name: Bug Report
about: Report a bug or critical performance issue
title: 'Bug Report: [DESCRIBE YOUR BUG IN DETAIL HERE]'
labels: bug
---
[weed]: <> (FILL THIS ISSUE THING OUT AS MUCH AS POSSIBLE)
[weed]: <> (OR ELSE YOUR ISSUE WILL BE LESS LIKELY TO BE SOLVED!)
[weed]: <> (DO NOT POST ABOUT ISSUES FROM OTHER FNF MOD ENGINES! I CANNOT AND PROBABLY WON'T SOLVE THOSE!)
[weed]: <> (GO TO THEIR RESPECTIVE GITHUB ISSUES AND REPORT THEM THERE LOL!)
[weed]: <> (ALSO MAKE SURE THAT YOU USE PROPER LABELS, IF YOU'RE RUNNING INTO COMPILER ISSUES, USE THE compiler issue LABEL!!!)
#### Please check for duplicates or similar issues, as well performing simple troubleshooting steps (such as clearing cookies, clearing AppData, trying another browser) before submitting an issue.
### If you are playing the game in a browser, what site are you playing it from?
[weed]: <> (Put an X in the [ ] thingies to fill out checkbox!)
[weed]: <> (something like [x] pretty much, don't screw up or you will look stupid)
- [ ] [Newgrounds](https://www.newgrounds.com/portal/view/770371)
- [ ] [Itch.io](https://ninja-muffin24.itch.io/funkin)? Specify below
- - [ ] Windows
- - [ ] Mac
- - [ ] Linux
### If you are playing the game in a browser, what browser are you using?
[weed]: <> (Again, put an x in the [ ] box!)
- [ ] Google Chrome (or chomium based like Brave, vivaldi, MS Edge)
- [ ] Firefox
- [ ] Safari
## What version of the game are you using? Look in the bottom left corner of the main menu. (ex: 0.2.7, 0.2.1, shit like that)
## Have you identified any steps to reproduce the bug? If so, please describe them below in as much detail as possible. Use images if possible.
## Please describe your issue. Provide extensive detail and images if possible.
## If you're game is FROZEN and you're playing a web version, press F12 to open up browser dev window, and go to console, and copy-paste whatever red error you're getting
+62
View File
@@ -0,0 +1,62 @@
name: Bug Report
description: Report a bug or an issue in the game.
labels: ["type: minor bug", "status: pending triage"]
title: "Bug Report: "
body:
- type: checkboxes
attributes:
label: Issue Checklist
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
- type: dropdown
attributes:
label: What platform are you using?
options:
- Newgrounds (Web)
- Itch.io (Web)
- Itch.io (Downloadable Build) - Windows
- Itch.io (Downloadable Build) - MacOS
- Itch.io (Downloadable Build) - Linux
validations:
required: true
- type: dropdown
attributes:
label: If you are playing on a browser, which one are you using?
options:
- Google Chrome
- Microsoft Edge
- Firefox
- Opera
- Safari
- Other (Specify below)
- type: input
attributes:
label: Version
description: What version are you using?
placeholder: ex. 0.4.1
validations:
required: true
- type: markdown
attributes:
value: "## Describe your bug."
- 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 images, videos, etc.)
- type: textarea
attributes:
label: Steps to reproduce (or crash logs, errors, etc.)
-25
View File
@@ -1,25 +0,0 @@
---
name: Compiling help
about: If you need help compiling the game, and you're running into issues. (Look through the 'compiling help' label in case it's been solved!)
title: 'Compiling help: [BRIEF DESCRIPTION / ERROR MESSAGE OUTPUT]'
labels: compiling help
---
[weed]: <> (FILL THIS ISSUE THING OUT AS MUCH AS POSSIBLE)
[weed]: <> (OR ELSE YOUR ISSUE WILL BE LESS LIKELY TO BE SOLVED!)
[weed]: <> (DO NOT POST ABOUT ISSUES FROM OTHER FNF MOD ENGINES! I CANNOT AND PROBABLY WON'T SOLVE THOSE!)
[weed]: <> (GO TO THEIR RESPECTIVE GITHUB ISSUES AND REPORT THEM THERE LOL!)
#### Please check for duplicates or similar compiler issues by filtering for 'compiler help'
[weed]: <> (Put an X in the [ ] thingies to fill out checkbox!)
[weed]: <> (something like [x] pretty much, don't screw up or you will look stupid)
- [ ] Windows
- [ ] Mac
- [ ] Linux
- [ ] HTML5
## Please describe your issue. Provide extensive detail and images if possible.
+1
View File
@@ -0,0 +1 @@
blank_issues_enabled: false
+70
View File
@@ -0,0 +1,70 @@
name: Crash Report
description: Report a crash that occurred while playing the game.
labels: ["type: major bug", "status: pending triage"]
title: "Crash Report: "
body:
- type: checkboxes
attributes:
label: Issue Checklist
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
- type: dropdown
attributes:
label: What platform are you using?
options:
- Newgrounds (Web)
- Itch.io (Web)
- Itch.io (Downloadable Build) - Windows
- Itch.io (Downloadable Build) - MacOS
- Itch.io (Downloadable Build) - Linux
validations:
required: true
- type: dropdown
attributes:
label: If you are playing on a browser, which one are you using?
options:
- Google Chrome
- Microsoft Edge
- Firefox
- Opera
- Safari
- Other (Specify below)
- type: input
attributes:
label: Version
description: What version are you using?
placeholder: ex. 0.4.1
validations:
required: true
- type: markdown
attributes:
value: "## Describe your issue."
- 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
validations:
required: true
- type: textarea
attributes:
label: Crash logs (can be found in the logs folder where Funkin.exe is)
validations:
required: true
-8
View File
@@ -1,8 +0,0 @@
---
name: Enhancement
about: Suggest a new feature
title: 'Enhancement: '
labels: enhancement
---
#### Please check for duplicates or similar issues before creating this issue.
## What is your suggestion, and why should it be implemented?
+15
View File
@@ -0,0 +1,15 @@
name: Enhancement
description: Suggest a new feature.
labels: ["type: enhancement", "status: pending triage"]
title: "Enhancement: "
body:
- type: checkboxes
attributes:
label: Issue Checklist
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
- type: textarea
attributes:
label: What is your suggestion, and why should it be implemented?
-12
View File
@@ -1,12 +0,0 @@
---
name: Question
about: Ask a general question
title: 'Question: '
labels: question
---
[weed]: <> (This isn't a place for AMA type questions, if you want to ask any of the devs something, reach out to them on twitter prob )
[weed]: <> (any biz bullshit can go to cameron.taylor.ninja@gmail.com)
#### Please check for duplicates or similar issues before asking your question.
## What is your question?
-10
View File
@@ -1,10 +0,0 @@
---
name: Bug Fix
about: Fix a bug or critical performance issue
title: 'Bug Fix: '
labels: bug
---
#### Please check for duplicates or similar PRs before creating this issue.
## Does this PR close any issue(s)? If so, link them below.
## Briefly describe the issue(s) fixed.
@@ -1,10 +0,0 @@
---
name: Enhancement
about: Add a new feature
title: 'Enhancement: '
labels: enhancement
---
#### Please check for duplicates or similar PRs before creating this issue.
## Does this PR close any issue(s)? If so, link them below.
## What do your change(s) add, and why should they be implemented?
+16 -6
View File
@@ -44,7 +44,7 @@ runs:
g++ \
libx11-dev libxi-dev libxext-dev libxinerama-dev libxrandr-dev \
libgl-dev libgl1-mesa-dev \
libasound2-dev
libasound2-dev libpulse-dev
ln -s /usr/lib/x86_64-linux-gnu/libffi.so.8 /usr/lib/x86_64-linux-gnu/libffi.so.6 || true
- name: Install linux-specific dependencies
if: ${{ runner.os == 'Linux' && contains(inputs.targets, 'linux') }}
@@ -56,12 +56,17 @@ runs:
shell: bash
run: |
echo "TIMER_HAXELIB=$(date +%s)" >> "$GITHUB_ENV"
haxelib --debug --never install haxelib 4.1.0 --global
haxelib --debug --never deleterepo || true
haxelib fixrepo --global || true
haxelib --debug --never --global install haxelib 4.1.0
haxelib --debug --global set haxelib 4.1.0
haxelib --global remove haxelib git || true
haxelib --global remove hmm || true
rm -rf .haxelib
haxelib --debug --never --global git haxelib https://github.com/FunkinCrew/haxelib.git funkin-patches --skip-dependencies
haxelib --debug --never --global git hmm https://github.com/FunkinCrew/hmm funkin-patches
haxelib --debug --never newrepo
haxelib version
echo "HAXEPATH=$(haxelib config)" >> "$GITHUB_ENV"
haxelib --debug --never git haxelib https://github.com/HaxeFoundation/haxelib.git master
haxelib --debug --global install hmm
echo "TIMER_DEPS=$(date +%s)" >> "$GITHUB_ENV"
- name: Restore cached dependencies
@@ -75,7 +80,12 @@ runs:
name: Prep git for dependency install
uses: gacts/run-and-post-run@v1
with:
run: git config --global 'url.https://x-access-token:${{ inputs.gh-token }}@github.com/.insteadOf' https://github.com/
run: |
git config --global --name-only --get-regexp 'url\.https\:\/\/x-access-token:.+@github\.com\/\.insteadOf' \
| xargs -I {} git config --global --unset {}
git config -l --show-scope --show-origin
git config --global 'url.https://x-access-token:${{ inputs.gh-token }}@github.com/.insteadOf' https://github.com/
post: git config --global --unset 'url.https://x-access-token:${{ inputs.gh-token }}@github.com/.insteadOf'
- if: ${{ steps.cache-hmm.outputs.cache-hit != 'true' }}
+12
View File
@@ -0,0 +1,12 @@
# Add 'small' to any changes below 10 lines
small:
max: 9
# Add 'medium' to any changes between 10 and 100 lines
medium:
min: 10
max: 99
# Add 'large' to any changes for more than 100 lines
large:
min: 100
-1
View File
@@ -1,7 +1,6 @@
# Add Documentation tag to PR's changing markdown files, or anyhting in the docs folder
Documentation:
- changed-files:
- any-glob-to-any-file:
- any-glob-to-any-file:
- docs/*
- '**/*.md'
+6
View File
@@ -0,0 +1,6 @@
<!-- Please check for duplicates or similar PRs before submitting this PR. -->
## Does this PR close any issues? If so, link them below.
## Briefly describe the issue(s) fixed.
## Include any relevant screenshots or videos.
+7 -1
View File
@@ -45,7 +45,11 @@ jobs:
uses: ./.github/actions/setup-haxe
with:
gh-token: ${{ steps.app_token.outputs.token }}
- name: Setup HXCPP dev commit
run: |
cd .haxelib/hxcpp/git/tools/hxcpp
haxe compile.hxml
cd ../../../../..
- name: Build game
if: ${{ matrix.target == 'windows' }}
run: |
@@ -107,7 +111,9 @@ jobs:
name: Install dependencies
run: |
git config --global 'url.https://x-access-token:${{ steps.app_token.outputs.token }}@github.com/.insteadOf' https://github.com/
git config --global advice.detachedHead false
haxelib --global run hmm install -q
cd .haxelib/hxcpp/git/tools/hxcpp && haxe compile.hxml
- if: ${{ matrix.target != 'html5' }}
name: Restore hxcpp cache
+14 -1
View File
@@ -9,6 +9,19 @@ jobs:
pull-requests: write
runs-on: ubuntu-latest
steps:
- uses: actions/labeler@v5
- name: Set basic labels
uses: actions/labeler@v5
with:
sync-labels: true
changed-lines-count-labeler:
permissions:
contents: read
pull-requests: write
runs-on: ubuntu-latest
name: An action for automatically labelling pull requests based on the changed lines count
steps:
- name: Set change count labels
uses: vkirilichev/changed-lines-count-labeler@v0.2
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
configuration-path: .github/changed-lines-count-labeler.yml
+1
View File
@@ -13,3 +13,4 @@ shitAudio/
node_modules/
package.json
package-lock.json
.aider*
+2 -2
View File
@@ -1,6 +1,6 @@
[submodule "assets"]
path = assets
url = https://github.com/FunkinCrew/funkin.assets
url = https://github.com/FunkinCrew/Funkin-Assets-secret
[submodule "art"]
path = art
url = https://github.com/FunkinCrew/funkin.art
url = https://github.com/FunkinCrew/Funkin-Art-secret
+15 -15
View File
@@ -94,12 +94,12 @@
{
"label": "Windows / Debug",
"target": "windows",
"args": ["-debug", "-DFORCE_DEBUG_VERSION"]
"args": ["-debug", "-DFEATURE_DEBUG_FUNCTIONS"]
},
{
"label": "Linux / Debug",
"target": "linux",
"args": ["-debug", "-DFORCE_DEBUG_VERSION"]
"args": ["-debug", "-DFEATURE_DEBUG_FUNCTIONS"]
},
{
"label": "HashLink / Debug",
@@ -109,7 +109,7 @@
{
"label": "Windows / Debug (FlxAnimate Test)",
"target": "windows",
"args": ["-debug", "-DANIMATE", "-DFORCE_DEBUG_VERSION"]
"args": ["-debug", "-DANIMATE", "-DFEATURE_DEBUG_FUNCTIONS"]
},
{
"label": "HashLink / Debug (FlxAnimate Test)",
@@ -119,7 +119,7 @@
{
"label": "Windows / Debug (Straight to Freeplay)",
"target": "windows",
"args": ["-debug", "-DFREEPLAY", "-DFORCE_DEBUG_VERSION"]
"args": ["-debug", "-DFREEPLAY", "-DFEATURE_DEBUG_FUNCTIONS"]
},
{
"label": "HashLink / Debug (Straight to Freeplay)",
@@ -132,13 +132,13 @@
"args": [
"-debug",
"-DSONG=bopeebo -DDIFFICULTY=normal",
"-DFORCE_DEBUG_VERSION"
"-DFEATURE_DEBUG_FUNCTIONS"
]
},
{
"label": "Windows / Debug (Straight to Play - 2hot)",
"target": "windows",
"args": ["-debug", "-DSONG=2hot", "-DFORCE_DEBUG_VERSION"]
"args": ["-debug", "-DSONG=2hot", "-DFEATURE_DEBUG_FUNCTIONS"]
},
{
"label": "HashLink / Debug (Straight to Play - Bopeebo Normal)",
@@ -148,7 +148,7 @@
{
"label": "Windows / Debug (Conversation Test)",
"target": "windows",
"args": ["-debug", "-DDIALOGUE", "-DFORCE_DEBUG_VERSION"]
"args": ["-debug", "-DDIALOGUE", "-DFEATURE_DEBUG_FUNCTIONS"]
},
{
"label": "HashLink / Debug (Conversation Test)",
@@ -163,7 +163,7 @@
{
"label": "Windows / Debug (Straight to Chart Editor)",
"target": "windows",
"args": ["-debug", "-DCHARTING", "-DFORCE_DEBUG_VERSION"]
"args": ["-debug", "-DCHARTING", "-DFEATURE_DEBUG_FUNCTIONS"]
},
{
"label": "HashLink / Debug (Straight to Chart Editor)",
@@ -173,12 +173,12 @@
{
"label": "Windows / Debug (Straight to Animation Editor)",
"target": "windows",
"args": ["-debug", "-DANIMDEBUG", "-DFORCE_DEBUG_VERSION"]
"args": ["-debug", "-DANIMDEBUG", "-DFEATURE_DEBUG_FUNCTIONS"]
},
{
"label": "Windows / Debug (Debug hxCodec)",
"target": "windows",
"args": ["-debug", "-DHXC_LIBVLC_LOGGING", "-DFORCE_DEBUG_VERSION"]
"args": ["-debug", "-DHXC_LIBVLC_LOGGING", "-DFEATURE_DEBUG_FUNCTIONS"]
},
{
"label": "HashLink / Debug (Straight to Animation Editor)",
@@ -188,7 +188,7 @@
{
"label": "Windows / Debug (Latency Test)",
"target": "windows",
"args": ["-debug", "-DLATENCY", "-DFORCE_DEBUG_VERSION"]
"args": ["-debug", "-DLATENCY", "-DFEATURE_DEBUG_FUNCTIONS"]
},
{
"label": "HashLink / Debug (Latency Test)",
@@ -198,7 +198,7 @@
{
"label": "Windows / Debug (Waveform Test)",
"target": "windows",
"args": ["-debug", "-DWAVEFORM", "-DFORCE_DEBUG_VERSION"]
"args": ["-debug", "-DWAVEFORM", "-DFEATURE_DEBUG_FUNCTIONS"]
},
{
"label": "Windows / Release",
@@ -218,17 +218,17 @@
{
"label": "HTML5 / Debug",
"target": "html5",
"args": ["-debug", "-DFORCE_DEBUG_VERSION"]
"args": ["-debug", "-DFEATURE_DEBUG_FUNCTIONS"]
},
{
"label": "HTML5 / Debug (Watch)",
"target": "html5",
"args": ["-debug", "-watch", "-DFORCE_DEBUG_VERSION"]
"args": ["-debug", "-watch", "-DFEATURE_DEBUG_FUNCTIONS"]
},
{
"label": "macOS / Debug",
"target": "mac",
"args": ["-debug", "-DFORCE_DEBUG_VERSION"]
"args": ["-debug", "-DFEATURE_DEBUG_FUNCTIONS"]
},
{
"label": "macOS / Release",
+119 -11
View File
@@ -4,6 +4,112 @@ 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.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
- Bopeebo (Pico Mix)
- Fresh (Pico Mix)
- DadBattle (Pico Mix)
- Spookeez (Pico Mix)
- South (Pico Mix)
- Philly Nice (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
- Darnell (BF Mix)
- Added 2 new Erect remixes! Access them by switching difficulty on the song
- Cocoa Erect
- Ugh Erect
- Implemented support for a new Instrumental Selector in Freeplay
- Beating a Pico remix lets you use that instrumental when playing as Boyfriend
- Added the first batch of Erect Stages! These graphical overhauls of the original stages will be used when playing Erect remixes and Pico remixes
- Week 1 Erect Stage
- Week 2 Erect Stage
- Week 3 Erect Stage
- Week 4 Erect Stage
- Week 5 Erect Stage
- Weekend 1 Erect Stage
- Implemented alternate animations and music for Pico in the results screen.
- 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)
## 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!
- Altered how Week 6 displays sprites to make things look more retro.
- Character offsets are now independent of the character's scale.
- This should resolve issues with offsets when porting characters from older mods.
- Pixel character offsets have been modified to compensate.
- Note style data can now specify custom combo count graphics, judgement graphics, countdown graphics, and countdown audio. (community feature by anysad)
- These were previously using hardcoded values based on whether the stage was `school` or `schoolEvil`.
- The `danceEvery` property of characters and stage props can now use values with a precision of `0.25`, to play their idle animation up to four times per beat.
- Reworked the JSON merging system in Polymod; you can now include JSONPatch files under `_merge` in your mod folder to add, modify, or remove values in a JSON without replacing it entirely!
- Cutscenes now automatically pause when tabbing out (community fix by AbnormalPoof)
- Characters will now respect the `danceEvery` property (community fix by gamerbross)
- The F5 function now reloads the current song's chart data from disc (community feature by gamerbross)
- Refactored the compilation guide and added common troubleshooting steps (community fix by Hundrec)
- Made several layout improvements and fixes to the Animation Offsets editor in the Debug menu (community fix by gamerbross)
- Fixed a bug where the Back sound would be not played when leaving the Story menu and Options menu (community fix by AppleHair)
- Animation offsets no longer directly modify the `x` and `y` position of props, which makes props work better with tweens (community fix by Sword352)
- The YEAH! events in Tutorial now use chart events rather than being hard-coded (community fix by anysad)
- The player's Score now displays commas in it (community fix by loggo)
## Fixed
- Fixed an issue where songs with no notes would crash on the Results screen.
- Fixed an issue where the old icon easter egg would not work properly on pixel levels.
- Fixed an issue where you could play notes during the Thorns cutscene.
- Fixed an issue where the Heart icon when favoriting a song in Freeplay would be malformed.
- Fixed an issue where Pico's death animation displays a faint blue background (community fix by doggogit)
- Fixed an issue where mod songs would not play a preview in the Freeplay menu (community fix by KarimAkra)
- Fixed an issue where the Memory Usage counter could overflow and display a negative number (community fix by KarimAkra)
- Fixed an issue where pressing the Chart Editor keybind while playtesting a chart would reset the chart editor (community fix by gamerbross)
- Fixed a crash bug when pressing F5 after seeing the sticker transition (community fix by gamerbross)
- Fixed an issue where the Story Mode menu couldn't be scrolled with a mouse (community fix by JVNpixels)
- Fixed an issue causing the song to majorly desync sometimes (community fix by Burgerballs)
- Fixed an issue where the Freeplay song preview would not respect the instrumental ID specified in the song metadata (community fix by AppleHair)
- Fixed an issue where Tankman's icon wouldn't display in the Chart Editor (community fix by hundrec)
- Fixed an issue where pausing the game during a camera zoom would zoom the pause menu. (community fix by gamerbros)
- Fixed an issue where certain UI elements would not flash at a consistent rate (community fix by cyn0x8)
- Fixed an issue where the game would not use the placeholder health icon as a fallback (community fix by gamerbross)
- Fixed an issue where the chart editor could get stuck creating a hold note when using Live Inputs (community fix by gamerbross)
- Fixed an issue where character graphics could not be placed in week folders (community fix by 7oltan)
- Fixed a crash issue when a Freeplay song has no `Normal` difficulty (community fix by Applehair and gamerbross)
- Fixed an issue in Story Mode where a song that isn't valid for the current variation could be selected (community fix by Applehair)
## [0.4.1] - 2024-06-12
### Added
- Pressing ESCAPE on the title screen on desktop now exits the game, allowing you to exit the game while in fullscreen on desktop
- Freeplay menu controls (favoriting and switching categories) are now rebindable from the Options menu, and now have default binds on controllers.
### Changed
- Highscores and ranks are now saved separately, which fixes the issue where people would overwrite their saves with higher scores,
which would remove their rank if they had a lower one.
- A-Bot speaker now reacts to the user's volume preference on desktop (thanks to [M7theguy for the issue report/suggestion](https://github.com/FunkinCrew/Funkin/issues/2744)!)
- On Freeplay, heart icons are shifted to the right when you favorite a song that has no rank on it.
- Only play `scrollMenu` sound effect when there's a real change on the freeplay menu ([thanks gamerbross for the PR!](https://github.com/FunkinCrew/Funkin/pull/2741))
- Gave antialiasing to the edge of the dad graphic on Freeplay
- Rearranged some controls in the controls menu
- Made several chart revisions
- Re-enabled custom camera events in Roses (Erect/Nightmare)
- Tweaked the chart for Lit Up (Hard)
- Corrected the difficulty ratings for M.I.L.F. (Easy/Normal/Hard)
### Fixed
- Fixed an issue in the controls menu where some control binds would overlap their names
- Fixed crash when attempting to exit the gameover screen when also attempting to retry the song ([thanks DMMaster636 for the PR!](https://github.com/FunkinCrew/Funkin/pull/2709))
- Fix botplay sustain release bug ([thanks Hundrec!](Fix botplay sustain release bug #2683))
- Fix for the camera not pausing during a gameplay pause ([thanks gamerbross!](https://github.com/FunkinCrew/Funkin/pull/2684))
- Fixed issue where Pico's gameplay sprite would unintentionally appear on the gameover screen when dying on 2Hot from an explosion
- Freeplay previews properly fade volume during the BF idle animation
- Fixed bug where Dadbattle incorrectly appeared as Dadbattle Erect when returning to freeplay on Hard
- Fixed 2Hot not appearing under the "#" category in Freeplay menu
- Fixed a bug where the Chart Editor would crash when attempting to select an event with the Event toolbox open
- Improved offsets for Pico and Tankman opponents so they don't slide around as much.
- Fixed the black "temp" graphic on freeplay from being incorrectly sized / masked, now it's identical to the dad freeplay graphic
## [0.4.0] - 2024-06-06
### Added
- 2 new Erect remixes, Eggnog and Satin Panties. Check them out from the Freeplay menu!
@@ -32,27 +138,29 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Custom note styles are now properly supported for songs; add new notestyles via JSON, then select it for use from the Chart Editor Metadata toolbox. (thanks Keoiki!)
- Health icons now support a Winning frame without requiring a spritesheet, simply include a third frame in the icon file. (thanks gamerbross!)
- Remember that for more complex behaviors such as animations or transitions, you should use an XML file to define each frame.
- Improved the Event Toolbox in the Chart Editor; dropdowns are now bigger, include search field, and display elements in alphabetical order rather than a random order.
### Fixed
- Fixed an issue where Nene's visualizer would not play on Desktop builds
- Fixed a bug where the game would silently fail to load saves on HTML5
- Fixed some bugs with the props on the Story Menu not bopping properly
- Improved offsets for Pico and Tankman opponents so they don't slide around as much.
- Additional fixes to the Loading bar on HTML5 (thanks lemz1!)
- Fixed several bugs with the TitleState, including missing music when returning from the Main Menu (thanks gamerbross!)
- Fixed a camera bug in the Main Menu (thanks richTrash21!)
- Fixed a bug where changing difficulties in Story mode wouldn't update the score (thanks sectorA!)
- Fixed a crash in Freeplay caused by a level referencing an invalid song (thanks gamerbross!)
- Fixed a bug where pressing the volume keys would stop the Toy commercial (thanks gamerbross!)
- Fixed a bug where the Chart Editor Playtest would crash when losing (thanks gamerbross!)
- Fixed a bug where hold notes would display improperly in the Chart Editor when downscroll was enabled for gameplay (thanks gamerbross!)
- Fixed a bug where hold notes would be positioned wrong on downscroll (thanks MaybeMaru!)
- Removed a large number of unused imports to optimize builds (thanks Ethan-makes-music!)
- Improved debug logging for unscripted stages (thanks gamerbross!)
- Made improvements to compiling documentation (thanks gedehari!)
- Fixed a crash on Linux caused by an old version of hxCodec (thanks Noobz4Life!)
- Optimized animation handling for characters (thanks richTrash21!)
- Made improvements to compiling documentation (thanks gedehari!)
- Fixed a bug where pressing the volume keys would stop the Toy commercial (thanks gamerbross!)
- Fixed a bug where the Chart Editor Playtest would crash when losing (thanks gamerbross!)
- Removed a large number of unused imports to optimize builds (thanks Ethan-makes-music!)
- Fixed a bug where hold notes would be positioned wrong on downscroll (thanks MaybeMaru!)
- Additional fixes to the Loading bar on HTML5 (thanks lemz1!)
- Fixed a crash in Freeplay caused by a level referencing an invalid song (thanks gamerbross!)
- Improved debug logging for unscripted stages (thanks gamerbross!)
- Fixed a bug where changing difficulties in Story mode wouldn't update the score (thanks sectorA!)
- Fixed an issue where the Chart Editor would use an incorrect instrumental on imported Legacy songs (thanks gamerbross!)
- Fixed a camera bug in the Main Menu (thanks richTrash21!)
- Fixed several bugs with the TitleState, including missing music when returning from the Main Menu (thanks gamerbross!)
- Fixed a bug where opening the game from the command line would crash the preloader (thanks NotHyper474!)
- Fixed a bug where hold notes would display improperly in the Chart Editor when downscroll was enabled for gameplay (thanks gamerbross!)
- Fixed a bug where characters would sometimes use the wrong scale value (thanks PurSnake!)
- Additional bug fixes and optimizations.
-269
View File
@@ -1,269 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<project xmlns="http://lime.openfl.org/project/1.0.4" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://lime.openfl.org/project/1.0.4 http://lime.openfl.org/xsd/project-1.0.4.xsd">
<!-- _________________________ Application Settings _________________________ -->
<app title="Friday Night Funkin'" file="Funkin" packageName="com.funkin.fnf" package="com.funkin.fnf" main="Main" version="0.4.0" company="ninjamuffin99" />
<!--Switch Export with Unique ApplicationID and Icon-->
<set name="APP_ID" value="0x0100f6c013bbc000" />
<!--
Define the OpenFL sprite which displays the preloader.
You can't replace the preloader's logic here, sadly, but you can extend it.
Basic preloading logic is done by `openfl.display.Preloader`.
-->
<app preloader="funkin.ui.transition.preload.FunkinPreloader" />
<!--Minimum without FLX_NO_GAMEPAD: 11.8, without FLX_NO_NATIVE_CURSOR: 11.2-->
<set name="SWF_VERSION" value="11.8" />
<!-- ____________________________ Window Settings ___________________________ -->
<!--These window settings apply to all targets-->
<window width="1280" height="720" fps="60" background="#000000" hardware="true" vsync="false" />
<!--HTML5-specific-->
<window if="html5" resizable="true" />
<!--Desktop-specific-->
<window if="desktop" orientation="landscape" fullscreen="false" resizable="true" vsync="false" />
<!--Mobile-specific-->
<window if="mobile" orientation="landscape" fullscreen="true" width="0" height="0" resizable="false" />
<!-- _____________________________ Path Settings ____________________________ -->
<set name="BUILD_DIR" value="export/debug" if="debug" />
<set name="BUILD_DIR" value="export/release" unless="debug" />
<set name="BUILD_DIR" value="export/32bit" if="32bit" />
<source path="source" />
<assets path="assets/preload" rename="assets" exclude="*.ogg|*.wav" if="web" />
<assets path="assets/preload" rename="assets" exclude="*.mp3|*.wav" unless="web" />
<define name="PRELOAD_ALL" unless="web" />
<define name="NO_PRELOAD_ALL" unless="PRELOAD_ALL" />
<section if="PRELOAD_ALL">
<library name="songs" preload="true" />
<library name="shared" preload="true" />
<library name="tutorial" preload="true" />
<library name="week1" preload="true" />
<library name="week2" preload="true" />
<library name="week3" preload="true" />
<library name="week4" preload="true" />
<library name="week5" preload="true" />
<library name="week6" preload="true" />
<library name="week7" preload="true" />
<library name="weekend1" preload="true" />
<library name="videos" preload="true" />
</section>
<section if="NO_PRELOAD_ALL">
<library name="songs" preload="false" />
<library name="shared" preload="false" />
<library name="tutorial" preload="false" />
<library name="week1" preload="false" />
<library name="week2" preload="false" />
<library name="week3" preload="false" />
<library name="week4" preload="false" />
<library name="week5" preload="false" />
<library name="week6" preload="false" />
<library name="week7" preload="false" />
<library name="weekend1" preload="false" />
<library name="videos" preload="false" />
</section>
<library name="art" preload="false" />
<assets path="assets/songs" library="songs" exclude="*.fla|*.ogg|*.wav" if="web" />
<assets path="assets/songs" library="songs" exclude="*.fla|*.mp3|*.wav" unless="web" />
<!-- Videos go in their own library because web never needs to preload them, they can just be streamed. -->
<assets path="assets/videos" library="videos" />
<assets path="assets/shared" library="shared" exclude="*.fla|*.ogg|*.wav" if="web" />
<assets path="assets/shared" library="shared" exclude="*.fla|*.mp3|*.wav" unless="web" />
<assets path="assets/tutorial" library="tutorial" exclude="*.fla|*.ogg|*.wav" if="web" />
<assets path="assets/tutorial" library="tutorial" exclude="*.fla|*.mp3|*.wav" unless="web" />
<assets path="assets/week1" library="week1" exclude="*.fla|*.ogg|*.wav" if="web" />
<assets path="assets/week1" library="week1" exclude="*.fla|*.mp3|*.wav" unless="web" />
<assets path="assets/week2" library="week2" exclude="*.fla|*.ogg|*.wav" if="web" />
<assets path="assets/week2" library="week2" exclude="*.fla|*.mp3|*.wav" unless="web" />
<assets path="assets/week3" library="week3" exclude="*.fla|*.ogg|*.wav" if="web" />
<assets path="assets/week3" library="week3" exclude="*.fla|*.mp3|*.wav" unless="web" />
<assets path="assets/week4" library="week4" exclude="*.fla|*.ogg|*.wav" if="web" />
<assets path="assets/week4" library="week4" exclude="*.fla|*.mp3|*.wav" unless="web" />
<assets path="assets/week5" library="week5" exclude="*.fla|*.ogg|*.wav" if="web" />
<assets path="assets/week5" library="week5" exclude="*.fla|*.mp3|*.wav" unless="web" />
<assets path="assets/week6" library="week6" exclude="*.fla|*.ogg|*.wav" if="web" />
<assets path="assets/week6" library="week6" exclude="*.fla|*.mp3|*.wav" unless="web" />
<assets path="assets/week7" library="week7" exclude="*.fla|*.ogg|*.wav" if="web" />
<assets path="assets/week7" library="week7" exclude="*.fla|*.mp3|*.wav" unless="web" />
<assets path="assets/weekend1" library="weekend1" exclude="*.fla|*.ogg|*.wav" if="web" />
<assets path="assets/weekend1" library="weekend1" exclude="*.fla|*.mp3|*.wav" unless="web" />
<!-- <assets path='example_mods' rename='mods' embed='false'/> -->
<!--
AUTOMATICALLY MOVING EXAMPLE MODS INTO THE BUILD CAUSES ISSUES
Currently, this line will add the mod files to the library manifest,
which causes issues if the mod is not enabled.
If we can exclude the `mods` folder from the manifest, we can re-enable this line.
<assets path='example_mods' rename='mods' embed='false' exclude="*.md" />
-->
<assets path="art/readme.txt" rename="do NOT readme.txt" library="art"/>
<assets path="CHANGELOG.md" rename="changelog.txt" library="art"/>
<!-- NOTE FOR FUTURE SELF SINCE FONTS ARE ALWAYS FUCKY
TO FIX ONE OF THEM, I CONVERTED IT TO OTF. DUNNO IF YOU NEED TO
THEN UHHH I USED THE NAME OF THE FONT WITH SETFORMAT() ON THE TEXT!!!
NOT USING A DIRECT THING TO THE ASSET!!!
-->
<assets path="assets/fonts" embed="true" />
<!-- If compiled via github actions, show debug version number. -->
<define name="FORCE_DEBUG_VERSION" if="GITHUB_BUILD" />
<define name="NO_REDIRECT_ASSETS_FOLDER" if="GITHUB_BUILD" />
<define name="TOUCH_HERE_TO_PLAY" if="web" />
<!-- _______________________________ Libraries ______________________________ -->
<haxelib name="lime" /> <!-- Game engine backend -->
<haxelib name="openfl" /> <!-- Game engine backend -->
<haxelib name="flixel" /> <!-- Game engine -->
<haxedev set="webgl" />
<haxelib name="flixel-addons" /> <!-- Additional utilities for Flixel -->
<haxelib name="hscript" /> <!-- Scripting -->
<haxelib name="flixel-ui" /> <!-- UI framework (DEPRECATED) -->
<haxelib name="haxeui-core" /> <!-- UI framework -->
<haxelib name="haxeui-flixel" /> <!-- Integrate HaxeUI with Flixel -->
<haxelib name="flixel-text-input" /> <!-- Improved text field rendering for HaxeUI -->
<haxelib name="polymod" /> <!-- Modding framework -->
<haxelib name="flxanimate" /> <!-- Texture atlas rendering -->
<haxelib name="hxCodec" if="desktop" unless="hl" /> <!-- Video playback -->
<haxelib name="funkin.vis"/>
<haxelib name="grig.audio" />
<haxelib name="FlxPartialSound" /> <!-- Loading partial sound data -->
<haxelib name="json2object" /> <!-- JSON parsing -->
<haxelib name="thx.core" /> <!-- General utility library, "the lodash of Haxe" -->
<haxelib name="thx.semver" /> <!-- Version string handling -->
<haxelib name="hxcpp-debug-server" if="desktop debug" /> <!-- VSCode debug support -->
<!--Disable the Flixel core focus lost screen-->
<haxedef name="FLX_NO_FOCUS_LOST_SCREEN" />
<!--Disable the Flixel core debugger. Automatically gets set whenever you compile in release mode!-->
<haxedef name="FLX_NO_DEBUG" unless="debug || FORCE_DEBUG_VERSION" />
<!--Enable this for Nape release builds for a serious peformance improvement-->
<haxedef name="NAPE_RELEASE_BUILD" unless="debug" />
<!--
Hide deprecation warnings until they're fixed.
TODO: REMOVE THIS!!!!
<haxeflag name="-w" value="-WDeprecated" />
-->
<!-- Haxe 4.3.0+: Enable pretty syntax errors and stuff. -->
<haxedef name="message.reporting" value="pretty" />
<!-- _________________________________ Custom _______________________________ -->
<!-- Disable trace() calls in release builds to bump up performance.
<haxeflag name="- -no-traces" unless="debug" />-->
<!-- HScript relies heavily on Reflection, which means we can't use DCE. -->
<haxeflag name="-dce no" />
<!-- Ensure all Funkin' classes are available at runtime. -->
<haxeflag name="--macro" value="include('funkin')" />
<!-- Ensure all UI components are available at runtime. -->
<haxeflag name="--macro" value="include('haxe.ui.backend.flixel.components')" />
<haxeflag name="--macro" value="include('haxe.ui.containers.dialogs')" />
<haxeflag name="--macro" value="include('haxe.ui.containers.menus')" />
<haxeflag name="--macro" value="include('haxe.ui.containers.properties')" />
<haxeflag name="--macro" value="include('haxe.ui.core')" />
<haxeflag name="--macro" value="include('haxe.ui.components')" />
<haxeflag name="--macro" value="include('haxe.ui.containers')" />
<!--
Ensure additional class packages are available at runtime (some only really used by scripts).
Ignore packages we can't include.
-->
<haxeflag name="--macro" value="include('flixel', true, [ 'flixel.addons.editors.spine.*', 'flixel.addons.nape.*', 'flixel.system.macros.*' ])" />
<!-- Necessary to provide stack traces for HScript. -->
<haxedef name="hscriptPos" />
<haxedef name="safeMode"/>
<haxedef name="HXCPP_CHECK_POINTER" />
<haxedef name="HXCPP_STACK_LINE" />
<haxedef name="HXCPP_STACK_TRACE" />
<!-- This macro allows addition of new functionality to existing Flixel. -->
<haxeflag name="--macro" value="addMetadata('@:build(funkin.util.macro.FlxMacro.buildFlxBasic())', 'flixel.FlxBasic')" />
<!--Place custom nodes like icons here (higher priority to override the HaxeFlixel icon)-->
<icon path="art/icon16.png" size="16" />
<icon path="art/icon32.png" size="32" />
<icon path="art/icon64.png" size="64" />
<icon path="art/iconOG.png" />
<haxedef name="CAN_OPEN_LINKS" unless="switch" />
<haxedef name="CAN_CHEAT" if="switch debug" />
<!-- I don't remember what this is for. -->
<haxedef name="haxeui_no_mouse_reset" />
<!-- Clicking outside a dialog should deselect the current focused component. -->
<haxedef name="haxeui_focus_out_on_click" />
<!-- Required to use haxe.ui.backend.flixel.UIState with build macros. -->
<haxedef name="haxeui_dont_impose_base_class" />
<haxedef name="HARDCODED_CREDITS" />
<!-- Skip the Intro -->
<section if="debug">
<!-- Starts the game at the specified week, at the first song -->
<!-- <haxedef name="week" value="1" if="debug"/> -->
<!-- Starts the game at the specified song -->
<!-- <haxedef name="song" value="bopeebo" if="debug"/> -->
<!-- Difficulty, only used for week or song, defaults to 1 -->
<!-- <haxedef name="dif" value="2" if="debug"/> -->
</section>
<section if="newgrounds">
<!-- Enables Ng.core.verbose -->
<!-- <haxedef name="NG_VERBOSE" /> -->
<!-- Enables a NG debug session, so medals don't permently unlock -->
<!-- <haxedef name="NG_DEBUG" /> -->
<!-- pretends that the saved session Id was expired, forcing the reconnect prompt -->
<!-- <haxedef name="NG_FORCE_EXPIRED_SESSION" if="debug" /> -->
</section>
<!-- Uncomment this to wipe your input settings. -->
<!-- <haxedef name="CLEAR_INPUT_SAVE"/> -->
<section if="debug" unless="NO_REDIRECT_ASSETS_FOLDER || html5 || GITHUB_BUILD">
<!--
Use the parent assets folder rather than the exported one
No more will we accidentally undo our changes!
-->
<haxedef name="REDIRECT_ASSETS_FOLDER" />
</section>
<section>
<!--
This flag enables the popup/crashlog error handler.
However, it also messes with breakpoints on some platforms.
-->
<haxedef name="openfl-enable-handle-error" />
</section>
<!-- Run a script before and after building. -->
<prebuild haxe="source/Prebuild.hx"/> -->
<postbuild haxe="source/Postbuild.hx"/> -->
<!-- Enable this on platforms which do not support dropping files onto the window. -->
<haxedef name="FILE_DROP_UNSUPPORTED" if="mac" />
<section unless="FILE_DROP_UNSUPPORTED">
<haxedef name="FILE_DROP_SUPPORTED" />
</section>
<!-- Enable this on platforms which do not support the edsior views. -->
<haxedef name="CHART_EDITOR_UNSUPPORTED" if="web" />
<haxedef name="CHART_EDITOR_SUPPORTED" unless="web"/>
<!-- Options for Polymod -->
<section if="polymod">
<!-- Turns on additional debug logging. -->
<haxedef name="POLYMOD_DEBUG" value="true" if="debug" />
<!-- The file extension to use for script files. -->
<haxedef name="POLYMOD_SCRIPT_EXT" value=".hscript" />
<!-- Which asset library to use for scripts. -->
<haxedef name="POLYMOD_SCRIPT_LIBRARY" value="scripts" />
<!-- The base path from which scripts should be accessed. -->
<haxedef name="POLYMOD_ROOT_PATH" value="scripts/" />
<!-- Determines the subdirectory of the mod folder used for file appending. -->
<haxedef name="POLYMOD_APPEND_FOLDER" value="_append" />
<!-- Determines the subdirectory of the mod folder used for file merges. -->
<haxedef name="POLYMOD_MERGE_FOLDER" value="_merge" />
<!-- Determines the file in the mod folder used for metadata. -->
<haxedef name="POLYMOD_MOD_METADATA_FILE" value="_polymod_meta.json" />
<!-- Determines the file in the mod folder used for the icon. -->
<haxedef name="POLYMOD_MOD_ICON_FILE" value="_polymod_icon.png" />
</section>
</project>
+1 -1
View File
@@ -2,7 +2,7 @@
Friday Night Funkin' is a rhythm game. Built using HaxeFlixel for Ludum Dare 47.
This game was made with love to Newgrounds and it's community. Extra love to Tom Fulp.
This game was made with love to Newgrounds and its community. Extra love to Tom Fulp.
- [Playable web demo on Newgrounds!](https://www.newgrounds.com/portal/view/770371)
- [Demo download builds for Windows, Mac, and Linux from Itch.io!](https://ninja-muffin24.itch.io/funkin)
+1 -1
Submodule art updated: 66572f85d8...0dee03f11a
+1 -1
Submodule assets updated: 3b8235e953...bc7009b424
+3 -3
View File
@@ -83,7 +83,7 @@ apt-fast install -y --no-install-recommends \
libc6-dev libffi-dev \
libx11-dev libxi-dev libxext-dev libxinerama-dev libxrandr-dev \
libgl-dev libgl1-mesa-dev \
libasound2-dev \
libasound2-dev libpulse-dev \
libvlc-dev libvlccore-dev
EOF
@@ -137,8 +137,8 @@ ENV PATH="$HAXEPATH:$PATH"
RUN <<EOF
HOME=/etc haxelib setup "$HAXEPATH/lib"
haxelib --global --never install haxelib $haxelib_version
haxelib --global --never git haxelib https://github.com/HaxeFoundation/haxelib.git master
haxelib --global --never install hmm
haxelib --global --never git haxelib https://github.com/FunkinCrew/haxelib.git funkin-patches --skip-dependencies
haxelib --global --never git hmm https://github.com/FunkinCrew/hmm funkin-patches
EOF
# hxcpp
+2 -1
View File
@@ -327,7 +327,8 @@
"INLINE",
"DYNAMIC",
"FINAL"
]
],
"severity": "IGNORE"
},
"type": "ModifierOrder"
},
+35 -10
View File
@@ -2,13 +2,19 @@
0. Setup
- Download Haxe from [Haxe.org](https://haxe.org)
1. Cloning the Repository: Make sure when you clone, you clone the submodules to get the assets repo:
- `git clone --recurse-submodules https://github.com/FunkinCrew/funkin.git`
- If you accidentally cloned without the `assets` submodule (aka didn't follow the step above), you can run `git submodule update --init --recursive` to get the assets in a foolproof way.
2. Install `hmm` (run `haxelib --global install hmm` and then `haxelib --global run hmm setup`)
3. Install all haxelibs of the current branch by running `hmm install`
4. Setup lime: `haxelib run lime setup`
5. Platform setup
- Download Git from [git-scm.com](https://www.git-scm.com)
- Do NOT download the repository using the Download ZIP button on GitHub or you may run into errors!
- Instead, open a command prompt and do the following steps...
1. Run `cd the\directory\you\want\the\source\code\in` to specify which folder the command prompt is working in.
- For example, `cd C:\Users\YOURNAME\Documents` would instruct the command prompt to perform the next steps in your Documents folder.
2. Run `git clone https://github.com/FunkinCrew/funkin.git` to clone the base repository.
3. Run `cd funkin` to enter the cloned repository's directory.
4. Run `git submodule update --init --recursive` to download the game's assets.
- NOTE: By performing this operation, you are downloading Content which is proprietary and protected by national and international copyright and trademark laws. See [the LICENSE.md file for the Funkin.assets](https://github.com/FunkinCrew/funkin.assets/blob/main/LICENSE.md) repo for more information.
5. Run `haxelib --global install hmm` and then `haxelib --global run hmm setup` to install hmm.json
6. Run `hmm install` to install all haxelibs of the current branch
7. Run `haxelib run lime setup` to set up lime
8. Perform additional platform setup
- For Windows, download the [Visual Studio Build Tools](https://aka.ms/vs/17/release/vs_BuildTools.exe)
- When prompted, select "Individual Components" and make sure to download the following:
- MSVC v143 VS 2022 C++ x64/x86 build tools
@@ -16,9 +22,28 @@
- Mac: [`lime setup mac` Documentation](https://lime.openfl.org/docs/advanced-setup/macos/)
- Linux: [`lime setup linux` Documentation](https://lime.openfl.org/docs/advanced-setup/linux/)
- HTML5: Compiles without any extra setup
6. If you are targeting for native, you may need to run `lime rebuild PLATFORM` and `lime rebuild PLATFORM -debug`
7. `lime test PLATFORM` ! Add `-debug` to enable several debug features such as time travel (`PgUp`/`PgDn` in Play State).
9. If you are targeting for native, you may need to run `lime rebuild <PLATFORM>` and `lime rebuild <PLATFORM> -debug`
10. `lime test <PLATFORM>` to build and launch the game for your platform (for example, `lime test windows`)
# Troubleshooting
## Build Flags
There are several useful build flags you can add to a build to affect how it works. A full list can be found in `project.hxp`, but here's information on some of them:
- `-debug` to build the game in debug mode. This automatically enables several useful debug features.
- This includes enabling in-game debug functions, disables compile-time optimizations, enabling asset redirection (see below), and enabling the VSCode debug server (which can slow the game on some machines but allows for powerful debugging through breakpoints).
- `-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
- `-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_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!
- 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**.
+57 -30
View File
@@ -1,51 +1,53 @@
{
"dependencies": [
{
"name": "FlxPartialSound",
"type": "git",
"dir": null,
"ref": "a1eab7b9bf507b87200a3341719054fe427f3b15",
"url": "https://github.com/FunkinCrew/FlxPartialSound.git"
},
{
"name": "discord_rpc",
"type": "git",
"dir": null,
"ref": "2d83fa863ef0c1eace5f1cf67c3ac315d1a3a8a5",
"url": "https://github.com/Aidan63/linc_discord-rpc"
"url": "https://github.com/FunkinCrew/linc_discord-rpc"
},
{
"name": "flixel",
"type": "git",
"dir": null,
"ref": "a7d8e3bad89a0a3506a4714121f73d8e34522c49",
"ref": "f2b090d6c608471e730b051c8ee22b8b378964b1",
"url": "https://github.com/FunkinCrew/flixel"
},
{
"name": "flixel-addons",
"type": "git",
"dir": null,
"ref": "a523c3b56622f0640933944171efed46929e360e",
"ref": "9c6fb47968e894eb36bf10e94725cd7640c49281",
"url": "https://github.com/FunkinCrew/flixel-addons"
},
{
"name": "flixel-text-input",
"type": "haxelib",
"version": "1.1.0"
"type": "git",
"dir": null,
"ref": "951a0103a17bfa55eed86703ce50b4fb0d7590bc",
"url": "https://github.com/FunkinCrew/flixel-text-input"
},
{
"name": "flixel-ui",
"type": "git",
"dir": null,
"ref": "719b4f10d94186ed55f6fef1b6618d32abec8c15",
"ref": "27f1ba626f80a6282fa8a187115e79a4a2133dc2",
"url": "https://github.com/HaxeFlixel/flixel-ui"
},
{
"name": "flxanimate",
"type": "git",
"dir": null,
"ref": "17e0d59fdbc2b6283a5c0e4df41f1c7f27b71c49",
"url": "https://github.com/FunkinCrew/flxanimate"
},
{
"name": "FlxPartialSound",
"type": "git",
"dir": null,
"ref": "f986332ba5ab02abd386ce662578baf04904604a",
"url": "https://github.com/FunkinCrew/FlxPartialSound.git"
"ref": "0654797e5eb7cd7de0c1b2dbaa1efe5a1e1d9412",
"url": "https://github.com/Dot-Stuff/flxanimate"
},
{
"name": "format",
@@ -56,7 +58,7 @@
"name": "funkin.vis",
"type": "git",
"dir": null,
"ref": "38261833590773cb1de34ac5d11e0825696fc340",
"ref": "22b1ce089dd924f15cdc4632397ef3504d464e90",
"url": "https://github.com/FunkinCrew/funkVis"
},
{
@@ -75,20 +77,22 @@
"name": "haxeui-core",
"type": "git",
"dir": null,
"ref": "0212d8fdfcafeb5f0d5a41e1ddba8ff21d0e183b",
"ref": "22f7c5a8ffca90d4677cffd6e570f53761709fbc",
"url": "https://github.com/haxeui/haxeui-core"
},
{
"name": "haxeui-flixel",
"type": "git",
"dir": null,
"ref": "63a906a6148958dbfde8c7b48d90b0693767fd95",
"ref": "28bb710d0ae5d94b5108787593052165be43b980",
"url": "https://github.com/haxeui/haxeui-flixel"
},
{
"name": "hscript",
"type": "haxelib",
"version": "2.5.0"
"type": "git",
"dir": null,
"ref": "12785398e2f07082f05034cb580682e5671442a2",
"url": "https://github.com/FunkinCrew/hscript"
},
{
"name": "hxCodec",
@@ -99,8 +103,10 @@
},
{
"name": "hxcpp",
"type": "haxelib",
"version": "4.3.2"
"type": "git",
"dir": null,
"ref": "904ea40643b050a5a154c5e4c33a83fd2aec18b1",
"url": "https://github.com/HaxeFoundation/hxcpp"
},
{
"name": "hxcpp-debug-server",
@@ -109,10 +115,17 @@
"ref": "147294123f983e35f50a966741474438069a7a8f",
"url": "https://github.com/FunkinCrew/hxcpp-debugger"
},
{
"name": "hxjsonast",
"type": "git",
"dir": null,
"ref": "20e72cc68c823496359775ac1f06500e67f189d5",
"url": "https://github.com/nadako/hxjsonast/"
},
{
"name": "hxp",
"type": "haxelib",
"version": "1.2.2"
"version": "1.3.0"
},
{
"name": "json2object",
@@ -121,11 +134,25 @@
"ref": "a8c26f18463c98da32f744c214fe02273e1823fa",
"url": "https://github.com/FunkinCrew/json2object"
},
{
"name": "jsonpatch",
"type": "git",
"dir": null,
"ref": "f9b83215acd586dc28754b4ae7f69d4c06c3b4d3",
"url": "https://github.com/EliteMasterEric/jsonpatch"
},
{
"name": "jsonpath",
"type": "git",
"dir": null,
"ref": "7a24193717b36393458c15c0435bb7c4470ecdda",
"url": "https://github.com/EliteMasterEric/jsonpath"
},
{
"name": "lime",
"type": "git",
"dir": null,
"ref": "872ff6db2f2d27c0243d4ff76802121ded550dd7",
"ref": "fe3368f611a84a19afc03011353945ae4da8fffd",
"url": "https://github.com/FunkinCrew/lime"
},
{
@@ -160,29 +187,29 @@
"name": "openfl",
"type": "git",
"dir": null,
"ref": "228c1b5063911e2ad75cef6e3168ef0a4b9f9134",
"ref": "8306425c497766739510ab29e876059c96f77bd2",
"url": "https://github.com/FunkinCrew/openfl"
},
{
"name": "polymod",
"type": "git",
"dir": null,
"ref": "bfbe30d81601b3543d80dce580108ad6b7e182c7",
"ref": "0fbdf27fe124549730accd540cec8a183f8652c0",
"url": "https://github.com/larsiusprime/polymod"
},
{
"name": "thx.core",
"type": "git",
"dir": null,
"ref": "22605ff44f01971d599641790d6bae4869f7d9f4",
"url": "https://github.com/FunkinCrew/thx.core"
"ref": "76d87418fadd92eb8e1b61f004cff27d656e53dd",
"url": "https://github.com/fponticelli/thx.core"
},
{
"name": "thx.semver",
"type": "git",
"dir": null,
"ref": "cf8d213589a2c7ce4a59b0fdba9e8ff36bc029fa",
"url": "https://github.com/FunkinCrew/thx.semver"
"ref": "bdb191fe7cf745c02a980749906dbf22719e200b",
"url": "https://github.com/fponticelli/thx.semver"
}
]
}
+1109
View File
File diff suppressed because it is too large Load Diff
+8 -2
View File
@@ -22,7 +22,7 @@ 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
#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?
@@ -66,6 +66,12 @@ class Main extends Sprite
function init(?event:Event):Void
{
#if web
// set this variable (which is a function) from the lime version at lime/_internal/backend/html5/HTML5Application.hx
// The framerate cap will more thoroughly initialize via Preferences in InitState.hx
funkin.Preferences.lockedFramerateFunction = untyped js.Syntax.code("window.requestAnimationFrame");
#end
if (hasEventListener(Event.ADDED_TO_STAGE))
{
removeEventListener(Event.ADDED_TO_STAGE, init);
@@ -113,7 +119,7 @@ class Main extends Sprite
addChild(game);
#if debug
#if FEATURE_DEBUG_FUNCTIONS
game.debugger.interaction.addTool(new funkin.util.TrackerToolButtonUtil());
#end
+38
View File
@@ -0,0 +1,38 @@
package funkin;
/**
* 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
{
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);
}
public static function getBytes(path:String):haxe.io.Bytes
{
return openfl.utils.Assets.getBytes(path);
}
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>
{
return openfl.utils.Assets.list(type);
}
}
+26 -8
View File
@@ -1,5 +1,6 @@
package funkin;
import funkin.data.freeplay.player.PlayerRegistry;
import funkin.ui.debug.charting.ChartEditorState;
import funkin.ui.transition.LoadingState;
import flixel.FlxState;
@@ -18,6 +19,7 @@ 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;
@@ -26,13 +28,14 @@ import funkin.data.dialogue.speaker.SpeakerRegistry;
import funkin.data.freeplay.album.AlbumRegistry;
import funkin.data.song.SongRegistry;
import funkin.play.character.CharacterData.CharacterDataParser;
import funkin.play.notes.notekind.NoteKindManager;
import funkin.modding.module.ModuleHandler;
import funkin.ui.title.TitleState;
import funkin.util.CLIUtil;
import funkin.util.CLIUtil.CLIParams;
import funkin.util.TimerUtil;
import funkin.util.TrackerUtil;
#if discord_rpc
#if FEATURE_DISCORD_RPC
import Discord.DiscordClient;
#end
@@ -121,7 +124,7 @@ class InitState extends FlxState
//
// DISCORD API SETUP
//
#if discord_rpc
#if FEATURE_DISCORD_RPC
DiscordClient.initialize();
Application.current.onExit.add(function(exitCode) {
@@ -142,7 +145,7 @@ class InitState extends FlxState
// Plugins provide a useful interface for globally active Flixel objects,
// that receive update events regardless of the current state.
// TODO: Move scripted Module behavior to a Flixel plugin.
#if debug
#if FEATURE_DEBUG_FUNCTIONS
funkin.util.plugins.MemoryGCPlugin.initialize();
#end
funkin.util.plugins.EvacuateDebugPlugin.initialize();
@@ -164,9 +167,11 @@ class InitState extends FlxState
SongRegistry.instance.loadEntries();
LevelRegistry.instance.loadEntries();
NoteStyleRegistry.instance.loadEntries();
PlayerRegistry.instance.loadEntries();
ConversationRegistry.instance.loadEntries();
DialogueBoxRegistry.instance.loadEntries();
SpeakerRegistry.instance.loadEntries();
FreeplayStyleRegistry.instance.loadEntries();
AlbumRegistry.instance.loadEntries();
StageRegistry.instance.loadEntries();
@@ -174,6 +179,8 @@ class InitState extends FlxState
// Move it to use a BaseRegistry.
CharacterDataParser.loadCharacterCache();
NoteKindManager.loadScripts();
ModuleHandler.buildModuleCallbacks();
ModuleHandler.loadModuleCache();
ModuleHandler.callOnCreate();
@@ -218,9 +225,10 @@ class InitState extends FlxState
// -DRESULTS
FlxG.switchState(() -> new funkin.play.ResultState(
{
storyMode: false,
storyMode: true,
title: "Cum Song Erect by Kawai Sprite",
songId: "cum",
characterId: "pico-playable",
difficultyId: "nightmare",
isNewHighscore: true,
scoreData:
@@ -236,8 +244,13 @@ class InitState extends FlxState
combo: 69,
maxCombo: 69,
totalNotesHit: 140,
totalNotes: 200 // 0,
totalNotes: 190
}
// 2400 total notes = 7% = LOSS
// 240 total notes = 79% = GOOD
// 230 total notes = 82% = GREAT
// 210 total notes = 91% = EXCELLENT
// 190 total notes = PERFECT
},
}));
#elseif ANIMDEBUG
@@ -363,11 +376,16 @@ class InitState extends FlxState
//
// FLIXEL DEBUG SETUP
//
#if (debug || FORCE_DEBUG_VERSION)
// Make errors and warnings less annoying.
// Forcing this always since I have never been happy to have the debugger to pop up
#if FEATURE_DEBUG_FUNCTIONS
trace('Initializing Flixel debugger...');
#if !debug
// Make errors less annoying on release builds.
LogStyle.ERROR.openConsole = false;
LogStyle.ERROR.errorSound = null;
#end
// Make errors and warnings less annoying.
LogStyle.WARNING.openConsole = false;
LogStyle.WARNING.errorSound = null;
+9 -2
View File
@@ -11,9 +11,16 @@ class Paths
{
static var currentLevel:Null<String> = null;
public static function setCurrentLevel(name:String):Void
public static function setCurrentLevel(name:Null<String>):Void
{
currentLevel = name.toLowerCase();
if (name == null)
{
currentLevel = null;
}
else
{
currentLevel = name.toLowerCase();
}
}
public static function stripLibrary(path:String):String
+53
View File
@@ -128,6 +128,48 @@ class Preferences
return value;
}
public static var unlockedFramerate(get, set):Bool;
static function get_unlockedFramerate():Bool
{
return Save?.instance?.options?.unlockedFramerate;
}
static function set_unlockedFramerate(value:Bool):Bool
{
if (value != Save.instance.options.unlockedFramerate)
{
#if web
toggleFramerateCap(value);
#end
}
var save:Save = Save.instance;
save.options.unlockedFramerate = value;
save.flush();
return value;
}
#if web
// We create a haxe version of this just for readability.
// We use these to override `window.requestAnimationFrame` in Javascript to uncap the framerate / "animation" request rate
// Javascript is crazy since u can just do stuff like that lol
public static function unlockedFramerateFunction(callback, element)
{
var currTime = Date.now().getTime();
var timeToCall = 0;
var id = js.Browser.window.setTimeout(function() {
callback(currTime + timeToCall);
}, timeToCall);
return id;
}
// Lime already implements their own little framerate cap, so we can just use that
// This also gets set in the init function in Main.hx, since we need to definitely override it
public static var lockedFramerateFunction = untyped js.Syntax.code("window.requestAnimationFrame");
#end
/**
* Loads the user's preferences from the save data and apply them.
*/
@@ -137,6 +179,17 @@ class Preferences
FlxG.autoPause = Preferences.autoPause;
// Apply the debugDisplay setting (enables the FPS and RAM display).
toggleDebugDisplay(Preferences.debugDisplay);
#if web
toggleFramerateCap(Preferences.unlockedFramerate);
#end
}
static function toggleFramerateCap(unlocked:Bool):Void
{
#if web
var framerateFunction = unlocked ? unlockedFramerateFunction : lockedFramerateFunction;
untyped js.Syntax.code("window.requestAnimationFrame = framerateFunction;");
#end
}
static function toggleDebugDisplay(show:Bool):Void
+2 -2
View File
@@ -1,13 +1,13 @@
package funkin.api.discord;
import Sys.sleep;
#if discord_rpc
#if FEATURE_DISCORD_RPC
import discord_rpc.DiscordRpc;
#end
class DiscordClient
{
#if discord_rpc
#if FEATURE_DISCORD_RPC
public function new()
{
trace("Discord Client starting...");
+3 -3
View File
@@ -24,7 +24,7 @@ class NGUnsafe
NG.core.calls.event.logEvent(event).send();
trace('should have logged: ' + event);
#else
#if debug
#if FEATURE_DEBUG_FUNCTIONS
trace('event:$event - not logged, missing NG.io lib');
#end
#end
@@ -39,7 +39,7 @@ class NGUnsafe
if (!medal.unlocked) medal.sendUnlock();
}
#else
#if debug
#if FEATURE_DEBUG_FUNCTIONS
trace('medal:$id - not unlocked, missing NG.io lib');
#end
#end
@@ -63,7 +63,7 @@ class NGUnsafe
}
}
#else
#if debug
#if FEATURE_DEBUG_FUNCTIONS
trace('Song:$song, Score:$score - not posted, missing NG.io lib');
#end
#end
+3 -3
View File
@@ -239,7 +239,7 @@ class NGio
NG.core.calls.event.logEvent(event).send();
trace('should have logged: ' + event);
#else
#if debug
#if FEATURE_DEBUG_FUNCTIONS
trace('event:$event - not logged, missing NG.io lib');
#end
#end
@@ -254,7 +254,7 @@ class NGio
if (!medal.unlocked) medal.sendUnlock();
}
#else
#if debug
#if FEATURE_DEBUG_FUNCTIONS
trace('medal:$id - not unlocked, missing NG.io lib');
#end
#end
@@ -278,7 +278,7 @@ class NGio
}
}
#else
#if debug
#if FEATURE_DEBUG_FUNCTIONS
trace('Song:$song, Score:$score - not posted, missing NG.io lib');
#end
#end
+22 -7
View File
@@ -227,12 +227,12 @@ class FunkinSound extends FlxSound implements ICloneable<FunkinSound>
// already paused before we lost focus.
if (_lostFocus && !_alreadyPaused)
{
trace('Resuming audio (${this._label}) on focus!');
// trace('Resuming audio (${this._label}) on focus!');
resume();
}
else
{
trace('Not resuming audio (${this._label}) on focus!');
// trace('Not resuming audio (${this._label}) on focus!');
}
_lostFocus = false;
}
@@ -242,7 +242,7 @@ class FunkinSound extends FlxSound implements ICloneable<FunkinSound>
*/
override function onFocusLost():Void
{
trace('Focus lost, pausing audio!');
// trace('Focus lost, pausing audio!');
_lostFocus = true;
_alreadyPaused = _paused;
pause();
@@ -340,6 +340,8 @@ class FunkinSound extends FlxSound implements ICloneable<FunkinSound>
if (songMusicData != null)
{
Conductor.instance.mapTimeChanges(songMusicData.timeChanges);
if (songMusicData.looped != null && params.loop == null) params.loop = songMusicData.looped;
}
else
{
@@ -388,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);
var music = FunkinSound.load(pathToUse, params?.startingVolume ?? 1.0, params.loop ?? true, false, true, params.onComplete);
if (music != null)
{
FlxG.sound.music = music;
@@ -396,6 +398,8 @@ class FunkinSound extends FlxSound implements ICloneable<FunkinSound>
// Prevent repeat update() and onFocus() calls.
FlxG.sound.list.remove(FlxG.sound.music);
if (FlxG.sound.music != null && params.onLoad != null) params.onLoad();
return true;
}
else
@@ -491,8 +495,10 @@ class FunkinSound extends FlxSound implements ICloneable<FunkinSound>
var promise:lime.app.Promise<Null<FunkinSound>> = new lime.app.Promise<Null<FunkinSound>>();
// split the path and get only after first :
// we are bypassing the openfl/lime asset library fuss
// we are bypassing the openfl/lime asset library fuss on web only
#if web
path = Paths.stripLibrary(path);
#end
var soundRequest = FlxPartialSound.partialLoadFromFile(path, start, end);
@@ -533,11 +539,12 @@ class FunkinSound extends FlxSound implements ICloneable<FunkinSound>
* Play a sound effect once, then destroy it.
* @param key
* @param volume
* @return static function construct():FunkinSound
* @return A `FunkinSound` object, or `null` if the sound could not be loaded.
*/
public static function playOnce(key:String, volume:Float = 1.0, ?onComplete:Void->Void, ?onLoad:Void->Void):Void
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);
return result;
}
/**
@@ -562,6 +569,14 @@ class FunkinSound extends FlxSound implements ICloneable<FunkinSound>
return sound;
}
/**
* Produces a string representation suitable for debugging.
*/
public override function toString():String
{
return 'FunkinSound(${this._label})';
}
}
/**
+5
View File
@@ -113,6 +113,11 @@ class SoundGroup extends FlxTypedGroup<FunkinSound>
public function play(forceRestart:Bool = false, startTime:Float = 0.0, ?endTime:Float)
{
forEachAlive(function(sound:FunkinSound) {
if (sound.length < startTime)
{
// trace('Queuing sound (${sound.toString()} past its length! Skipping...)');
return;
}
sound.play(forceRestart, startTime, endTime);
});
}
+8 -2
View File
@@ -54,12 +54,12 @@ class ABotVis extends FlxTypedSpriteGroup<FlxSprite>
public function initAnalyzer()
{
@:privateAccess
analyzer = new SpectralAnalyzer(snd._channel.__source, 7, 0.1, 30);
analyzer = new SpectralAnalyzer(snd._channel.__audioSource, 7, 0.1, 40);
#if desktop
// On desktop it uses FFT stuff that isn't as optimized as the direct browser stuff we use on HTML5
// So we want to manually change it!
analyzer.fftN = 512;
analyzer.fftN = 256;
#end
// analyzer.maxDb = -35;
@@ -101,6 +101,12 @@ class ABotVis extends FlxTypedSpriteGroup<FlxSprite>
{
var animFrame:Int = Math.round(levels[i].value * 5);
#if desktop
// Web version scales with the Flixel volume level.
// This line brings platform parity but looks worse.
// animFrame = Math.round(animFrame * FlxG.sound.volume);
#end
animFrame = Math.floor(Math.min(5, animFrame));
animFrame = Math.floor(Math.max(0, animFrame));
+1 -1
View File
@@ -117,7 +117,7 @@ class VisShit
{
// Math.pow3
@:privateAccess
var buf = snd._channel.__source.buffer;
var buf = snd._channel.__audioSource.buffer;
// @:privateAccess
audioData = cast buf.data; // jank and hacky lol! kinda busted on HTML5 also!!
@@ -16,7 +16,7 @@ class WaveformDataParser
// Method 1. This only works if the sound has been played before.
@:privateAccess
var soundBuffer:Null<lime.media.AudioBuffer> = sound?._channel?.__source?.buffer;
var soundBuffer:Null<lime.media.AudioBuffer> = sound?._channel?.__audioSource?.buffer;
if (soundBuffer == null)
{
+1 -1
View File
@@ -263,7 +263,7 @@ abstract class BaseRegistry<T:(IRegistryEntry<J> & Constructible<EntryConstructo
* @param version The entry's version (use `fetchEntryVersion(id)`).
* @return The created entry.
*/
public function parseEntryDataWithMigration(id:String, version:thx.semver.Version):Null<J>
public function parseEntryDataWithMigration(id:String, version:Null<thx.semver.Version>):Null<J>
{
if (version == null)
{
@@ -46,7 +46,7 @@ class SongEventRegistry
if (event != null)
{
trace(' Loaded built-in song event: (${event.id})');
trace(' Loaded built-in song event: ${event.id}');
eventCache.set(event.id, event);
}
else
@@ -59,9 +59,9 @@ class SongEventRegistry
static function registerScriptedEvents()
{
var scriptedEventClassNames:Array<String> = ScriptedSongEvent.listScriptClasses();
trace('Instantiating ${scriptedEventClassNames.length} scripted song events...');
if (scriptedEventClassNames == null || scriptedEventClassNames.length == 0) return;
trace('Instantiating ${scriptedEventClassNames.length} scripted song events...');
for (eventCls in scriptedEventClassNames)
{
var event:SongEvent = ScriptedSongEvent.init(eventCls, "UKNOWN");
@@ -0,0 +1,9 @@
# Freeplay Playable Character Data Schema Changelog
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.0]
Initial release.
@@ -0,0 +1,380 @@
package funkin.data.freeplay.player;
import funkin.data.animation.AnimationData;
@:nullSafety
class PlayerData
{
/**
* The sematic version number of the player data JSON format.
* Supports fancy comparisons like NPM does it's neat.
*/
@:default(funkin.data.freeplay.player.PlayerRegistry.PLAYER_DATA_VERSION)
public var version:String;
/**
* A readable name for this playable character.
*/
public var name:String = 'Unknown';
/**
* The character IDs this character is associated with.
* Only songs that use these characters will show up in Freeplay.
*/
@:default([])
public var ownedChars:Array<String> = [];
/**
* Whether to show songs with character IDs that aren't associated with any specific character.
*/
@:optional
@:default(false)
public var showUnownedChars:Bool = false;
/**
* Which freeplay style to use for this character.
*/
@:optional
@:default("bf")
public var freeplayStyle:String = Constants.DEFAULT_FREEPLAY_STYLE;
/**
* Data for displaying this character in the Freeplay menu.
* If null, display no DJ.
*/
@:optional
public var freeplayDJ:Null<PlayerFreeplayDJData> = null;
/**
* Data for displaying this character in the Character Select menu.
* If null, exclude from Character Select.
*/
@:optional
public var charSelect:Null<PlayerCharSelectData> = null;
/**
* Data for displaying this character in the results screen.
*/
@:optional
public var results:Null<PlayerResultsData> = null;
/**
* Whether this character is unlocked by default.
* Use a ScriptedPlayableCharacter to add custom logic.
*/
@:optional
@:default(true)
public var unlocked:Bool = true;
public function new()
{
this.version = PlayerRegistry.PLAYER_DATA_VERSION;
}
/**
* Convert this StageData into a JSON string.
*/
public function serialize(pretty:Bool = true):String
{
// Update generatedBy and version before writing.
updateVersionToLatest();
var writer = new json2object.JsonWriter<PlayerData>();
return writer.write(this, pretty ? ' ' : null);
}
public function updateVersionToLatest():Void
{
this.version = PlayerRegistry.PLAYER_DATA_VERSION;
}
}
class PlayerFreeplayDJData
{
var assetPath:String;
var animations:Array<AnimationData>;
@:optional
@:default("BOYFRIEND")
var text1:String;
@:optional
@:default("HOT BLOODED IN MORE WAYS THAN ONE")
var text2:String;
@:optional
@:default("PROTECT YO NUTS")
var text3:String;
@:jignored
var animationMap:Map<String, AnimationData>;
@:jignored
var prefixToOffsetsMap:Map<String, Array<Float>>;
@:optional
var charSelect:Null<PlayerFreeplayDJCharSelectData>;
@:optional
var cartoon:Null<PlayerFreeplayDJCartoonData>;
@:optional
var fistPump:Null<PlayerFreeplayDJFistPumpData>;
public function new()
{
animationMap = new Map();
}
function mapAnimations()
{
if (animationMap == null) animationMap = new Map();
if (prefixToOffsetsMap == null) prefixToOffsetsMap = new Map();
animationMap.clear();
prefixToOffsetsMap.clear();
for (anim in animations)
{
animationMap.set(anim.name, anim);
prefixToOffsetsMap.set(anim.prefix, anim.offsets);
}
}
public function getAtlasPath():String
{
return Paths.animateAtlas(assetPath);
}
public function getFreeplayDJText(index:Int):String
{
switch (index)
{
case 1:
return text1;
case 2:
return text2;
case 3:
return text3;
default:
return '';
}
}
public function getAnimationPrefix(name:String):Null<String>
{
if (animationMap.size() == 0) mapAnimations();
var anim = animationMap.get(name);
if (anim == null) return null;
return anim.prefix;
}
public function getAnimationOffsetsByPrefix(?prefix:String):Array<Float>
{
if (prefixToOffsetsMap.size() == 0) mapAnimations();
if (prefix == null) return [0, 0];
return prefixToOffsetsMap.get(prefix);
}
public function getAnimationOffsets(name:String):Array<Float>
{
return getAnimationOffsetsByPrefix(getAnimationPrefix(name));
}
// TODO: These should really be frame labels, ehe.
public function getCartoonSoundClickFrame():Int
{
return cartoon?.soundClickFrame ?? 80;
}
public function getCartoonSoundCartoonFrame():Int
{
return cartoon?.soundCartoonFrame ?? 85;
}
public function getCartoonLoopBlinkFrame():Int
{
return cartoon?.loopBlinkFrame ?? 112;
}
public function getCartoonLoopFrame():Int
{
return cartoon?.loopFrame ?? 166;
}
public function getCartoonChannelChangeFrame():Int
{
return cartoon?.channelChangeFrame ?? 60;
}
public function getFistPumpIntroStartFrame():Int
{
return fistPump?.introStartFrame ?? 0;
}
public function getFistPumpIntroEndFrame():Int
{
return fistPump?.introEndFrame ?? 0;
}
public function getFistPumpLoopStartFrame():Int
{
return fistPump?.loopStartFrame ?? 0;
}
public function getFistPumpLoopEndFrame():Int
{
return fistPump?.loopEndFrame ?? 0;
}
public function getFistPumpIntroBadStartFrame():Int
{
return fistPump?.introBadStartFrame ?? 0;
}
public function getFistPumpIntroBadEndFrame():Int
{
return fistPump?.introBadEndFrame ?? 0;
}
public function getFistPumpLoopBadStartFrame():Int
{
return fistPump?.loopBadStartFrame ?? 0;
}
public function getFistPumpLoopBadEndFrame():Int
{
return fistPump?.loopBadEndFrame ?? 0;
}
public function getCharSelectTransitionDelay():Float
{
return charSelect?.transitionDelay ?? 0.25;
}
}
class PlayerCharSelectData
{
/**
* A zero-indexed number for the character's preferred position in the grid.
* 0 = top left, 4 = center, 8 = bottom right
* In the event of a conflict, the first character alphabetically gets it,
* and others get shifted over.
*/
@:optional
public var position:Null<Int>;
}
typedef PlayerResultsData =
{
var music:PlayerResultsMusicData;
var perfect:Array<PlayerResultsAnimationData>;
var excellent:Array<PlayerResultsAnimationData>;
var great:Array<PlayerResultsAnimationData>;
var good:Array<PlayerResultsAnimationData>;
var loss:Array<PlayerResultsAnimationData>;
};
typedef PlayerResultsMusicData =
{
@:optional
var PERFECT_GOLD:String;
@:optional
var PERFECT:String;
@:optional
var EXCELLENT:String;
@:optional
var GREAT:String;
@:optional
var GOOD:String;
@:optional
var SHIT:String;
}
typedef PlayerResultsAnimationData =
{
/**
* `sparrow` or `animate` or whatever
*/
var renderType:String;
var assetPath:String;
@:optional
@:default([0, 0])
var offsets:Array<Float>;
@:optional
@:default(500)
var zIndex:Int;
@:optional
@:default(0.0)
var delay:Float;
@:optional
@:default(1.0)
var scale:Float;
@:optional
@:default('')
var startFrameLabel:Null<String>;
@:optional
@:default(true)
var looped:Bool;
@:optional
var loopFrame:Null<Int>;
@:optional
var loopFrameLabel:Null<String>;
};
typedef PlayerFreeplayDJCharSelectData =
{
var transitionDelay:Float;
}
typedef PlayerFreeplayDJCartoonData =
{
var soundClickFrame:Int;
var soundCartoonFrame:Int;
var loopBlinkFrame:Int;
var loopFrame:Int;
var channelChangeFrame:Int;
}
typedef PlayerFreeplayDJFistPumpData =
{
@:default(0)
var introStartFrame:Int;
@:default(4)
var introEndFrame:Int;
@:default(4)
var loopStartFrame:Int;
@:default(-1)
var loopEndFrame:Int;
@:default(0)
var introBadStartFrame:Int;
@:default(4)
var introBadEndFrame:Int;
@:default(4)
var loopBadStartFrame:Int;
@:default(-1)
var loopBadEndFrame:Int;
};
@@ -0,0 +1,208 @@
package funkin.data.freeplay.player;
import funkin.data.freeplay.player.PlayerData;
import funkin.ui.freeplay.charselect.PlayableCharacter;
import funkin.ui.freeplay.charselect.ScriptedPlayableCharacter;
import funkin.save.Save;
class PlayerRegistry extends BaseRegistry<PlayableCharacter, PlayerData>
{
/**
* The current version string for the stage data format.
* Handle breaking changes by incrementing this value
* and adding migration to the `migratePlayerData()` function.
*/
public static final PLAYER_DATA_VERSION:thx.semver.Version = "1.0.0";
public static final PLAYER_DATA_VERSION_RULE:thx.semver.VersionRule = "1.0.x";
public static var instance(get, never):PlayerRegistry;
static var _instance:Null<PlayerRegistry> = null;
static function get_instance():PlayerRegistry
{
if (_instance == null) _instance = new PlayerRegistry();
return _instance;
}
/**
* A mapping between stage character IDs and Freeplay playable character IDs.
*/
var ownedCharacterIds:Map<String, String> = [];
public function new()
{
super('PLAYER', 'players', PLAYER_DATA_VERSION_RULE);
}
public override function loadEntries():Void
{
super.loadEntries();
for (playerId in listEntryIds())
{
var player = fetchEntry(playerId);
if (player == null) continue;
var currentPlayerCharIds = player.getOwnedCharacterIds();
for (characterId in currentPlayerCharIds)
{
ownedCharacterIds.set(characterId, playerId);
}
}
log('Loaded ${countEntries()} playable characters with ${ownedCharacterIds.size()} associations.');
}
public function countUnlockedCharacters():Int
{
var count = 0;
for (charId in listEntryIds())
{
var player = fetchEntry(charId);
if (player == null) continue;
if (player.isUnlocked()) count++;
}
return count;
}
public function hasNewCharacter():Bool
{
var charactersSeen = Save.instance.charactersSeen.clone();
for (charId in listEntryIds())
{
var player = fetchEntry(charId);
if (player == null) continue;
if (!player.isUnlocked()) continue;
if (charactersSeen.contains(charId)) continue;
// This character is unlocked but we haven't seen them in Freeplay yet.
return true;
}
// Fallthrough case.
return false;
}
public function listNewCharacters():Array<String>
{
var charactersSeen = Save.instance.charactersSeen.clone();
var result = [];
for (charId in listEntryIds())
{
var player = fetchEntry(charId);
if (player == null) continue;
if (!player.isUnlocked()) continue;
if (charactersSeen.contains(charId)) continue;
// This character is unlocked but we haven't seen them in Freeplay yet.
result.push(charId);
}
return result;
}
/**
* Get the playable character associated with a given stage character.
* @param characterId The stage character ID.
* @return The playable character.
*/
public function getCharacterOwnerId(characterId:Null<String>):Null<String>
{
if (characterId == null) return null;
return ownedCharacterIds[characterId];
}
/**
* Return true if the given stage character is associated with a specific playable character.
* If so, the level should only appear if that character is selected in Freeplay.
* @param characterId The stage character ID.
* @return Whether the character is owned by any one character.
*/
public function isCharacterOwned(characterId:String):Bool
{
return ownedCharacterIds.exists(characterId);
}
/**
* Read, parse, and validate the JSON data and produce the corresponding data object.
*/
public function parseEntryData(id:String):Null<PlayerData>
{
// JsonParser does not take type parameters,
// otherwise this function would be in BaseRegistry.
var parser = new json2object.JsonParser<PlayerData>();
parser.ignoreUnknownVariables = false;
switch (loadEntryFile(id))
{
case {fileName: fileName, contents: contents}:
parser.fromJson(contents, fileName);
default:
return null;
}
if (parser.errors.length > 0)
{
printErrors(parser.errors, id);
return null;
}
return parser.value;
}
/**
* Parse and validate the JSON data and produce the corresponding data object.
*
* NOTE: Must be implemented on the implementation class.
* @param contents The JSON as a string.
* @param fileName An optional file name for error reporting.
*/
public function parseEntryDataRaw(contents:String, ?fileName:String):Null<PlayerData>
{
var parser = new json2object.JsonParser<PlayerData>();
parser.ignoreUnknownVariables = false;
parser.fromJson(contents, fileName);
if (parser.errors.length > 0)
{
printErrors(parser.errors, fileName);
return null;
}
return parser.value;
}
function createScriptedEntry(clsName:String):PlayableCharacter
{
return ScriptedPlayableCharacter.init(clsName, "unknown");
}
function getScriptedClassNames():Array<String>
{
return ScriptedPlayableCharacter.listScriptClasses();
}
/**
* A list of all the playable characters from the base game, in order.
*/
public function listBaseGamePlayerIds():Array<String>
{
return ["bf", "pico"];
}
/**
* A list of all installed playable characters that are not from the base game.
*/
public function listModdedPlayerIds():Array<String>
{
return listEntryIds().filter(function(id:String):Bool {
return listBaseGamePlayerIds().indexOf(id) == -1;
});
}
}
@@ -0,0 +1,9 @@
# Freeplay Style Data Schema Changelog
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.0]
Initial release.
@@ -0,0 +1,48 @@
package funkin.data.freeplay.style;
import funkin.data.animation.AnimationData;
/**
* A type definition for the data for an album of songs.
* It includes things like what graphics to display in Freeplay.
* @see https://lib.haxe.org/p/json2object/
*/
typedef FreeplayStyleData =
{
/**
* Semantic version for style data.
*/
public var version:String;
/**
* Asset key for the background image.
*/
public var bgAsset:String;
/**
* Asset key for the difficulty selector image.
*/
public var selectorAsset:String;
/**
* Asset key for the numbers shown at the top right of the screen.
*/
public var numbersAsset:String;
/**
* Asset key for the freeplay capsules.
*/
public var capsuleAsset:String;
/**
* Color data for the capsule text outline.
* the order of this array goes as follows: [DESELECTED, SELECTED]
*/
public var capsuleTextColors:Array<String>;
/**
* Delay time after confirming a song selection, before entering PlayState.
* Useful for letting longer animations play out.
*/
public var startDelay:Float;
}
@@ -0,0 +1,84 @@
package funkin.data.freeplay.style;
import funkin.ui.freeplay.FreeplayStyle;
import funkin.data.freeplay.style.FreeplayStyleData;
import funkin.ui.freeplay.ScriptedFreeplayStyle;
class FreeplayStyleRegistry extends BaseRegistry<FreeplayStyle, FreeplayStyleData>
{
/**
* The current version string for the style data format.
* Handle breaking changes by incrementing this value
* and adding migration to the `migrateStyleData()` function.
*/
public static final FREEPLAYSTYLE_DATA_VERSION:thx.semver.Version = '1.0.0';
public static final FREEPLAYSTYLE_DATA_VERSION_RULE:thx.semver.VersionRule = '1.0.x';
public static final instance:FreeplayStyleRegistry = new FreeplayStyleRegistry();
public function new()
{
super('FREEPLAYSTYLE', 'ui/freeplay/styles', FREEPLAYSTYLE_DATA_VERSION_RULE);
}
/**
* Read, parse, and validate the JSON data and produce the corresponding data object.
* @param id The ID of the entry to load.
* @return The parsed data object.
*/
public function parseEntryData(id:String):Null<FreeplayStyleData>
{
// JsonParser does not take type parameters,
// otherwise this function would be in BaseRegistry.
var parser:json2object.JsonParser<FreeplayStyleData> = new json2object.JsonParser<FreeplayStyleData>();
parser.ignoreUnknownVariables = false;
switch (loadEntryFile(id))
{
case {fileName: fileName, contents: contents}:
parser.fromJson(contents, fileName);
default:
return null;
}
if (parser.errors.length > 0)
{
printErrors(parser.errors, id);
return null;
}
return parser.value;
}
/**
* Parse and validate the JSON data and produce the corresponding data object.
*
* NOTE: Must be implemented on the implementation class.
* @param contents The JSON as a string.
* @param fileName An optional file name for error reporting.
* @return The parsed data object.
*/
public function parseEntryDataRaw(contents:String, ?fileName:String):Null<FreeplayStyleData>
{
var parser:json2object.JsonParser<FreeplayStyleData> = new json2object.JsonParser<FreeplayStyleData>();
parser.ignoreUnknownVariables = false;
parser.fromJson(contents, fileName);
if (parser.errors.length > 0)
{
printErrors(parser.errors, fileName);
return null;
}
return parser.value;
}
function createScriptedEntry(clsName:String):FreeplayStyle
{
return ScriptedFreeplayStyle.init(clsName, 'unknown');
}
function getScriptedClassNames():Array<String>
{
return ScriptedFreeplayStyle.listScriptClasses();
}
}
+31
View File
@@ -0,0 +1,31 @@
# Note Style Data Schema Changelog
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.1.0]
### Added
- Added several new `assets`:
- `countdownThree`
- `countdownTwo`
- `countdownOne`
- `countdownGo`
- `judgementSick`
- `judgementGood`
- `judgementBad`
- `judgementShit`
- `comboNumber0`
- `comboNumber1`
- `comboNumber2`
- `comboNumber3`
- `comboNumber4`
- `comboNumber5`
- `comboNumber6`
- `comboNumber7`
- `comboNumber8`
- `comboNumber9`
## [1.0.0]
Initial version.
+95 -1
View File
@@ -74,6 +74,84 @@ typedef NoteStyleAssetsData =
*/
@:optional
var holdNoteCover:NoteStyleAssetData<NoteStyleData_HoldNoteCover>;
/**
* The THREE sound (and an optional pre-READY graphic).
*/
@:optional
var countdownThree:NoteStyleAssetData<NoteStyleData_Countdown>;
/**
* The TWO sound and READY graphic.
*/
@:optional
var countdownTwo:NoteStyleAssetData<NoteStyleData_Countdown>;
/**
* The ONE sound and SET graphic.
*/
@:optional
var countdownOne:NoteStyleAssetData<NoteStyleData_Countdown>;
/**
* The GO sound and GO! graphic.
*/
@:optional
var countdownGo:NoteStyleAssetData<NoteStyleData_Countdown>;
/**
* The SICK! judgement.
*/
@:optional
var judgementSick:NoteStyleAssetData<NoteStyleData_Judgement>;
/**
* The GOOD! judgement.
*/
@:optional
var judgementGood:NoteStyleAssetData<NoteStyleData_Judgement>;
/**
* The BAD! judgement.
*/
@:optional
var judgementBad:NoteStyleAssetData<NoteStyleData_Judgement>;
/**
* The SHIT! judgement.
*/
@:optional
var judgementShit:NoteStyleAssetData<NoteStyleData_Judgement>;
@:optional
var comboNumber0:NoteStyleAssetData<NoteStyleData_ComboNum>;
@:optional
var comboNumber1:NoteStyleAssetData<NoteStyleData_ComboNum>;
@:optional
var comboNumber2:NoteStyleAssetData<NoteStyleData_ComboNum>;
@:optional
var comboNumber3:NoteStyleAssetData<NoteStyleData_ComboNum>;
@:optional
var comboNumber4:NoteStyleAssetData<NoteStyleData_ComboNum>;
@:optional
var comboNumber5:NoteStyleAssetData<NoteStyleData_ComboNum>;
@:optional
var comboNumber6:NoteStyleAssetData<NoteStyleData_ComboNum>;
@:optional
var comboNumber7:NoteStyleAssetData<NoteStyleData_ComboNum>;
@:optional
var comboNumber8:NoteStyleAssetData<NoteStyleData_ComboNum>;
@:optional
var comboNumber9:NoteStyleAssetData<NoteStyleData_ComboNum>;
}
/**
@@ -109,10 +187,19 @@ typedef NoteStyleAssetData<T> =
@:optional
var isPixel:Bool;
/**
* If true, animations will be played on the graphic.
* @default `false` to save performance.
*/
@:default(false)
@:optional
var animated:Bool;
/**
* The structure of this data depends on the asset.
*/
var data:T;
@:optional
var data:Null<T>;
}
typedef NoteStyleData_Note =
@@ -123,7 +210,14 @@ typedef NoteStyleData_Note =
var right:UnnamedAnimationData;
}
typedef NoteStyleData_Countdown =
{
var audioPath:String;
}
typedef NoteStyleData_HoldNote = {}
typedef NoteStyleData_Judgement = {}
typedef NoteStyleData_ComboNum = {}
/**
* Data on animations for each direction of the strumline.
@@ -11,9 +11,9 @@ class NoteStyleRegistry extends BaseRegistry<NoteStyle, NoteStyleData>
* Handle breaking changes by incrementing this value
* and adding migration to the `migrateNoteStyleData()` function.
*/
public static final NOTE_STYLE_DATA_VERSION:thx.semver.Version = "1.0.0";
public static final NOTE_STYLE_DATA_VERSION:thx.semver.Version = "1.1.0";
public static final NOTE_STYLE_DATA_VERSION_RULE:thx.semver.VersionRule = "1.0.x";
public static final NOTE_STYLE_DATA_VERSION_RULE:thx.semver.VersionRule = "1.1.x";
public static var instance(get, never):NoteStyleRegistry;
static var _instance:Null<NoteStyleRegistry> = null;
+9
View File
@@ -5,6 +5,15 @@ 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.2.4]
### Added
- Added `playData.characters.opponentVocals` to specify which vocal track(s) to play for the opponent.
- If the value isn't present, it will use the `playData.characters.opponent`, but if it is present, it will be used (even if it's empty, in which case no vocals will be used for the opponent)
- Added `playData.characters.playerVocals` to specify which vocal track(s) to play for the player.
- If the value isn't present, it will use the `playData.characters.player`, but if it is present, it will be used (even if it's empty, in which case no vocals will be used for the player)
- Added `offsets.altVocals` field to apply vocal offsets when alternate instrumentals are used.
## [2.2.3]
### Added
- Added `charter` field to denote authorship of a chart.
+111 -36
View File
@@ -257,18 +257,27 @@ class SongOffsets implements ICloneable<SongOffsets>
public var altInstrumentals:Map<String, Float>;
/**
* The offset, in milliseconds, to apply to the song's vocals, relative to the chart.
* The offset, in milliseconds, to apply to the song's vocals, relative to the song's base instrumental.
* These are applied ON TOP OF the instrumental offset.
*/
@:optional
@:default([])
public var vocals:Map<String, Float>;
public function new(instrumental:Float = 0.0, ?altInstrumentals:Map<String, Float>, ?vocals:Map<String, Float>)
/**
* The offset, in milliseconds, to apply to the songs vocals, relative to each alternate instrumental.
* This is useful for the circumstance where, for example, an alt instrumental has a few seconds of lead in before the song starts.
*/
@:optional
@:default([])
public var altVocals:Map<String, Map<String, Float>>;
public function new(instrumental:Float = 0.0, ?altInstrumentals:Map<String, Float>, ?vocals:Map<String, Float>, ?altVocals:Map<String, Map<String, Float>>)
{
this.instrumental = instrumental;
this.altInstrumentals = altInstrumentals == null ? new Map<String, Float>() : altInstrumentals;
this.vocals = vocals == null ? new Map<String, Float>() : vocals;
this.altVocals = altVocals == null ? new Map<String, Map<String, Float>>() : altVocals;
}
public function getInstrumentalOffset(?instrumental:String):Float
@@ -293,11 +302,19 @@ class SongOffsets implements ICloneable<SongOffsets>
return value;
}
public function getVocalOffset(charId:String):Float
public function getVocalOffset(charId:String, ?instrumental:String):Float
{
if (!this.vocals.exists(charId)) return 0.0;
return this.vocals.get(charId);
if (instrumental == null)
{
if (!this.vocals.exists(charId)) return 0.0;
return this.vocals.get(charId);
}
else
{
if (!this.altVocals.exists(instrumental)) return 0.0;
if (!this.altVocals.get(instrumental).exists(charId)) return 0.0;
return this.altVocals.get(instrumental).get(charId);
}
}
public function setVocalOffset(charId:String, value:Float):Float
@@ -320,7 +337,7 @@ class SongOffsets implements ICloneable<SongOffsets>
*/
public function toString():String
{
return 'SongOffsets(${this.instrumental}ms, ${this.altInstrumentals}, ${this.vocals})';
return 'SongOffsets(${this.instrumental}ms, ${this.altInstrumentals}, ${this.vocals}, ${this.altVocals})';
}
}
@@ -529,12 +546,26 @@ class SongCharacterData implements ICloneable<SongCharacterData>
@:default([])
public var altInstrumentals:Array<String> = [];
public function new(player:String = '', girlfriend:String = '', opponent:String = '', instrumental:String = '')
@:optional
public var opponentVocals:Null<Array<String>> = null;
@:optional
public var playerVocals:Null<Array<String>> = null;
public function new(player:String = '', girlfriend:String = '', opponent:String = '', instrumental:String = '', ?altInstrumentals:Array<String>,
?opponentVocals:Array<String>, ?playerVocals:Array<String>)
{
this.player = player;
this.girlfriend = girlfriend;
this.opponent = opponent;
this.instrumental = instrumental;
this.altInstrumentals = altInstrumentals;
this.opponentVocals = opponentVocals;
this.playerVocals = playerVocals;
if (opponentVocals == null) this.opponentVocals = [opponent];
if (playerVocals == null) this.playerVocals = [player];
}
public function clone():SongCharacterData
@@ -722,18 +753,6 @@ class SongEventDataRaw implements ICloneable<SongEventDataRaw>
{
return new SongEventDataRaw(this.time, this.eventKind, this.value);
}
}
/**
* Wrap SongEventData in an abstract so we can overload operators.
*/
@:forward(time, eventKind, value, activated, getStepTime, clone)
abstract SongEventData(SongEventDataRaw) from SongEventDataRaw to SongEventDataRaw
{
public function new(time:Float, eventKind:String, value:Dynamic = null)
{
this = new SongEventDataRaw(time, eventKind, value);
}
public function valueAsStruct(?defaultKey:String = "key"):Dynamic
{
@@ -757,27 +776,27 @@ abstract SongEventData(SongEventDataRaw) from SongEventDataRaw to SongEventDataR
}
}
public inline function getHandler():Null<SongEvent>
public function getHandler():Null<SongEvent>
{
return SongEventRegistry.getEvent(this.eventKind);
}
public inline function getSchema():Null<SongEventSchema>
public function getSchema():Null<SongEventSchema>
{
return SongEventRegistry.getEventSchema(this.eventKind);
}
public inline function getDynamic(key:String):Null<Dynamic>
public function getDynamic(key:String):Null<Dynamic>
{
return this.value == null ? null : Reflect.field(this.value, key);
}
public inline function getBool(key:String):Null<Bool>
public function getBool(key:String):Null<Bool>
{
return this.value == null ? null : cast Reflect.field(this.value, key);
}
public inline function getInt(key:String):Null<Int>
public function getInt(key:String):Null<Int>
{
if (this.value == null) return null;
var result = Reflect.field(this.value, key);
@@ -787,7 +806,7 @@ abstract SongEventData(SongEventDataRaw) from SongEventDataRaw to SongEventDataR
return cast result;
}
public inline function getFloat(key:String):Null<Float>
public function getFloat(key:String):Null<Float>
{
if (this.value == null) return null;
var result = Reflect.field(this.value, key);
@@ -797,17 +816,17 @@ abstract SongEventData(SongEventDataRaw) from SongEventDataRaw to SongEventDataR
return cast result;
}
public inline function getString(key:String):String
public function getString(key:String):String
{
return this.value == null ? null : cast Reflect.field(this.value, key);
}
public inline function getArray(key:String):Array<Dynamic>
public function getArray(key:String):Array<Dynamic>
{
return this.value == null ? null : cast Reflect.field(this.value, key);
}
public inline function getBoolArray(key:String):Array<Bool>
public function getBoolArray(key:String):Array<Bool>
{
return this.value == null ? null : cast Reflect.field(this.value, key);
}
@@ -839,6 +858,19 @@ abstract SongEventData(SongEventDataRaw) from SongEventDataRaw to SongEventDataR
return result;
}
}
/**
* Wrap SongEventData in an abstract so we can overload operators.
*/
@:forward(time, eventKind, value, activated, getStepTime, clone, getHandler, getSchema, getDynamic, getBool, getInt, getFloat, getString, getArray,
getBoolArray, buildTooltip, valueAsStruct)
abstract SongEventData(SongEventDataRaw) from SongEventDataRaw to SongEventDataRaw
{
public function new(time:Float, eventKind:String, value:Dynamic = null)
{
this = new SongEventDataRaw(time, eventKind, value);
}
public function clone():SongEventData
{
@@ -951,12 +983,18 @@ class SongNoteDataRaw implements ICloneable<SongNoteDataRaw>
return this.kind = value;
}
public function new(time:Float, data:Int, length:Float = 0, kind:String = '')
@:alias("p")
@:default([])
@:optional
public var params:Array<NoteParamData>;
public function new(time:Float, data:Int, length:Float = 0, kind:String = '', ?params:Array<NoteParamData>)
{
this.time = time;
this.data = data;
this.length = length;
this.kind = kind;
this.params = params ?? [];
}
/**
@@ -1051,9 +1089,19 @@ class SongNoteDataRaw implements ICloneable<SongNoteDataRaw>
_stepLength = null;
}
public function cloneParams():Array<NoteParamData>
{
var params:Array<NoteParamData> = [];
for (param in this.params)
{
params.push(param.clone());
}
return params;
}
public function clone():SongNoteDataRaw
{
return new SongNoteDataRaw(this.time, this.data, this.length, this.kind);
return new SongNoteDataRaw(this.time, this.data, this.length, this.kind, cloneParams());
}
public function toString():String
@@ -1069,9 +1117,9 @@ class SongNoteDataRaw implements ICloneable<SongNoteDataRaw>
@:forward
abstract SongNoteData(SongNoteDataRaw) from SongNoteDataRaw to SongNoteDataRaw
{
public function new(time:Float, data:Int, length:Float = 0, kind:String = '')
public function new(time:Float, data:Int, length:Float = 0, kind:String = '', ?params:Array<NoteParamData>)
{
this = new SongNoteDataRaw(time, data, length, kind);
this = new SongNoteDataRaw(time, data, length, kind, params);
}
public static function buildDirectionName(data:Int, strumlineSize:Int = 4):String
@@ -1115,7 +1163,7 @@ abstract SongNoteData(SongNoteDataRaw) from SongNoteDataRaw to SongNoteDataRaw
if (other.kind == '' || this.kind == null) return false;
}
return this.time == other.time && this.data == other.data && this.length == other.length;
return this.time == other.time && this.data == other.data && this.length == other.length && this.params == other.params;
}
@:op(A != B)
@@ -1134,7 +1182,7 @@ abstract SongNoteData(SongNoteDataRaw) from SongNoteDataRaw to SongNoteDataRaw
if (other.kind == '') return true;
}
return this.time != other.time || this.data != other.data || this.length != other.length;
return this.time != other.time || this.data != other.data || this.length != other.length || this.params != other.params;
}
@:op(A > B)
@@ -1171,7 +1219,7 @@ abstract SongNoteData(SongNoteDataRaw) from SongNoteDataRaw to SongNoteDataRaw
public function clone():SongNoteData
{
return new SongNoteData(this.time, this.data, this.length, this.kind);
return new SongNoteData(this.time, this.data, this.length, this.kind, this.params);
}
/**
@@ -1183,3 +1231,30 @@ abstract SongNoteData(SongNoteDataRaw) from SongNoteDataRaw to SongNoteDataRaw
+ (this.kind != '' ? ' [kind: ${this.kind}])' : ')');
}
}
class NoteParamData implements ICloneable<NoteParamData>
{
@:alias("n")
public var name:String;
@:alias("v")
@:jcustomparse(funkin.data.DataParse.dynamicValue)
@:jcustomwrite(funkin.data.DataWrite.dynamicValue)
public var value:Dynamic;
public function new(name:String, value:Dynamic)
{
this.name = name;
this.value = value;
}
public function clone():NoteParamData
{
return new NoteParamData(this.name, this.value);
}
public function toString():String
{
return 'NoteParamData(${this.name}, ${this.value})';
}
}
+1 -1
View File
@@ -20,7 +20,7 @@ class SongRegistry extends BaseRegistry<Song, SongMetadata>
* Handle breaking changes by incrementing this value
* and adding migration to the `migrateStageData()` function.
*/
public static final SONG_METADATA_VERSION:thx.semver.Version = "2.2.3";
public static final SONG_METADATA_VERSION:thx.semver.Version = "2.2.4";
public static final SONG_METADATA_VERSION_RULE:thx.semver.VersionRule = "2.2.x";
@@ -199,6 +199,8 @@ class FNFLegacyImporter
{
// Handle the dumb logic for mustHitSection.
var noteData = note.data;
if (noteData < 0) continue; // Exclude Psych event notes.
if (noteData > (STRUMLINE_SIZE * 2)) noteData = noteData % (2 * STRUMLINE_SIZE); // Handle other engine event notes.
// Flip notes if mustHitSection is FALSE (not true lol).
if (!mustHitSection)
+4 -4
View File
@@ -140,12 +140,12 @@ typedef StageDataProp =
* If not zero, this prop will play an animation every X beats of the song.
* This requires animations to be defined. If `danceLeft` and `danceRight` are defined,
* they will alternated between, otherwise the `idle` animation will be used.
*
* @default 0
* Supports up to 0.25 precision.
* @default 0.0
*/
@:default(0)
@:default(0.0)
@:optional
var danceEvery:Int;
var danceEvery:Float;
/**
* How much the prop scrolls relative to the camera. Used to create a parallax effect.
+2 -2
View File
@@ -93,8 +93,8 @@ class StageRegistry extends BaseRegistry<Stage, StageData>
public function listBaseGameStageIds():Array<String>
{
return [
"mainStage", "spookyMansion", "phillyTrain", "limoRide", "mallXmas", "mallEvil", "school", "schoolEvil", "tankmanBattlefield", "phillyStreets",
"phillyBlazin",
"mainStage", "mainStageErect", "spookyMansion", "phillyTrain", "phillyTrainErect", "limoRide", "limoRideErect", "mallXmas", "mallXmasErect", "mallEvil",
"school", "schoolEvil", "tankmanBattlefield", "phillyStreets", "phillyStreetsErect", "phillyBlazin",
];
}
+5 -3
View File
@@ -91,11 +91,13 @@ typedef LevelPropData =
/**
* The frequency to bop at, in beats.
* @default 1 = every beat, 2 = every other beat, etc.
* 1 = every beat, 2 = every other beat, etc.
* Supports up to 0.25 precision.
* @default 1.0
*/
@:default(1)
@:default(1.0)
@:optional
var danceEvery:Int;
var danceEvery:Float;
/**
* The offset on the position to render the prop at.
+106
View File
@@ -0,0 +1,106 @@
package funkin.effects;
import flixel.util.FlxTimer;
import flixel.FlxCamera;
import openfl.filters.ColorMatrixFilter;
class RetroCameraFade
{
// im lazy, but we only use this for week 6
// and also sorta yoinked for djflixel, lol !
public static function fadeWhite(camera:FlxCamera, camSteps:Int = 5, time:Float = 1):Void
{
var steps:Int = 0;
var stepsTotal:Int = camSteps;
new FlxTimer().start(time / stepsTotal, _ -> {
var V:Float = (1 / stepsTotal) * steps;
if (steps == stepsTotal) V = 1;
var matrix = [
1, 0, 0, 0, V * 255,
0, 1, 0, 0, V * 255,
0, 0, 1, 0, V * 255,
0, 0, 0, 1, 0
];
camera.filters = [new ColorMatrixFilter(matrix)];
steps++;
}, stepsTotal + 1);
}
public static function fadeFromWhite(camera:FlxCamera, camSteps:Int = 5, time:Float = 1):Void
{
var steps:Int = camSteps;
var stepsTotal:Int = camSteps;
var matrixDerp = [
1, 0, 0, 0, 1.0 * 255,
0, 1, 0, 0, 1.0 * 255,
0, 0, 1, 0, 1.0 * 255,
0, 0, 0, 1, 0
];
camera.filters = [new ColorMatrixFilter(matrixDerp)];
new FlxTimer().start(time / stepsTotal, _ -> {
var V:Float = (1 / stepsTotal) * steps;
if (steps == stepsTotal) V = 1;
var matrix = [
1, 0, 0, 0, V * 255,
0, 1, 0, 0, V * 255,
0, 0, 1, 0, V * 255,
0, 0, 0, 1, 0
];
camera.filters = [new ColorMatrixFilter(matrix)];
steps--;
}, camSteps);
}
public static function fadeToBlack(camera:FlxCamera, camSteps:Int = 5, time:Float = 1):Void
{
var steps:Int = 0;
var stepsTotal:Int = camSteps;
new FlxTimer().start(time / stepsTotal, _ -> {
var V:Float = (1 / stepsTotal) * steps;
if (steps == stepsTotal) V = 1;
var matrix = [
1, 0, 0, 0, -V * 255,
0, 1, 0, 0, -V * 255,
0, 0, 1, 0, -V * 255,
0, 0, 0, 1, 0
];
camera.filters = [new ColorMatrixFilter(matrix)];
steps++;
}, camSteps);
}
public static function fadeBlack(camera:FlxCamera, camSteps:Int = 5, time:Float = 1):Void
{
var steps:Int = camSteps;
var stepsTotal:Int = camSteps;
var matrixDerp = [
1, 0, 0, 0, -1.0 * 255,
0, 1, 0, 0, -1.0 * 255,
0, 0, 1, 0, -1.0 * 255,
0, 0, 0, 1, 0
];
camera.filters = [new ColorMatrixFilter(matrixDerp)];
new FlxTimer().start(time / stepsTotal, _ -> {
var V:Float = (1 / stepsTotal) * steps;
if (steps == stepsTotal) V = 1;
var matrix = [
1, 0, 0, 0, -V * 255,
0, 1, 0, 0, -V * 255,
0, 0, 1, 0, -V * 255,
0, 0, 0, 1, 0
];
camera.filters = [new ColorMatrixFilter(matrix)];
steps--;
}, camSteps + 1);
}
}
+419
View File
@@ -0,0 +1,419 @@
package funkin.graphics;
import flixel.FlxBasic;
import flixel.FlxCamera;
import flixel.FlxG;
import flixel.FlxSprite;
import flixel.graphics.FlxGraphic;
import flixel.graphics.frames.FlxFrame;
import flixel.math.FlxMatrix;
import flixel.math.FlxPoint;
import flixel.math.FlxRect;
import flixel.util.FlxColor;
import lime.graphics.cairo.Cairo;
import openfl.display.BitmapData;
import openfl.display.BlendMode;
import openfl.display.DisplayObjectRenderer;
import openfl.display.Graphics;
import openfl.display.OpenGLRenderer;
import openfl.display._internal.Context3DGraphics;
import openfl.display3D.Context3D;
import openfl.display3D.Context3DClearMask;
import openfl.filters.BitmapFilter;
import openfl.filters.BlurFilter;
import openfl.geom.ColorTransform;
import openfl.geom.Matrix;
import openfl.geom.Point;
import openfl.geom.Rectangle;
#if (js && html5)
import lime._internal.graphics.ImageCanvasUtil;
import openfl.display.CanvasRenderer;
import openfl.display._internal.CanvasGraphics as GfxRenderer;
#else
import openfl.display.CairoRenderer;
import openfl.display._internal.CairoGraphics as GfxRenderer;
#end
/**
* A modified `FlxSprite` that supports filters.
* The name's pretty much self-explanatory.
*/
@:access(openfl.geom.Rectangle)
@:access(openfl.filters.BitmapFilter)
@:access(flixel.graphics.frames.FlxFrame)
class FlxFilteredSprite extends FlxSprite
{
@:noCompletion var _renderer:FlxAnimateFilterRenderer = new FlxAnimateFilterRenderer();
@:noCompletion var _filterMatrix:FlxMatrix;
/**
* An `Array` of shader filters (aka `BitmapFilter`).
*/
public var filters(default, set):Array<BitmapFilter>;
/**
* a flag to update the image with the filters.
* Useful when trying to render a shader at all times.
*/
public var filterDirty:Bool = false;
@:noCompletion var filtered:Bool;
@:noCompletion var _blankFrame:FlxFrame;
var _filterBmp1:BitmapData;
var _filterBmp2:BitmapData;
override public function update(elapsed:Float)
{
super.update(elapsed);
if (!filterDirty && filters != null)
{
for (filter in filters)
{
if (filter.__renderDirty)
{
filterDirty = true;
break;
}
}
}
}
@:noCompletion
override function initVars():Void
{
super.initVars();
_filterMatrix = new FlxMatrix();
filters = null;
filtered = false;
}
override public function draw():Void
{
checkEmptyFrame();
if (alpha == 0 || _frame.type == FlxFrameType.EMPTY) return;
if (dirty) // rarely
calcFrame(useFramePixels);
if (filterDirty) filterFrame();
for (camera in cameras)
{
if (!camera.visible || !camera.exists || !isOnScreen(camera)) continue;
getScreenPosition(_point, camera).subtractPoint(offset);
if (isSimpleRender(camera)) drawSimple(camera);
else
drawComplex(camera);
#if FLX_DEBUG
FlxBasic.visibleCount++;
#end
}
#if FLX_DEBUG
if (FlxG.debugger.drawDebug) drawDebug();
#end
}
@:noCompletion
override function drawComplex(camera:FlxCamera):Void
{
_frame.prepareMatrix(_matrix, FlxFrameAngle.ANGLE_0, checkFlipX(), checkFlipY());
_matrix.concat(_filterMatrix);
_matrix.translate(-origin.x, -origin.y);
_matrix.scale(scale.x, scale.y);
if (bakedRotationAngle <= 0)
{
updateTrig();
if (angle != 0) _matrix.rotateWithTrig(_cosAngle, _sinAngle);
}
_point.add(origin.x, origin.y);
_matrix.translate(_point.x, _point.y);
if (isPixelPerfectRender(camera))
{
_matrix.tx = Math.floor(_matrix.tx);
_matrix.ty = Math.floor(_matrix.ty);
}
camera.drawPixels((filtered) ? _blankFrame : _frame, framePixels, _matrix, colorTransform, blend, antialiasing, shader);
}
@:noCompletion
function filterFrame()
{
filterDirty = false;
_filterMatrix.identity();
if (filters != null && filters.length > 0)
{
_flashRect.setEmpty();
for (filter in filters)
{
_flashRect.__expand(-filter.__leftExtension,
-filter.__topExtension, filter.__leftExtension
+ filter.__rightExtension,
filter.__topExtension
+ filter.__bottomExtension);
}
_flashRect.width += frameWidth;
_flashRect.height += frameHeight;
if (_blankFrame == null) _blankFrame = new FlxFrame(null);
if (_blankFrame.parent == null || _flashRect.width > _blankFrame.parent.width || _flashRect.height > _blankFrame.parent.height)
{
if (_blankFrame.parent != null)
{
_blankFrame.parent.destroy();
_filterBmp1.dispose();
_filterBmp2.dispose();
}
_blankFrame.parent = FlxGraphic.fromRectangle(Math.ceil(_flashRect.width * 1.25), Math.ceil(_flashRect.height * 1.25), 0, true);
_filterBmp1 = new BitmapData(_blankFrame.parent.width, _blankFrame.parent.height, 0);
_filterBmp2 = new BitmapData(_blankFrame.parent.width, _blankFrame.parent.height, 0);
}
_blankFrame.offset.copyFrom(_frame.offset);
_blankFrame.parent.bitmap = _renderer.applyFilter(_blankFrame.parent.bitmap, _filterBmp1, _filterBmp2, frame.parent.bitmap, filters, _flashRect,
frame.frame.copyToFlash());
_blankFrame.frame = FlxRect.get(0, 0, _blankFrame.parent.bitmap.width, _blankFrame.parent.bitmap.height);
_filterMatrix.translate(_flashRect.x, _flashRect.y);
_frame = _blankFrame.copyTo();
filtered = true;
}
else
{
resetFrame();
filtered = false;
}
}
@:noCompletion
function set_filters(value:Array<BitmapFilter>)
{
if (filters != value) filterDirty = true;
return filters = value;
}
@:noCompletion
override function set_frame(value:FlxFrame)
{
if (value != frame) filterDirty = true;
return super.set_frame(value);
}
override public function destroy()
{
super.destroy();
}
}
@:noCompletion
@:access(openfl.display.OpenGLRenderer)
@:access(openfl.filters.BitmapFilter)
@:access(openfl.geom.Rectangle)
@:access(openfl.display.Stage)
@:access(openfl.display.Graphics)
@:access(openfl.display.Shader)
@:access(openfl.display.BitmapData)
@:access(openfl.geom.ColorTransform)
@:access(openfl.display.DisplayObject)
@:access(openfl.display3D.Context3D)
@:access(openfl.display.CanvasRenderer)
@:access(openfl.display.CairoRenderer)
@:access(openfl.display3D.Context3D)
class FlxAnimateFilterRenderer
{
var renderer:OpenGLRenderer;
var context:Context3D;
public function new()
{
// context = new openfl.display3D.Context3D(null);
renderer = new OpenGLRenderer(FlxG.game.stage.context3D);
renderer.__worldTransform = new Matrix();
renderer.__worldColorTransform = new ColorTransform();
}
@:noCompletion function setRenderer(renderer:DisplayObjectRenderer, rect:Rectangle)
{
@:privateAccess
if (true)
{
var displayObject = FlxG.game;
var pixelRatio = FlxG.game.stage.__renderer.__pixelRatio;
var offsetX = rect.x > 0 ? Math.ceil(rect.x) : Math.floor(rect.x);
var offsetY = rect.y > 0 ? Math.ceil(rect.y) : Math.floor(rect.y);
if (renderer.__worldTransform == null)
{
renderer.__worldTransform = new Matrix();
renderer.__worldColorTransform = new ColorTransform();
}
if (displayObject.__cacheBitmapColorTransform == null) displayObject.__cacheBitmapColorTransform = new ColorTransform();
renderer.__stage = displayObject.stage;
renderer.__allowSmoothing = true;
renderer.__setBlendMode(NORMAL);
renderer.__worldAlpha = 1 / displayObject.__worldAlpha;
renderer.__worldTransform.identity();
renderer.__worldTransform.invert();
renderer.__worldTransform.concat(new Matrix());
renderer.__worldTransform.tx -= offsetX;
renderer.__worldTransform.ty -= offsetY;
renderer.__worldTransform.scale(pixelRatio, pixelRatio);
renderer.__pixelRatio = pixelRatio;
}
}
public function applyFilter(target:BitmapData = null, target1:BitmapData = null, target2:BitmapData = null, bmp:BitmapData, filters:Array<BitmapFilter>,
rect:Rectangle, bmpRect:Rectangle)
{
if (filters == null || filters.length == 0) return bmp;
renderer.__setBlendMode(NORMAL);
renderer.__worldAlpha = 1;
if (renderer.__worldTransform == null)
{
renderer.__worldTransform = new Matrix();
renderer.__worldColorTransform = new ColorTransform();
}
renderer.__worldTransform.identity();
renderer.__worldColorTransform.__identity();
var bitmap:BitmapData = (target == null) ? new BitmapData(Math.ceil(rect.width * 1.25), Math.ceil(rect.height * 1.25), true, 0) : target;
var bitmap2 = (target1 == null) ? new BitmapData(Math.ceil(rect.width * 1.25), Math.ceil(rect.height * 1.25), true, 0) : target1,
bitmap3 = (target2 == null) ? bitmap2.clone() : target2;
renderer.__setRenderTarget(bitmap);
bmp.__renderTransform.translate(Math.abs(rect.x) - bmpRect.x, Math.abs(rect.y) - bmpRect.y);
bmpRect.x = Math.abs(rect.x);
bmpRect.y = Math.abs(rect.y);
var bestResolution = renderer.__context3D.__backBufferWantsBestResolution;
renderer.__context3D.__backBufferWantsBestResolution = false;
renderer.__scissorRect(bmpRect);
renderer.__renderFilterPass(bmp, renderer.__defaultDisplayShader, true);
renderer.__scissorRect();
renderer.__context3D.__backBufferWantsBestResolution = bestResolution;
bmp.__renderTransform.identity();
var shader, cacheBitmap = null;
for (filter in filters)
{
if (filter.__preserveObject)
{
renderer.__setRenderTarget(bitmap3);
renderer.__renderFilterPass(bitmap, renderer.__defaultDisplayShader, filter.__smooth);
}
for (i in 0...filter.__numShaderPasses)
{
shader = filter.__initShader(renderer, i, (filter.__preserveObject) ? bitmap3 : null);
renderer.__setBlendMode(filter.__shaderBlendMode);
renderer.__setRenderTarget(bitmap2);
renderer.__renderFilterPass(bitmap, shader, filter.__smooth);
cacheBitmap = bitmap;
bitmap = bitmap2;
bitmap2 = cacheBitmap;
}
filter.__renderDirty = false;
}
if (target1 == null) bitmap2.dispose();
if (target2 == null) bitmap3.dispose();
// var gl = renderer.__gl;
// var renderBuffer = bitmap.getTexture(renderer.__context3D);
// @:privateAccess
// gl.readPixels(0, 0, bitmap.width, bitmap.height, renderBuffer.__format, gl.UNSIGNED_BYTE, bitmap.image.data);
// bitmap.image.version = 0;
// @:privateAccess
// bitmap.__textureVersion = -1;
return bitmap;
}
public function applyBlend(blend:BlendMode, bitmap:BitmapData)
{
bitmap.__update(false, true);
var bmp = new BitmapData(bitmap.width, bitmap.height, 0);
#if (js && html5)
ImageCanvasUtil.convertToCanvas(bmp.image);
@:privateAccess
var renderer = new CanvasRenderer(bmp.image.buffer.__srcContext);
#else
var renderer = new CairoRenderer(new Cairo(bmp.getSurface()));
#end
// setRenderer(renderer, bmp.rect);
var m = new Matrix();
var c = new ColorTransform();
renderer.__allowSmoothing = true;
renderer.__overrideBlendMode = blend;
renderer.__worldTransform = m;
renderer.__worldAlpha = 1;
renderer.__worldColorTransform = c;
renderer.__setBlendMode(blend);
#if (js && html5)
bmp.__drawCanvas(bitmap, renderer);
#else
bmp.__drawCairo(bitmap, renderer);
#end
return bitmap;
}
public function graphicstoBitmapData(gfx:Graphics)
{
if (gfx.__bounds == null) return null;
// var cacheRTT = renderer.__context3D.__state.renderToTexture;
// var cacheRTTDepthStencil = renderer.__context3D.__state.renderToTextureDepthStencil;
// var cacheRTTAntiAlias = renderer.__context3D.__state.renderToTextureAntiAlias;
// var cacheRTTSurfaceSelector = renderer.__context3D.__state.renderToTextureSurfaceSelector;
// var bmp = new BitmapData(Math.ceil(gfx.__width), Math.ceil(gfx.__height), 0);
// renderer.__context3D.setRenderToTexture(bmp.getTexture(renderer.__context3D));
// gfx.__owner.__renderTransform.identity();
// gfx.__renderTransform.identity();
// Context3DGraphics.render(gfx, renderer);
GfxRenderer.render(gfx, cast renderer.__softwareRenderer);
var bmp = gfx.__bitmap;
gfx.__bitmap = null;
// if (cacheRTT != null)
// {
// renderer.__context3D.setRenderToTexture(cacheRTT, cacheRTTDepthStencil, cacheRTTAntiAlias, cacheRTTSurfaceSelector);
// }
// else
// {
// renderer.__context3D.setRenderToBackBuffer();
// }
return bmp;
}
}
+101
View File
@@ -7,6 +7,10 @@ import flixel.tweens.FlxTween;
import openfl.display3D.textures.TextureBase;
import funkin.graphics.framebuffer.FixedBitmapData;
import openfl.display.BitmapData;
import flixel.math.FlxRect;
import flixel.math.FlxPoint;
import flixel.graphics.frames.FlxFrame;
import flixel.FlxCamera;
/**
* An FlxSprite with additional functionality.
@@ -269,6 +273,103 @@ class FunkinSprite extends FlxSprite
return result;
}
@:access(flixel.FlxCamera)
override function getBoundingBox(camera:FlxCamera):FlxRect
{
getScreenPosition(_point, camera);
_rect.set(_point.x, _point.y, width, height);
_rect = camera.transformRect(_rect);
if (isPixelPerfectRender(camera))
{
_rect.width = _rect.width / this.scale.x;
_rect.height = _rect.height / this.scale.y;
_rect.x = _rect.x / this.scale.x;
_rect.y = _rect.y / this.scale.y;
_rect.floor();
_rect.x = _rect.x * this.scale.x;
_rect.y = _rect.y * this.scale.y;
_rect.width = _rect.width * this.scale.x;
_rect.height = _rect.height * this.scale.y;
}
return _rect;
}
/**
* Returns the screen position of this object.
*
* @param result Optional arg for the returning point
* @param camera The desired "screen" coordinate space. If `null`, `FlxG.camera` is used.
* @return The screen position of this object.
*/
public override function getScreenPosition(?result:FlxPoint, ?camera:FlxCamera):FlxPoint
{
if (result == null) result = FlxPoint.get();
if (camera == null) camera = FlxG.camera;
result.set(x, y);
if (pixelPerfectPosition)
{
_rect.width = _rect.width / this.scale.x;
_rect.height = _rect.height / this.scale.y;
_rect.x = _rect.x / this.scale.x;
_rect.y = _rect.y / this.scale.y;
_rect.round();
_rect.x = _rect.x * this.scale.x;
_rect.y = _rect.y * this.scale.y;
_rect.width = _rect.width * this.scale.x;
_rect.height = _rect.height * this.scale.y;
}
return result.subtract(camera.scroll.x * scrollFactor.x, camera.scroll.y * scrollFactor.y);
}
override function drawSimple(camera:FlxCamera):Void
{
getScreenPosition(_point, camera).subtractPoint(offset);
if (isPixelPerfectRender(camera))
{
_point.x = _point.x / this.scale.x;
_point.y = _point.y / this.scale.y;
_point.round();
_point.x = _point.x * this.scale.x;
_point.y = _point.y * this.scale.y;
}
_point.copyToFlash(_flashPoint);
camera.copyPixels(_frame, framePixels, _flashRect, _flashPoint, colorTransform, blend, antialiasing);
}
override function drawComplex(camera:FlxCamera):Void
{
_frame.prepareMatrix(_matrix, FlxFrameAngle.ANGLE_0, checkFlipX(), checkFlipY());
_matrix.translate(-origin.x, -origin.y);
_matrix.scale(scale.x, scale.y);
if (bakedRotationAngle <= 0)
{
updateTrig();
if (angle != 0) _matrix.rotateWithTrig(_cosAngle, _sinAngle);
}
getScreenPosition(_point, camera).subtractPoint(offset);
_point.add(origin.x, origin.y);
_matrix.translate(_point.x, _point.y);
if (isPixelPerfectRender(camera))
{
_matrix.tx = Math.round(_matrix.tx / this.scale.x) * this.scale.x;
_matrix.ty = Math.round(_matrix.ty / this.scale.y) * this.scale.y;
}
camera.drawPixels(_frame, framePixels, _matrix, colorTransform, blend, antialiasing, shader);
}
public override function destroy():Void
{
frames = null;
@@ -4,8 +4,12 @@ import flixel.util.FlxSignal.FlxTypedSignal;
import flxanimate.FlxAnimate;
import flxanimate.FlxAnimate.Settings;
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;
/**
* A sprite which provides convenience functions for rendering a texture atlas with animations.
@@ -18,16 +22,21 @@ class FlxAtlasSprite extends FlxAnimate
FrameRate: 24.0,
Reversed: false,
// ?OnComplete:Void -> Void,
ShowPivot: #if debug false #else false #end,
ShowPivot: false,
Antialiasing: true,
ScrollFactor: null,
// Offset: new FlxPoint(0, 0), // This is just FlxSprite.offset
};
/**
* Signal dispatched when an animation finishes playing.
* Signal dispatched when an animation advances to the next frame.
*/
public var onAnimationFinish:FlxTypedSignal<String->Void> = new FlxTypedSignal<String->Void>();
public var onAnimationFrame:FlxTypedSignal<String->Int->Void> = new FlxTypedSignal();
/**
* Signal dispatched when a non-looping animation finishes playing.
*/
public var onAnimationComplete:FlxTypedSignal<String->Void> = new FlxTypedSignal();
var currentAnimation:String;
@@ -42,19 +51,28 @@ class FlxAtlasSprite extends FlxAnimate
throw 'Null path specified for FlxAtlasSprite!';
}
// Validate asset path.
if (!Assets.exists('${path}/Animation.json'))
{
throw 'FlxAtlasSprite does not have an Animation.json file at the specified path (${path})';
}
super(x, y, path, settings);
if (this.anim.curInstance == null)
if (this.anim.stageInstance == null)
{
throw 'FlxAtlasSprite not initialized properly. Are you sure the path (${path}) exists?';
}
onAnimationFinish.add(cleanupAnimation);
onAnimationComplete.add(cleanupAnimation);
// This defaults the sprite to play the first animation in the atlas,
// then pauses it. This ensures symbols are intialized properly.
this.anim.play('');
this.anim.pause();
this.anim.onComplete.add(_onAnimationComplete);
this.anim.onFrame.add(_onAnimationFrame);
}
/**
@@ -62,9 +80,13 @@ class FlxAtlasSprite extends FlxAnimate
*/
public function listAnimations():Array<String>
{
if (this.anim == null) return [];
return this.anim.getFrameLabels();
// return [""];
var mainSymbol = this.anim.symbolDictionary[this.anim.stageInstance.symbol.name];
if (mainSymbol == null)
{
FlxG.log.error('FlxAtlasSprite does not have its main symbol!');
return [];
}
return mainSymbol.getFrameLabels().map(keyFrame -> keyFrame.name).filterNull();
}
/**
@@ -73,7 +95,7 @@ class FlxAtlasSprite extends FlxAnimate
*/
public function hasAnimation(id:String):Bool
{
return getLabelIndex(id) != -1;
return getLabelIndex(id) != -1 || anim.symbolDictionary.exists(id);
}
/**
@@ -84,22 +106,13 @@ class FlxAtlasSprite extends FlxAnimate
return this.currentAnimation;
}
/**
* `anim.finished` always returns false on looping animations,
* but this function will return true if we are on the last frame of the looping animation.
*/
public function isLoopFinished():Bool
{
if (this.anim == null) return false;
if (!this.anim.isPlaying) return false;
var _completeAnim:Bool = false;
// Reverse animation finished.
if (this.anim.reversed && this.anim.curFrame == 0) return true;
// Forward animation finished.
if (!this.anim.reversed && this.anim.curFrame >= (this.anim.length - 1)) return true;
var fr:FlxKeyFrame = null;
return false;
}
var looping:Bool = false;
public var ignoreExclusionPref:Array<String> = [];
/**
* Plays an animation.
@@ -107,61 +120,86 @@ class FlxAtlasSprite extends FlxAnimate
* @param restart Whether to restart the animation if it is already playing.
* @param ignoreOther Whether to ignore all other animation inputs, until this one is done playing
* @param loop Whether to loop the animation
* @param startFrame The frame to start the animation on
* NOTE: `loop` and `ignoreOther` are not compatible with each other!
*/
public function playAnimation(id:String, restart:Bool = false, ignoreOther:Bool = false, ?loop:Bool = false):Void
public function playAnimation(id:String, restart:Bool = false, ignoreOther:Bool = false, loop:Bool = false, startFrame:Int = 0):Void
{
if (loop == null) loop = false;
// Skip if not allowed to play animations.
if ((!canPlayOtherAnims && !ignoreOther)) return;
if ((!canPlayOtherAnims))
{
if (this.currentAnimation == id && restart) {}
else if (ignoreExclusionPref != null && ignoreExclusionPref.length > 0)
{
var detected:Bool = false;
for (entry in ignoreExclusionPref)
{
if (StringTools.startsWith(id, entry))
{
detected = true;
break;
}
}
if (!detected) return;
}
else
return;
}
if (anim == null) return;
if (id == null || id == '') id = this.currentAnimation;
if (this.currentAnimation == id && !restart)
{
if (anim.isPlaying)
if (!anim.isPlaying)
{
// Skip if animation is already playing.
return;
}
else
{
// Resume animation if it's paused.
anim.play('', false, false);
}
}
if (fr != null) anim.curFrame = fr.index + startFrame;
else
anim.curFrame = startFrame;
// Skip if the animation doesn't exist
if (!hasAnimation(id))
// Resume animation if it's paused.
anim.resume();
}
return;
}
else if (!hasAnimation(id))
{
// Skip if the animation doesn't exist
trace('Animation ' + id + ' not found');
return;
}
anim.callback = function(_, frame:Int) {
var offset = loop ? 0 : -1;
this.currentAnimation = id;
anim.onComplete.removeAll();
anim.onComplete.add(function() {
_onAnimationComplete();
});
var frameLabel = anim.getFrameLabel(id);
if (frame == (frameLabel.duration + offset) + frameLabel.index)
{
if (loop)
{
playAnimation(id, true, false, true);
}
else
{
onAnimationFinish.dispatch(id);
}
}
};
looping = loop;
// Prevent other animations from playing if `ignoreOther` is true.
if (ignoreOther) canPlayOtherAnims = false;
// Move to the first frame of the animation.
goToFrameLabel(id);
this.currentAnimation = id;
// goToFrameLabel(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);
this.currentAnimation = anim.curSymbol.name;
fr = null;
}
// Only call goToFrameLabel if there is a frame label with that name. This prevents annoying warnings!
if (getFrameLabelNames().indexOf(id) != -1)
{
goToFrameLabel(id);
fr = anim.getFrameLabel(id);
anim.curFrame += startFrame;
}
}
override public function update(elapsed:Float)
@@ -169,6 +207,29 @@ class FlxAtlasSprite extends FlxAnimate
super.update(elapsed);
}
/**
* Returns true if the animation has finished playing.
* Never true if animation is configured to loop.
*/
public function isAnimationFinished():Bool
{
return this.anim.finished;
}
/**
* Returns true if the animation has reached the last frame.
* Can be true even if animation is configured to loop.
*/
public function isLoopComplete():Bool
{
if (this.anim == null) return false;
if (!this.anim.isPlaying) return false;
if (fr != null) return (anim.reversed && anim.curFrame < fr.index || !anim.reversed && anim.curFrame >= (fr.index + fr.duration));
return (anim.reversed && anim.curFrame == 0 || !(anim.reversed) && (anim.curFrame) >= (anim.length - 1));
}
/**
* Stops the current animation.
*/
@@ -192,6 +253,18 @@ class FlxAtlasSprite extends FlxAnimate
this.anim.goToFrameLabel(label);
}
function getFrameLabelNames(?layer:haxe.extern.EitherType<Int, String> = null)
{
var labels = this.anim.getFrameLabels(layer);
var array = [];
for (label in labels)
{
array.push(label.name);
}
return array;
}
function getNextFrameLabel(label:String):String
{
return listAnimations()[(getLabelIndex(label) + 1) % listAnimations().length];
@@ -213,4 +286,95 @@ class FlxAtlasSprite extends FlxAnimate
// this.currentAnimation = null;
this.anim.pause();
}
function _onAnimationFrame(frame:Int):Void
{
if (currentAnimation != null)
{
onAnimationFrame.dispatch(currentAnimation, frame);
if (isLoopComplete())
{
anim.pause();
_onAnimationComplete();
if (looping)
{
anim.curFrame = (fr != null) ? fr.index : 0;
anim.resume();
}
else if (fr != null && anim.curFrame != anim.length - 1)
{
anim.curFrame--;
}
}
}
}
function _onAnimationComplete():Void
{
if (currentAnimation != null)
{
onAnimationComplete.dispatch(currentAnimation);
}
else
{
onAnimationComplete.dispatch('');
}
}
var prevFrames:Map<Int, FlxFrame> = [];
public function replaceFrameGraphic(index:Int, ?graphic:FlxGraphicAsset):Void
{
if (graphic == null || !Assets.exists(graphic))
{
var prevFrame:Null<FlxFrame> = prevFrames.get(index);
if (prevFrame == null) return;
prevFrame.copyTo(frames.getByIndex(index));
return;
}
var prevFrame:FlxFrame = prevFrames.get(index) ?? frames.getByIndex(index).copyTo();
prevFrames.set(index, prevFrame);
var frame = FlxG.bitmap.add(graphic).imageFrame.frame;
frame.copyTo(frames.getByIndex(index));
// Additional sizing fix.
@:privateAccess
if (true)
{
var frame = frames.getByIndex(index);
frame.tileMatrix[0] = prevFrame.frame.width / frame.frame.width;
frame.tileMatrix[3] = prevFrame.frame.height / frame.frame.height;
}
}
public function getBasePosition():Null<FlxPoint>
{
// var stagePos = new FlxPoint(anim.stageInstance.matrix.tx, anim.stageInstance.matrix.ty);
var instancePos = new FlxPoint(anim.curInstance.matrix.tx, anim.curInstance.matrix.ty);
var firstElement = anim.curSymbol.timeline?.get(0)?.get(0)?.get(0);
if (firstElement == null) return instancePos;
var firstElementPos = new FlxPoint(firstElement.matrix.tx, firstElement.matrix.ty);
return instancePos + firstElementPos;
}
public function getPivotPosition():Null<FlxPoint>
{
return anim.curInstance.symbol.transformationPoint;
}
public override function destroy():Void
{
for (prevFrameId in prevFrames.keys())
{
replaceFrameGraphic(prevFrameId, null);
}
super.destroy();
}
}
@@ -0,0 +1,55 @@
package funkin.graphics.shaders;
import flixel.addons.display.FlxRuntimeShader;
import funkin.Paths;
import openfl.utils.Assets;
class AdjustColorShader extends FlxRuntimeShader
{
public var hue(default, set):Float;
public var saturation(default, set):Float;
public var brightness(default, set):Float;
public var contrast(default, set):Float;
public function new()
{
super(Assets.getText(Paths.frag('adjustColor')));
// FlxG.debugger.addTrackerProfile(new TrackerProfile(HSVShader, ['hue', 'saturation', 'brightness', 'contrast']));
hue = 0;
saturation = 0;
brightness = 0;
contrast = 0;
}
function set_hue(value:Float):Float
{
this.setFloat('hue', value);
this.hue = value;
return this.hue;
}
function set_saturation(value:Float):Float
{
this.setFloat('saturation', value);
this.saturation = value;
return this.saturation;
}
function set_brightness(value:Float):Float
{
this.setFloat('brightness', value);
this.brightness = value;
return this.brightness;
}
function set_contrast(value:Float):Float
{
this.setFloat('contrast', value);
this.contrast = value;
return this.contrast;
}
}
+72 -19
View File
@@ -1,43 +1,96 @@
package funkin.graphics.shaders;
import flixel.system.FlxAssets.FlxShader;
import flixel.util.FlxColor;
class AngleMask extends FlxShader
{
public var extraColor(default, set):FlxColor = 0xFFFFFFFF;
function set_extraColor(value:FlxColor):FlxColor
{
extraTint.value = [value.redFloat, value.greenFloat, value.blueFloat];
this.extraColor = value;
return this.extraColor;
}
@:glFragmentSource('
#pragma header
uniform vec2 endPosition;
void main()
{
vec4 base = texture2D(bitmap, openfl_TextureCoordv);
#pragma header
vec2 uv = openfl_TextureCoordv.xy;
uniform vec3 extraTint;
uniform vec2 endPosition;
vec2 hash22(vec2 p) {
vec3 p3 = fract(vec3(p.xyx) * vec3(.1031, .1030, .0973));
p3 += dot(p3, p3.yzx + 33.33);
return fract((p3.xx + p3.yz) * p3.zy);
}
vec2 start = vec2(0.0, 0.0);
vec2 end = vec2(endPosition.x / openfl_TextureSize.x, 1.0);
// ====== GAMMA CORRECTION ====== //
// Helps with color mixing -- good to have by default in almost any shader
// See https://www.shadertoy.com/view/lscSzl
vec3 gamma(in vec3 color) {
return pow(color, vec3(1.0 / 2.2));
}
float dx = end.x - start.x;
float dy = end.y - start.y;
vec4 mainPass(vec2 fragCoord) {
vec4 base = texture2D(bitmap, fragCoord);
float angle = atan(dy, dx);
vec2 uv = fragCoord.xy;
uv.x -= start.x;
uv.y -= start.y;
vec2 start = vec2(0.0, 0.0);
vec2 end = vec2(endPosition.x / openfl_TextureSize.x, 1.0);
float uvA = atan(uv.y, uv.x);
float dx = end.x - start.x;
float dy = end.y - start.y;
if (uvA < angle)
gl_FragColor = base;
else
gl_FragColor = vec4(0.0);
float angle = atan(dy, dx);
}')
uv.x -= start.x;
uv.y -= start.y;
float uvA = atan(uv.y, uv.x);
if (uvA < angle)
return base;
else
return vec4(0.0);
}
vec4 antialias(vec2 fragCoord) {
const float AA_STAGES = 2.0;
const float AA_TOTAL_PASSES = AA_STAGES * AA_STAGES + 1.0;
const float AA_JITTER = 0.5;
// Run the shader multiple times with a random subpixel offset each time and average the results
vec4 color = mainPass(fragCoord);
for (float x = 0.0; x < AA_STAGES; x++)
{
for (float y = 0.0; y < AA_STAGES; y++)
{
vec2 offset = AA_JITTER * (2.0 * hash22(vec2(x, y)) - 1.0) / openfl_TextureSize.xy;
color += mainPass(fragCoord + offset);
}
}
return color / AA_TOTAL_PASSES;
}
void main() {
vec4 col = antialias(openfl_TextureCoordv);
col.xyz = col.xyz * extraTint.xyz;
// col.xyz = gamma(col.xyz);
gl_FragColor = col;
}')
public function new()
{
super();
endPosition.value = [90, 100]; // 100 AS DEFAULT WORKS NICELY FOR FREEPLAY?
extraTint.value = [1, 1, 1];
}
}
@@ -0,0 +1,51 @@
package funkin.graphics.shaders;
import flixel.system.FlxAssets.FlxShader;
import flixel.tweens.FlxEase;
import flixel.tweens.FlxTween;
class BlueFade extends FlxShader
{
public var fadeVal(default, set):Float;
function set_fadeVal(val:Float):Float
{
fadeAmt.value = [val];
fadeVal = val;
// trace(fadeVal);
return val;
}
public function fade(startAmt:Float = 0, targetAmt:Float = 1, duration:Float, _options:TweenOptions):Void
{
fadeVal = startAmt;
FlxTween.tween(this, {fadeVal: targetAmt}, duration, _options);
}
@:glFragmentSource('
#pragma header
// Value from (0, 1)
uniform float fadeAmt;
// fade the image to blue as it fades to black
void main()
{
vec4 tex = flixel_texture2D(bitmap, openfl_TextureCoordv);
vec4 finalColor = mix(vec4(vec4(0.0, 0.0, tex.b, tex.a) * fadeAmt), vec4(tex * fadeAmt), fadeAmt);
// Output to screen
gl_FragColor = finalColor;
}
')
public function new()
{
super();
this.fadeVal = 1;
}
}
@@ -0,0 +1,23 @@
package funkin.graphics.shaders;
import flixel.addons.display.FlxRuntimeShader;
import openfl.utils.Assets;
import funkin.Paths;
import flixel.math.FlxPoint;
class MosaicEffect extends FlxRuntimeShader
{
public var blockSize:FlxPoint = FlxPoint.get(1.0, 1.0);
public function new()
{
super(Assets.getText(Paths.frag('mosaic')));
setBlockSize(1.0, 1.0);
}
public function setBlockSize(w:Float, h:Float)
{
blockSize.set(w, h);
setFloatArray("uBlocksize", [w, h]);
}
}
@@ -2,6 +2,7 @@ package funkin.graphics.shaders;
import flixel.FlxCamera;
import flixel.FlxG;
import flixel.graphics.frames.FlxFrame;
import flixel.addons.display.FlxRuntimeShader;
import lime.graphics.opengl.GLProgram;
import lime.utils.Log;
@@ -32,6 +33,9 @@ class RuntimePostEffectShader extends FlxRuntimeShader
// equals (camera.viewLeft, camera.viewTop, camera.viewRight, camera.viewBottom)
uniform vec4 uCameraBounds;
// equals (frame.left, frame.top, frame.right, frame.bottom)
uniform vec4 uFrameBounds;
// screen coord -> world coord conversion
// returns world coord in px
vec2 screenToWorld(vec2 screenCoord) {
@@ -56,6 +60,25 @@ class RuntimePostEffectShader extends FlxRuntimeShader
return (worldCoord - offset) / scale;
}
// screen coord -> frame coord conversion
// returns normalized frame coord
vec2 screenToFrame(vec2 screenCoord) {
float left = uFrameBounds.x;
float top = uFrameBounds.y;
float right = uFrameBounds.z;
float bottom = uFrameBounds.w;
float width = right - left;
float height = bottom - top;
float clampedX = clamp(screenCoord.x, left, right);
float clampedY = clamp(screenCoord.y, top, bottom);
return vec2(
(clampedX - left) / (width),
(clampedY - top) / (height)
);
}
// internally used to get the maximum `openfl_TextureCoordv`
vec2 bitmapCoordScale() {
return openfl_TextureCoordv / screenCoord;
@@ -80,6 +103,8 @@ class RuntimePostEffectShader extends FlxRuntimeShader
{
super(fragmentSource, null, glVersion);
uScreenResolution.value = [FlxG.width, FlxG.height];
uCameraBounds.value = [0, 0, FlxG.width, FlxG.height];
uFrameBounds.value = [0, 0, FlxG.width, FlxG.height];
}
// basically `updateViewInfo(FlxG.width, FlxG.height, FlxG.camera)` is good
@@ -89,6 +114,12 @@ class RuntimePostEffectShader extends FlxRuntimeShader
uCameraBounds.value = [camera.viewLeft, camera.viewTop, camera.viewRight, camera.viewBottom];
}
public function updateFrameInfo(frame:FlxFrame)
{
// NOTE: uv.width is actually the right pos and uv.height is the bottom pos
uFrameBounds.value = [frame.uv.x, frame.uv.y, frame.uv.width, frame.uv.height];
}
override function __createGLProgram(vertexSource:String, fragmentSource:String):GLProgram
{
try
@@ -4,6 +4,7 @@ import flixel.system.FlxAssets.FlxShader;
import openfl.display.BitmapData;
import openfl.display.ShaderParameter;
import openfl.display.ShaderParameterType;
import flixel.util.FlxColor;
import openfl.utils.Assets;
typedef Light =
@@ -32,6 +33,14 @@ class RuntimeRainShader extends RuntimePostEffectShader
return time = value;
}
public var spriteMode(default, set):Bool = false;
function set_spriteMode(value:Bool):Bool
{
this.setBool('uSpriteMode', value);
return spriteMode = value;
}
// The scale of the rain depends on the world coordinate system, so higher resolution makes
// the raindrops smaller. This parameter can be used to adjust the total scale of the scene.
// The size of the raindrops is proportional to the value of this parameter.
@@ -86,6 +95,14 @@ class RuntimeRainShader extends RuntimePostEffectShader
return mask = value;
}
public var rainColor(default, set):FlxColor;
function set_rainColor(color:FlxColor):FlxColor
{
this.setFloatArray("uRainColor", [color.red / 255, color.green / 255, color.blue / 255]);
return rainColor = color;
}
public var lightMap(default, set):BitmapData;
function set_lightMap(value:BitmapData):BitmapData
@@ -105,6 +122,7 @@ class RuntimeRainShader extends RuntimePostEffectShader
public function new()
{
super(Assets.getText(Paths.frag('rain')));
this.rainColor = 0xFF6680cc;
}
public function update(elapsed:Float):Void
@@ -0,0 +1,48 @@
package funkin.graphics.shaders;
import flixel.system.FlxAssets.FlxShader;
import flixel.util.FlxColor;
import openfl.display.BitmapData;
class TextureSwap extends FlxShader
{
public var swappedImage(default, set):BitmapData;
public var amount(default, set):Float;
function set_swappedImage(_bitmapData:BitmapData):BitmapData
{
image.input = _bitmapData;
return _bitmapData;
}
function set_amount(val:Float):Float
{
fadeAmount.value = [val];
return val;
}
@:glFragmentSource('
#pragma header
uniform sampler2D image;
uniform float fadeAmount;
void main()
{
vec4 tex = flixel_texture2D(bitmap, openfl_TextureCoordv);
vec4 tex2 = flixel_texture2D(image, openfl_TextureCoordv);
vec4 finalColor = mix(tex, vec4(tex2.rgb, tex.a), fadeAmount);
gl_FragColor = finalColor;
}
')
public function new()
{
super();
this.amount = 1;
}
}
File diff suppressed because it is too large Load Diff
+17 -11
View File
@@ -73,6 +73,22 @@ interface INoteScriptedClass extends IScriptedClass
public function onNoteMiss(event:NoteScriptEvent):Void;
}
/**
* Defines a set of callbacks available to scripted classes which represent sprites synced with the BPM.
*/
interface IBPMSyncedScriptedClass extends IScriptedClass
{
/**
* Called once every step of the song.
*/
public function onStepHit(event:SongTimeScriptEvent):Void;
/**
* Called once every beat of the song.
*/
public function onBeatHit(event:SongTimeScriptEvent):Void;
}
/**
* Developer note:
*
@@ -86,7 +102,7 @@ interface INoteScriptedClass extends IScriptedClass
/**
* Defines a set of callbacks available to scripted classes that involve the lifecycle of the Play State.
*/
interface IPlayStateScriptedClass extends INoteScriptedClass
interface IPlayStateScriptedClass extends INoteScriptedClass extends IBPMSyncedScriptedClass
{
/**
* Called when the game is paused.
@@ -136,16 +152,6 @@ interface IPlayStateScriptedClass extends INoteScriptedClass
*/
public function onSongEvent(event:SongEventScriptEvent):Void;
/**
* Called once every step of the song.
*/
public function onStepHit(event:SongTimeScriptEvent):Void;
/**
* Called once every beat of the song.
*/
public function onBeatHit(event:SongTimeScriptEvent):Void;
/**
* Called when the countdown of the song starts.
*/
+39 -7
View File
@@ -7,7 +7,9 @@ import funkin.data.dialogue.speaker.SpeakerRegistry;
import funkin.data.event.SongEventRegistry;
import funkin.data.story.level.LevelRegistry;
import funkin.data.notestyle.NoteStyleRegistry;
import funkin.play.notes.notekind.NoteKindManager;
import funkin.data.song.SongRegistry;
import funkin.data.freeplay.player.PlayerRegistry;
import funkin.data.stage.StageRegistry;
import funkin.data.freeplay.album.AlbumRegistry;
import funkin.modding.module.ModuleHandler;
@@ -26,11 +28,10 @@ class PolymodHandler
{
/**
* The API version that mods should comply with.
* Format this with Semantic Versioning; <MAJOR>.<MINOR>.<PATCH>.
* Bug fixes increment the patch version, new features increment the minor version.
* Changes that break old mods increment the major version.
* Indicates which mods are compatible with this version of the game.
* Minor updates rarely impact mods but major versions often do.
*/
static final API_VERSION:String = '0.1.0';
static final API_VERSION:String = "0.5.0"; // Constants.VERSION;
/**
* Where relative to the executable that mods are located.
@@ -176,7 +177,7 @@ class PolymodHandler
loadedModIds.push(mod.id);
}
#if debug
#if FEATURE_DEBUG_FUNCTIONS
var fileList:Array<String> = Polymod.listModFiles(PolymodAssetType.IMAGE);
trace('Installed mods have replaced ${fileList.length} images.');
for (item in fileList)
@@ -232,6 +233,12 @@ class PolymodHandler
// NOTE: Scripted classes are automatically aliased to their parent class.
Polymod.addImportAlias('flixel.math.FlxPoint', flixel.math.FlxPoint.FlxBasePoint);
Polymod.addImportAlias('funkin.data.event.SongEventSchema', funkin.data.event.SongEventSchema.SongEventSchemaRaw);
// `lime.utils.Assets` literally just has a private `resolveClass` function for some reason? so we replace it with our own.
Polymod.addImportAlias('lime.utils.Assets', funkin.Assets);
Polymod.addImportAlias('openfl.utils.Assets', funkin.Assets);
// Add blacklisting for prohibited classes and packages.
// `Sys`
@@ -250,8 +257,28 @@ class PolymodHandler
// Lib.load() can load malicious DLLs
Polymod.blacklistImport('cpp.Lib');
// `Unserializer`
// Unserializerr.DEFAULT_RESOLVER.resolveClass() can access blacklisted packages
Polymod.blacklistImport('Unserializer');
// `lime.system.CFFI`
// Can load and execute compiled binaries.
Polymod.blacklistImport('lime.system.CFFI');
// `lime.system.JNI`
// Can load and execute compiled binaries.
Polymod.blacklistImport('lime.system.JNI');
// `lime.system.System`
// System.load() can load malicious DLLs
Polymod.blacklistImport('lime.system.System');
// `openfl.desktop.NativeProcess`
// Can load native processes on the host operating system.
Polymod.blacklistImport('openfl.desktop.NativeProcess');
// `polymod.*`
// You can probably unblacklist a module
// Contains functions which may allow for un-blacklisting other modules.
for (cls in ClassMacro.listClassesInPackage('polymod'))
{
if (cls == null) continue;
@@ -260,6 +287,7 @@ class PolymodHandler
}
// `sys.*`
// Access to system utilities such as the file system.
for (cls in ClassMacro.listClassesInPackage('sys'))
{
if (cls == null) continue;
@@ -369,16 +397,20 @@ class PolymodHandler
// These MUST be imported at the top of the file and not referred to by fully qualified name,
// to ensure build macros work properly.
SongEventRegistry.loadEventCache();
SongRegistry.instance.loadEntries();
LevelRegistry.instance.loadEntries();
NoteStyleRegistry.instance.loadEntries();
SongEventRegistry.loadEventCache();
PlayerRegistry.instance.loadEntries();
ConversationRegistry.instance.loadEntries();
DialogueBoxRegistry.instance.loadEntries();
SpeakerRegistry.instance.loadEntries();
AlbumRegistry.instance.loadEntries();
StageRegistry.instance.loadEntries();
CharacterDataParser.loadCharacterCache(); // TODO: Migrate characters to BaseRegistry.
NoteKindManager.loadScripts();
ModuleHandler.loadModuleCache();
}
}
@@ -1,8 +0,0 @@
package funkin.modding.base;
/**
* A script that can be tied to an FlxUIState.
* Create a scripted class that extends FlxUIState to use this.
*/
@:hscriptClass
class ScriptedFlxUIState extends flixel.addons.ui.FlxUIState implements HScriptedClass {}
+23 -2
View File
@@ -140,16 +140,37 @@ class HitNoteScriptEvent extends NoteScriptEvent
*/
public var score:Int;
public function new(note:NoteSprite, healthChange:Float, score:Int, judgement:String, comboCount:Int = 0):Void
/**
* If the hit causes a combo break.
*/
public var isComboBreak:Bool = false;
/**
* The time difference when the player hit the note
*/
public var hitDiff:Float = 0;
/**
* Whether this note hit causes a note splash to display.
* Defaults to true only on "sick" notes.
*/
public var doesNotesplash:Bool = false;
public function new(note:NoteSprite, healthChange:Float, score:Int, judgement:String, isComboBreak:Bool, comboCount:Int = 0, hitDiff:Float = 0,
doesNotesplash:Bool = false):Void
{
super(NOTE_HIT, note, healthChange, comboCount, true);
this.score = score;
this.judgement = judgement;
this.isComboBreak = isComboBreak;
this.doesNotesplash = doesNotesplash;
this.hitDiff = hitDiff;
}
public override function toString():String
{
return 'HitNoteScriptEvent(note=' + note + ', comboCount=' + comboCount + ', judgement=' + judgement + ', score=' + score + ')';
return 'HitNoteScriptEvent(note=' + note + ', comboCount=' + comboCount + ', judgement=' + judgement + ', score=' + score + ', isComboBreak='
+ isComboBreak + ', hitDiff=' + hitDiff + ', doesNotesplash=' + doesNotesplash + ')';
}
}
@@ -94,6 +94,21 @@ class ScriptEventDispatcher
}
}
if (Std.isOfType(target, IBPMSyncedScriptedClass))
{
var t:IBPMSyncedScriptedClass = cast(target, IBPMSyncedScriptedClass);
switch (event.type)
{
case SONG_BEAT_HIT:
t.onBeatHit(cast event);
return;
case SONG_STEP_HIT:
t.onStepHit(cast event);
return;
default: // Continue;
}
}
if (Std.isOfType(target, IPlayStateScriptedClass))
{
var t:IPlayStateScriptedClass = cast(target, IPlayStateScriptedClass);
@@ -102,12 +117,6 @@ class ScriptEventDispatcher
case NOTE_GHOST_MISS:
t.onNoteGhostMiss(cast event);
return;
case SONG_BEAT_HIT:
t.onBeatHit(cast event);
return;
case SONG_STEP_HIT:
t.onStepHit(cast event);
return;
case SONG_START:
t.onSongStart(event);
return;
@@ -20,7 +20,7 @@ enum abstract ScriptEventType(String) from String to String
var DESTROY = 'DESTROY';
/**
* Called when the relevent object is added to the game state.
* Called when the relevant object is added to the game state.
* This assumes all data is loaded and ready to go.
*
* This event is not cancelable.
+68 -91
View File
@@ -9,7 +9,11 @@ import funkin.modding.module.ModuleHandler;
import funkin.modding.events.ScriptEvent;
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;
class Countdown
{
@@ -18,6 +22,24 @@ class Countdown
*/
public static var countdownStep(default, null):CountdownStep = BEFORE;
/**
* Which alternate graphic/sound on countdown to use.
* This is set via the current notestyle.
* For example, in Week 6 it is `pixel`.
*/
public static var soundSuffix:String = '';
/**
* Which alternate graphic on countdown to use.
* You can set this via script.
* For example, in Week 6 it is `-pixel`.
*/
public static var graphicSuffix:String = '';
static var noteStyle:NoteStyle;
static var fallbackNoteStyle:Null<NoteStyle>;
/**
* The currently running countdown. This will be null if there is no countdown running.
*/
@@ -29,7 +51,7 @@ class Countdown
* This will automatically stop and restart the countdown if it is already running.
* @returns `false` if the countdown was cancelled by a script.
*/
public static function performCountdown(isPixelStyle:Bool):Bool
public static function performCountdown():Bool
{
countdownStep = BEFORE;
var cancelled:Bool = propagateCountdownEvent(countdownStep);
@@ -64,10 +86,10 @@ class Countdown
// PlayState.instance.dispatchEvent(new SongTimeScriptEvent(SONG_BEAT_HIT, 0, 0));
// Countdown graphic.
showCountdownGraphic(countdownStep, isPixelStyle);
showCountdownGraphic(countdownStep);
// Countdown sound.
playCountdownSound(countdownStep, isPixelStyle);
playCountdownSound(countdownStep);
// Event handling bullshit.
var cancelled:Bool = propagateCountdownEvent(countdownStep);
@@ -117,7 +139,7 @@ class Countdown
*
* If you want to call this from a module, it's better to use the event system and cancel the onCountdownStep event.
*/
public static function pauseCountdown()
public static function pauseCountdown():Void
{
if (countdownTimer != null && !countdownTimer.finished)
{
@@ -130,7 +152,7 @@ class Countdown
*
* If you want to call this from a module, it's better to use the event system and cancel the onCountdownStep event.
*/
public static function resumeCountdown()
public static function resumeCountdown():Void
{
if (countdownTimer != null && !countdownTimer.finished)
{
@@ -143,7 +165,7 @@ class Countdown
*
* If you want to call this from a module, it's better to use the event system and cancel the onCountdownStart event.
*/
public static function stopCountdown()
public static function stopCountdown():Void
{
if (countdownTimer != null)
{
@@ -156,7 +178,7 @@ class Countdown
/**
* Stops the current countdown, then starts the song for you.
*/
public static function skipCountdown()
public static function skipCountdown():Void
{
stopCountdown();
// This will trigger PlayState.startSong()
@@ -176,114 +198,69 @@ class Countdown
}
/**
* Retrieves the graphic to use for this step of the countdown.
* TODO: Make this less dumb. Unhardcode it? Use modules? Use notestyles?
*
* This is public so modules can do lol funny shit.
* Reset the countdown configuration to the default.
*/
public static function showCountdownGraphic(index:CountdownStep, isPixelStyle:Bool):Void
public static function reset()
{
var spritePath:String = null;
noteStyle = null;
}
if (isPixelStyle)
{
switch (index)
{
case TWO:
spritePath = 'weeb/pixelUI/ready-pixel';
case ONE:
spritePath = 'weeb/pixelUI/set-pixel';
case GO:
spritePath = 'weeb/pixelUI/date-pixel';
default:
// null
}
}
else
{
switch (index)
{
case TWO:
spritePath = 'ready';
case ONE:
spritePath = 'set';
case GO:
spritePath = 'go';
default:
// null
}
}
/**
* Retrieve the note style data (if we haven't already)
* @param noteStyleId The id of the note style to fetch. Defaults to the one used by the current PlayState.
* @param force Fetch the note style from the registry even if we've already fetched it.
*/
static function fetchNoteStyle(?noteStyleId:String, force:Bool = false):Void
{
if (noteStyle != null && !force) return;
if (spritePath == null) return;
if (noteStyleId == null) noteStyleId = PlayState.instance?.currentChart?.noteStyle;
var countdownSprite:FunkinSprite = FunkinSprite.create(spritePath);
countdownSprite.scrollFactor.set(0, 0);
noteStyle = NoteStyleRegistry.instance.fetchEntry(noteStyleId);
if (noteStyle == null) noteStyle = NoteStyleRegistry.instance.fetchDefault();
}
if (isPixelStyle) countdownSprite.setGraphicSize(Std.int(countdownSprite.width * Constants.PIXEL_ART_SCALE));
/**
* Retrieves the graphic to use for this step of the countdown.
*/
public static function showCountdownGraphic(index:CountdownStep):Void
{
fetchNoteStyle();
countdownSprite.antialiasing = !isPixelStyle;
var countdownSprite = noteStyle.buildCountdownSprite(index);
if (countdownSprite == null) return;
countdownSprite.updateHitbox();
countdownSprite.screenCenter();
var fadeEase = FlxEase.cubeInOut;
if (noteStyle.isCountdownSpritePixel(index)) fadeEase = EaseUtil.stepped(8);
// Fade sprite in, then out, then destroy it.
FlxTween.tween(countdownSprite, {y: countdownSprite.y += 100, alpha: 0}, Conductor.instance.beatLengthMs / 1000,
FlxTween.tween(countdownSprite, {alpha: 0}, Conductor.instance.beatLengthMs / 1000,
{
ease: FlxEase.cubeInOut,
ease: fadeEase,
onComplete: function(twn:FlxTween) {
countdownSprite.destroy();
}
});
countdownSprite.cameras = [PlayState.instance.camHUD];
PlayState.instance.add(countdownSprite);
countdownSprite.screenCenter();
var offsets = noteStyle.getCountdownSpriteOffsets(index);
countdownSprite.x += offsets[0];
countdownSprite.y += offsets[1];
}
/**
* Retrieves the sound file to use for this step of the countdown.
* TODO: Make this less dumb. Unhardcode it? Use modules? Use notestyles?
*
* This is public so modules can do lol funny shit.
*/
public static function playCountdownSound(index:CountdownStep, isPixelStyle:Bool):Void
public static function playCountdownSound(step:CountdownStep):FunkinSound
{
var soundPath:String = null;
fetchNoteStyle();
var path = noteStyle.getCountdownSoundPath(step);
if (path == null) return null;
if (isPixelStyle)
{
switch (index)
{
case THREE:
soundPath = 'intro3-pixel';
case TWO:
soundPath = 'intro2-pixel';
case ONE:
soundPath = 'intro1-pixel';
case GO:
soundPath = 'introGo-pixel';
default:
// null
}
}
else
{
switch (index)
{
case THREE:
soundPath = 'intro3';
case TWO:
soundPath = 'intro2';
case ONE:
soundPath = 'intro1';
case GO:
soundPath = 'introGo';
default:
// null
}
}
if (soundPath == null) return;
FunkinSound.playOnce(Paths.sound(soundPath), Constants.COUNTDOWN_VOLUME);
return FunkinSound.playOnce(path, Constants.COUNTDOWN_VOLUME);
}
public static function decrement(step:CountdownStep):CountdownStep
+45 -8
View File
@@ -16,6 +16,8 @@ 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;
/**
* A substate which renders over the PlayState when the player dies.
@@ -71,7 +73,7 @@ class GameOverSubState extends MusicBeatSubState
var gameOverMusic:Null<FunkinSound> = null;
/**
* Whether the player has confirmed and prepared to restart the level.
* Whether the player has confirmed and prepared to restart the level or to go back to the freeplay menu.
* This means the animation and transition have already started.
*/
var isEnding:Bool = false;
@@ -144,6 +146,7 @@ class GameOverSubState extends MusicBeatSubState
else
{
boyfriend = PlayState.instance.currentStage.getBoyfriend(true);
boyfriend.canPlayOtherAnims = true;
boyfriend.isDead = true;
add(boyfriend);
boyfriend.resetCharacter();
@@ -166,8 +169,8 @@ class GameOverSubState extends MusicBeatSubState
// Assign a camera follow point to the boyfriend's position.
cameraFollowPoint = new FlxObject(PlayState.instance.cameraFollowPoint.x, PlayState.instance.cameraFollowPoint.y, 1, 1);
cameraFollowPoint.x = boyfriend.getGraphicMidpoint().x;
cameraFollowPoint.y = boyfriend.getGraphicMidpoint().y;
cameraFollowPoint.x = getMidPointOld(boyfriend).x;
cameraFollowPoint.y = getMidPointOld(boyfriend).y;
var offsets:Array<Float> = boyfriend.getDeathCameraOffsets();
cameraFollowPoint.x += offsets[0];
cameraFollowPoint.y += offsets[1];
@@ -178,6 +181,21 @@ class GameOverSubState extends MusicBeatSubState
targetCameraZoom = (PlayState?.instance?.currentStage?.camZoom ?? 1.0) * boyfriend.getDeathCameraZoom();
}
/**
* FlxSprite.getMidpoint(); calculations changed in this git commit
* https://github.com/HaxeFlixel/flixel/commit/1553b5af0871462fcefedc091b7885437d6c36d2
* https://github.com/HaxeFlixel/flixel/pull/3125
*
* So we use this to do the old math that gets the midpoint of our graphics
* Luckily, we don't use getGraphicMidpoint() much in the code, so it's fine being in GameoverSubState here.
* @return FlxPoint
*/
function getMidPointOld(spr:FlxSprite, ?point:FlxPoint):FlxPoint
{
if (point == null) point = FlxPoint.get();
return point.set(spr.x + spr.frameWidth * 0.5 * spr.scale.x, spr.y + spr.frameHeight * 0.5 * spr.scale.y);
}
/**
* Forcibly reset the camera zoom level to that of the current stage.
* This prevents camera zoom events from adversely affecting the game over state.
@@ -237,15 +255,16 @@ class GameOverSubState extends MusicBeatSubState
}
// KEYBOARD ONLY: Restart the level when pressing the assigned key.
if (controls.ACCEPT && blueballed)
if (controls.ACCEPT && blueballed && !mustNotExit)
{
blueballed = false;
confirmDeath();
}
// KEYBOARD ONLY: Return to the menu when pressing the assigned key.
if (controls.BACK && !mustNotExit)
if (controls.BACK && !mustNotExit && !isEnding)
{
isEnding = true;
blueballed = false;
PlayState.instance.deathCounter = 0;
// PlayState.seenCutscene = false; // old thing...
@@ -330,9 +349,12 @@ class GameOverSubState extends MusicBeatSubState
// After the animation finishes...
new FlxTimer().start(0.7, function(tmr:FlxTimer) {
// ...fade out the graphics. Then after that happens...
FlxG.camera.fade(FlxColor.BLACK, 2, false, function() {
var resetPlaying = function(pixel:Bool = false) {
// ...close the GameOverSubState.
FlxG.camera.fade(FlxColor.BLACK, 1, true, null, true);
if (pixel) RetroCameraFade.fadeBlack(FlxG.camera, 10, 1);
else
FlxG.camera.fade(FlxColor.BLACK, 1, true, null, true);
PlayState.instance.needsReset = true;
if (PlayState.instance.isMinimalMode || boyfriend == null) {}
@@ -349,7 +371,22 @@ class GameOverSubState extends MusicBeatSubState
// Close the substate.
close();
});
};
if (musicSuffix == '-pixel')
{
RetroCameraFade.fadeToBlack(FlxG.camera, 10, 2);
new FlxTimer().start(2, _ -> {
FlxG.camera.filters = [];
resetPlaying(true);
});
}
else
{
FlxG.camera.fade(FlxColor.BLACK, 2, false, function() {
resetPlaying();
});
}
});
}
}
+5 -4
View File
@@ -306,7 +306,7 @@ class PauseSubState extends MusicBeatSubState
metadataDifficulty.setFormat(Paths.font('vcr.ttf'), 32, FlxColor.WHITE, FlxTextAlign.RIGHT);
if (PlayState.instance?.currentDifficulty != null)
{
metadataDifficulty.text += PlayState.instance.currentDifficulty.toTitleCase();
metadataDifficulty.text += PlayState.instance.currentDifficulty.replace('-', ' ').toTitleCase();
}
metadataDifficulty.scrollFactor.set(0, 0);
metadata.add(metadataDifficulty);
@@ -430,7 +430,7 @@ class PauseSubState extends MusicBeatSubState
resume(this);
}
#if (debug || FORCE_DEBUG_VERSION)
#if FEATURE_DEBUG_FUNCTIONS
// to pause the game and get screenshots easy, press H on pause menu!
if (FlxG.keys.justPressed.H)
{
@@ -449,13 +449,14 @@ class PauseSubState extends MusicBeatSubState
*/
function changeSelection(change:Int = 0):Void
{
FunkinSound.playOnce(Paths.sound('scrollMenu'), 0.4);
var prevEntry:Int = currentEntry;
currentEntry += change;
if (currentEntry < 0) currentEntry = currentMenuEntries.length - 1;
if (currentEntry >= currentMenuEntries.length) currentEntry = 0;
if (currentEntry != prevEntry) FunkinSound.playOnce(Paths.sound('scrollMenu'), 0.4);
for (entryIndex in 0...currentMenuEntries.length)
{
var isCurrent:Bool = entryIndex == currentEntry;
File diff suppressed because it is too large Load Diff
+205 -278
View File
@@ -4,6 +4,8 @@ import funkin.util.MathUtil;
import funkin.ui.story.StoryMenuState;
import funkin.graphics.adobeanimate.FlxAtlasSprite;
import flixel.FlxSprite;
import flixel.FlxState;
import flixel.FlxSubState;
import funkin.graphics.FunkinSprite;
import flixel.effects.FlxFlicker;
import flixel.graphics.frames.FlxBitmapFont;
@@ -14,6 +16,9 @@ import flixel.math.FlxRect;
import flixel.text.FlxBitmapText;
import funkin.ui.freeplay.FreeplayScore;
import flixel.text.FlxText;
import funkin.data.freeplay.player.PlayerRegistry;
import funkin.data.freeplay.player.PlayerData;
import funkin.ui.freeplay.charselect.PlayableCharacter;
import flixel.util.FlxColor;
import flixel.tweens.FlxEase;
import funkin.graphics.FunkinCamera;
@@ -55,14 +60,19 @@ class ResultState extends MusicBeatSubState
final highscoreNew:FlxSprite;
final score:ResultScore;
var bfPerfect:Null<FlxAtlasSprite> = null;
var heartsPerfect:Null<FlxAtlasSprite> = null;
var bfExcellent:Null<FlxAtlasSprite> = null;
var bfGreat:Null<FlxAtlasSprite> = null;
var gfGreat:Null<FlxAtlasSprite> = null;
var bfGood:Null<FlxSprite> = null;
var gfGood:Null<FlxSprite> = null;
var bfShit:Null<FlxAtlasSprite> = null;
var characterAtlasAnimations:Array<
{
sprite:FlxAtlasSprite,
delay:Float,
forceLoop:Bool
}> = [];
var characterSparrowAnimations:Array<
{
sprite:FunkinSprite,
delay:Float
}> = [];
var playerCharacterId:Null<String>;
var rankBg:FunkinSprite;
final cameraBG:FunkinCamera;
@@ -157,118 +167,98 @@ class ResultState extends MusicBeatSubState
soundSystem.zIndex = 1100;
add(soundSystem);
switch (rank)
// Fetch playable character data. Default to BF on the results screen if we can't find it.
playerCharacterId = PlayerRegistry.instance.getCharacterOwnerId(params.characterId);
var playerCharacter:Null<PlayableCharacter> = PlayerRegistry.instance.fetchEntry(playerCharacterId ?? 'bf');
trace('Got playable character: ${playerCharacter?.getName()}');
// Query JSON data based on the rank, then use that to build the animation(s) the player sees.
var playerAnimationDatas:Array<PlayerResultsAnimationData> = playerCharacter != null ? playerCharacter.getResultsAnimationDatas(rank) : [];
for (animData in playerAnimationDatas)
{
case PERFECT | PERFECT_GOLD:
heartsPerfect = new FlxAtlasSprite(1342, 370, Paths.animateAtlas("resultScreen/results-bf/resultsPERFECT/hearts", "shared"));
heartsPerfect.visible = false;
heartsPerfect.zIndex = 501;
add(heartsPerfect);
if (animData == null) continue;
heartsPerfect.anim.onComplete = () -> {
if (heartsPerfect != null)
var animPath:String = Paths.stripLibrary(animData.assetPath);
var animLibrary:String = Paths.getLibrary(animData.assetPath);
var offsets = animData.offsets ?? [0, 0];
switch (animData.renderType)
{
case 'animateatlas':
var animation:FlxAtlasSprite = new FlxAtlasSprite(offsets[0], offsets[1], Paths.animateAtlas(animPath, animLibrary));
animation.zIndex = animData.zIndex ?? 500;
animation.scale.set(animData.scale ?? 1.0, animData.scale ?? 1.0);
if (!(animData.looped ?? true))
{
// bfPerfect.anim.curFrame = 137;
heartsPerfect.anim.curFrame = 43;
heartsPerfect.anim.play(); // unpauses this anim, since it's on PlayOnce!
// Animation is not looped.
animation.onAnimationComplete.add((_name:String) -> {
trace("AHAHAH 2");
if (animation != null)
{
animation.anim.pause();
}
});
}
};
bfPerfect = new FlxAtlasSprite(1342, 370, Paths.animateAtlas("resultScreen/results-bf/resultsPERFECT", "shared"));
bfPerfect.visible = false;
bfPerfect.zIndex = 500;
add(bfPerfect);
bfPerfect.anim.onComplete = () -> {
if (bfPerfect != null)
else if (animData.loopFrameLabel != null)
{
// bfPerfect.anim.curFrame = 137;
bfPerfect.anim.curFrame = 137;
bfPerfect.anim.play(); // unpauses this anim, since it's on PlayOnce!
animation.onAnimationComplete.add((_name:String) -> {
trace("AHAHAH 2");
if (animation != null)
{
animation.playAnimation(animData.loopFrameLabel ?? '', true, false, true); // unpauses this anim, since it's on PlayOnce!
}
});
}
};
case EXCELLENT:
bfExcellent = new FlxAtlasSprite(1329, 429, Paths.animateAtlas("resultScreen/results-bf/resultsEXCELLENT", "shared"));
bfExcellent.visible = false;
bfExcellent.zIndex = 500;
add(bfExcellent);
bfExcellent.anim.onComplete = () -> {
if (bfExcellent != null)
else if (animData.loopFrame != null)
{
bfExcellent.anim.curFrame = 28;
bfExcellent.anim.play(); // unpauses this anim, since it's on PlayOnce!
animation.onAnimationComplete.add((_name:String) -> {
if (animation != null)
{
trace("AHAHAH");
animation.anim.curFrame = animData.loopFrame ?? 0;
animation.anim.play(); // unpauses this anim, since it's on PlayOnce!
}
});
}
};
case GREAT:
gfGreat = new FlxAtlasSprite(802, 331, Paths.animateAtlas("resultScreen/results-bf/resultsGREAT/gf", "shared"));
gfGreat.visible = false;
gfGreat.zIndex = 499;
add(gfGreat);
// Hide until ready to play.
animation.visible = false;
// Queue to play.
characterAtlasAnimations.push(
{
sprite: animation,
delay: animData.delay ?? 0.0,
forceLoop: (animData.loopFrame ?? -1) == 0
});
// Add to the scene.
add(animation);
case 'sparrow':
var animation:FunkinSprite = FunkinSprite.createSparrow(offsets[0], offsets[1], animPath);
animation.animation.addByPrefix('idle', '', 24, false, false, false);
gfGreat.scale.set(0.93, 0.93);
gfGreat.anim.onComplete = () -> {
if (gfGreat != null)
if (animData.loopFrame != null)
{
gfGreat.anim.curFrame = 9;
gfGreat.anim.play(); // unpauses this anim, since it's on PlayOnce!
animation.animation.finishCallback = (_name:String) -> {
if (animation != null)
{
animation.animation.play('idle', true, false, animData.loopFrame ?? 0);
}
}
}
};
bfGreat = new FlxAtlasSprite(929, 363, Paths.animateAtlas("resultScreen/results-bf/resultsGREAT/bf", "shared"));
bfGreat.visible = false;
bfGreat.zIndex = 500;
add(bfGreat);
bfGreat.scale.set(0.93, 0.93);
bfGreat.anim.onComplete = () -> {
if (bfGreat != null)
{
bfGreat.anim.curFrame = 15;
bfGreat.anim.play(); // unpauses this anim, since it's on PlayOnce!
}
};
case GOOD:
gfGood = FunkinSprite.createSparrow(625, 325, 'resultScreen/results-bf/resultsGOOD/resultGirlfriendGOOD');
gfGood.animation.addByPrefix("clap", "Girlfriend Good Anim", 24, false);
gfGood.visible = false;
gfGood.zIndex = 500;
gfGood.animation.finishCallback = _ -> {
if (gfGood != null)
{
gfGood.animation.play('clap', true, false, 9);
}
};
add(gfGood);
bfGood = FunkinSprite.createSparrow(640, -200, 'resultScreen/results-bf/resultsGOOD/resultBoyfriendGOOD');
bfGood.animation.addByPrefix("fall", "Boyfriend Good Anim0", 24, false);
bfGood.visible = false;
bfGood.zIndex = 501;
bfGood.animation.finishCallback = function(_) {
if (bfGood != null)
{
bfGood.animation.play('fall', true, false, 14);
}
};
add(bfGood);
case SHIT:
bfShit = new FlxAtlasSprite(0, 20, Paths.animateAtlas("resultScreen/results-bf/resultsSHIT", "shared"));
bfShit.visible = false;
bfShit.zIndex = 500;
add(bfShit);
bfShit.onAnimationFinish.add((animName) -> {
if (bfShit != null)
{
bfShit.playAnimation('Loop Start');
}
});
// Hide until ready to play.
animation.visible = false;
// Queue to play.
characterSparrowAnimations.push(
{
sprite: animation,
delay: animData.delay ?? 0.0
});
// Add to the scene.
add(animation);
}
}
var diffSpr:String = 'diff_${params?.difficultyId ?? 'Normal'}';
@@ -419,28 +409,26 @@ class ResultState extends MusicBeatSubState
// }
new FlxTimer().start(rank.getMusicDelay(), _ -> {
if (rank.hasMusicIntro())
var introMusic:String = Paths.music(getMusicPath(playerCharacter, rank) + '/' + getMusicPath(playerCharacter, rank) + '-intro');
if (Assets.exists(introMusic))
{
// Play the intro music.
var introMusic:String = Paths.music(rank.getMusicPath() + '/' + rank.getMusicPath() + '-intro');
FunkinSound.load(introMusic, 1.0, false, true, true, () -> {
FunkinSound.playMusic(rank.getMusicPath(),
FunkinSound.playMusic(getMusicPath(playerCharacter, rank),
{
startingVolume: 1.0,
overrideExisting: true,
restartTrack: true,
loop: rank.shouldMusicLoop()
restartTrack: true
});
});
}
else
{
FunkinSound.playMusic(rank.getMusicPath(),
FunkinSound.playMusic(getMusicPath(playerCharacter, rank),
{
startingVolume: 1.0,
overrideExisting: true,
restartTrack: true,
loop: rank.shouldMusicLoop()
restartTrack: true
});
}
});
@@ -456,6 +444,11 @@ class ResultState extends MusicBeatSubState
super.create();
}
function getMusicPath(playerCharacter:Null<PlayableCharacter>, rank:ScoringRank):String
{
return playerCharacter?.getResultsMusicPath(rank) ?? 'resultsNORMAL';
}
var rankTallyTimer:Null<FlxTimer> = null;
var clearPercentTarget:Int = 100;
var clearPercentLerp:Int = 0;
@@ -464,7 +457,9 @@ class ResultState extends MusicBeatSubState
{
bgFlash.visible = true;
FlxTween.tween(bgFlash, {alpha: 0}, 5 / 24);
var clearPercentFloat = (params.scoreData.tallies.sick + params.scoreData.tallies.good) / params.scoreData.tallies.totalNotes * 100;
// NOTE: Only divide if totalNotes > 0 to prevent divide-by-zero errors.
var clearPercentFloat = params.scoreData.tallies.totalNotes == 0 ? 0.0 : (params.scoreData.tallies.sick +
params.scoreData.tallies.good) / params.scoreData.tallies.totalNotes * 100;
clearPercentTarget = Math.floor(clearPercentFloat);
// Prevent off-by-one errors.
@@ -585,94 +580,22 @@ class ResultState extends MusicBeatSubState
{
showSmallClearPercent();
switch (rank)
for (atlas in characterAtlasAnimations)
{
case PERFECT | PERFECT_GOLD:
if (bfPerfect == null)
{
trace("Could not build PERFECT animation!");
}
else
{
bfPerfect.visible = true;
bfPerfect.playAnimation('');
}
new FlxTimer().start(106 / 24, _ -> {
if (heartsPerfect == null)
{
trace("Could not build heartsPerfect animation!");
}
else
{
heartsPerfect.visible = true;
heartsPerfect.playAnimation('');
}
});
case EXCELLENT:
if (bfExcellent == null)
{
trace("Could not build EXCELLENT animation!");
}
else
{
bfExcellent.visible = true;
bfExcellent.playAnimation('');
}
case GREAT:
if (bfGreat == null)
{
trace("Could not build GREAT animation!");
}
else
{
bfGreat.visible = true;
bfGreat.playAnimation('');
}
new FlxTimer().start(atlas.delay, _ -> {
if (atlas.sprite == null) return;
atlas.sprite.visible = true;
atlas.sprite.playAnimation('');
});
}
new FlxTimer().start(6 / 24, _ -> {
if (gfGreat == null)
{
trace("Could not build GREAT animation for gf!");
}
else
{
gfGreat.visible = true;
gfGreat.playAnimation('');
}
});
case SHIT:
if (bfShit == null)
{
trace("Could not build SHIT animation!");
}
else
{
bfShit.visible = true;
bfShit.playAnimation('Intro');
}
case GOOD:
if (bfGood == null)
{
trace("Could not build GOOD animation!");
}
else
{
bfGood.animation.play('fall');
bfGood.visible = true;
new FlxTimer().start((1 / 24) * 22, _ -> {
// plays about 22 frames (at 24fps timing) after bf spawns in
if (gfGood != null)
{
gfGood.animation.play('clap', true);
gfGood.visible = true;
}
else
{
trace("Could not build GOOD animation!");
}
});
}
default:
for (sprite in characterSparrowAnimations)
{
new FlxTimer().start(sprite.delay, _ -> {
if (sprite.sprite == null) return;
sprite.sprite.visible = true;
sprite.sprite.animation.play('idle', true);
});
}
}
@@ -774,52 +697,6 @@ class ResultState extends MusicBeatSubState
// }));
// }
// if(heartsPerfect != null){
// if (FlxG.keys.justPressed.I)
// {
// heartsPerfect.y -= 1;
// trace(heartsPerfect.x, heartsPerfect.y);
// }
// if (FlxG.keys.justPressed.J)
// {
// heartsPerfect.x -= 1;
// trace(heartsPerfect.x, heartsPerfect.y);
// }
// if (FlxG.keys.justPressed.L)
// {
// heartsPerfect.x += 1;
// trace(heartsPerfect.x, heartsPerfect.y);
// }
// if (FlxG.keys.justPressed.K)
// {
// heartsPerfect.y += 1;
// trace(heartsPerfect.x, heartsPerfect.y);
// }
// }
// if(bfGreat != null){
// if (FlxG.keys.justPressed.W)
// {
// bfGreat.y -= 1;
// trace(bfGreat.x, bfGreat.y);
// }
// if (FlxG.keys.justPressed.A)
// {
// bfGreat.x -= 1;
// trace(bfGreat.x, bfGreat.y);
// }
// if (FlxG.keys.justPressed.D)
// {
// bfGreat.x += 1;
// trace(bfGreat.x, bfGreat.y);
// }
// if (FlxG.keys.justPressed.S)
// {
// bfGreat.y += 1;
// trace(bfGreat.x, bfGreat.y);
// }
// }
// maskShaderSongName.swagSprX = songName.x;
maskShaderDifficulty.swagSprX = difficulty.x;
@@ -857,53 +734,93 @@ class ResultState extends MusicBeatSubState
}
});
}
// Determining the target state(s) to go to.
// Default to main menu because that's better than `null`.
var targetState:flixel.FlxState = new funkin.ui.mainmenu.MainMenuState();
var shouldTween = false;
var shouldUseSubstate = false;
if (params.storyMode)
{
openSubState(new funkin.ui.transition.StickerSubState(null, (sticker) -> new StoryMenuState(sticker)));
if (PlayerRegistry.instance.hasNewCharacter())
{
// New character, display the notif.
targetState = new StoryMenuState(null);
var newCharacters = PlayerRegistry.instance.listNewCharacters();
for (charId in newCharacters)
{
shouldTween = true;
// This works recursively, ehe!
targetState = new funkin.ui.charSelect.CharacterUnlockState(charId, targetState);
}
}
else
{
// No new characters.
shouldTween = false;
shouldUseSubstate = true;
targetState = new funkin.ui.transition.StickerSubState(null, (sticker) -> new StoryMenuState(sticker));
}
}
else
{
var rigged:Bool = true;
if (rank > Scoring.calculateRank(params?.prevScoreData)) // if (rigged)
if (rank > Scoring.calculateRank(params?.prevScoreData))
{
trace('THE RANK IS Higher.....');
FlxTween.tween(rankBg, {alpha: 1}, 0.5,
shouldTween = true;
targetState = FreeplayState.build(
{
ease: FlxEase.expoOut,
onComplete: function(_) {
FlxG.switchState(FreeplayState.build(
{
character: playerCharacterId ?? "bf",
fromResults:
{
{
fromResults:
{
oldRank: Scoring.calculateRank(params?.prevScoreData),
newRank: rank,
songId: params.songId,
difficultyId: params.difficultyId,
playRankAnim: true
}
}
}));
oldRank: Scoring.calculateRank(params?.prevScoreData),
newRank: rank,
songId: params.songId,
difficultyId: params.difficultyId,
playRankAnim: true
}
}
});
}
else
{
trace('rank is lower...... and/or equal');
openSubState(new funkin.ui.transition.StickerSubState(null, (sticker) -> FreeplayState.build(
{
shouldTween = false;
shouldUseSubstate = true;
targetState = new funkin.ui.transition.StickerSubState(null, (sticker) -> FreeplayState.build(null, sticker));
}
}
if (shouldTween)
{
FlxTween.tween(rankBg, {alpha: 1}, 0.5,
{
ease: FlxEase.expoOut,
onComplete: function(_) {
if (shouldUseSubstate && targetState is FlxSubState)
{
fromResults:
{
oldRank: null,
playRankAnim: false,
newRank: rank,
songId: params.songId,
difficultyId: params.difficultyId
}
openSubState(cast targetState);
}
}, sticker)));
else
{
FlxG.switchState(targetState);
}
}
});
}
else
{
if (shouldUseSubstate && targetState is FlxSubState)
{
openSubState(cast targetState);
}
else
{
FlxG.switchState(targetState);
}
}
}
@@ -920,12 +837,22 @@ typedef ResultsStateParams =
var storyMode:Bool;
/**
* A readable title for the song we just played.
* Either "Song Name by Artist Name" or "Week Name"
*/
var title:String;
/**
* The internal song ID for the song we just played.
*/
var songId:String;
/**
* The character ID for the song we just played.
* @default `bf`
*/
var ?characterId:String;
/**
* Whether the displayed score is a new highscore
*/
@@ -109,8 +109,6 @@ class AnimateAtlasCharacter extends BaseCharacter
var loop:Bool = animData.looped;
this.mainSprite.playAnimation(prefix, restart, ignoreOther, loop);
animFinished = false;
}
public override function hasAnimation(name:String):Bool
@@ -124,17 +122,21 @@ class AnimateAtlasCharacter extends BaseCharacter
*/
public override function isAnimationFinished():Bool
{
return animFinished;
return mainSprite?.isAnimationFinished() ?? false;
}
function loadAtlasSprite():FlxAtlasSprite
{
trace('[ATLASCHAR] Loading sprite atlas for ${characterId}.');
var sprite:FlxAtlasSprite = new FlxAtlasSprite(0, 0, Paths.animateAtlas(_data.assetPath, 'shared'));
var animLibrary:String = Paths.getLibrary(_data.assetPath);
var animPath:String = Paths.stripLibrary(_data.assetPath);
var assetPath:String = Paths.animateAtlas(animPath, animLibrary);
sprite.onAnimationFinish.removeAll();
sprite.onAnimationFinish.add(this.onAnimationFinished);
var sprite:FlxAtlasSprite = new FlxAtlasSprite(0, 0, assetPath);
// sprite.onAnimationComplete.removeAll();
sprite.onAnimationComplete.add(this.onAnimationFinished);
return sprite;
}
@@ -152,7 +154,6 @@ class AnimateAtlasCharacter extends BaseCharacter
// Make the game hold on the last frame.
this.mainSprite.cleanupAnimation(prefix);
// currentAnimName = null;
animFinished = true;
// Fallback to idle!
// playAnimation('idle', true, false);
@@ -165,6 +166,13 @@ class AnimateAtlasCharacter extends BaseCharacter
this.mainSprite = sprite;
mainSprite.ignoreExclusionPref = ["sing"];
// This forces the atlas to recalcuate its width and height
this.mainSprite.alpha = 0.0001;
this.mainSprite.draw();
this.mainSprite.alpha = 1.0;
var feetPos:FlxPoint = feetPosition;
this.updateHitbox();
+101 -44
View File
@@ -118,22 +118,6 @@ class BaseCharacter extends Bopper
*/
public var cameraFocusPoint(default, null):FlxPoint = new FlxPoint(0, 0);
override function set_animOffsets(value:Array<Float>):Array<Float>
{
if (animOffsets == null) value = [0, 0];
if ((animOffsets[0] == value[0]) && (animOffsets[1] == value[1])) return value;
// Make sure animOffets are halved when scale is 0.5.
var xDiff = (animOffsets[0] * this.scale.x / (this.isPixel ? 6 : 1)) - value[0];
var yDiff = (animOffsets[1] * this.scale.y / (this.isPixel ? 6 : 1)) - value[1];
// Call the super function so that camera focus point is not affected.
super.set_x(this.x + xDiff);
super.set_y(this.y + yDiff);
return animOffsets = value;
}
/**
* If the x position changes, other than via changing the animation offset,
* then we need to update the camera focus point.
@@ -164,9 +148,11 @@ class BaseCharacter extends Bopper
public function new(id:String, renderType:CharacterRenderType)
{
super();
super(CharacterDataParser.DEFAULT_DANCEEVERY);
this.characterId = id;
ignoreExclusionPref = ["sing"];
_data = CharacterDataParser.fetchCharacterData(this.characterId);
if (_data == null)
{
@@ -180,6 +166,7 @@ class BaseCharacter extends Bopper
{
this.characterName = _data.name;
this.name = _data.name;
this.danceEvery = _data.danceEvery;
this.singTimeSteps = _data.singTime;
this.globalOffsets = _data.offsets;
this.flipX = _data.flipX;
@@ -308,13 +295,26 @@ class BaseCharacter extends Bopper
// so we can query which ones are available.
this.comboNoteCounts = findCountAnimations('combo'); // example: combo50
this.dropNoteCounts = findCountAnimations('drop'); // example: drop50
// trace('${this.animation.getNameList()}');
// trace('Combo note counts: ' + this.comboNoteCounts);
// trace('Drop note counts: ' + this.dropNoteCounts);
if (comboNoteCounts.length > 0) trace('Combo note counts: ' + this.comboNoteCounts);
if (dropNoteCounts.length > 0) trace('Drop note counts: ' + this.dropNoteCounts);
super.onCreate(event);
}
override function onAnimationFinished(animationName:String):Void
{
super.onAnimationFinished(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'))
{
// Force the character to play the idle after the animation ends.
this.dance(true);
}
}
function resetCameraFocusPoint():Void
{
// Calculate the camera focus point
@@ -368,9 +368,18 @@ class BaseCharacter extends Bopper
// and Darnell (this keeps the flame on his lighter flickering).
// Works for idle, singLEFT/RIGHT/UP/DOWN, alt singing animations, and anything else really.
if (!getCurrentAnimation().endsWith('-hold') && hasAnimation(getCurrentAnimation() + '-hold') && isAnimationFinished())
if (isAnimationFinished()
&& !getCurrentAnimation().endsWith(Constants.ANIMATION_HOLD_SUFFIX)
&& hasAnimation(getCurrentAnimation() + Constants.ANIMATION_HOLD_SUFFIX))
{
playAnimation(getCurrentAnimation() + '-hold');
playAnimation(getCurrentAnimation() + Constants.ANIMATION_HOLD_SUFFIX);
}
else
{
if (isAnimationFinished())
{
// trace('Not playing hold (${getCurrentAnimation()}) (${isAnimationFinished()}, ${getCurrentAnimation().endsWith(Constants.ANIMATION_HOLD_SUFFIX)}, ${hasAnimation(getCurrentAnimation() + Constants.ANIMATION_HOLD_SUFFIX)})');
}
}
// Handle character note hold time.
@@ -395,7 +404,24 @@ class BaseCharacter extends Bopper
{
trace('holdTimer reached ${holdTimer}sec (> ${singTimeSec}), stopping sing animation');
holdTimer = 0;
dance(true);
var currentAnimation:String = getCurrentAnimation();
// Strip "-hold" from the end.
if (currentAnimation.endsWith(Constants.ANIMATION_HOLD_SUFFIX)) currentAnimation = currentAnimation.substring(0,
currentAnimation.length - Constants.ANIMATION_HOLD_SUFFIX.length);
var endAnimation:String = currentAnimation + Constants.ANIMATION_END_SUFFIX;
if (hasAnimation(endAnimation))
{
// Play the '-end' animation, if one exists.
trace('${characterId}: playing ${endAnimation}');
playAnimation(endAnimation);
}
else
{
// Play the idle animation.
dance(true);
}
}
}
else
@@ -408,7 +434,8 @@ class BaseCharacter extends Bopper
public function isSinging():Bool
{
return getCurrentAnimation().startsWith('sing');
var currentAnimation:String = getCurrentAnimation();
return currentAnimation.startsWith('sing') && !currentAnimation.endsWith(Constants.ANIMATION_END_SUFFIX);
}
override function dance(force:Bool = false):Void
@@ -418,15 +445,14 @@ class BaseCharacter extends Bopper
if (!force)
{
// Prevent dancing while a singing animation is playing.
if (isSinging()) return;
// Prevent dancing while a non-idle special animation is playing.
var currentAnimation:String = getCurrentAnimation();
if ((currentAnimation == 'hey' || currentAnimation == 'cheer') && !isAnimationFinished()) return;
if (!currentAnimation.startsWith('dance') && !currentAnimation.startsWith('idle') && !isAnimationFinished()) return;
}
// Prevent dancing while another animation is playing.
if (!force && isSinging()) return;
// Otherwise, fallback to the super dance() method, which handles playing the idle animation.
super.dance();
}
@@ -487,6 +513,9 @@ class BaseCharacter extends Bopper
{
super.onNoteHit(event);
// If another script cancelled the event, don't do anything.
if (event.eventCanceled) return;
if (event.note.noteData.getMustHitNote() && characterType == BF)
{
// If the note is from the same strumline, play the sing animation.
@@ -499,6 +528,16 @@ class BaseCharacter extends Bopper
this.playSingAnimation(event.note.noteData.getDirection(), false);
holdTimer = 0;
}
else if (characterType == GF && event.note.noteData.getMustHitNote())
{
switch (event.judgement)
{
case 'sick' | 'good':
playComboAnimation(event.comboCount);
default:
playComboDropAnimation(event.comboCount);
}
}
}
/**
@@ -509,6 +548,9 @@ class BaseCharacter extends Bopper
{
super.onNoteMiss(event);
// If another script cancelled the event, don't do anything.
if (event.eventCanceled) return;
if (event.note.noteData.getMustHitNote() && characterType == BF)
{
// If the note is from the same strumline, play the sing animation.
@@ -521,31 +563,46 @@ class BaseCharacter extends Bopper
}
else if (event.note.noteData.getMustHitNote() && characterType == GF)
{
var dropAnim = '';
playComboDropAnimation(Highscore.tallies.combo);
}
}
// Choose the combo drop anim to play.
// If there are several (for example, drop10 and drop50) the highest one will be used.
// If the combo count is too low, no animation will be played.
for (count in dropNoteCounts)
{
if (event.comboCount >= count)
{
dropAnim = 'drop${count}';
}
}
function playComboAnimation(comboCount:Int):Void
{
var comboAnim = 'combo${comboCount}';
if (hasAnimation(comboAnim))
{
trace('Playing GF combo animation: ${comboAnim}');
this.playAnimation(comboAnim, true, true);
}
}
if (dropAnim != '')
function playComboDropAnimation(comboCount:Int):Void
{
var dropAnim:Null<String> = null;
// Choose the combo drop anim to play.
// If there are several (for example, drop10 and drop50) the highest one will be used.
// If the combo count is too low, no animation will be played.
for (count in dropNoteCounts)
{
if (comboCount >= count)
{
trace('Playing GF combo drop animation: ${dropAnim}');
this.playAnimation(dropAnim, true, true);
dropAnim = 'drop${count}';
}
}
if (dropAnim != null)
{
trace('Playing GF combo drop animation: ${dropAnim}');
this.playAnimation(dropAnim, true, true);
}
}
/**
* Every time a wrong key is pressed, play the miss animation if we are Boyfriend.
*/
public override function onNoteGhostMiss(event:GhostMissNoteScriptEvent)
public override function onNoteGhostMiss(event:GhostMissNoteScriptEvent):Void
{
super.onNoteGhostMiss(event);
@@ -579,12 +636,12 @@ 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}...');
playAnimation(anim, true);
}
public override function playAnimation(name:String, restart:Bool = false, ignoreOther:Bool = false, reversed:Bool = false):Void
{
// FlxG.watch.addQuick('playAnim(${characterName})', name);
super.playAnimation(name, restart, ignoreOther, reversed);
}
}
+23 -19
View File
@@ -305,8 +305,10 @@ class CharacterDataParser
icon = "darnell";
case "senpai-angry":
icon = "senpai";
case "tankman" | "tankman-atlas":
icon = "tankmen";
case "spooky-dark":
icon = "spooky";
case "tankman-atlas":
icon = "tankman";
}
var path = Paths.image("freeplay/icons/" + icon + "pixel");
@@ -383,21 +385,21 @@ class CharacterDataParser
* Values that are too high will cause the character to hold their singing pose for too long after they're done.
* @default `8 steps`
*/
static final DEFAULT_SINGTIME:Float = 8.0;
public static final DEFAULT_SINGTIME:Float = 8.0;
static final DEFAULT_DANCEEVERY:Int = 1;
static final DEFAULT_FLIPX:Bool = false;
static final DEFAULT_FLIPY:Bool = false;
static final DEFAULT_FRAMERATE:Int = 24;
static final DEFAULT_ISPIXEL:Bool = false;
static final DEFAULT_LOOP:Bool = false;
static final DEFAULT_NAME:String = 'Untitled Character';
static final DEFAULT_OFFSETS:Array<Float> = [0, 0];
static final DEFAULT_HEALTHICON_OFFSETS:Array<Int> = [0, 25];
static final DEFAULT_RENDERTYPE:CharacterRenderType = CharacterRenderType.Sparrow;
static final DEFAULT_SCALE:Float = 1;
static final DEFAULT_SCROLL:Array<Float> = [0, 0];
static final DEFAULT_STARTINGANIM:String = 'idle';
public static final DEFAULT_DANCEEVERY:Float = 1.0;
public static final DEFAULT_FLIPX:Bool = false;
public static final DEFAULT_FLIPY:Bool = false;
public static final DEFAULT_FRAMERATE:Int = 24;
public static final DEFAULT_ISPIXEL:Bool = false;
public static final DEFAULT_LOOP:Bool = false;
public static final DEFAULT_NAME:String = 'Untitled Character';
public static final DEFAULT_OFFSETS:Array<Float> = [0, 0];
public static final DEFAULT_HEALTHICON_OFFSETS:Array<Int> = [0, 25];
public static final DEFAULT_RENDERTYPE:CharacterRenderType = CharacterRenderType.Sparrow;
public static final DEFAULT_SCALE:Float = 1;
public static final DEFAULT_SCROLL:Array<Float> = [0, 0];
public static final DEFAULT_STARTINGANIM:String = 'idle';
/**
* Set unspecified parameters to their defaults.
@@ -665,10 +667,12 @@ typedef CharacterData =
/**
* The frequency at which the character will play its idle animation, in beats.
* Increasing this number will make the character dance less often.
*
* @default 1
* Supports up to `0.25` precision.
* @default `1.0` on characters
*/
var danceEvery:Null<Int>;
@:optional
@:default(1.0)
var danceEvery:Null<Float>;
/**
* The minimum duration that a character will play a note animation for, in beats.
@@ -41,6 +41,8 @@ class MultiSparrowCharacter extends BaseCharacter
{
this.isPixel = true;
this.antialiasing = false;
pixelPerfectRender = true;
pixelPerfectPosition = true;
}
else
{
@@ -60,11 +62,13 @@ class MultiSparrowCharacter extends BaseCharacter
}
}
var texture:FlxAtlasFrames = Paths.getSparrowAtlas(_data.assetPath, 'shared');
var texture:FlxAtlasFrames = Paths.getSparrowAtlas(_data.assetPath);
if (texture == null)
{
trace('Multi-Sparrow atlas could not load PRIMARY texture: ${_data.assetPath}');
FlxG.log.error('Multi-Sparrow atlas could not load PRIMARY texture: ${_data.assetPath}');
return;
}
else
{
@@ -74,7 +78,7 @@ class MultiSparrowCharacter extends BaseCharacter
for (asset in assetList)
{
var subTexture:FlxAtlasFrames = Paths.getSparrowAtlas(asset, 'shared');
var subTexture:FlxAtlasFrames = Paths.getSparrowAtlas(asset);
// If we don't do this, the unused textures will be removed as soon as they're loaded.
if (subTexture == null)
@@ -30,7 +30,7 @@ class PackerCharacter extends BaseCharacter
{
trace('[PACKERCHAR] Loading spritesheet ${_data.assetPath} for ${characterId}');
var tex:FlxFramesCollection = Paths.getPackerAtlas(_data.assetPath, 'shared');
var tex:FlxFramesCollection = Paths.getPackerAtlas(_data.assetPath);
if (tex == null)
{
trace('Could not load Packer sprite: ${_data.assetPath}');
@@ -43,6 +43,8 @@ class PackerCharacter extends BaseCharacter
{
this.isPixel = true;
this.antialiasing = false;
pixelPerfectRender = true;
pixelPerfectPosition = true;
}
else
{
@@ -33,7 +33,7 @@ class SparrowCharacter extends BaseCharacter
{
trace('[SPARROWCHAR] Loading spritesheet ${_data.assetPath} for ${characterId}');
var tex:FlxFramesCollection = Paths.getSparrowAtlas(_data.assetPath, 'shared');
var tex:FlxFramesCollection = Paths.getSparrowAtlas(_data.assetPath);
if (tex == null)
{
trace('Could not load Sparrow sprite: ${_data.assetPath}');
@@ -46,6 +46,8 @@ class SparrowCharacter extends BaseCharacter
{
this.isPixel = true;
this.antialiasing = false;
pixelPerfectRender = true;
pixelPerfectPosition = true;
}
else
{
+62 -27
View File
@@ -49,12 +49,13 @@ class HealthIcon extends FunkinSprite
* this value allows you to set a relative scale for the icon.
* @default 1x scale = 150px width and height.
*/
public var size:FlxPoint = new FlxPoint(1, 1);
public var size:FlxPoint;
/**
* Apply the "bop" animation once every X steps.
* Defaults to once per beat.
*/
public var bopEvery:Int = 4;
public var bopEvery:Int = Constants.STEPS_PER_BEAT;
/**
* The amount, in degrees, to rotate the icon by when boping.
@@ -119,11 +120,15 @@ class HealthIcon extends FunkinSprite
{
super(0, 0);
this.playerId = playerId;
this.size = new FlxCallbackPoint(onSetSize);
this.scrollFactor.set();
size.set(1.0, 1.0);
this.characterId = char;
}
initTargetSize();
function onSetSize(value:FlxPoint):Void
{
snapToTargetSize();
}
function set_characterId(value:Null<String>):Null<String>
@@ -149,13 +154,17 @@ class HealthIcon extends FunkinSprite
{
if (characterId == 'bf-old')
{
isPixel = PlayState.instance.currentStage.getBoyfriend().isPixel;
PlayState.instance.currentStage.getBoyfriend().initHealthIcon(false);
}
else
{
characterId = 'bf-old';
isPixel = false;
loadCharacter(characterId);
}
lerpIconSize(true);
}
/**
@@ -199,31 +208,61 @@ class HealthIcon extends FunkinSprite
if (bopEvery != 0)
{
// Lerp the health icon back to its normal size,
// while maintaining aspect ratio.
if (this.width > this.height)
{
// Apply linear interpolation while accounting for frame rate.
var targetSize:Int = Std.int(MathUtil.coolLerp(this.width, HEALTH_ICON_SIZE * this.size.x, 0.15));
setGraphicSize(targetSize, 0);
}
else
{
var targetSize:Int = Std.int(MathUtil.coolLerp(this.height, HEALTH_ICON_SIZE * this.size.y, 0.15));
setGraphicSize(0, targetSize);
}
lerpIconSize();
// Lerp the health icon back to its normal angle.
this.angle = MathUtil.coolLerp(this.angle, 0, 0.15);
this.updateHitbox();
}
this.updatePosition();
}
/**
* Does the calculation to lerp the icon size. Usually called every frame, but can be forced to the target size.
* Mainly forced when changing to old icon to not have a weird lerp related to changing from pixel icon to non-pixel old icon
* @param force Force the icon immedialtely to be the target size. Defaults to false.
*/
function lerpIconSize(force:Bool = false):Void
{
// Lerp the health icon back to its normal size,
// while maintaining aspect ratio.
if (this.width > this.height)
{
// Apply linear interpolation while accounting for frame rate.
var targetSize:Int = Std.int(MathUtil.coolLerp(this.width, HEALTH_ICON_SIZE * this.size.x, 0.15));
if (force) targetSize = Std.int(HEALTH_ICON_SIZE * this.size.x);
setGraphicSize(targetSize, 0);
}
else
{
var targetSize:Int = Std.int(MathUtil.coolLerp(this.height, HEALTH_ICON_SIZE * this.size.y, 0.15));
if (force) targetSize = Std.int(HEALTH_ICON_SIZE * this.size.y);
setGraphicSize(0, targetSize);
}
this.updateHitbox();
}
/*
* Immediately snap the health icon to its target size without lerping.
*/
public function snapToTargetSize():Void
{
if (this.width > this.height)
{
setGraphicSize(Std.int(HEALTH_ICON_SIZE * this.size.x), 0);
}
else
{
setGraphicSize(0, Std.int(HEALTH_ICON_SIZE * this.size.y));
}
updateHitbox();
}
/**
* Update the position (and status) of the health icon.
*/
@@ -282,12 +321,6 @@ class HealthIcon extends FunkinSprite
}
}
inline function initTargetSize():Void
{
setGraphicSize(HEALTH_ICON_SIZE);
updateHitbox();
}
function updateHealthIcon(health:Float):Void
{
// We want to efficiently handle animation playback
@@ -411,6 +444,8 @@ class HealthIcon extends FunkinSprite
isLegacyStyle = !isNewSpritesheet(charId);
trace(' Loading health icon for character: $charId (legacy: $isLegacyStyle)');
if (!isLegacyStyle)
{
loadSparrow('icons/icon-$charId');
+55 -96
View File
@@ -7,53 +7,60 @@ import flixel.util.FlxDirection;
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;
class PopUpStuff extends FlxTypedGroup<FlxSprite>
@:nullSafety
class PopUpStuff extends FlxTypedGroup<FunkinSprite>
{
public var offsets:Array<Int> = [0, 0];
/**
* The current note style to use. This determines which graphics to display.
* For example, Week 6 uses the `pixel` note style, and mods can create their own.
*/
var noteStyle:NoteStyle;
override public function new()
/**
* Offsets that are applied to all elements, independent of the note style.
* Used to allow scripts to reposition the elements.
*/
var offsets:Array<Int> = [0, 0];
override public function new(noteStyle:NoteStyle)
{
super();
this.noteStyle = noteStyle;
}
public function displayRating(daRating:String)
public function displayRating(daRating:Null<String>)
{
var perfStart:Float = TimerUtil.start();
if (daRating == null) daRating = "good";
var ratingPath:String = daRating;
if (PlayState.instance.currentStageId.startsWith('school')) ratingPath = "weeb/pixelUI/" + ratingPath + "-pixel";
var rating:FunkinSprite = FunkinSprite.create(0, 0, ratingPath);
rating.scrollFactor.set(0.2, 0.2);
var rating:Null<FunkinSprite> = noteStyle.buildJudgementSprite(daRating);
if (rating == null) return;
rating.zIndex = 1000;
rating.x = (FlxG.width * 0.474) + offsets[0];
// rating.x -= FlxG.camera.scroll.x * 0.2;
rating.y = (FlxG.camera.height * 0.45 - 60) + offsets[1];
rating.x = (FlxG.width * 0.474);
rating.x -= rating.width / 2;
rating.y = (FlxG.camera.height * 0.45 - 60);
rating.y -= rating.height / 2;
rating.x += offsets[0];
rating.y += offsets[1];
var styleOffsets = noteStyle.getJudgementSpriteOffsets(daRating);
rating.x += styleOffsets[0];
rating.y += styleOffsets[1];
rating.acceleration.y = 550;
rating.velocity.y -= FlxG.random.int(140, 175);
rating.velocity.x -= FlxG.random.int(0, 10);
add(rating);
if (PlayState.instance.currentStageId.startsWith('school'))
{
rating.setGraphicSize(Std.int(rating.width * Constants.PIXEL_ART_SCALE * 0.7));
rating.antialiasing = false;
}
else
{
rating.setGraphicSize(Std.int(rating.width * 0.65));
rating.antialiasing = true;
}
rating.updateHitbox();
rating.x -= rating.width / 2;
rating.y -= rating.height / 2;
var fadeEase = noteStyle.isJudgementSpritePixel(daRating) ? EaseUtil.stepped(2) : null;
FlxTween.tween(rating, {alpha: 0}, 0.2,
{
@@ -61,58 +68,13 @@ class PopUpStuff extends FlxTypedGroup<FlxSprite>
remove(rating, true);
rating.destroy();
},
startDelay: Conductor.instance.beatLengthMs * 0.001
startDelay: Conductor.instance.beatLengthMs * 0.001,
ease: fadeEase
});
trace('displayRating took: ${TimerUtil.seconds(perfStart)}');
}
public function displayCombo(?combo:Int = 0):Int
public function displayCombo(combo:Int = 0):Void
{
var perfStart:Float = TimerUtil.start();
if (combo == null) combo = 0;
var pixelShitPart1:String = "";
var pixelShitPart2:String = '';
if (PlayState.instance.currentStageId.startsWith('school'))
{
pixelShitPart1 = 'weeb/pixelUI/';
pixelShitPart2 = '-pixel';
}
var comboSpr:FunkinSprite = FunkinSprite.create(pixelShitPart1 + 'combo' + pixelShitPart2);
comboSpr.y = (FlxG.camera.height * 0.44) + offsets[1];
comboSpr.x = (FlxG.width * 0.507) + offsets[0];
// comboSpr.x -= FlxG.camera.scroll.x * 0.2;
comboSpr.acceleration.y = 600;
comboSpr.velocity.y -= 150;
comboSpr.velocity.x += FlxG.random.int(1, 10);
// add(comboSpr);
if (PlayState.instance.currentStageId.startsWith('school'))
{
comboSpr.setGraphicSize(Std.int(comboSpr.width * Constants.PIXEL_ART_SCALE * 0.7));
comboSpr.antialiasing = false;
}
else
{
comboSpr.setGraphicSize(Std.int(comboSpr.width * 0.7));
comboSpr.antialiasing = true;
}
comboSpr.updateHitbox();
FlxTween.tween(comboSpr, {alpha: 0}, 0.2,
{
onComplete: function(tween:FlxTween) {
remove(comboSpr, true);
comboSpr.destroy();
},
startDelay: Conductor.instance.beatLengthMs * 0.001
});
var seperatedScore:Array<Int> = [];
var tempCombo:Int = combo;
@@ -127,43 +89,40 @@ class PopUpStuff extends FlxTypedGroup<FlxSprite>
// seperatedScore.reverse();
var daLoop:Int = 1;
for (i in seperatedScore)
for (digit in seperatedScore)
{
var numScore:FunkinSprite = FunkinSprite.create(0, comboSpr.y, pixelShitPart1 + 'num' + Std.int(i) + pixelShitPart2);
var numScore:Null<FunkinSprite> = noteStyle.buildComboNumSprite(digit);
if (numScore == null) continue;
if (PlayState.instance.currentStageId.startsWith('school'))
{
numScore.setGraphicSize(Std.int(numScore.width * Constants.PIXEL_ART_SCALE * 0.7));
numScore.antialiasing = false;
}
else
{
numScore.setGraphicSize(Std.int(numScore.width * 0.45));
numScore.antialiasing = true;
}
numScore.updateHitbox();
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];
numScore.y += offsets[1];
var styleOffsets = noteStyle.getComboNumSpriteOffsets(digit);
numScore.x += styleOffsets[0];
numScore.y += styleOffsets[1];
numScore.x = comboSpr.x - (36 * daLoop) - 65; //- 90;
numScore.acceleration.y = FlxG.random.int(250, 300);
numScore.velocity.y -= FlxG.random.int(130, 150);
numScore.velocity.x = FlxG.random.float(-5, 5);
add(numScore);
var fadeEase = noteStyle.isComboNumSpritePixel(digit) ? EaseUtil.stepped(2) : null;
FlxTween.tween(numScore, {alpha: 0}, 0.2,
{
onComplete: function(tween:FlxTween) {
remove(numScore, true);
numScore.destroy();
},
startDelay: Conductor.instance.beatLengthMs * 0.002
startDelay: Conductor.instance.beatLengthMs * 0.002,
ease: fadeEase
});
daLoop++;
}
trace('displayCombo took: ${TimerUtil.seconds(perfStart)}');
return combo;
}
}
+1 -3
View File
@@ -81,7 +81,6 @@ class VideoCutscene
// Trigger the cutscene. Don't play the song in the background.
PlayState.instance.isInCutscene = true;
PlayState.instance.camHUD.visible = false;
PlayState.instance.camCutscene.visible = true;
// Display a black screen to hide the game while the video is playing.
blackScreen = new FlxSprite(-200, -200).makeGraphic(FlxG.width * 2, FlxG.height * 2, FlxColor.BLACK);
@@ -145,7 +144,7 @@ class VideoCutscene
{
vid.zIndex = 0;
vid.bitmap.onEndReached.add(finishVideo.bind(0.5));
vid.autoPause = false;
vid.autoPause = FlxG.autoPause;
vid.cameras = [PlayState.instance.camCutscene];
@@ -305,7 +304,6 @@ class VideoCutscene
vid = null;
#end
PlayState.instance.camCutscene.visible = true;
PlayState.instance.camHUD.visible = true;
FlxTween.tween(blackScreen, {alpha: 0}, transitionTime,
@@ -114,7 +114,7 @@ class ZoomCameraSongEvent extends SongEvent
name: 'zoom',
title: 'Zoom Level',
defaultValue: 1.0,
step: 0.1,
step: 0.05,
type: SongEventFieldType.FLOAT,
units: 'x'
},
+48 -8
View File
@@ -1,6 +1,7 @@
package funkin.play.notes;
import funkin.data.song.SongData.SongNoteData;
import funkin.data.song.SongData.NoteParamData;
import funkin.play.notes.notestyle.NoteStyle;
import flixel.graphics.frames.FlxAtlasFrames;
import flixel.FlxSprite;
@@ -65,6 +66,22 @@ class NoteSprite extends FunkinSprite
return this.noteData.kind = value;
}
/**
* An array of custom parameters for this note
*/
public var params(get, set):Array<NoteParamData>;
function get_params():Array<NoteParamData>
{
return this.noteData?.params ?? [];
}
function set_params(value:Array<NoteParamData>):Array<NoteParamData>
{
if (this.noteData == null) return value;
return this.noteData.params = value;
}
/**
* The data of the note (i.e. the direction.)
*/
@@ -74,7 +91,7 @@ class NoteSprite extends FunkinSprite
{
if (frames == null) return value;
animation.play(DIRECTION_COLORS[value] + 'Scroll');
playNoteAnimation(value);
this.direction = value;
return this.direction;
@@ -135,19 +152,37 @@ class NoteSprite extends FunkinSprite
this.hsvShader = new HSVShader();
setupNoteGraphic(noteStyle);
// Disables the update() function for performance.
this.active = false;
}
function setupNoteGraphic(noteStyle:NoteStyle):Void
/**
* Creates frames and animations
* @param noteStyle The `NoteStyle` instance
*/
public function setupNoteGraphic(noteStyle:NoteStyle):Void
{
noteStyle.buildNoteSprite(this);
setGraphicSize(Strumline.STRUMLINE_SIZE);
updateHitbox();
this.shader = hsvShader;
// `false` disables the update() function for performance.
this.active = noteStyle.isNoteAnimated();
}
/**
* Retrieve the value of the param with the given name
* @param name Name of the param
* @return Null<Dynamic>
*/
public function getParam(name:String):Null<Dynamic>
{
for (param in params)
{
if (param.name == name)
{
return param.value;
}
}
return null;
}
#if FLX_DEBUG
@@ -173,6 +208,11 @@ class NoteSprite extends FunkinSprite
}
#end
function playNoteAnimation(value:Int):Void
{
animation.play(DIRECTION_COLORS[value] + 'Scroll');
}
public function desaturate():Void
{
this.hsvShader.saturation = 0.2;
+68 -8
View File
@@ -16,6 +16,7 @@ import funkin.data.song.SongData.SongNoteData;
import funkin.ui.options.PreferencesMenu;
import funkin.util.SortUtil;
import funkin.modding.events.ScriptEvent;
import funkin.play.notes.notekind.NoteKindManager;
/**
* A group of sprites which handles the receptor, the note splashes, and the notes (with sustains) for a given player.
@@ -37,7 +38,7 @@ class Strumline extends FlxSpriteGroup
static function get_RENDER_DISTANCE_MS():Float
{
return FlxG.height / 0.45;
return FlxG.height / Constants.PIXELS_PER_MS;
}
/**
@@ -93,6 +94,10 @@ class Strumline extends FlxSpriteGroup
final noteStyle:NoteStyle;
#if FEATURE_GHOST_TAPPING
var ghostTapTimer:Float = 0.0;
#end
/**
* The note data for the song. Should NOT be altered after the song starts,
* so we can easily rewind.
@@ -178,21 +183,36 @@ class Strumline extends FlxSpriteGroup
super.update(elapsed);
updateNotes();
#if FEATURE_GHOST_TAPPING
updateGhostTapTimer(elapsed);
#end
}
#if FEATURE_GHOST_TAPPING
/**
* Returns `true` if no notes are in range of the strumline and the player can spam without penalty.
*/
public function mayGhostTap():Bool
{
// TODO: Refine this. Only querying "can be hit" is too tight but "is being rendered" is too loose.
// Also, if you just hit a note, there should be a (short) period where this is off so you can't spam.
// Any notes in range of the strumline.
if (getNotesMayHit().length > 0)
{
return false;
}
// Any hold notes in range of the strumline.
if (getHoldNotesHitOrMissed().length > 0)
{
return false;
}
// If there are any notes on screen, we can't ghost tap.
return notes.members.filter(function(note:NoteSprite) {
return note != null && note.alive && !note.hasBeenHit;
}).length == 0;
// Note has been hit recently.
if (ghostTapTimer > 0.0) return false;
// **yippee**
return true;
}
#end
/**
* Return notes that are within `Constants.HIT_WINDOW` ms of the strumline.
@@ -491,6 +511,32 @@ class Strumline extends FlxSpriteGroup
}
}
/**
* Return notes that are within, or way after, `Constants.HIT_WINDOW` ms of the strumline.
* @return An array of `NoteSprite` objects.
*/
public function getNotesOnScreen():Array<NoteSprite>
{
return notes.members.filter(function(note:NoteSprite) {
return note != null && note.alive && !note.hasBeenHit;
});
}
#if FEATURE_GHOST_TAPPING
function updateGhostTapTimer(elapsed:Float):Void
{
// If it's still our turn, don't update the ghost tap timer.
if (getNotesOnScreen().length > 0) return;
ghostTapTimer -= elapsed;
if (ghostTapTimer <= 0)
{
ghostTapTimer = 0;
}
}
#end
/**
* Called when the PlayState skips a large amount of time forward or backward.
*/
@@ -562,6 +608,10 @@ class Strumline extends FlxSpriteGroup
playStatic(dir);
}
resetScrollSpeed();
#if FEATURE_GHOST_TAPPING
ghostTapTimer = 0;
#end
}
public function applyNoteData(data:Array<SongNoteData>):Void
@@ -598,10 +648,13 @@ class Strumline extends FlxSpriteGroup
{
note.holdNoteSprite.hitNote = true;
note.holdNoteSprite.missedNote = false;
note.holdNoteSprite.alpha = 1.0;
note.holdNoteSprite.sustainLength = (note.holdNoteSprite.strumTime + note.holdNoteSprite.fullSustainLength) - conductorInUse.songPosition;
}
#if FEATURE_GHOST_TAPPING
ghostTapTimer = Constants.GHOST_TAP_DELAY;
#end
}
public function killNote(note:NoteSprite):Void
@@ -709,11 +762,15 @@ class Strumline extends FlxSpriteGroup
if (noteSprite != null)
{
var noteKindStyle:NoteStyle = NoteKindManager.getNoteStyle(note.kind, this.noteStyle.id) ?? this.noteStyle;
noteSprite.setupNoteGraphic(noteKindStyle);
noteSprite.direction = note.getDirection();
noteSprite.noteData = note;
noteSprite.x = this.x;
noteSprite.x += getXPos(DIRECTIONS[note.getDirection() % KEY_COUNT]);
noteSprite.x -= (noteSprite.width - Strumline.STRUMLINE_SIZE) / 2; // Center it
noteSprite.x -= NUDGE;
// noteSprite.x += INITIAL_OFFSET;
noteSprite.y = -9999;
@@ -728,6 +785,9 @@ class Strumline extends FlxSpriteGroup
if (holdNoteSprite != null)
{
var noteKindStyle:NoteStyle = NoteKindManager.getNoteStyle(note.kind, this.noteStyle.id) ?? this.noteStyle;
holdNoteSprite.setupHoldNoteGraphic(noteKindStyle);
holdNoteSprite.parentStrumline = this;
holdNoteSprite.noteData = note;
holdNoteSprite.strumTime = note.time;
@@ -75,6 +75,13 @@ class StrumlineNote extends FlxSprite
function setup(noteStyle:NoteStyle):Void
{
if (noteStyle == null)
{
// If you get an exception on this line, check the debug console.
// You probably have a parsing error in your note style's JSON file.
throw "FATAL ERROR: Attempted to initialize PlayState with an invalid NoteStyle.";
}
noteStyle.applyStrumlineFrames(this);
noteStyle.applyStrumlineAnimations(this, this.direction);
+34 -11
View File
@@ -99,7 +99,27 @@ class SustainTrail extends FlxSprite
*/
public function new(noteDirection:NoteDirection, sustainLength:Float, noteStyle:NoteStyle)
{
super(0, 0, noteStyle.getHoldNoteAssetPath());
super(0, 0);
// BASIC SETUP
this.sustainLength = sustainLength;
this.fullSustainLength = sustainLength;
this.noteDirection = noteDirection;
setupHoldNoteGraphic(noteStyle);
indices = new DrawData<Int>(12, true, TRIANGLE_VERTEX_INDICES);
this.active = true; // This NEEDS to be true for the note to be drawn!
}
/**
* Creates hold note graphic and applies correct zooming
* @param noteStyle The note style
*/
public function setupHoldNoteGraphic(noteStyle:NoteStyle):Void
{
loadGraphic(noteStyle.getHoldNoteAssetPath());
antialiasing = true;
@@ -109,13 +129,14 @@ class SustainTrail extends FlxSprite
endOffset = bottomClip = 1;
antialiasing = false;
}
else
{
endOffset = 0.5;
bottomClip = 0.9;
}
zoom = 1.0;
zoom *= noteStyle.fetchHoldNoteScale();
// BASIC SETUP
this.sustainLength = sustainLength;
this.fullSustainLength = sustainLength;
this.noteDirection = noteDirection;
zoom *= 0.7;
// CALCULATE SIZE
@@ -131,9 +152,6 @@ class SustainTrail extends FlxSprite
updateColorTransform();
updateClipping();
indices = new DrawData<Int>(12, true, TRIANGLE_VERTEX_INDICES);
this.active = true; // This NEEDS to be true for the note to be drawn!
}
function getBaseScrollSpeed()
@@ -160,7 +178,7 @@ class SustainTrail extends FlxSprite
*/
public static inline function sustainHeight(susLength:Float, scroll:Float)
{
return (susLength * 0.45 * scroll);
return (susLength * Constants.PIXELS_PER_MS * scroll);
}
function set_sustainLength(s:Float):Float
@@ -195,6 +213,11 @@ class SustainTrail extends FlxSprite
*/
public function updateClipping(songTime:Float = 0):Void
{
if (graphic == null)
{
return;
}
var clipHeight:Float = FlxMath.bound(sustainHeight(sustainLength - (songTime - strumTime), parentStrumline?.scrollSpeed ?? 1.0), 0, graphicHeight);
if (clipHeight <= 0.1)
{
@@ -0,0 +1,119 @@
package funkin.play.notes.notekind;
import funkin.modding.IScriptedClass.INoteScriptedClass;
import funkin.modding.events.ScriptEvent;
import flixel.math.FlxMath;
/**
* Class for note scripts
*/
class NoteKind implements INoteScriptedClass
{
/**
* The name of the note kind
*/
public var noteKind:String;
/**
* Description used in chart editor
*/
public var description:String;
/**
* Custom note style
*/
public var noteStyleId:Null<String>;
/**
* Custom parameters for the chart editor
*/
public var params:Array<NoteKindParam>;
public function new(noteKind:String, description:String = "", ?noteStyleId:String, ?params:Array<NoteKindParam>)
{
this.noteKind = noteKind;
this.description = description;
this.noteStyleId = noteStyleId;
this.params = params ?? [];
}
public function toString():String
{
return noteKind;
}
/**
* Retrieve all notes of this kind
* @return Array<NoteSprite>
*/
function getNotes():Array<NoteSprite>
{
var allNotes:Array<NoteSprite> = PlayState.instance.playerStrumline.notes.members.concat(PlayState.instance.opponentStrumline.notes.members);
return allNotes.filter(function(note:NoteSprite) {
return note != null && note.noteData.kind == this.noteKind;
});
}
public function onScriptEvent(event:ScriptEvent):Void {}
public function onCreate(event:ScriptEvent):Void {}
public function onDestroy(event:ScriptEvent):Void {}
public function onUpdate(event:UpdateScriptEvent):Void {}
public function onNoteIncoming(event:NoteScriptEvent):Void {}
public function onNoteHit(event:HitNoteScriptEvent):Void {}
public function onNoteMiss(event:NoteScriptEvent):Void {}
}
/**
* Abstract for setting the type of the `NoteKindParam`
* This was supposed to be an enum but polymod kept being annoying
*/
abstract NoteKindParamType(String) from String to String
{
public static final STRING:String = 'String';
public static final INT:String = 'Int';
public static final FLOAT:String = 'Float';
}
typedef NoteKindParamData =
{
/**
* If `min` is null, there is no minimum
*/
?min:Null<Float>,
/**
* If `max` is null, there is no maximum
*/
?max:Null<Float>,
/**
* If `step` is null, it will use 1.0
*/
?step:Null<Float>,
/**
* If `precision` is null, there will be 0 decimal places
*/
?precision:Null<Int>,
?defaultValue:Dynamic
}
/**
* Typedef for creating custom parameters in the chart editor
*/
typedef NoteKindParam =
{
name:String,
description:String,
type:NoteKindParamType,
?data:NoteKindParamData
}
@@ -0,0 +1,121 @@
package funkin.play.notes.notekind;
import funkin.modding.events.ScriptEventDispatcher;
import funkin.modding.events.ScriptEvent;
import funkin.ui.debug.charting.util.ChartEditorDropdowns;
import funkin.data.notestyle.NoteStyleRegistry;
import funkin.play.notes.notestyle.NoteStyle;
import funkin.play.notes.notekind.ScriptedNoteKind;
import funkin.play.notes.notekind.NoteKind.NoteKindParam;
class NoteKindManager
{
static var noteKinds:Map<String, NoteKind> = [];
public static function loadScripts():Void
{
var scriptedClassName:Array<String> = ScriptedNoteKind.listScriptClasses();
if (scriptedClassName.length > 0)
{
trace('Instantiating ${scriptedClassName.length} scripted note kind(s)...');
for (scriptedClass in scriptedClassName)
{
try
{
var script:NoteKind = ScriptedNoteKind.init(scriptedClass, "unknown");
trace(' Initialized scripted note kind: ${script.noteKind}');
noteKinds.set(script.noteKind, script);
ChartEditorDropdowns.NOTE_KINDS.set(script.noteKind, script.description);
}
catch (e)
{
trace(' FAILED to instantiate scripted note kind: ${scriptedClass}');
trace(e);
}
}
}
}
/**
* Calls the given event for note kind scripts
* @param event The event
*/
public static function callEvent(event:ScriptEvent):Void
{
// if it is a note script event,
// then only call the event for the specific note kind script
if (Std.isOfType(event, NoteScriptEvent))
{
var noteEvent:NoteScriptEvent = cast(event, NoteScriptEvent);
var noteKind:NoteKind = noteKinds.get(noteEvent.note.kind);
if (noteKind != null)
{
ScriptEventDispatcher.callEvent(noteKind, event);
}
}
else // call the event for all note kind scripts
{
for (noteKind in noteKinds.iterator())
{
ScriptEventDispatcher.callEvent(noteKind, event);
}
}
}
/**
* Retrieve the note style from the given note kind
* @param noteKind note kind name
* @param suffix Used for song note styles
* @return NoteStyle
*/
public static function getNoteStyle(noteKind:String, ?suffix:String):Null<NoteStyle>
{
var noteStyleId:Null<String> = getNoteStyleId(noteKind, suffix);
if (noteStyleId == null)
{
return null;
}
return NoteStyleRegistry.instance.fetchEntry(noteStyleId);
}
/**
* Retrieve the note style id from the given note kind
* @param noteKind Note kind name
* @param suffix Used for song note styles
* @return Null<String>
*/
public static function getNoteStyleId(noteKind:String, ?suffix:String):Null<String>
{
if (suffix == '')
{
suffix = null;
}
var noteStyleId:Null<String> = noteKinds.get(noteKind)?.noteStyleId;
if (noteStyleId != null && suffix != null)
{
noteStyleId = NoteStyleRegistry.instance.hasEntry('$noteStyleId-$suffix') ? '$noteStyleId-$suffix' : noteStyleId;
}
return noteStyleId;
}
/**
* Retrive custom params of the given note kind
* @param noteKind Name of the note kind
* @return Array<NoteKindParam>
*/
public static function getParams(noteKind:Null<String>):Array<NoteKindParam>
{
if (noteKind == null)
{
return [];
}
return noteKinds.get(noteKind)?.params ?? [];
}
}

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