Compare commits

...
311 Commits
Author SHA1 Message Date
Hundrec 90eabf0b38 Bump docs and templates to 0.8.4
Build and Upload nightly game builds / gather-changes (push) Canceled after 0s
Build and Upload nightly game builds / gather-tags (push) Canceled after 0s
Build and Upload nightly game builds / build-game-on-host (macos, macos) (push) Canceled after 0s
Build and Upload nightly game builds / build-game-on-host (windows, windows) (push) Canceled after 0s
Build and Upload nightly game builds / docker-image (push) Canceled after 0s
Build and Upload nightly game builds / build-game-in-container (html5) (push) Canceled after 0s
Build and Upload nightly game builds / build-game-in-container (linux) (push) Canceled after 0s
2026-03-25 16:19:29 -06:00
Hundrec b3959a5935 Bump version to 0.8.4 2026-03-22 00:02:55 -06:00
HundrecandAbnormal cdca3bf307 Changelog for 0.8.4
Co-Authored-By: Abnormal <86753001+AbnormalPoof@users.noreply.github.com>
2026-03-22 00:01:19 -06:00
Karim AkraandHundrec e491c5e841 [CHORE] rename mobile FNFCUtil classes for a cleaner structure 2026-03-21 16:01:13 -06:00
Karim AkraandHundrec f9b125e44a [FIX] Bump lime to fix FNFC loading on iOS 2026-03-21 16:01:13 -06:00
VirtuGuyandHundrec 1ceb4fad1a Fix ingame cutscenes crashing on mobile 2026-03-21 06:40:41 -06:00
Hyper_andHundrec 21fc59c997 Fix TextureSwap not loading ASTC assets properly 2026-03-21 06:40:33 -06:00
EliteMasterEricandHundrec 0cbde53f86 Update default value just in case resetEvents(events) doesn't get called. 2026-03-21 04:57:45 -06:00
VirtuGuyandHundrec 5119cf1b72 Fix songs crashing 2026-03-21 04:57:45 -06:00
927f3fc300 Use an optional argument for event querying
Co-Authored-By: Eric <4635334+EliteMasterEric@users.noreply.github.com>
2026-03-20 16:54:27 -06:00
EliteMasterEricandHundrec d1e4a17f46 Add null checks to some scripts 2026-03-20 16:52:53 -06:00
ec868f8ef5 Fix HTML5 not compiling due to blacklisted Polymod field
Co-Authored-By: Kolo <67389779+KoloInDaCrib@users.noreply.github.com>
Co-Authored-By: Keoiki <55053690+Keoiki@users.noreply.github.com>
2026-03-20 04:19:23 -06:00
MAJigsaw77andHundrec 1e0a238463 Patch extension-admob setup command so theres no unexpected behaviour 2026-03-20 03:58:18 -06:00
Hundrec e07e59a288 Undo No Animation hold timer change
It was making animations behave differently after a change to hold timers
2026-03-19 23:29:42 -06:00
ADA-FunniandHundrec d6410d5e42 Fallback for old song metadata files causing the song preview to go mute 2026-03-19 23:29:42 -06:00
TrayfellowandHundrec 5974c1a482 Fix freeplay percentage not fully exiting out if it has 3 digits 2026-03-19 21:02:20 -06:00
KoloandHundrec ffdcbdbf21 optimize the script event dispatching 2026-03-19 21:02:20 -06:00
KoloandHundrec 3b27ec5b66 optimization: potentially optimize how events are queried 2026-03-19 21:02:20 -06:00
FuroandHundrec 56a56dbfaa Include lime and openfl for modding 2026-03-19 20:00:18 -06:00
EliteMasterEricandHundrec 537bd5dd83 Add a few more items to the blacklist 2026-03-19 20:00:18 -06:00
charlesisfelineandHundrec b0fd471f8a Blacklist 'readObject` from scripts 2026-03-19 20:00:18 -06:00
ImVeryBadandHundrec 3633df3fdc Add makeVarArgs to ReflectUtil.hx 2026-03-19 20:00:18 -06:00
VirtuGuyandHundrec e6234397f5 Fix camera movement when paused 2026-03-19 19:34:04 -06:00
MAJigsaw77andHundrec 68ce5ce90b Update lime 2026-03-19 18:50:43 -06:00
MAJigsaw77andHundrec a6066f9905 Update flixel-addons 2026-03-19 04:21:37 -06:00
KolzeandHundrec 75506f71a9 Fix spirit trail being fps-dependent 2026-03-19 04:21:25 -06:00
RaltyandHundrec c4b5462a5a Remove duplicated code in project.hxp 2026-03-19 03:15:35 -06:00
MAJigsaw77andHundrec 47d4d77c86 Update hxcpp 2026-03-19 02:50:50 -06:00
MAJigsaw77andHundrec acf17f6165 Properly adjust the debug display math based of the supported mem usages 2026-03-19 02:50:50 -06:00
MAJigsaw77andHundrec 2db26070c6 Properly delete the assets folder on hl across all desktop targets 2026-03-19 02:50:50 -06:00
MAJigsaw77andHundrec e0f9c7336b Update libs refs 2026-03-19 02:50:50 -06:00
AbnormalPoofandHundrec a28a28ae4c Clamp the DPI scale to 1 in the blend shader 2026-03-18 00:26:45 -06:00
Hundrec 7160f748eb Tweak dropdown width 2026-03-17 23:55:20 -06:00
sector-aandHundrec c8e60bed34 Add additional adjustments in the ZoomCamerasong event for widescreen 2026-03-17 23:55:19 -06:00
sector-aandHundrec 11c826daa6 Resize ENUM dropdowns to make them fit in the frames 2026-03-17 23:55:03 -06:00
sector-aandHundrec 6c887b4632 Put some of least used event params under Advanced frame. 2026-03-17 23:55:03 -06:00
MAJigsaw77andHundrec ecfb897dae Remove useless prints 2026-03-17 22:59:20 -06:00
AbnormalPoofandHundrec 56d5767004 Fix HashLink not clearing assets on macOS 2026-03-17 22:59:12 -06:00
MAJigsaw77andHundrec 7d3bfa32ca Run clearAssets only on non display 2026-03-17 22:59:04 -06:00
KolzeandHundrec 348647f486 Fix global offset changing speed 2026-03-17 22:58:00 -06:00
ExcodeandHundrec 48ed659800 Update LevelData.hx 2026-03-17 22:57:43 -06:00
ExcodeandHundrec 8aafe62f9c Update LevelProp.hx 2026-03-17 22:57:43 -06:00
MrMaderaandHundrec 0f7859bfb6 Gamepad binds showed in Freeplay's hint
_lastDeviceUsed -> lastDeviceUsed
2026-03-17 22:56:32 -06:00
Hundrec c3d3d2e547 Move Week 6 Erect results transition further down 2026-03-17 02:52:50 -06:00
37dc3461af Re-implement curNoteKind.suffix
Co-authored-by: TechnikTil <techniktil@tilnotdrip.org>
2026-03-17 02:52:14 -06:00
MightyTheArmiddiloandHundrec c11ac1f658 Fix Compile Errors With FLX_NO_DEBUG 2026-03-17 02:52:10 -06:00
TrayfellowandHundrec 47bbf67ae6 Updated level schema version 2026-03-17 02:51:46 -06:00
TrayfellowandHundrec 528e9e4f03 Data-driven changeable capsule texts 2026-03-17 02:50:30 -06:00
echolotlandHundrec 7626700495 Consistent line width + fix min/max of easing preview graph 2026-03-16 20:34:42 -06:00
AbnormalPoofandHundrec 0d2a663346 Enable null-safety on FunkinFilterRenderer 2026-03-16 13:08:36 -06:00
TechnikTilandHundrec 22736b27da Add filters to FunkinSprite
This commit also removes `FlxFilteredSprite`

Signed-off-by: TechnikTil <techniktil@tilnotdrip.org>
2026-03-16 13:08:36 -06:00
MAJigsaw77andHundrec dcfad7b7e8 Update libs ref 2026-03-16 13:08:35 -06:00
Hundrec ef625b3d9d Bump assets for a few minor fixes 2026-03-16 04:40:11 -06:00
MAJigsaw77andHundrec 6ce3a2e93e Update hxvlc to fix a couple of issues 2026-03-16 03:47:03 -06:00
SuperEricandHundrec b8c2854007 Adjust backingImage size 2026-03-14 23:36:29 -06:00
JVNpixelsandHundrec 04fffe8ade Commas For Story Mode Score 2026-03-14 23:14:15 -06:00
MAJigsaw77andHundrec c37862445f Update lime ref 2026-03-14 23:00:45 -06:00
VirtuGuyandHundrec 0613e9d295 Fix rimlight alt masks not working on web 2026-03-14 22:24:39 -06:00
MAJigsaw77andHundrec bed249dca0 Remove the framerate options on web 2026-03-14 22:13:54 -06:00
MAJigsaw77andHundrec 139940f9ec Update libs refs 2026-03-14 17:30:27 -06:00
Hyper_andHundrec 36e2f47577 Fix Random capsule not updating OST text 2026-03-13 21:48:13 -06:00
VirtuGuyandHundrec ce493a03c9 Fix favoriting songs breaking song text cycling 2026-03-13 21:48:13 -06:00
AnimatingLegendandHundrec aabd1aa9f7 fix: miss-animation timing in no-anim events 2026-03-13 21:25:52 -06:00
KoloandHundrec 89029220e4 optimization: remove a spammy trace 2026-03-13 21:25:52 -06:00
ImVeryBadandHundrec dca54de087 Add isBlank to StringTools for easier blank string checking. 2026-03-13 21:25:52 -06:00
KoloandHundrec 15bef89d71 Script event support for Song Events 2026-03-12 01:43:08 -06:00
6c1f3800db Fix duplicate asset paths in note styles crashing when exiting PlayState in Chart Editor.
Co-authored-by: Kolo <67389779+koloindacrib@users.noreply.github.com>
2026-03-12 01:43:08 -06:00
AbnormalPoofandHundrec 8507f799a1 Update polymod to the latest commit 2026-03-12 01:43:08 -06:00
EliteMasterEricandHundrec dba2794780 Use the font family instead of the file path 2026-03-12 01:42:47 -06:00
KoloandHundrec 48752e444c softcode freeplay capsule level labels 2026-03-12 01:42:24 -06:00
8a1d74b82c Re-enable FlxG.autoPause when doing stickers
Co-Authored-By: Hyper_ <40342021+NotHyper-474@users.noreply.github.com>
2026-03-12 01:40:26 -06:00
AnimatingLegendandHundrec 0d1db6ae9e fix(ui): prevent nametag pixelation on web builds 2026-03-12 01:39:13 -06:00
EliteMasterEricandHundrec 1f1851990f Make sure to update the schema version when adding fields, people! 0.0.x versions for new fields with no breaking changes. 2026-03-12 01:36:31 -06:00
Hyper_andHundrec 67d2a9811b feat: Custom OST names 2026-03-12 01:35:51 -06:00
LasercarandHundrec a782b3f9e8 Improved context menus Directly set the item's position and for hold notes, it's length as well Values can be shown and set in milliseconds or steptime 2026-03-12 01:34:08 -06:00
EricandHundrec 74e28a18ff Add an extra space 2026-03-12 01:31:20 -06:00
MoonDroidandHundrec 220636e01e Style leftover INFO logs with Ansi 2026-03-12 01:31:02 -06:00
MightyTheArmiddiloandHundrec 4f316003af FunkinGroup 2026-03-12 01:28:15 -06:00
AbnormalPoofandHundrec 1a04e35db7 Change instances of FlxG.onMobile to use preprocessor defines 2026-03-11 02:44:30 -06:00
MAJigsaw77andHundrec d3e83dd72d Add Vungle mediation for Admob 2026-03-11 02:34:04 -06:00
c4e2b900c1 Implement SDL3
Co-Authored-By: Abnormal <86753001+AbnormalPoof@users.noreply.github.com>
Co-Authored-By: Karim Akra <144803230+KarimAkra@users.noreply.github.com>
2026-03-10 04:54:26 -05:00
AbnormalPoof ac3178118c Remove FlxColorUtil as Polymod supports FlxColor 2026-03-10 04:37:12 -05:00
AbnormalPoof 681f7a6d07 Remove AbstractUtil since Polymod now supports FlxSignal proper 2026-03-10 04:37:00 -05:00
AbnormalPoof aa24c94782 Remove import aliases for abstracts 2026-03-10 04:36:58 -05:00
ComedyLostandAbnormalPoof 7075c8af4b Fix a crash for inst only songs 2026-03-10 04:33:14 -05:00
AbnormalPoof efc33403b6 fix: Fix REDIRECT_ASSETS_FOLDER not working on HashLink on macOS 2026-03-10 04:33:07 -05:00
Hundrec 25a42b8182 Reword Stage Editor unsaved work prompt 2026-03-09 20:16:07 -06:00
KoloandHundrec 0389af2202 fix moving globally offset characters not working 2026-03-09 20:16:07 -06:00
Hyper_andHundrec b694ec08d6 fix: Improve Preloader time on HashLink 2026-03-09 20:16:07 -06:00
PurSnakeandHundrec 423ccfab98 Implement ScriptedBaseFreeplayDJ usage 2026-03-09 09:38:58 -06:00
AbnormalPoofandHundrec edc1f7113b Update polymod to the latest commits 2026-03-09 09:38:58 -06:00
ImVeryBadandHundrec f0b50de9fa Add support for the new Polymod mod ID system. 2026-03-09 09:38:58 -06:00
LasercarandHundrec 0ad2d507ef Random cap difficulty & BPM value visible fix 2026-03-09 09:16:39 -06:00
LasercarandHundrec 6c13444211 Hide character select keybinds until unlock 2026-03-09 09:06:58 -06:00
MightyTheArmiddiloandHundrec 5a0b4310a2 Add onPause dispatching for cutscenes and conversations 2026-03-09 09:06:58 -06:00
LasercarandHundrec 6b1fc0372b Disable edit buttons if no selection 2026-03-09 08:41:21 -06:00
ImVeryBadandHundrec cf69125d25 Clean up Cursor.hx code 2026-03-09 08:34:15 -06:00
Redar13andHundrec 84b2d5b48d Fix GF bopping when switching levels in the story menu. 2026-03-09 08:28:18 -06:00
RudyrueandHundrec dcb5b3a935 fix timing windows being 1 ms tighter 2026-03-09 08:11:45 -06:00
TrofemandHundrec 011f1541b1 control + character icon combination for character preview 2026-03-09 07:50:49 -06:00
sector-aandHundrec 13c1bf8ac0 Fix null object reference when using collapsible 2026-03-09 07:50:49 -06:00
1893f2b2f6 Implement SetTargetBopSpeed Event
Co-Authored-By: Eric <4635334+EliteMasterEric@users.noreply.github.com>
2026-03-09 07:25:40 -06:00
VirtuGuyandHundrec a0caa41edc Fix phillyStreets rain not fading out 2026-03-09 06:55:23 -06:00
FuroandHundrec 456b2ff6c4 Prevent Importing non osu!mania beatmaps 2026-03-09 03:32:32 -06:00
AbnormalPoofandHundrec a1d1b1b2d1 Fix garbage collection being mostly broken on HashLink 2026-03-09 03:32:32 -06:00
Hyper_andHundrec 0db4ce11b7 fix: Make types explicit to fix crash on HashLink 2026-03-09 02:51:06 -06:00
340fd5dcf1 Add proper HashLink support
Co-authored-by: Sinco <113909588+sphis-Sinco@users.noreply.github.com>
2026-03-09 02:51:06 -06:00
EliteMasterEricandHundrec d569690a51 I think I was tired when I made that last commit lmao... 2026-03-09 02:51:06 -06:00
EliteMasterEricandHundrec 4a5afa2fc7 Oops there was a compile error 2026-03-09 02:51:06 -06:00
EliteMasterEricandHundrec 59c593b812 Adjust scroll speed tween duration based on playback rate 2026-03-09 02:51:06 -06:00
EliteMasterEricandHundrec 6ba9e00a9f Adjust camera zoom tween duration based on playback rate 2026-03-09 02:51:06 -06:00
EliteMasterEricandHundrec ec7bdd32e2 Adjust camera follow tween duration based on playback rate 2026-03-09 02:51:06 -06:00
AnimatingLegendandHundrec 939528a9bd refactor: remove discord_rpc from background process
DiscordRPC is being handled somewhere else. having these managers running twice, both for the same reasons its kind of pointless.
2026-03-09 02:51:06 -06:00
LasercarandHundrec 08b3af959d Chart editor - select above/below playhead 2026-03-06 05:17:14 -07:00
FuroandHundrec cea54e394c Legacy Voices System 2026-03-06 03:45:04 -07:00
Honton129andHundrec e710198afe Edit Note option in Context Menu
Shortcut to the  ``Notes`` toolbox by right-clicking a note and selecting ``Edit Note``.
2026-03-06 03:31:27 -07:00
Hyper_andHundrec bf3601ea8d fix: Properly trace Ansi code for exit trace 2026-03-06 03:31:24 -07:00
Hundrec c5566c8644 Exclude Week 7 bricks from ASTC 2026-03-04 23:21:51 -07:00
MAJigsaw77andHundrec 5944f5b55d Add Pangle mediation for Admob 2026-03-04 23:10:39 -07:00
RaltyandHundrec 077fbf6978 Fix sound tray playing multiple sounds at once, not appearing in lags 2026-03-04 23:10:39 -07:00
Hundrec f02bdc4225 Bump assets 2026-03-04 22:39:17 -07:00
EliteMasterEricandHundrec 8da9ed4ea0 Make sure only one stretchy sound plays at a time. 2026-03-04 22:39:17 -07:00
EliteMasterEricandHundrec 5ed4a2ddd0 Flag instrumental and vocal tracks as important to prevent them getting overriden by other sounds. 2026-03-04 22:39:17 -07:00
EliteMasterEricandHundrec 6293e2808b Reuse the sound objects for the stretchy sounds, to prevent too many of them playing at once. 2026-03-04 22:39:15 -07:00
Hundrec c6dc562769 Adjust some wording in the Backup window 2026-03-04 20:45:54 -07:00
marcoandHundrec a607396d04 Rename button text from 'Take Me There' to 'Open In Folder'
makes it clearer about what it does
2026-03-04 20:45:51 -07:00
ImVeryBadandHundrec 365f8dcfea Filter out unavailable difficulties from Story Mode levels. 2026-03-04 20:45:51 -07:00
FuroandHundrec b3eb709f4e Pixel Icon now changes the character value only if its valid 2026-03-04 15:25:30 -07:00
FuroandHundrec fcbce0a66b Fix Rank Slamming Animation 2026-03-04 15:25:21 -07:00
ComedyLostandHundrec 05032e3126 Play danceLeft anim for alternating characters 2026-03-04 15:25:16 -07:00
Hundrec b8a7189e24 Don't do Sys.exit force-kill on Mobile 2026-03-04 02:43:32 -07:00
AnimatingLegendandHundrec 881aba3b03 fix: prevent background processing upon game exit 2026-03-04 01:38:52 -07:00
Hundrec 5480774afe Fix Polymod for Mobile and HTML5 compiling 2026-03-03 17:21:59 -07:00
VirtuGuyandHundrec d62c8af20c Fix hold note length when hitting too early 2026-03-03 16:40:54 -07:00
MoonDroidandHundrec 7d0644f3c8 Add missing feature flag 2026-03-03 15:03:11 -07:00
Hyper_andHundrec fe21c0addd docs: Debug Hotkeys - Remove duplicate entry, fix error and add Mirrored Notes debug key 2026-03-02 20:16:03 -07:00
Hyper_andHundrec 219143c02d fix non existant paths not being sanitized properly on Linux 2026-03-02 20:16:03 -07:00
MightyTheArmiddiloandHundrec 03930a29c3 Remove duplicate blacklisting of the funkin.api.newgrounds package 2026-03-02 20:16:03 -07:00
ImVeryBadandHundrec 5d378cd9f2 Remove more traces from classes. 2026-03-02 20:16:03 -07:00
HundrecandKade e5db402025 Bump Polymod and adjust outdated mod error message
Co-Authored-By: Kade <26305836+Kade-github@users.noreply.github.com>
2026-03-02 20:16:03 -07:00
ImVeryBadandHundrec d348ef3127 Optional dependencies no longer throw window errors and improve log output messages. 2026-03-02 20:16:03 -07:00
Hundrec 9301c0c7dd Remove Song Preview 0 end times 2026-03-02 18:46:33 -07:00
ADA-FunniandHundrec 02ee8e64c8 Fix an issue where metadata stuff was acting weird. 2026-03-02 18:45:28 -07:00
ADA-FunniandHundrec 40eab2e461 Add customisable Freeplay song previews.
Any preview values over 15,000 get turned into 0 (start) and 0.2 (end).
2026-03-02 18:45:28 -07:00
AbnormalPoofandHundrec d6a65ca681 Tweak some animation lengths for Boyfriend DJ 2026-03-02 18:45:15 -07:00
EliteMasterEricandHundrec f8841bab35 Use a float internally to hold the Score, ensuring hold notes get scored correctly relative to the current framerate. 2026-03-02 01:38:30 -07:00
EliteMasterEricandAbnormalPoof dc23a116dd Update the PolymodErrorHandler to display an error message for API version or dependency issues. 2026-03-02 01:50:09 -06:00
AbnormalPoofandHundrec 024994e85a Re-export Boyfriend DJ using the latest BTA 2026-03-01 22:30:40 -07:00
MAJigsaw77andHundrec 9be1633320 Update extension-admob. 2026-03-01 04:21:54 -07:00
AnimatingLegendandHundrec 3b15873fc7 fix: chart editor playback-speed rounding upon reload 2026-02-28 00:05:34 -07:00
ComedyLostandHundrec 786f19c57d Stop playtest results with botplay 2026-02-28 00:05:34 -07:00
ComedyLostandHundrec ccb874e97a Stop the playbar head dragging when in song 2026-02-28 00:05:34 -07:00
VirtuGuyandHundrec f7fd7a57c3 Play SFX When Undoing Add Event 2026-02-28 00:05:33 -07:00
Hundrec 23f79aef58 Update assets submodule 2026-02-27 21:28:49 -07:00
EliteMasterEricandHundrec 2c394cc636 Fix an issue where displaying Tooltips would mess up HaxeUI field focus. 2026-02-27 21:26:11 -07:00
Hundrec d7a0139e4f Adjust focus lost volume level to 25%
Reducing to 50% wasn't noticeable enough, but 25% should be a clean reduction.
2026-02-27 21:25:57 -07:00
Karim AkraandHundrec 562d23005d Properly center the sound tray when the resolution is changed 2026-02-27 21:25:57 -07:00
EliteMasterEricandHundrec 671c152463 Fix a bug when the HUD camera zoom would be disabled when the MAIN camera zoom (different camera!) was above 1.35x. 2026-02-26 20:21:16 -07:00
EliteMasterEricandHundrec 3ce7c7939f Updated tooltips to use the note kind description 2026-02-25 00:52:47 -07:00
EliteMasterEricandHundrec 28450ccfc6 Build the list of note kinds from the NoteKindManager instead of hardcoding it 2026-02-25 00:52:45 -07:00
Hundrec 31dbd68194 Bump version to 0.8.3
Build and Upload nightly game builds / gather-changes (push) Canceled after 0s
Build and Upload nightly game builds / gather-tags (push) Canceled after 0s
Build and Upload nightly game builds / build-game-on-host (macos, macos) (push) Canceled after 0s
Build and Upload nightly game builds / build-game-on-host (windows, windows) (push) Canceled after 0s
Build and Upload nightly game builds / docker-image (push) Canceled after 0s
Build and Upload nightly game builds / build-game-in-container (html5) (push) Canceled after 0s
Build and Upload nightly game builds / build-game-in-container (linux) (push) Canceled after 0s
2026-02-23 17:11:08 -07:00
Hundrec 29d776061c Changelog for 0.8.3 + adjustments 2026-02-23 17:10:35 -07:00
Hundrec 0805ec914e Bump docs to 0.8.3 2026-02-23 16:47:57 -07:00
Hundrec 98ac6a6ce1 Bump Polymod to fix 2hot script error on Web 2026-02-23 16:04:47 -07:00
ACrazyTownandHundrec 823120cdef Use FlxBitmapText for scoreText 2026-02-23 16:04:29 -07:00
Hundrec 1b13c6c53b Bump version to 0.8.2
Build and Upload nightly game builds / gather-changes (push) Canceled after 0s
Build and Upload nightly game builds / gather-tags (push) Canceled after 0s
Build and Upload nightly game builds / build-game-on-host (macos, macos) (push) Canceled after 0s
Build and Upload nightly game builds / build-game-on-host (windows, windows) (push) Canceled after 0s
Build and Upload nightly game builds / docker-image (push) Canceled after 0s
Build and Upload nightly game builds / build-game-in-container (html5) (push) Canceled after 0s
Build and Upload nightly game builds / build-game-in-container (linux) (push) Canceled after 0s
2026-02-20 22:54:45 -07:00
HundrecandAbnormal 036de96143 Changelog for 0.8.2
Co-Authored-By: Abnormal <86753001+AbnormalPoof@users.noreply.github.com>
2026-02-20 22:50:57 -07:00
ComedyLostandHundrec 0b046cae9c Fix the Freeplay crash when scrolling too fast 2026-02-20 19:50:18 -07:00
Hundrec a4c5341b3b Revert Freeplay capsule timer clearing change 2026-02-20 17:04:30 -07:00
Hyper_andHundrec 5cbfab4f99 fix: Fix a plugin not initializing cameras on the correct frontend
Kevin and Michael found alive and well emoji whatthehappy
2026-02-19 03:14:51 -07:00
Hundrec baf887155b Bump assets for one minor chart adjustment 2026-02-18 01:24:29 -07:00
ImVeryBadandHundrec a5bbe94871 Add more default imports used by mods 2026-02-17 01:06:38 -07:00
ImVeryBadandHundrec ab26b28130 Remove spammy traces from some classes. 2026-02-17 01:06:38 -07:00
RagdollClashandHundrec 2606031ed2 Add an extra pixel to the cutout bitmaps 2026-02-16 14:23:00 -07:00
RagdollClashandHundrec 72f9d32a2f Account for offset when adding the fake cutouts 2026-02-16 14:23:00 -07:00
AbnormalPoofandHundrec 4b87bbf1cd Use a newer export for Title Screen text that got lost in rebasing 2026-02-16 14:23:00 -07:00
AbnormalPoofandHundrec c9802fdcf2 Fix confirm-hold not playing for pixel icons in Character Select... again 2026-02-16 14:22:56 -07:00
Hundrec e7f252953d Two quick chart fixes 2026-02-15 21:48:14 -07:00
Hundrec 7f299d8348 Revert "Use MenuList camera for Touch Detection instead"
This reverts commit 0400f4bd4a.
2026-02-15 21:01:28 -07:00
9d83d05c96 Blacklist lime.utils.AssetLibrary from scripts
Co-authored-by: charlesisfeline <62410083+charlesisfeline@users.noreply.github.com>
2026-02-15 21:01:28 -07:00
PurSnakeandHundrec d6919683c3 Remove dead objects from Freeplay capsule batching 2026-02-15 21:01:28 -07:00
EliteMasterEricandHundrec 879955c4a2 Format a few additional files. 2026-02-15 21:01:28 -07:00
AbnormalPoofandHundrec 6026e0b908 Run haxe-formatter on every file in source/ 2026-02-15 21:01:26 -07:00
32ef5404d8 fix: ResultsState - Start with song name hidden until the top bar shows up
Co-authored-by: Trayfellow <48515908+trayfellow@users.noreply.github.com>
2026-02-13 20:34:11 -07:00
AbnormalPoofandHundrec 3544a36de0 Rework Monster and Monster (Christmas) to use frame labels 2026-02-13 20:34:01 -07:00
RaltyandHundrec 06a1894946 Use MenuList camera for Touch Detection instead 2026-02-13 20:33:58 -07:00
AbnormalPoofandHundrec 40bb5b7a74 Rework Daddy Dearest to use frame labels 2026-02-13 20:33:41 -07:00
RagdollClashandHundrec 062c2fa331 Prevent goBack() from running if mustNotExit is true
Fixes mobile exiting GameOverSubState regardless of said variable.
2026-02-13 20:33:39 -07:00
AbnormalPoofandHundrec 49846dbc13 Re-export the Title Screen text to texture atlas 2026-02-13 20:33:39 -07:00
Karim AkraandHundrec e5a47aa74d Prevent a weird crash when freeplay is loaded 2026-02-13 20:33:20 -07:00
Karim AkraandHundrec 77fffdf370 Improve scrolling in freeplay for different framerates 2026-02-13 20:33:20 -07:00
EliteMasterEricandHundrec eaad0f2450 Additional readability changes. 2026-02-13 20:33:20 -07:00
77faf38d61 Cleanup GRhythmUtil.mirrorNoteDirection() along with a few other changes... ...like accounting for Strumline.KEY_COUNT which is now public, removing an unused temporary variable, and formatting GRhythmUtil.hx
Co-authored-by: ImVeryBad <nightbear843@yahoo.com>
Co-authored-by: ADA-Funni <codingking263@gmail.com>
2026-02-13 20:33:04 -07:00
gamerbrossandHundrec 134d220298 Fix chart editor vocals waveform with tempo changes 2026-02-13 20:33:04 -07:00
KoloandHundrec d4610f5f16 hide the tooltips when killing notes/events 2026-02-13 20:33:04 -07:00
AbnormalPoofandHundrec f5129b3283 Run oxipng on every image in assets/ 2026-02-13 20:32:51 -07:00
AbnormalPoofandHundrec ee6583fa82 Bump flixel-animate to fix an issue with the character select locks 2026-02-13 20:32:40 -07:00
AbnormalPoofandHundrec af72895e54 Blend with every camera underneath 2026-02-13 20:32:29 -07:00
AbnormalPoofandHundrec 8d17ad3dd1 Add cross-camera blending to the blend shader 2026-02-13 20:32:23 -07:00
EliteMasterEricandHundrec 723dd81e2b Modify several checkstyle and hxformat rules. 2026-02-13 20:32:11 -07:00
AbnormalPoofandHundrec 5c45d24e2e Bump polymod to fix BF DJ's cartoons 2026-02-11 02:05:24 -07:00
AbnormalPoofandHundrec ffe72b89a7 Re-export both Freeplay DJs to use frame labels 2026-02-11 02:05:24 -07:00
AbnormalPoofandHundrec bc92d6cebf Add useAnimatePosition and make BF and Pico use it 2026-02-11 02:05:20 -07:00
AbnormalPoofandHundrec b4bc3ca6cf Frame label support for Freeplay DJs 2026-02-11 02:05:20 -07:00
AbnormalPoofandHundrec 8439272d00 Optimize Character Select atlases 2026-02-11 02:05:02 -07:00
AbnormalPoofandHundrec c5a7442415 Change a final to a var in BF DJ's script 2026-02-11 02:05:00 -07:00
Hundrec 31b7fdf02b Re-export every chart + song metadata in the game
The new 0.8.2 json2object library exports charts consistently!
I've re-exported all 61 songs in the game to ensure that future chart changes have readable diffs!
2026-02-10 18:55:38 -07:00
dafe4fe918 Fix a few comment typos
Very important, thank you

Co-Authored-By: charlesisfeline <62410083+charlesisfeline@users.noreply.github.com>
2026-02-10 18:42:20 -07:00
Hundrec 6737146571 Fix ctrl-click on hold note crashing Chart Editor 2026-02-10 18:41:38 -07:00
Hundrec 33d1fd578e Bump Polymod again to fix error on Web 2026-02-06 15:00:35 -07:00
MAJigsaw77andHundrec 0c9edf93c3 Fix multiple script errors cause by the Polymod update. 2026-02-06 15:00:26 -07:00
AbnormalPoofandHundrec 241f140a98 Bump polymod to the latest commit 2026-02-06 15:00:24 -07:00
EliteMasterEricandHundrec 0311c7373e Remove ScriptedObject since it's deprecated anyway (scripts don't have to extend anything anymore) 2026-02-06 15:00:20 -07:00
EliteMasterEricandHundrec ca95fa78c4 Update polymod to the latest experimental. 2026-02-06 15:00:20 -07:00
EliteMasterEricandHundrec 7fa5d77db7 Switch from .init() to .scriptInit() 2026-02-06 15:00:20 -07:00
AbnormalPoofandHundrec dcc3baae26 Re-export Blazin' characters using BTA 2026-02-03 00:56:16 -07:00
ccb270612c Quad batch capsules to prevent a memory leak
Co-Authored-By: Hyper_ <40342021+NotHyper-474@users.noreply.github.com>
Co-Authored-By: Mario Hernando <97055307+MaybeMaru@users.noreply.github.com>
2026-02-02 21:35:06 -07:00
EliteMasterEricandHundrec 404b601012 An extensive review and commenting of various code style enforcements. 2026-02-02 21:35:06 -07:00
AbnormalPoofandHundrec 02d83a766d Re-export the bottom boppers in Week 5 Erect to texture atlas 2026-02-02 21:34:49 -07:00
AbnormalPoofandHundrec f40da353a2 Re-export Pico (Christmas) to texture atlas 2026-02-02 21:34:47 -07:00
ComedyLostandHundrec c0c550e209 Fix Freeplay difficulty graphics not accounting for modded difficulties/variations 2026-02-02 03:26:46 -07:00
AbnormalPoofandHundrec 29ac2ad58b Fix an issue where the sprite didn't respect render texture or stage matrix settings 2026-02-02 03:26:46 -07:00
AbnormalPoofandHundrec 9b0b273004 Adjusted offsets for Pico (Playable) 2026-02-01 03:33:53 -07:00
AbnormalPoofandHundrec 17f120f5ee Fix an issue where multiple characters couldn't be used if they had multiple animate atlases 2026-02-01 03:33:50 -07:00
VirtuGuyandHundrec 284cfc7ebc Use pointer cursor for moveable UI components 2026-02-01 01:23:40 -07:00
Hundrec aa5d30eecc Remove 30% threshold for Chart Editor Results 2026-02-01 01:23:40 -07:00
AbnormalPoofandHundrec c11ecfcb6f Bump polymod to fix in-game cutscenes being unskippable 2026-02-01 01:23:40 -07:00
AbnormalPoofandHundrec aa251af116 Fix Boyfriend (Christmas) being default Boyfriend 2026-01-31 21:15:26 -07:00
AbnormalPoofandHundrec ea7bc750d2 Fix Pico (Playable) throwing null object reference when loaded twice 2026-01-31 21:15:23 -07:00
AbnormalPoofandHundrec a043512f0e Revert a screen bounds fix now that they're fixed in flixel-animate proper 2026-01-31 21:15:23 -07:00
AbnormalPoofandHundrec 5805c310c1 Rework some flickers to use FlxTween.flicker instead of FlxFlicker 2026-01-31 20:22:51 -07:00
AbnormalPoofandHundrec bf0135d48e Bump polymod to the latest experimental commit 2026-01-31 20:10:23 -07:00
AbnormalPoofandHundrec e1f950d3e6 Bump flixel-animate to the latest version 2026-01-31 20:10:23 -07:00
AbnormalPoofandHundrec 018780620d Bump openfl to fix an issue with the Week 6 note splashes 2026-01-31 20:10:23 -07:00
Hundrec ba2f8df30b Fix up 2hot 2026-01-31 17:57:02 -07:00
Hundrec ba77fc6677 Batch of chart fixes and adjustments for 0.8.2
Includes 24 changed charts
View assets commit for diffs
2026-01-31 17:23:19 -07:00
LasercarandHundrec ff3a5c4b9b Cancel screenshot spam timer in pre-state switch 2026-01-31 00:07:57 -07:00
MaybeMaruandHundrec 3aef0e5432 Disable Character Select fade shader when unused 2026-01-31 00:07:57 -07:00
MightyTheArmiddiloandHundrec 83fb754e8e Save the Playtest Results Preference 2026-01-31 00:07:35 -07:00
AbnormalPoofandHundrec 5042448e98 Re-export Nene (Christmas) to texture atlas 2026-01-31 00:07:31 -07:00
AbnormalPoofandHundrec bca18170e7 Disable debug draw for the perspective floor in Spaghetti 2026-01-31 00:07:19 -07:00
EliteMasterEricandHundrec 524468135d Cleanup HScript to stop using Polymod to access other scripted classes (since that can be done directly now). 2026-01-31 00:07:17 -07:00
AbnormalPoofandHundrec de5fe9b950 Fix A-Bot's visualizer showing full bars for a single frame when entering a song 2026-01-29 22:49:19 -07:00
AbnormalPoofandHundrec 17ed98ee4d Re-export Pico (Playable) and Pico (Dark) to texture atlases 2026-01-29 22:27:42 -07:00
AbnormalPoofandHundrec 1b6c2d1f93 Reset the symbol graphic when the Album is destroyed 2026-01-29 22:27:38 -07:00
MAJigsaw77andHundrec 7c90aee994 Fix paths on Windows Subsystem for Linux. 2026-01-29 22:27:38 -07:00
AbnormalPoofandHundrec 96bdfac0b9 Adjust some character scripts 2026-01-29 22:27:22 -07:00
Karim AkraandHundrec 359661b549 FIx the game position on low resolution 4:3 displays 2026-01-29 22:08:00 -07:00
AbnormalPoofandHundrec 1e43902fff Rework 3 Nene variants to use the script extending system 2026-01-29 22:08:00 -07:00
AbnormalPoofandHundrec 84a79f6833 Tweak the blacklist a bit more and add back modOptions map 2026-01-29 22:08:00 -07:00
EliteMasterEricandHundrec bcd3b03a75 Update Polymod again (HScript is now built-in) 2026-01-29 22:07:59 -07:00
EliteMasterEricandHundrec 1ff79a7825 Modified funkin.Save blacklist, and added a new function specifically for retrieving and saving modded preferences in a standard way. 2026-01-29 22:07:59 -07:00
EliteMasterEricandHundrec c3cdddc46e Bump Polymod to the latest version 2026-01-29 22:07:59 -07:00
EliteMasterEricandHundrec ac2f1f602b Tweak FlxSave to use field blacklisting. 2026-01-29 22:07:59 -07:00
Hundrec 40ea803c56 Also process all events other than playAnimation 2026-01-29 22:07:59 -07:00
EliteMasterEricandHundrec dce987b345 Add the processOldEvents parameter to song events, and enable it for FocusCamera. 2026-01-29 22:07:59 -07:00
AbnormalPoofandHundrec 5804aa100d Re-export Pico's GREAT animation to not have huge black and white boxes in the spritemap 2026-01-29 22:07:59 -07:00
HundrecandHyper_ f1276a64a0 Fix crash when saving a chart
Co-Authored-By: Hyper_ <40342021+nothyper-474@users.noreply.github.com>
2026-01-29 22:07:59 -07:00
AbnormalPoofandHundrec 503bbaaa46 Small fix to make the blend shader a lot more accurate 2026-01-29 22:07:59 -07:00
AbnormalPoofandHundrec 0dbd8439bd Remove blend baking from some atlases in the game 2026-01-29 22:07:59 -07:00
LasercarandHundrec 40e5d1a4c1 chart editor - popup when time change added at grid playhead 2026-01-29 22:07:59 -07:00
HundrecandVirtuGuy 58803cd221 Don't smooth the edges of Stage Editor crosshair
Co-Authored-By: VirtuGuy <103977942+virtuguy@users.noreply.github.com>
2026-01-29 22:07:59 -07:00
ff0a226f53 Fix Stage Editor load dialog showing as save
Co-Authored-By: Hyper_ <40342021+nothyper-474@users.noreply.github.com>
Co-Authored-By: Pāvels Rimašs <69017727+anysad@users.noreply.github.com>
2026-01-29 22:07:59 -07:00
LasercarandHundrec 1d19286f6b More Stage Editor selection functionality 2026-01-29 22:07:59 -07:00
KoloandHundrec 5cf114143c reset gameover/pause/countdown stuff after leaving editors 2026-01-29 22:07:59 -07:00
AbnormalPoofandHundrec 8331a1fa7f Re-export the can to restore the unused sparkling effect 2026-01-29 22:07:59 -07:00
db7bee7902 Add support for khronos blend modes, enabling 14 new blend modes to work properly
Co-authored-by: Hyper_ <40342021+NotHyper-474@users.noreply.github.com>
Co-authored-by: ACrazyTown <47027981+ACrazyTown@users.noreply.github.com>
Co-authored-by: PurSnake <56314743+PurSnake@users.noreply.github.com>
2026-01-29 22:07:59 -07:00
Hundrec 2ba0f37a5a Update LICENSE to 2026 2026-01-29 22:07:59 -07:00
Karim AkraandHundrec 31f873ffc2 add ios assets path to clearAssets 2026-01-29 22:07:59 -07:00
Karim AkraandHundrec f7b5d5c62f Lock the game's controls onto keyboard mode as long as a keyboard/gamepad device is connected 2026-01-29 22:07:59 -07:00
ImVeryBadandHundrec 94570d8c7c Center waveforms on health icons and adjust icon X-offsets in Chart Editor 2026-01-29 22:07:59 -07:00
PurSnakeandHundrec f6036343c9 Change FlxPieDial to FlxRadialGauge and display it more nicely visually 2026-01-29 22:07:59 -07:00
MightyTheArmiddiloandHundrec cc8060db5b Fix hold cover positioning 2026-01-29 22:07:59 -07:00
boopboyandHundrec 511f4d5b64 Make musicSuffix accept any pixel suffix 2026-01-29 22:07:58 -07:00
ComedyLostandHundrec b04a7708b1 Clear Freeplay previews when switching selection
Makes it harder to crash Freeplay when scrolling really fast
2026-01-29 22:07:58 -07:00
VirtuGuyandHundrec dd512d02e7 Fix Missing Album Title Showing Flixel Icon 2026-01-29 22:07:58 -07:00
VirtuGuyandHundrec ff89c09b6f Fix album roll after character select exit 2026-01-29 22:07:58 -07:00
VirtuGuyandHundrec 429e018749 Fix capsules going offset in ranks 2026-01-29 22:07:58 -07:00
VirtuGuyandHundrec babe37a0f0 Fix last BPM digit for capsules 2026-01-29 22:07:58 -07:00
VirtuGuyandHundrec 122df21223 Fix freeplay pixel icon not selecting 2026-01-29 22:07:58 -07:00
VirtuGuyandHundrec 016c53061c Fix soundtray appearing under stickers 2026-01-29 22:07:58 -07:00
VirtuGuyandHundrec 429704676a Apply alpha to onion skin after character change 2026-01-29 22:07:58 -07:00
VirtuGuyandHundrec cda1ca6897 Fix crash when closing game within stage editor 2026-01-29 22:07:58 -07:00
KoloandHundrec 8954dee6d6 don't use the default names for stage editor stuff 2026-01-29 22:07:58 -07:00
Hyper_andHundrec b71e12ec5c Fix 2nd measure not being rendered and previous measure check being useless 2026-01-29 22:07:58 -07:00
KoloandHundrec c2055a322d add support for decimals in cam bop offset and rate 2026-01-29 22:07:58 -07:00
KadeandHundrec 583700006c less confusing instructions 2026-01-29 22:07:58 -07:00
Kade-gtihubandHundrec 928c2fcc19 QOL and fixes for OffsetMenu 2026-01-29 22:07:58 -07:00
Hundrec 3c913d29e3 Bump assets 2026-01-29 22:07:58 -07:00
VirtuGuyandHundrec 52e015ad14 Fix strange menu scrolling behavior on web 2026-01-29 22:07:58 -07:00
EliteMasterEricandHundrec bef8cf9a0e I got a crash in the Crash Handler when the crash happened before FlxGame initialized. 2026-01-29 22:07:58 -07:00
VirtuGuyandHundrec eae4cb2160 Fix char select lock anim not playing on mobile 2026-01-29 22:07:58 -07:00
Hundrec 955c94ed79 Properly credit contributor in a Changelog entry 2026-01-29 22:07:58 -07:00
KoloandHundrec 95109daedb use character's camera focus point to determine the game over cam position 2026-01-29 22:07:58 -07:00
MoonDroidandHundrec 00f28fdb79 Remove duped function and add extra docs 2026-01-29 22:07:57 -07:00
LasercarandHundrec aad014a0ba Mirror notes Chart Editor command 2026-01-29 22:07:57 -07:00
ImVeryBadandHundrec 4917bd0591 Ignore the .idea folder from mods. 2026-01-29 22:07:57 -07:00
charlesisfelineandHundrec 54943b22f8 Remove unused ButtonRemapSubstate 2026-01-29 22:07:57 -07:00
TrofemandHundrec ec6e26c298 Update example mod's API version to 0.8.0 2026-01-29 22:07:57 -07:00
3db958a76b A bunch of typo fixes
Co-Authored-By: charlesisfeline <62410083+charlesisfeline@users.noreply.github.com>
Co-Authored-By: TechnikTil <techniktil@tilnotdrip.org>
Co-Authored-By: MightyTheArmiddilo <132609476+mightythearmiddilo@users.noreply.github.com>
Co-Authored-By: BaranMuzu <104278499+baranmuzu@users.noreply.github.com>
2026-01-29 22:07:57 -07:00
Karim AkraandHundrec f5f2a2ac4c replace the AVM events with ad load/dismiss events and suspend the audio context instead of each audio manually 2026-01-29 22:07:57 -07:00
Cameron TaylorandHundrec 26fe00b559 fix a few of the scripts to point from art/ -> scripts/ when needed 2026-01-29 22:07:57 -07:00
Cameron TaylorandHundrec 899d793e1c move some scripts from art/ submodule to main funkin repo 2026-01-29 22:07:57 -07:00
AbnormalPoofandHundrec 430e2b9dcc Removed an unused TitleOutline shader 2026-01-29 22:07:57 -07:00
AbnormalPoofandHundrec 9189c35585 Title screen cleanup 2026-01-29 22:07:57 -07:00
Hundrec 0855b4da4e Bump assets submod 2026-01-29 22:07:57 -07:00
EliteMasterEricandHundrec ad9c6581ff Update docs for SongLoadScriptEvent so people know what it does. 2026-01-29 22:07:57 -07:00
Kade-gtihubandHundrec 293d303c16 Add Mirror to PlayState Params 2026-01-29 22:07:57 -07:00
PurSnakeandHundrec e4a4197482 Ease Previews 2026-01-29 22:07:57 -07:00
2886e29d58 Add currentStage var to clean up scripts
Co-Authored-By: Kade <26305836+Kade-github@users.noreply.github.com>
Co-Authored-By: Abnormal <86753001+AbnormalPoof@users.noreply.github.com>
2026-01-29 22:07:57 -07:00
EliteMasterEricandHundrec 5868cb1d78 Update json2object to respect @:order when exporting + skip default values
* @:order is only for Maps, not Arrays (IDK how this compiled before lol?)
* Don't use @:default on version number.
* Don't use @:default for ChartManifestData
* Don't use @:default for generatedBy
2026-01-13 21:02:24 -07:00
401 changed files with 13357 additions and 8219 deletions
+3 -3
View File
@@ -48,19 +48,19 @@ body:
attributes:
label: Mobile Device Model
description: (Mobile users only) What mobile device are you playing on?
placeholder: ex. iPhone 17, Galaxy S25, iPad 11th Gen
placeholder: ex. iPhone 17, Galaxy S26, iPad 11th Gen
- type: input
attributes:
label: Mobile OS Version
description: (Mobile users only) What version is your Operating System?
placeholder: ex. iOS 26.2, Android 16, iPadOS 26.2
placeholder: ex. iOS 26.4, Android 16, iPadOS 26.4
- type: input
attributes:
label: Version
description: Which version are you playing on? The game version is in the bottom left corner of the main menu.
placeholder: ex. 0.8.1
placeholder: ex. 0.8.4
validations:
required: true
+2 -2
View File
@@ -36,7 +36,7 @@ body:
attributes:
label: Version
description: Which version are you playing on? The game version is in the bottom left corner of the main menu.
placeholder: ex. 0.8.1
placeholder: ex. 0.8.4
validations:
required: true
@@ -52,7 +52,7 @@ body:
attributes:
label: Location
description: Where did you find the issue(s)? Include the name of the song, the variation, the difficulty, the time/section of the song, and any images or videos.
placeholder: ex. Cocoa Erect on Erect/Nightmare difficulties at Section 30
placeholder: ex. Cocoa Erect [Nightmare] at Section 30, step 5
validations:
required: true
+1 -1
View File
@@ -36,7 +36,7 @@ body:
attributes:
label: Version
description: Which version are you compiling? The game version is in the bottom left corner of the main menu or in the project.hxp file.
placeholder: ex. 0.8.1
placeholder: ex. 0.8.4
validations:
required: true
+3 -3
View File
@@ -49,19 +49,19 @@ body:
attributes:
label: Mobile Device Model
description: (Mobile users only) What mobile device are you playing on?
placeholder: ex. iPhone 17, Galaxy S25, iPad 11th Gen
placeholder: ex. iPhone 17, Galaxy S26, iPad 11th Gen
- type: input
attributes:
label: Mobile OS Version
description: (Mobile users only) What version is your Operating System?
placeholder: ex. iOS 26.2, Android 16, iPadOS 26.2
placeholder: ex. iOS 26.4, Android 16, iPadOS 26.4
- type: input
attributes:
label: Version
description: Which version are you playing on? The game version is in the bottom left corner of the main menu.
placeholder: ex. 0.8.1
placeholder: ex. 0.8.4
validations:
required: true
+1 -2
View File
@@ -72,7 +72,6 @@
"haxecheckstyle.externalSourceRoots": [],
"haxecheckstyle.configurationFile": "checkstyle.json",
"haxecheckstyle.codeSimilarityBufferSize": 100,
"lime.projectFile": "project.hxp",
"lime.targets": [
{ "name": "windows", "enabled": true, "label": "Windows" },
{ "name": "mac", "enabled": true, "label": "macOS" },
@@ -80,8 +79,8 @@
{ "name": "html5", "enabled": true, "label": "HTML5" },
{ "name": "android", "enabled": true, "label": "Android" },
{ "name": "ios", "enabled": true, "label": "iOS" },
{ "name": "hl", "enabled": true, "label": "HashLink" },
// Disabled targets
{ "name": "hl", "enabled": false, "label": "HashLink" },
{ "name": "air", "enabled": false },
{ "name": "electron", "enabled": false },
{ "name": "flash", "enabled": false },
+260 -2
View File
@@ -4,6 +4,264 @@ 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.8.4] - 2026-03-26
### Added
- Added several new features to Polymod:
- Added FULL support for abstracts! (Previously, only `FlxColor` was supported)
- Added support for getting the code of a single character string (i.e `’h’.code`) (Thanks NotHyper-474!)
- Added support for import defaults (`import.hx`/`import.hxc`), allowing scripted classes with the same package to share imports. (Thanks KoloInDaCrib!)
- Added `scriptInit` and `listScriptClasses` functions to scripted classes. (Thanks KoloInDaCrib!)
- `.hx` files can now be parsed. (Thanks Starexify!)
- Added support for preprocessing (`#if`/`#else` syntax), allowing for platform-specific code to be implemented in an easier way. (Thanks KoloInDaCrib!)
- Added support for mod IDs. (Thanks Starexify!)
- Implemented `_merge` support for scripts. (Thanks KoloInDaCrib!)
- Please refer to the Cookbook to learn how to use this.
- Added widescreen scale properties to the Zoom Camera event in the Chart Editor to account for widescreen resolutions.
- Added a flipY field for Story Mode level props. ([48ed659](https://github.com/FunkinCrew/Funkin/commit/48ed65980005366371fda7a66c04f73bb5b86200)) - by @ExtraCode75 in [#6340](https://github.com/FunkinCrew/Funkin/pull/6340)
- Implemented working start and end times for Freeplay song previews. ([40eab2e](https://github.com/FunkinCrew/Funkin/commit/40eab2e4618ebb6dc67a06ef67df817920773c56)) - by @ADA-Funni in [#6725](https://github.com/FunkinCrew/Funkin/pull/6725)
- Added a new albumOSTName property to Freeplay album data to make the "OFFICIAL OST" text moddable. ([67d2a98](https://github.com/FunkinCrew/Funkin/commit/67d2a9811b5c92409bdc76e287c984d5777d8621)) - by @NotHyper-474 in [#6578](https://github.com/FunkinCrew/Funkin/pull/6578)
- Added an optional 'capsule' field to level data to display any week label on Freeplay capsules. ([528e9e4](https://github.com/FunkinCrew/Funkin/commit/528e9e4f03c40e59f3932d8b4c522b6eeb66783b)) - by @Trayfellow in [#7149](https://github.com/FunkinCrew/Funkin/pull/7149)
- Implemented ScriptedBaseFreeplayDJ, allowing modders to customize how custom Freeplay DJs are rendered. ([423ccfa](https://github.com/FunkinCrew/Funkin/commit/423ccfab98a29646e4998dacedaf403319d956ff)) - by @PurSnake in [#6806](https://github.com/FunkinCrew/Funkin/pull/6806)
- Added a new FunkinGroup class to make groups of sprites easier to modify. ([4f31600](https://github.com/FunkinCrew/Funkin/commit/4f316003af9a6ca46c77bf4971059e20543cbd7b)) - by @MightyTheArmiddilo in [#6758](https://github.com/FunkinCrew/Funkin/pull/6758)
- Added `Reflect.makeVarArgs` to allow modders to create functions with a variable number of arguments. ([3633df3](https://github.com/FunkinCrew/Funkin/commit/3633df3fdc6dc0af4f9886fcb1e1d4a8d2b8d5aa)) - by @Starexify in [#6738](https://github.com/FunkinCrew/Funkin/pull/6738)
- Added script event support for song events. ([15bef89](https://github.com/FunkinCrew/Funkin/commit/15bef89d71982c5685f4ce6f6d7e6e4d8321508c)) - by @KoloInDaCrib in [#4130](https://github.com/FunkinCrew/Funkin/pull/4130)
- Added a new Chart Editor event type: Set Target Bop Speed. ([1893f2b](https://github.com/FunkinCrew/Funkin/commit/1893f2b2f679d8a4d262052793dde24e94719ee6)) - by @roma-perec-bp in [#6769](https://github.com/FunkinCrew/Funkin/pull/6769)
- Added shortcuts to select all notes above or below the playhead in the Chart Editor. ([08b3af9](https://github.com/FunkinCrew/Funkin/commit/08b3af959d6657511bfe8418da545731050cb24a)) - by @Lasercar in [#4306](https://github.com/FunkinCrew/Funkin/pull/4306)
- Added the ability to view and edit the timing of a note or event through the Chart Editor context menu. ([a782b3f](https://github.com/FunkinCrew/Funkin/commit/a782b3f9e8498634babb864341fd1437bb2c01f6)) - by @Lasercar in [#4200](https://github.com/FunkinCrew/Funkin/pull/4200)
- Added an "Edit Note" option to the Chart Editor context menu that opens the Notes window. ([e710198](https://github.com/FunkinCrew/Funkin/commit/e710198afec9a0fe19effe4cd196ab3a247f4784)) - by @Honton129 in [#7010](https://github.com/FunkinCrew/Funkin/pull/7010)
- Added the ability to Ctrl-click on health icons in the Chart Editor to open character previews. ([011f154](https://github.com/FunkinCrew/Funkin/commit/011f1541b197fd4f962ab8a910cbd417f78c2d09)) - by @Trofem in [#7089](https://github.com/FunkinCrew/Funkin/pull/7089)
### Changed
- Upgraded the input handling system from SDL2 to SDL3!
- Added an “Unlocked Framerate” preference to Desktop platforms.
- The input system is now much more responsive and accurate down to the nanosecond.
- The game now properly supports more controllers and input devices.
- The game now shows popups when installed mods have issues, such as when the API version is incorrect.
- Unfocusing the game now reduces the game’s volume to 25% (down from 50%).
- The notekinds dropdown are no longer hardcoded in the Chart Editor.
- The Character Select key is now hidden in the Controls menu until a new character is unlocked. ([6c13444](https://github.com/FunkinCrew/Funkin/commit/6c134442118d3f5f61b9e3faa631512d210422fb)) - by @Lasercar in [#4882](https://github.com/FunkinCrew/Funkin/pull/4882)
- The Story Mode level score now displays with commas. ([04fffe8](https://github.com/FunkinCrew/Funkin/commit/04fffe8ade4c4b236d59a236f08534e8eede179f)) - by @JVNpixels in [#4965](https://github.com/FunkinCrew/Funkin/pull/4965)
- Freeplay capsule week labels are now softcoded and rendered using a font. ([48752e4](https://github.com/FunkinCrew/Funkin/commit/48752e444cc5f1b8cd0a3b579f843e9ab6580c46)) - by @KoloInDaCrib in [#5249](https://github.com/FunkinCrew/Funkin/pull/5249)
- The Freeplay change character hint now changes when a gamepad is connected. ([0f7859b](https://github.com/FunkinCrew/Funkin/commit/0f7859bfb6b829290804efab9d5c67fbdbec0903)) - by @MrMadera in [#6609](https://github.com/FunkinCrew/Funkin/pull/6609)
- Moved the Winter Horrorland intro cutscene logic into a script. ([9bbe73b](https://github.com/FunkinCrew/funkin.assets/commit/9bbe73b21ccbea29a5d5187709f91b4822bf7e31)) - by @mario64thane in [funkin.assets#63](https://github.com/FunkinCrew/funkin.assets/pull/63)
- Merged FlxFilteredSprite functionality into FunkinSprite. ([22736b2](https://github.com/FunkinCrew/Funkin/commit/22736b27da7d8de8b11ab6cc6c2a622e5579dccd)) - by @TechnikTil in [#7114](https://github.com/FunkinCrew/Funkin/pull/7114)
- Adjusted some wording in the Chart/Stage Editor backup window to be clearer. ([a607396](https://github.com/FunkinCrew/Funkin/commit/a607396d04f24388691ee23bd04022681ca54756)) - by @Marcosayfi in [#7071](https://github.com/FunkinCrew/Funkin/pull/7071)
### Fixed
- Conjoined string interpolation `$a$b` now parses properly in Polymod.
- Video cutscenes are no longer muted at volumes of 3 or lower.
- Video cutscenes no longer occasionally show glitches at the beginning.
- [MOBILE] Loading a cloud save from Newgrounds no longer carries over the volume level from Desktop.
- [HTML5] Scrolling the game out of view now pauses the game instead of allowing gameplay to continue processing.
- The Boyfriend Freeplay DJ new rank animation now transitions smoothly back to its idle animation.
- Hold notes now score much more consistently across different framerate values.
- The bricks in Week 7 stages are now better quality.
- Trimmed out the silent beat at the beginning of Ugh Erect.
- Camera bopping no longer stops at zoom values of 1.35x or higher.
- Charting many hold notes in a row no longer breaks audio handling.
- Adding collapsible frames in event schemas no longer crashes the game.
- Some event properties have been grouped under Advanced frames.
- Chart Editor dropdowns no longer refocus when a tooltip appears.
- Focus and Zoom Camera event durations now account for playback speed.
- [WINDOWS] Exiting the game no longer leaves it running as a background process. ([881aba3](https://github.com/FunkinCrew/Funkin/commit/881aba3b03a26764374441cab244cd2d360a30b9)) - by @AnimatingLegend in [#6885](https://github.com/FunkinCrew/Funkin/pull/6885)
- Story Mode now only shows difficulties that all of a level's songs have. ([365f8dc](https://github.com/FunkinCrew/Funkin/commit/365f8dcfea9569f2edba1ebfceb3d49819ad2b57)) - by @Starexify in [#7046](https://github.com/FunkinCrew/Funkin/pull/7046)
- The Girlfriend Story Mode prop now bops continuously when scrolling through levels. ([84b2d5b](https://github.com/FunkinCrew/Funkin/commit/84b2d5b48d9eb76c918fdba6987ccc1f5da76133)) - by @Redar13 in [#6830](https://github.com/FunkinCrew/Funkin/pull/6830)
- The Freeplay new rank slam animation now properly plays its glow effect. ([fcbce0a](https://github.com/FunkinCrew/Funkin/commit/fcbce0a66b75b0c1224c6a0e2907c170b71998ad)) - by @FuroYT in [#7015](https://github.com/FunkinCrew/Funkin/pull/7015)
- The Freeplay Random capsule no longer displays BPM and difficulty numbers. ([0ad2d50](https://github.com/FunkinCrew/Funkin/commit/0ad2d507efa9dcb577184e28bfd04091b3424bfb)) - by @Lasercar in [#4927](https://github.com/FunkinCrew/Funkin/pull/4927)
- Favoriting a song in Freeplay no longer breaks capsule text cycling. ([ce493a0](https://github.com/FunkinCrew/Funkin/commit/ce493a03c9ffb4c43c2c27885ed0fab0c1c3531d)) - by @VirtuGuy in [#7134](https://github.com/FunkinCrew/Funkin/pull/7134)
- Freeplay songs with invalid pixel icons no longer duplicate the icon from the previous song in the list. ([b3eb709](https://github.com/FunkinCrew/Funkin/commit/b3eb709f4ed535ed2544f3bb530ff3724e07be3f)) - by @FuroYT in [#7006](https://github.com/FunkinCrew/Funkin/pull/7006)
- A Freeplay clear percent of 100% now properly exits to the right when returning to the Main Menu. ([5974c1a](https://github.com/FunkinCrew/Funkin/commit/5974c1a48293f3185c5f249acb9130ebd6b35ae4)) - by @Trayfellow in [#7183](https://github.com/FunkinCrew/Funkin/pull/7183)
- Nudged the Freeplay backing image down by one pixel to align with the bottom of the screen. ([b8c2854](https://github.com/FunkinCrew/Funkin/commit/b8c2854007f36ac7a2b6897eead3f979e11f0ad7)) - by @SuperEric1 in [#6893](https://github.com/FunkinCrew/Funkin/pull/6893)
- Improved performance for songs that use a lot of events. ([3b27ec5](https://github.com/FunkinCrew/Funkin/commit/3b27ec5b66b2fa00d59a77f6ec07aff68e440860)) - by @KoloInDaCrib in [#7171](https://github.com/FunkinCrew/Funkin/pull/7171)
- Adjusted hit window logic to accurately reflect threshold values for all judgments. ([dcb5b3a](https://github.com/FunkinCrew/Funkin/commit/dcb5b3a9358a9bb126153b57aa2d38dc0684c39d)) - by @Rudyrue in [#7104](https://github.com/FunkinCrew/Funkin/pull/7104)
- Adjusted offsets for all health icons to be more consistent. ([83d8134](https://github.com/FunkinCrew/funkin.assets/commit/83d8134f9d0b3cf3b59e9e1d972fa1e200a98ba1)) - by @LeGooeyy in [funkin.assets#278](https://github.com/FunkinCrew/funkin.assets/pull/278)
- Hold notes no longer shift upward when hit early. ([d62c8af](https://github.com/FunkinCrew/Funkin/commit/d62c8af20c90ec3d6e4274aba8ddbfb378ab0256)) - by @VirtuGuy in [#7060](https://github.com/FunkinCrew/Funkin/pull/7060)
- The opponent no longer stops singing upon missing if Boyfriend has no vocals file. ([cea54e3](https://github.com/FunkinCrew/Funkin/commit/cea54e394c78544dd0ec0339721faaac140caa65)) - by @FuroYT in [#7007](https://github.com/FunkinCrew/Funkin/pull/7007)
- onPause script functions now properly trigger when pausing during a cutscene or dialogue. ([5a0b431](https://github.com/FunkinCrew/Funkin/commit/5a0b4310a2c39b033989e0e36b8f456bdac65a5b)) - by @MightyTheArmiddilo in [#6804](https://github.com/FunkinCrew/Funkin/pull/6804)
- Camera events now consistently pause when the Pause Menu is opened. ([e623439](https://github.com/FunkinCrew/Funkin/commit/e6234397f57d2af37035a0ff2504b8241e23949d)) - by @VirtuGuy in [#7145](https://github.com/FunkinCrew/Funkin/pull/7145)
- The Pause Menu global offset value now adjusts at the same rate across all framerates. ([348647f](https://github.com/FunkinCrew/Funkin/commit/348647f48629a24ee3bd2b759bbfc1bff168fb81)) - by @KolzeYT in [#7147](https://github.com/FunkinCrew/Funkin/pull/7147)
- Spirit's trail effect now renders consistently across all framerates. ([75506f7](https://github.com/FunkinCrew/Funkin/commit/75506f71a97d468f516a0232c8be5560afb0682e)) - by @KolzeYT in [#7179](https://github.com/FunkinCrew/Funkin/pull/7179)
- The sound tray now appears consistently and plays sound effects at the right volume. ([2b9906d](https://github.com/FunkinCrew/Funkin/commit/2b9906df29660057410d3054e897012896896d6a)) - by @Raltyro in [#7068](https://github.com/FunkinCrew/Funkin/pull/7068)
- The sticker transition now properly pauses when losing focus with Pause on Unfocus enabled. ([8a1d74b](https://github.com/FunkinCrew/Funkin/commit/8a1d74b82cceab97e777dc49e7a2117b8d27e59b)) - by @ComedyLost in [#7129](https://github.com/FunkinCrew/Funkin/pull/7129)
- [HTML5] Rimlight alt masks now render properly. ([0613e9d](https://github.com/FunkinCrew/Funkin/commit/0613e9d295179e66d30db3d2f6805870eac847d6)) - by @VirtuGuy in [#6900](https://github.com/FunkinCrew/Funkin/pull/6900)
- The Week 2 Erect stage lightning strike fade now pauses and cancels appropriately. ([cd05267](https://github.com/FunkinCrew/funkin.assets/commit/cd05267023859d04cc8920c787b8280682e5f0f5)) - by @ComedyLost in [funkin.assets#390](https://github.com/FunkinCrew/funkin.assets/pull/390)
- A-Bot (Dark)'s frame no longer renders as completely dark in Week 2 Erect. ([a142530](https://github.com/FunkinCrew/funkin.assets/commit/a142530cae6198ca17b560ff73e36d50f1582768)) - by @ComedyLost in [funkin.assets#368](https://github.com/FunkinCrew/funkin.assets/pull/368)
- Dying on the same frame as a lightning strike in Week 2 Erect no longer throws a script error. ([ef89bde](https://github.com/FunkinCrew/funkin.assets/commit/ef89bde19c397f15a53b0fda2f64ba93ff96f56f)) - by @KoloInDaCrib in [funkin.assets#363](https://github.com/FunkinCrew/funkin.assets/pull/363)
- Pico (Dark) and Nene (Dark) no longer throw script errors in debug editors. ([b16ce44](https://github.com/FunkinCrew/funkin.assets/commit/b16ce44beb43d4511c61418c824929fb4dfabb63)) - by @ComedyLost in [funkin.assets#367](https://github.com/FunkinCrew/funkin.assets/pull/367)
- Girlfriend's hair no longer falls when restarting the song in a Week 3 stage. ([ade80ab](https://github.com/FunkinCrew/funkin.assets/commit/ade80ab72915ddd47724c380bb41d6df4c1b79bd)) - by @AnimatingLegend in [funkin.assets#370](https://github.com/FunkinCrew/funkin.assets/pull/370)
- The camera transition to Results no longer reveals the edges of stage art in the Week 6 Erect stage. ([ecf4c54](https://github.com/FunkinCrew/funkin.assets/commit/ecf4c5458a2e1fadba7db31c3272cea485d22b2f)) - by @ComedyLost in [funkin.assets#383](https://github.com/FunkinCrew/funkin.assets/pull/383)
- Fine-tuned offsets for pixel characters. ([8b3c268](https://github.com/FunkinCrew/funkin.assets/commit/8b3c2680a6a966e81b62598e783c60f46355c759)) - by @CEliuxJV in [funkin.assets#376](https://github.com/FunkinCrew/funkin.assets/pull/376)
- Tankman's game over lines now properly play during game overs in Ugh (Pico Mix) and Guns (Pico Mix). ([b900208](https://github.com/FunkinCrew/funkin.assets/commit/b900208143f980adee25d70db247e0b176dd659c)) - by @hucks5 in [funkin.assets#373](https://github.com/FunkinCrew/funkin.assets/pull/373)
- Restarting during the mid-song animation in Stress (Pico Mix) now properly resets the characters' animations. ([2ca92de](https://github.com/FunkinCrew/funkin.assets/commit/2ca92de46eced3f53d305579704fcb7e8c051f3a)) - by @requazar in [funkin.assets#364](https://github.com/FunkinCrew/funkin.assets/pull/364)
- The rain shader now properly fades out with the transition to the Results Screen. ([a0caa41](https://github.com/FunkinCrew/Funkin/commit/a0caa41edcb26298e4f8c243a5eed0b4fe93fcf7)) - by @VirtuGuy in [#6776](https://github.com/FunkinCrew/Funkin/pull/6776)
- Exiting a Chart Editor playtest while using the pixel notestyle no longer crashes the game. ([6c1f380](https://github.com/FunkinCrew/Funkin/commit/6c1f3800dbc9b13fb4b409abce53c1dafc9bbe8f)) - by @Starexify and @KoloInDaCrib in [#7108](https://github.com/FunkinCrew/Funkin/pull/7108)
- Chart Editor Edit buttons are now appropriately disabled when nothing is selected. ([6b1fc03](https://github.com/FunkinCrew/Funkin/commit/6b1fc0372bca202d80f4ccf316580b13a5a80879)) - by @Lasercar in [#4386](https://github.com/FunkinCrew/Funkin/pull/4386)
- Undoing a Chart Editor event now plays the undo sound. ([f7fd7a5](https://github.com/FunkinCrew/Funkin/commit/f7fd7a57c36f0461f56c2ab627a17d752cb82320)) - by @VirtuGuy in [#6963](https://github.com/FunkinCrew/Funkin/pull/6963)
- The playback speed audio setting no longer rounds incorrectly upon reopening the Chart Editor. ([3b15873](https://github.com/FunkinCrew/Funkin/commit/3b15873fc7d0c20840c313f1d2cfed91014c664f)) - by @AnimatingLegend in [#7023](https://github.com/FunkinCrew/Funkin/pull/7023)
- The Chart Editor easing preview graph now properly displays tweens that exceed start/end values. ([7626700](https://github.com/FunkinCrew/Funkin/commit/7626700495743862caddbf50a7dafef51529a2a6)) - by @echolotl in [#7152](https://github.com/FunkinCrew/Funkin/pull/7152)
- The Chart Editor playbar head is no longer draggable during a playtest. ([ccb874e](https://github.com/FunkinCrew/Funkin/commit/ccb874e97a121859c26a8a71b394743d27f6ed37)) - by @ComedyLost in [#6987](https://github.com/FunkinCrew/Funkin/pull/6987)
- The Results Screen no longer shows up after a Chart Editor playtest with Bot Play enabled. ([786f19c](https://github.com/FunkinCrew/Funkin/commit/786f19c57d999dba9309cae28d912b080968670d)) - by @ComedyLost in [#7022](https://github.com/FunkinCrew/Funkin/pull/7022)
- The Osu!Mania Chart Editor importer no longer accepts non-Osu!Mania beatmaps. ([456b2ff](https://github.com/FunkinCrew/Funkin/commit/456b2ff6c4a127733120cef3d03d6102bdd7522f)) - by @FuroYT in [#6624](https://github.com/FunkinCrew/Funkin/pull/6624)
- Characters in the Stage Editor no longer fly away when clicking and dragging them. ([0389af2](https://github.com/FunkinCrew/Funkin/commit/0389af2202aa4dc6a21ce9b7eea95944bfaa6946)) - by @KoloInDaCrib in [#7002](https://github.com/FunkinCrew/Funkin/pull/7002)
- Characters with alternating idle animations now properly play danceLeft when pressing Space in the Animation Editor. ([05032e3](https://github.com/FunkinCrew/Funkin/commit/05032e3126eda78a2bbf70e8c975bcb04eed201b)) - by @ComedyLost in [#7056](https://github.com/FunkinCrew/Funkin/pull/7056)
- [LINUX] Paths are now properly sanitized as they are on other platforms. ([219143c](https://github.com/FunkinCrew/Funkin/commit/219143c02dcf65e68aec80701a82023ca0d70db6)) - by @NotHyper-474 in [#6395](https://github.com/FunkinCrew/Funkin/pull/6395)
- OpenFL and some Lime classes are now accessible to modders. ([56a56db](https://github.com/FunkinCrew/Funkin/commit/56a56dbfaa3f62a3f684df49c682f69a496e45f4)) - by @FuroYT in [#7115](https://github.com/FunkinCrew/Funkin/pull/7115)
- Sandboxed API classes can now be accessed by mods. ([03930a2](https://github.com/FunkinCrew/Funkin/commit/03930a29c3d8aa6a310147a7131c6b7cddefd475)) - by @MightyTheArmiddilo in [#6952](https://github.com/FunkinCrew/Funkin/pull/6952)
- Blacklisted some more classes for security.
- And even more fixes!
## New Contributors for 0.8.4
* @roma-perec-bp made their first contribution in [#6769](https://github.com/FunkinCrew/Funkin/pull/6769)
* @Redar13 made their first contribution in [#6830](https://github.com/FunkinCrew/Funkin/pull/6830)
* @SuperEric1 made their first contribution in [#6893](https://github.com/FunkinCrew/Funkin/pull/6893)
* @AnimatingLegend made their first contribution in [#7023](https://github.com/FunkinCrew/Funkin/pull/7023)
* @Marcosayfi made their first contribution in [#7071](https://github.com/FunkinCrew/Funkin/pull/7071)
* @Rudyrue made their first contribution in [#7104](https://github.com/FunkinCrew/Funkin/pull/7104)
* @KolzeYT made their first contribution in [#7147](https://github.com/FunkinCrew/Funkin/pull/7147)
* @echolotl made their first contribution in [#7152](https://github.com/FunkinCrew/Funkin/pull/7152)
* @mario64thane made their first contribution in [funkin.assets#63](https://github.com/FunkinCrew/funkin.assets/pull/63)
* @LeGooeyy made their first contribution in [funkin.assets#278](https://github.com/FunkinCrew/funkin.assets/pull/278)
* @requazar made their first contribution in [funkin.assets#364](https://github.com/FunkinCrew/funkin.assets/pull/364)
## [0.8.3] - 2026-02-23
### Fixed
- [HTML5] Hitting a can in 2hot no longer creates a script error. (Thanks NotHyper-474!)
- The game no longer consistently lag spikes during gameplay. ([823120c](https://github.com/FunkinCrew/Funkin/commit/823120cdef7bfbb2d3ec37c7085878fcbeebcb30)) - by @ACrazyTown in [#6970](https://github.com/FunkinCrew/Funkin/pull/6970)
## [0.8.2] - 2026-02-23
### Added
- Added 14 new blend modes, allowing the engine to render better visual effects.
- Added a PlayState parameter that mirrors notes during a song.
- Added preview graphs for Chart Editor event easing types. ([eea1265](https://github.com/FunkinCrew/Funkin/commit/eea12657b1d8131014a3fdc270c3f351fae6e851)) - by @PurSnake in [#6374](https://github.com/FunkinCrew/Funkin/pull/6374)
- Added the ability to mirror notes on the X and Y axes in the Chart Editor. ([fd0c2df](https://github.com/FunkinCrew/Funkin/commit/fd0c2df35ee8cda3f1566a297c4faec984d809bb)) - by @Lasercar in [#4372](https://github.com/FunkinCrew/Funkin/pull/4372)
- Added a deselect button and shortcut to the Stage Editor. ([a9f1d41](https://github.com/FunkinCrew/Funkin/commit/a9f1d41771f0c97fdd70d4d6c54087ac0e64ff38)) - by @Lasercar in [#5281](https://github.com/FunkinCrew/Funkin/pull/5281)
### Changed
- Made some improvements to Polymod:
- Added string interpolation support. (Thanks NotHyper-474!)
- Scripted classes can now extend nothing. (Thanks NotHyper-474!)
- Scripted classes can now extend other scripted classes. (Thanks KoloInDaCrib!)
- Tweaked some error messages to be more verbose.
- Added `scriptHas` and `staticScriptHas` functions to check if a script has a specific variable/function.
- The `is` operator is now more accurate to regular Haxe. (Thanks Starexify!)
- Static functions can now use static extensions (`using`s). (Thanks NotHyper-474!)
- `interface`s can now be properly parsed. (Thanks Starexify!)
- Optional fields and extensions can now be used in `typedef`s. (Thanks Starexify!)
- Added stricter checking for default/optional arguments in functions. (Thanks Starexify!)
- May be a breaking change for some scripts, so please update your scripts to account for this!
- Enums now have multiple arguments. (Thanks Starexify!)
- Basic types (e.g `String`, `Int`, `Bool`, etc.) can now be used with the `is` operator without having to import the type first.
- Tweaked charts for the following songs:
- Bopeebo (Pico Mix) [Normal/Hard] - Adjusted note timings and added a “hey” animation event in Sections 18, 26, and 27.
- Fresh Erect [Nightmare] - Added 2 notes where Boyfriend’s vocals echo.
- DadBattle Erect [Nightmare] - Added a missing jack note in Section 38, added holds to two notes in Section 63.
- DadBattle (Pico Mix) [all difficulties] - Adjusted timings for various notes in Sections 37-40 and 60.
- Spookeez Erect [Erect/Nightmare] - Adjusted many hold note lengths to better match vocals.
- Spookeez (Pico Mix) - Added one missing note to Section 14.
- South Erect [Erect/Nightmare] - Adjusted many hold note lengths to better match vocals.
- Pico [Easy] - Adjusted timings for one note each in Sections 36 and 38.
- Pico [Normal/Hard] - Adjusted timings for Boyfriend’s right notes to be a bit earlier in Sections 31-42.
- Pico [all difficulties] - Added a Focus Camera event on Girlfriend during the duet.
- Satin Panties Erect [Erect/Nightmare] - Split a hold note into two for Mom in Sections 14 and 18.
- High Erect [Erect/Nightmare] - Adjusted timing for one note each in Sections 25 and 41.
- M.I.L.F [Easy] - Adjusted timings for two notes in Section 73.
- M.I.L.F [Hard] - Changed one down note into an up note in Section 15 for consistency.
- Cocoa Erect [Nightmare] - Fixed one note not being a Mom notekind in Section 24, added holds to 2 notes in Section 67.
- Cocoa (Pico Mix) [all difficulties] - Adjusted timings for two notes in Section 15.
- Eggnog Erect [Erect/Nightmare] - Adjusted how a grace note is charted in Section 52, added 2 missing notes for Mom in Section 72, adjusted Camera Bop event in Section 63.
- Senpai (Pico Mix) [all difficulties] - Adjusted timing for one note in Section 10.
- Roses [Normal] - Adjusted timings for four notes in Sections 30, 32, 41, and 43.
- Thorns Erect [Erect] - Adjusted timings for two notes in Section 36, removed some double notes to differentiate the chart from Nightmare.
- Ugh Erect [Erect/Nightmare] - Adjusted some Zoom Camera events around Section 24.
- Guns (Pico Mix) [all difficulties] - Fixed many timing issues throughout the whole song.
- SPAGHETTI [Normal/Hard] - Added one note to match Boyfriend’s rapping.
- Darnell (BF Mix) [all difficulties] - Removed extra notes from Sections 49 and 50, adjusted various note timings throughout the song.
- Lit Up [Normal] - Added one missing note each in Sections 40 and 60.
- Lit Up (BF Mix) [Normal/Hard] - Adjusted timings for various grace notes in Sections 1, 52, 55, and 56.
- 2hot [Easy/Normal] - Recharted many sections to be more predictable.
- [macOS] Disabled high DPI to significantly improve performance on some displays.
- Improved the Lag Adjustment menu to better handle very large offsets.
- Chart Editor exporting now omits default values and orders values more consistently.
- Chart Editor playtests now processes all events before the starting position.
- Optimized the Week 2 Spooky Mansion stage background by using a texture atlas. ([2bdd5a7](https://github.com/FunkinCrew/funkin.assets/commit/2bdd5a713f0b5c7e945c457e2a4a92bdb367cc02)) - by @MaybeMaru and @Trayfellow in [funkin.assets#348](https://github.com/FunkinCrew/funkin.assets/pull/348)
- Added more default imports for mods. ([1620cf3](https://github.com/FunkinCrew/Funkin/commit/1620cf388973eab5d83e151eec28b2c8abc84eb1)) - by @Starexify in [#6706](https://github.com/FunkinCrew/Funkin/pull/6706)
- The Set Camera Bop event now supports decimal values for rate and offset at 0.25 precision. ([ffaba34](https://github.com/FunkinCrew/Funkin/commit/ffaba343258c4a0e5ee7e1bd7fa0e8138ae60bc1)) - by @KoloInDaCrib in [#6741](https://github.com/FunkinCrew/Funkin/pull/6741)
### Fixed
- Fixed some issues with Polymod:
- The super constructor for scripted classes can now accept more than 4 arguments. (Thanks NotHyper-474!)
- Functions can now accept more than 8 arguments. (Thanks NotHyper-474!)
- Script variables are no longer dropped early when passing them to a callback (ex. `FlxTimer`). (Thanks NotHyper-474!)
- Fix a memory leak that could happen if a script tried to reference an anonymous object with a lot of `StringMap`s. (Thanks NotHyper-474!)
- Properties (`get_`/`set_` functions) are now much more accurate to regular Haxe. (Thanks NotHyper-474!)
- Re-exported some assets to fix some issues:
- Re-exported all variations of Pico as texture atlases to optimize memory usage.
- Freeplay DJ Pico’s table sparks no longer persist when his gun is lifted.
- Pico (Blazin’)’s game over retry animation now properly displays its blend modes.
- Pico (Christmas) no longer shows several stray marks around his sprites.
- Nene (Christmas) no longer becomes slightly offset when her knife is raised.
- The running tankmen in Stress (Pico Mix) no longer tank the game’s performance.
- Daddy Dearest now properly holds his up pose.
- Monster (Christmas)’s hat no longer moves while he holds a pose.
- Darnell’s can in 2hot now shows a sparkling effect.
- [DESKTOP] Modded atlas characters with both .png and .astc spritesheets no longer crash the game.
- [DESKTOP] The game display no longer sometimes becomes offset from the window.
- [MOBILE] Selecting a song using touch controls when a keyboard is connected no longer disables the keyboard strumline layout.
- [ANDROID] Improved Freeplay scrolling behavior on high framerate displays.
- [WINDOWS] Chart Editor save dialog windows no longer freeze the game.
- The Chart Editor Results Screen playtest option now consistently shows the Results Screen after each playtest.
- Scrolling really quickly in Freeplay no longer crashes the game. ([76699b2](https://github.com/FunkinCrew/Funkin/commit/76699b235cd5b359bc34e6950cd05bbbb13918f8)) - by @ComedyLost in [#6962](https://github.com/FunkinCrew/Funkin/pull/6962)
- Fixed a memory leak in the Freeplay menu. ([910ba65](https://github.com/FunkinCrew/Funkin/commit/910ba650b0c1011802b151b85f4a9d8177ae95c7)) - by @KoloInDaCrib in [#6615](https://github.com/FunkinCrew/Funkin/pull/6615)
- Modded difficulty dots and graphics now render correctly in Freeplay. ([90b856d](https://github.com/FunkinCrew/Funkin/commit/90b856d88635ac4e5517e934298e3820b2e5f45c)) - by @ComedyLost in [#6205](https://github.com/FunkinCrew/Funkin/pull/6205)
- Freeplay capsules with long song names no longer display too far to the left during the new rank animation. ([17a914c](https://github.com/FunkinCrew/Funkin/commit/17a914c933592cb3ba79881ca6a8d900b8513cbc)) - by @VirtuGuy in [#6690](https://github.com/FunkinCrew/Funkin/pull/6690)
- Freeplay capsule BPM values ending in 1 now display with proper spacing. ([e5b4351](https://github.com/FunkinCrew/Funkin/commit/e5b43510dd810a74a7d06f7f02c52892d11d6f8b)) - by @VirtuGuy in [#6696](https://github.com/FunkinCrew/Funkin/pull/6696)
- The Freeplay pixel icon now properly plays its confirm animation when mashing the capsule. ([a56bc44](https://github.com/FunkinCrew/Funkin/commit/a56bc4462d1c49e8ec71462b9bd7ff338b743c93)) - by @VirtuGuy in [#6723](https://github.com/FunkinCrew/Funkin/pull/6723)
- [HTML5] Scrolling with the mouse now works properly in Story Mode and Freeplay. ([506d80b](https://github.com/FunkinCrew/Funkin/commit/506d80b287b969121dc3601714c2459cc71f7e55)) - by @VirtuGuy in [#6621](https://github.com/FunkinCrew/Funkin/pull/6621)
- Optimized rendering in the Character Select menu. ([2ecebf7](https://github.com/FunkinCrew/Funkin/commit/2ecebf79205a66b64148d64bbb3162c9fc073d85)) - by @MaybeMaru in [#6789](https://github.com/FunkinCrew/Funkin/pull/6789)
- [MOBILE] Tapping on a lock in Character Select now plays its reject animation. ([05148f0](https://github.com/FunkinCrew/Funkin/commit/05148f0e5dad4d60089e6074e616b583ba29a5e6)) - by @VirtuGuy in [#6779](https://github.com/FunkinCrew/Funkin/pull/6779)
- Hold note covers now follow when the strumline position is modified. ([77c6651](https://github.com/FunkinCrew/Funkin/commit/77c6651e245ea276b1bdf33e5d6732073dcb6037)) - by @MightyTheArmiddilo in [#6746](https://github.com/FunkinCrew/Funkin/pull/6746)
- The pause and game over screens no longer sometimes play the wrong character's themes. ([878644a](https://github.com/FunkinCrew/Funkin/commit/878644aee7ba425e482707b94b9f887ec23f6306)) - by @KoloInDaCrib in [#6812](https://github.com/FunkinCrew/Funkin/pull/6812)
- The game over camera focus point is now consistent, regardless of which animation was previously playing. ([18cceb4](https://github.com/FunkinCrew/Funkin/commit/18cceb4946a51fda0009d77baae1115437694415)) - by @KoloInDaCrib in [#6705](https://github.com/FunkinCrew/Funkin/pull/6705)
- Pico (Pixel) and other pixel characters now use RetroCameraFade as Boyfriend (Pixel) does. ([d1382aa](https://github.com/FunkinCrew/Funkin/commit/d1382aa985f97e3b40b0b629cb3d04301ebfb55e)) - by @afreetoplaynoob in [#6526](https://github.com/FunkinCrew/Funkin/pull/6526)
- [MOBILE] The back button can no longer exit during the Boyfriend fakeout death animation. ([9d06018](https://github.com/FunkinCrew/Funkin/commit/9d0601813e912de9e25a851ad9204a654316625a)) - by @ActualMandM in [#6917](https://github.com/FunkinCrew/Funkin/pull/6917)
- The song name text is now properly hidden at the beginning of the Results Screen animation. ([a5b15b9](https://github.com/FunkinCrew/Funkin/commit/a5b15b9424f16d8eadc7a92f1c355da647990c3a)) - by @NotHyper-474 and @Trayfellow in [#6931](https://github.com/FunkinCrew/Funkin/pull/6931)
- The sticker transition no longer covers the volume soundtray. ([616546d](https://github.com/FunkinCrew/Funkin/commit/616546d298a06c4135a32ffad41483be208552f1)) - by @VirtuGuy in [#6727](https://github.com/FunkinCrew/Funkin/pull/6727)
- Lightning now appears more regularly during South Erect and South (Pico Mix). ([9ca2092](https://github.com/FunkinCrew/funkin.assets/commit/9ca20929bc3dde6b07d74100c45fb45e48769c35)) - by @JackXson-Real in [funkin.assets#345](https://github.com/FunkinCrew/funkin.assets/pull/345)
- [HTML5] The city lights in the Week 3 stages now show up. ([603684f](https://github.com/FunkinCrew/funkin.assets/commit/603684ffb327f03d8216aaeaba143ca5f9cd77f0)) - by @VirtuGuy in [funkin.assets#342](https://github.com/FunkinCrew/funkin.assets/pull/342)
- The Week 3 Pico doppelganger cutscene background music no longer cuts off at the end. ([8ef58aa](https://github.com/FunkinCrew/funkin.assets/commit/8ef58aabdba8287d4c88808e2f0ecc0ac385b383)) - by @Trayfellow in [funkin.assets#349](https://github.com/FunkinCrew/funkin.assets/pull/349)
- The Story Mode cutscene before Stress now properly plays when viewed more than once. ([6ec45ec](https://github.com/FunkinCrew/funkin.assets/commit/6ec45ec82ca77188b1b2b9c58ada172f5c357103)) - by @NotHyper-474 in [funkin.assets#341](https://github.com/FunkinCrew/funkin.assets/pull/341)
- Darnell's can sound effects in 2hot no longer play twice with high offsets or when lagging. ([6315e25](https://github.com/FunkinCrew/funkin.assets/commit/6315e25eaaa8be4ca85e9b607f547595c699997a)) - by @JackXson-Real in [funkin.assets#354](https://github.com/FunkinCrew/funkin.assets/pull/354)
- [MOBILE] The cutscene after 2hot now properly accounts for different resolutions. ([dd3371a](https://github.com/FunkinCrew/Funkin/commit/dd3371a549f4e10f68f1a458f40ec1a342f07876)) - by @ActualMandM in [#6937](https://github.com/FunkinCrew/Funkin/pull/6937)
- Made the AttractState video skipping pie smoother. ([5a161b1](https://github.com/FunkinCrew/Funkin/commit/5a161b1d7342d7931950edf37554ce3a338736f9)) - by @PurSnake in [#6728](https://github.com/FunkinCrew/Funkin/pull/6728)
- The screenshot preview no longer breaks when changing states. ([dc78db8](https://github.com/FunkinCrew/Funkin/commit/dc78db8808a7ea205fe75eba006e4ec1c57a8190)) - by @Lasercar in [#6792](https://github.com/FunkinCrew/Funkin/pull/6792)
- Holding Ctrl and clicking on a hold note trail no longer crashes the Chart Editor (again). ([86ac336](https://github.com/FunkinCrew/Funkin/commit/86ac336d62a65fb420cdd6b1be739c3262d21159)) - by @Lasercar in [#6912](https://github.com/FunkinCrew/Funkin/pull/6912)
- Chart Editor tooltips no longer appear when hovering over a deleted note or event. ([091c18b](https://github.com/FunkinCrew/Funkin/commit/091c18bccd95b588ba0d4577a94d83acf5942417)) - by @KoloInDaCrib in [#6929](https://github.com/FunkinCrew/Funkin/pull/6929)
- Chart Editor vocal waveforms now render more accurately after BPM changes in the song. ([4e8f48d](https://github.com/FunkinCrew/Funkin/commit/4e8f48d5f0f1be4438c4ef9571137eaa35935f67)) - by @gamerbross in [#6833](https://github.com/FunkinCrew/Funkin/pull/6833)
- The Chart Editor vocal waveforms now display in the proper position regardless of the game's aspect ratio. ([1fb9040](https://github.com/FunkinCrew/Funkin/commit/1fb9040470432528a0441d7938d217e424ce27fd)) - by @Starexify in [#6193](https://github.com/FunkinCrew/Funkin/pull/6193)
- The second section number and divider now renders consistently in the Chart Editor. ([ac539bd](https://github.com/FunkinCrew/Funkin/commit/ac539bdf26ee7b5ecdcc52665c7c95287ef491c0)) - by @NotHyper-474 in [#6765](https://github.com/FunkinCrew/Funkin/pull/6765)
- The Chart Editor now saves the Show Results Screen setting. ([c893a73](https://github.com/FunkinCrew/Funkin/commit/c893a7320d72abd3743bc5c1ddeaecf073035eb1)) - by @MightyTheArmiddilo in [#6854](https://github.com/FunkinCrew/Funkin/pull/6854)
- Closing the game while in the Stage Editor no longer crashes the game. ([99cd4e2](https://github.com/FunkinCrew/Funkin/commit/99cd4e2cbd7fba87249b02b072a1e60f07c2c907)) - by @VirtuGuy in [#6775](https://github.com/FunkinCrew/Funkin/pull/6775)
- The onion skin now properly renders as transparent after changing characters in the Animation Editor. ([5c444f1](https://github.com/FunkinCrew/Funkin/commit/5c444f1109e5af04735a4383e577c69682b3713f)) - by @VirtuGuy in [#6545](https://github.com/FunkinCrew/Funkin/pull/6545)
- Blacklisted a class for security. ([3a113c2](https://github.com/FunkinCrew/Funkin/commit/3a113c270f92a6b14dfcda221124742437e1670a)) - by @charlesisfeline in [#6573](https://github.com/FunkinCrew/Funkin/pull/6573)
- Even more tiny fixes!
## [0.8.1] - 2026-01-04
### Added
@@ -20,7 +278,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [0.8.0] - 2025-12-31
## [0.8.0] - 2026-01-03
The LE SSERAFIM collab update!
@@ -112,7 +370,6 @@ The LE SSERAFIM collab update!
- [iOS] The navigation bar is no longer unlocked after watching an ad.
- [iOS] The “larger text” accessibility setting no longer causes the game to not fill the whole screen.
- [iOS] The game now displays error popups.
- [ANDROID] Keyboard detection and strumline positioning now work properly.
- [ANDROID] Taking a screenshot no longer pauses the game for a moment.
- The Title Screen no longer switches to Attract Mode while the Girlfriend’s Ringtone easter egg is playing.
- Holding Escape in the Main Menu no longer quickly closes the game.
@@ -151,6 +408,7 @@ The LE SSERAFIM collab update!
- Hold note covers no longer get permanently stuck playing after a lag spike. ([66882d9](https://github.com/FunkinCrew/Funkin/commit/66882d9677268396320ee003478a3e2627655755)) - by @KoloInDaCrib in [#6066](https://github.com/FunkinCrew/Funkin/pull/6066)
- Scrolling through Freeplay songs for the first time no longer stutters. ([cc486ad](https://github.com/FunkinCrew/Funkin/commit/cc486ad94b5e9806d18fb65165663fea0ce0d7b4)) - by @mikolka9144 in [#4851](https://github.com/FunkinCrew/Funkin/pull/4851)
- Re-implemented an error that appears when a video file does not exist. ([2ad5933](https://github.com/FunkinCrew/Funkin/commit/2ad593341f8bea8384646f4803dc8795a9efe32a)) - by @TechnikTil in [#6253](https://github.com/FunkinCrew/Funkin/pull/6253)
- [ANDROID] Keyboard detection and strumline positioning now work properly. ([5763ae5](https://github.com/FunkinCrew/Funkin/commit/5763ae5b728359c5639bbc578f15b65a16fa57b1)) - by @NotHyper-474 in [#6328](https://github.com/FunkinCrew/Funkin/pull/6328)
- The game now properly parses .json files beginning with a bracket. ([c7367ae](https://github.com/FunkinCrew/Funkin/commit/c7367ae33d7e11f57b821f7d5fbff39a3edc1604)) - by @NotHyper-474 in [#6164](https://github.com/FunkinCrew/Funkin/pull/6164)
- The Newgrounds logo no longer covers the intro text. ([28883fb](https://github.com/FunkinCrew/Funkin/commit/28883fb9ed025abf9f9aee2621f365cd6f4d8b6c)) - by @hucks5 in [#6196](https://github.com/FunkinCrew/Funkin/pull/6196)
- Exiting from the Save Data Options menu no longer exits the Options Menu as well. ([26b253d](https://github.com/FunkinCrew/Funkin/commit/26b253d8cac97f0dcd09a5ef233f7058cd26008e)) - by @VirtuGuy in [#6036](https://github.com/FunkinCrew/Funkin/pull/6036)
+1 -1
View File
@@ -197,7 +197,7 @@ You can view the `funkin-assets` license here: (https://github.com/FunkinCrew/fu
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright 2020-2024 The Funkin' Crew Inc.
Copyright 2020-2026 The Funkin' Crew Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
+1 -1
Submodule art updated: 2e68e371f8...429ab728b1
+1 -1
Submodule assets updated: 39d4b3fc95...d1d027d474
+26 -3
View File
@@ -41,6 +41,22 @@
"asset": "assets/shared/images/characters/sserafim/chaewon/spritemap1.png",
"blocksize": "4x4"
},
{
"asset": "assets/shared/images/characters/pico-dark/spritemap1.png",
"blocksize": "4x4"
},
{
"asset": "assets/shared/images/characters/pico/basic-animations/spritemap1.png",
"blocksize": "6x6"
},
{
"asset": "assets/shared/images/characters/pico/explosion-death/spritemap1.png",
"blocksize": "8x8"
},
{
"asset": "assets/shared/images/characters/pico/playable-animations/spritemap1.png",
"blocksize": "6x6"
},
{
"asset": "assets/shared/images/holdCoverBlue.png",
"blocksize": "4x4"
@@ -109,6 +125,10 @@
"asset": "assets/week1/image/erect/lights.png",
"blocksize": "6x6"
},
{
"asset": "assets/shared/images/characters/pico/death/spritemap1.png",
"blocksize": "6x6"
},
{
"asset": "assets/week1/images/erect/crowd.png",
"blocksize": "8x8"
@@ -127,6 +147,7 @@
}
],
"excludes": [
"assets/fonts/vcr-bmp.png",
"assets/preload/images/cursor/",
"assets/preload/images/fonts/",
"assets/preload/images/freeplay/",
@@ -134,8 +155,8 @@
"assets/preload/images/soundtray/",
"assets/preload/images/stageBuild/",
"assets/preload/images/storymenu/titles/",
"assets/preload/images/titleEnter.png",
"assets/preload/images/titleEnter_mobile.png",
"assets/preload/images/title-screen-text/spritemap1.png",
"assets/preload/images/title-screen-text-mobile/spritemap1.png",
"assets/preload/images/ui/popup/pixel/*",
"assets/shared/images/characters/abotPixel/*",
"assets/shared/images/characters/bfPixel.png",
@@ -177,6 +198,8 @@
"assets/week1/images/erect/orangeLight.png",
"assets/week2/images/erect/stairsDark.png",
"assets/week2/images/erect/stairsLight.png",
"assets/week6/"
"assets/week6/",
"assets/week7/images/bricksGround.png",
"assets/week7/images/erect/bricksGround.png"
]
}
+318 -163
View File
@@ -1,4 +1,6 @@
{
"version": 1,
"exclude": {},
"defaultSeverity": "INFO",
"extendsConfigPath": "",
"numberOfCheckerThreads": 5,
@@ -6,113 +8,124 @@
"defineCombinations": [],
"checks": [
{
"props": {},
"comment": "If enabled, prevents using anonymous types inline without creating a typedef for them.",
"props": { "severity": "INFO" },
"type": "Anonymous"
},
{
"comment": "If enabled, mandates spacing around array access syntax.",
"props": {
"spaceBefore": false,
"spaceInside": false
"spaceInside": false,
"severity": "INFO"
},
"type": "ArrayAccess"
},
{
"props": {},
"comment": "If enabled, mandates array literals be defined with [] instead of 'new'.",
"props": { "severity": "WARNING" },
"type": "ArrayLiteral"
},
{
"comment": "If enabled, mandates specific syntax for the use of array literals.",
"props": {
"allowSingleArgParens": true,
"allowReturn": true,
"allowFunction": true,
"allowCurlyBody": true
"allowCurlyBody": true,
"severity": "INFO"
},
"type": "ArrowFunction"
},
{
"props": {
"avoidIdentifiers": []
},
"comment": "Specify a list of variable and function names which are not allowed and should be renamed. Doesn't support regex.",
"props": { "avoidIdentifiers": [], "severity": "WARNING" },
"type": "AvoidIdentifier"
},
{
"props": {},
"comment": "If enabled, prevents imports like 'import flixel.*' from being used.",
"props": { "severity": "INFO" },
"type": "AvoidStarImport"
},
{
"props": {},
"comment": "If enabled, prevents conditional compilation from crossing blocks. This prevents the case where conditional compilation could potentially create invalid syntax.",
"props": { "severity": "INFO" },
"type": "BlockBreakingConditional"
},
{
"comment": "Specifies a specific naming format for the parameter of a catch block.",
"props": {
"format": "^(e|t|ex|[a-z][a-z][a-zA-Z]+)$"
"format": "^(e|t|ex|[a-z][a-z][a-zA-Z]+)$",
"severity": "INFO"
},
"type": "CatchParameterName"
},
{
"comment": "If enabled, flags when large blocks of similar code should be extracted to a function.",
"props": {
"thresholdSimilar": 120,
"severityIdentical": "WARNING",
"thresholdIdentical": 60
"thresholdIdentical": 60,
"severityIdentical": "IGNORE"
},
"type": "CodeSimilarity"
},
{
"props": {},
"comment": "If enabled, flags Haxe code that is commented out. Unused code should be removed and accessed via version control later if needed.",
"props": { "severity": "WARNING" },
"type": "CommentedOutCode"
},
{
"comment": "If enabled, flags when conditional compilation blocks are not properly aligned. NOTE:Disabled because it's kinda broken.",
"props": {
"severity": "IGNORE",
"policy": "aligned",
"allowSingleline": true
"allowSingleline": true,
"severity": "IGNORE"
},
"type": "ConditionalCompilation"
},
{
"comment": "Specifies a specific naming format for constant (static) identifiers.",
"props": {
"ignoreExtern": true,
"format": "^?:_[a-zA-Z0-9]+(?:_[a-zA-Z0-9]+)*$",
"tokens": ["INLINE", "NOTINLINE"]
"tokens": ["INLINE", "NOTINLINE"],
"severity": "INFO"
},
"type": "ConstantName"
},
{
"comment": "Calculates the complexity of methods using the McCabe metric, and throws warnings at certain thresholds. Indicates that a function should be refactored or split up.",
"props": {
"thresholds": [
{
"complexity": 20,
"severity": "WARNING"
},
{
"complexity": 25,
"severity": "ERROR"
}
{ "complexity": 20, "severity": "WARNING" },
{ "complexity": 25, "severity": "ERROR" }
],
"severity": "IGNORE"
},
"type": "CyclomaticComplexity"
},
{
"props": {},
"comment": "If enabled, the default case of a switch statement must be last.",
"props": { "severity": "INFO" },
"type": "DefaultComesLast"
},
{
"props": {
"lineStyle": "onestar",
"startStyle": "ignore"
},
"comment": "Specifies the format for doc-style comments ().",
"props": { "lineStyle": "onestar", "startStyle": "ignore" },
"type": "DocCommentStyle"
},
{
"comment": "If enabled, prevents the use of the Dynamic type.",
"props": { "severity": "IGNORE" },
"type": "Dynamic"
},
{
"props": {},
"comment": "If enabled, ensures ~/.../ is used instead of 'new EReg()'",
"props": { "severity": "WARNING" },
"type": "ERegLiteral"
},
{
"comment": "If enabled, enforces specific syntax on empty blocks (require only one line, etc.)",
"props": {
"tokens": [
"CLASS_DEF",
@@ -129,11 +142,13 @@
"TRY",
"CATCH"
],
"option": "empty"
"option": "empty",
"severity": "IGNORE"
},
"type": "EmptyBlock"
},
{
"comment": "If enabled, flags when consecutive empty lines are used.",
"props": {
"requireEmptyLineAfterPackage": true,
"requireEmptyLineAfterInterface": true,
@@ -141,17 +156,18 @@
"allowEmptyLineAfterSingleLineComment": true,
"max": 1,
"requireEmptyLineAfterClass": true,
"allowEmptyLineAfterMultiLineComment": true
"allowEmptyLineAfterMultiLineComment": true,
"severity": "IGNORE"
},
"type": "EmptyLines"
},
{
"props": {
"enforceEmptyPackage": true
},
"comment": "If enabled, mandates the use of 'package;' on root level modules.",
"props": { "enforceEmptyPackage": true, "severity": "WARNING" },
"type": "EmptyPackage"
},
{
"comment": "If enabled, provides advanced checking for when consecutive empty lines are used.",
"props": {
"none": [],
"upto": [],
@@ -160,11 +176,13 @@
"max": 1,
"ignore": [],
"atleast": [],
"skipSingleLineTypes": true
"skipSingleLineTypes": true,
"severity": "IGNORE"
},
"type": "ExtendedEmptyLines"
},
{
"comment": "If enabled, mandates documentation comments for public fields.",
"props": {
"requireParams": true,
"fieldType": "BOTH",
@@ -172,33 +190,33 @@
"ignoreOverride": true,
"tokens": ["ABSTRACT_DEF", "CLASS_DEF", "ENUM_DEF", "INTERFACE_DEF"],
"modifier": "PUBLIC",
"excludeNames": ["new", "toString"]
"excludeNames": ["new", "toString"],
"severity": "INFO"
},
"type": "FieldDocComment"
},
{
"props": {
"max": 1000,
"ignoreEmptyLines": true,
"severity": "IGNORE"
},
"comment": "If enabled, warns if files exceed a certain number of lines.",
"props": { "max": 1000, "ignoreEmptyLines": true, "severity": "IGNORE" },
"type": "FileLength"
},
{
"comment": "If enabled, requires modules match the casing of their file name.",
"type": "FileNameCase",
"props": {}
"props": { "severity": "WARNING" }
},
{
"comment": "If enabled, requires inline/static variables to be declared final.",
"type": "Final",
"props": {}
"props": { "severity": "IGNORE" }
},
{
"props": {
"option": "upperCase"
},
"comment": "If enabled, requires hexadecimal literals to be in upper case. 0xFFFFFF is valid and 0xffffff is invalid.",
"props": { "option": "upperCase", "severity": "WARNING" },
"type": "HexadecimalLiteral"
},
{
"comment": "If enabled, warns if a local variable or parameter shadows an existing field.",
"props": {
"ignoreSetter": true,
"ignoreFormat": "^(main|run)$",
@@ -207,108 +225,167 @@
"type": "HiddenField"
},
{
"props": {
"character": " ",
"severity": "IGNORE"
},
"comment": "If enabled, mandates indentation.",
"props": { "character": "", "severity": "IGNORE" },
"type": "Indentation"
},
{
"comment": "If enabled, mandates characters used for indentation.",
"props": {
"character": "space",
"severity": "INFO",
"severity": "IGNORE",
"ignorePattern": "^$"
},
"type": "IndentationCharacter"
},
{
"props": {
"ignoreReturnAssignments": true,
"severity": "WARNING"
},
"comment": "If enabled, warns about assignments performed within another expression, like 'if (a=b){}'",
"props": { "ignoreReturnAssignments": true, "severity": "WARNING" },
"type": "InnerAssignment"
},
{
"comment": "If enabled, enforces that interfaces should not contain properties.",
"props": {
"allowProperties": false,
"allowMarkerInterfaces": true
"allowMarkerInterfaces": true,
"severity": "WARNING"
},
"type": "Interface"
},
{
"comment": "If enabled, enforces a newline before the left curly brace of a block.",
"props": {
"option": "nl",
"ignoreEmptySingleline": true,
"tokens": [
"CLASS_DEF",
"ENUM_DEF",
"ABSTRACT_DEF",
"TYPEDEF_DEF",
"INTERFACE_DEF",
"FUNCTION",
"FOR",
"IF",
"WHILE",
"SWITCH",
"TRY",
"CATCH",
"REIFICATION",
"ARRAY_COMPREHENSION"
],
"severity": "INFO"
},
"type": "LeftCurly"
},
{
"comment": "If enabled, enforces the left curly brace occurs on the end of the line, without a newline.",
"props": {
"option": "eol",
"ignoreEmptySingleline": true,
"tokens": ["OBJECT_DECL"],
"severity": "IGNORE"
},
"type": "LeftCurly"
},
{
"comment": "If enabled, warns when lines of code exceed a certain length.",
"props": {
"max": 160,
"ignorePattern": "^(\\s*['\"][^'\"]*['\"].*)$"
"ignorePattern": "^(\\s*['\"][^'\"]*['\"].*)$",
"severity": "INFO"
},
"type": "LineLength"
},
{
"comment": "If enabled, mandates a specific naming convention for listener methods.",
"props": {
"listeners": ["addEventListener", "addListener", "on", "once"],
"format": "^_?[a-z][a-zA-Z0-9]*$"
"format": "^_?[a-z][a-zA-Z0-9]*$",
"severity": "IGNORE"
},
"type": "ListenerName"
},
{
"comment": "Specifies a specific naming format for local variables.",
"props": {
"ignoreExtern": true,
"format": "^[a-z][a-zA-Z0-9]*$",
"tokens": []
"tokens": [],
"severity": "INFO"
},
"type": "LocalVariableName"
},
{
"props": {
"ignoreNumbers": [-1, 0, 1, 2],
"severity": "IGNORE"
},
"comment": "If enabled, warns when unlabelled numeric values get used. Use named constants instead to improve code clarity.",
"props": { "ignoreNumbers": [-1, 0, 1, 2], "severity": "INFO" },
"type": "MagicNumber"
},
{
"props": {
"format": "^[A-Z][a-zA-Z0-9]*$",
"tokens": ["ABSTRACT"]
},
"type": "MemberName"
},
{
"comment": "Specifies a specific naming format for public abstract member fields.",
"props": {
"format": "^[_a-zA-Z][a-z][a-zA-Z0-9]*$",
"tokens": ["ABSTRACT"]
"tokens": ["PUBLIC", "ABSTRACT"]
},
"type": "MemberName"
},
{
"comment": "Specifies a specific naming format for private abstract member fields.",
"props": {
"ignoreExtern": true,
"format": "^[_a-z][a-zA-Z0-9]*$",
"tokens": ["PUBLIC", "PRIVATE", "CLASS", "TYPEDEF"]
"format": "^[_a-zA-Z][a-z][a-zA-Z0-9]*$",
"tokens": ["PRIVATE", "ABSTRACT"]
},
"type": "MemberName"
},
{
"comment": "Specifies a specific naming format for public class member fields.",
"props": {
"format": "^[_a-zA-Z][a-z][a-zA-Z0-9]*$",
"tokens": ["PUBLIC", "CLASS"]
},
"type": "MemberName"
},
{
"comment": "Specifies a specific naming format for private class member fields.",
"props": {
"format": "^[_a-zA-Z][a-z][a-zA-Z0-9]*$",
"tokens": ["PRIVATE", "CLASS"]
},
"type": "MemberName"
},
{
"comment": "Specifies a specific naming format for enum member fields.",
"props": {
"format": "^[_a-zA-Z][a-z][a-zA-Z0-9]*$",
"tokens": ["ENUM"]
},
"type": "MemberName"
},
{
"comment": "Specifies a specific naming format for typedef member fields.",
"props": {
"format": "^[_a-zA-Z][a-z][a-zA-Z0-9]*$",
"tokens": ["TYPEDEF"]
},
"type": "MemberName"
},
{
"comment": "If enabled, enforces that modules should not exceed a certain number of methods.",
"props": {
"maxPrivate": 100,
"maxPublic": 100,
"maxTotal": 100
"maxTotal": 100,
"severity": "IGNORE"
},
"type": "MethodCount"
},
{
"props": {
"max": 50,
"ignoreEmptyLines": true,
"severity": "IGNORE"
},
"comment": "If enabled, enforces that methods should not exceed a certain number of lines of code, excluding empty lines.",
"props": { "max": 50, "ignoreEmptyLines": true, "severity": "IGNORE" },
"type": "MethodLength"
},
{
"comment": "Specifies a specific naming format for method names.",
"props": {
"ignoreExtern": true,
"format": "^[a-z][a-zA-Z0-9]*$",
@@ -318,6 +395,7 @@
"type": "MethodName"
},
{
"comment": "Specifies a specific order for modifiers on fields.",
"props": {
"modifiers": [
"PUBLIC_PRIVATE",
@@ -333,57 +411,64 @@
"type": "ModifierOrder"
},
{
"comment": "If enabled, complains when a specific string literal is used in the same file multiple times. Use a named constant instead.",
"props": {
"minLength": 2,
"ignore": "^\\s+$",
"allowDuplicates": 5
"allowDuplicates": 5,
"severity": "IGNORE"
},
"type": "MultipleStringLiterals"
},
{
"props": {},
"comment": "If enabled, complains when a multiple variables are declared in a single expression. Use individual lines.",
"props": { "severity": "WARNING" },
"type": "MultipleVariableDeclarations"
},
{
"comment": "If enabled, mandates the use of braces on specific block types, unless they fit on a single line.",
"props": {
"allowSingleLineStatement": true,
"tokens": ["ELSE_IF", "WHILE", "DO_WHILE"]
"tokens": [
"FUNCTION",
"FOR",
"IF",
"ELSE_IF",
"WHILE",
"DO_WHILE",
"CATCH"
],
"severity": "INFO"
},
"type": "NeedBraces"
},
{
"props": {
"max": 3,
"severity": "IGNORE"
},
"comment": "If enabled, complains when control flow statements are nested too deep (indicating high complexity).",
"props": { "max": 3, "severity": "IGNORE" },
"type": "NestedControlFlow"
},
{
"props": {
"max": 1,
"severity": "IGNORE"
},
"comment": "If enabled, complains when 'for' loops are nested too deep (indicating high complexity).",
"props": { "max": 1, "severity": "IGNORE" },
"type": "NestedForDepth"
},
{
"props": {
"max": 4
},
"comment": "If enabled, complains when 'if' statements are nested too deep (indicating high complexity).",
"props": { "max": 4, "severity": "IGNORE" },
"type": "NestedIfDepth"
},
{
"props": {
"max": 1
},
"comment": "If enabled, complains when try/catch statements are nested too deep (indicating high complexity).",
"props": { "max": 1, "severity": "INFO" },
"type": "NestedTryDepth"
},
{
"props": {
"option": "questionMark"
},
"comment": "If enabled, enforces ?value rather than value = null.",
"props": { "option": "questionMark", "severity": "INFO" },
"type": "NullableParameter"
},
{
"comment": "If enabled, enforces that operators should be surrounded by whitespace.",
"props": {
"oldFunctionTypePolicy": "none",
"unaryOpPolicy": "none",
@@ -401,6 +486,7 @@
"type": "OperatorWhitespace"
},
{
"comment": "If enabled, enforces that most operators should be after a newline rather than before.",
"props": {
"tokens": [
"+",
@@ -443,54 +529,52 @@
"type": "OperatorWrap"
},
{
"props": {
"tokens": ["="],
"option": "eol"
},
"comment": "If enabled, enforces that assignment operators should be before a newline rather than after.",
"props": { "tokens": ["="], "option": "eol" },
"type": "OperatorWrap"
},
{
"comment": "Specifies a specific naming format for method parameter names.",
"props": {
"ignoreExtern": true,
"format": "^(_|[a-z][a-zA-Z0-9]*$)",
"tokens": []
"tokens": [],
"severity": "INFO"
},
"type": "ParameterName"
},
{
"props": {
"max": 7,
"ignoreOverriddenMethods": false
},
"comment": "If enabled, complains when there are too many parameters on a method.",
"props": { "max": 7, "ignoreOverriddenMethods": false },
"type": "ParameterNumber"
},
{
"props": {
"severity": "WARNING"
},
"comment": "If enabled, complains when you make a property accessor method public.",
"props": { "severity": "WARNING" },
"type": "PublicAccessor"
},
{
"props": {
"prohibitMeta": false
},
"comment": "If enabled, complains when an @:access metadata is redundant.",
"props": { "prohibitMeta": false, "severity": "INFO" },
"type": "RedundantAccessMeta"
},
{
"props": {
"prohibitMeta": false
},
"comment": "If enabled, complains when an @:allow metadata is redundant.",
"props": { "prohibitMeta": false, "severity": "INFO" },
"type": "RedundantAllowMeta"
},
{
"comment": "If enabled, complains when an access modifier is redundant.",
"props": {
"enforcePrivate": false,
"enforcePublic": true,
"enforcePublicPrivate": false
"enforcePublicPrivate": false,
"severity": "WARNING"
},
"type": "RedundantModifier"
},
{
"comment": "If enabled, enforces that a return type is specified for all methods.",
"props": {
"enforceReturnTypeForAnonymous": false,
"allowEmptyReturn": true,
@@ -499,44 +583,63 @@
"type": "Return"
},
{
"props": {
"ignoreFormat": "^$",
"max": 2,
"severity": "IGNORE"
},
"comment": "If enabled, mandates a maximum number of 'return' statements in a method.",
"props": { "ignoreFormat": "^$", "max": 2, "severity": "IGNORE" },
"type": "ReturnCount"
},
{
"comment": "If enabled, enforces a specific placement for curly braces. TODO:Choose between Allman/K&R and enforce project-wide.",
"props": {
"option": "aloneorsingle",
"tokens": [
"CLASS_DEF",
"ENUM_DEF",
"ABSTRACT_DEF",
"TYPEDEF_DEF",
"INTERFACE_DEF",
"OBJECT_DECL",
"FUNCTION",
"FOR",
"IF",
"WHILE",
"SWITCH",
"TRY",
"CATCH",
"REIFICATION",
"ARRAY_COMPREHENSION"
],
"severity": "IGNORE"
},
"type": "RightCurly"
},
{
"comment": "Enforces specific whitespace around certain separators, such as commas and semicolons.",
"props": {
"commaPolicy": "after",
"semicolonPolicy": "after",
"allowTrailingComma": false,
"dotPolicy": "none"
"dotPolicy": "none",
"severity": "INFO"
},
"type": "SeparatorWhitespace"
},
{
"props": {
"tokens": [","],
"option": "eol"
},
"comment": "Enforces specific line wrapping for certain separators, such as commas and semicolons.",
"props": { "tokens": [","], "option": "eol" },
"type": "SeparatorWrap"
},
{
"props": {},
"comment": "If enabled, complains about overly complicated boolean expressions.",
"props": { "severity": "WARNING" },
"type": "SimplifyBooleanExpression"
},
{
"props": {},
"comment": "If enabled, complains about overly complicated boolean return statements.",
"props": { "severity": "WARNING" },
"type": "SimplifyBooleanReturn"
},
{
"comment": "If enabled, enforce spacing in and around conditional statements and certain operators.",
"props": {
"spaceIfCondition": "should",
"spaceAroundBinop": true,
@@ -550,94 +653,147 @@
"type": "Spacing"
},
{
"comment": "Enforce a specific string literal style (either ' or \").",
"props": {
"policy": "onlySingle",
"allowException": true,
"severity": "IGNORE"
"severity": "INFO"
},
"type": "StringLiteral"
},
{
"comment": "Puts a warning on unresolved TODO/FIXME comments.",
"props": {
"format": "^\\s*(TODO|FIXME|HACK|XXX|BUG)"
"format": "^\\s*(TODO|FIXME|HACK|XXX|BUG)",
"severity": "INFO"
},
"type": "TODOComment"
},
{
"props": {
"ignorePattern": "^$"
},
"comment": "Checks if there are any tabs in the middle of a line.",
"props": { "severity": "INFO" },
"type": "TabForAligning"
},
{
"props": {
"severity": "IGNORE"
},
"comment": "If enabled, complains whenever trace() gets used in code.",
"props": { "severity": "IGNORE" },
"type": "Trace"
},
{
"props": {},
"comment": "If enabled, complains about trailing whitespaces at the end of lines.",
"props": { "severity": "INFO" },
"type": "TrailingWhitespace"
},
{
"type": "Type",
"props": {
"ignoreEnumAbstractValues": true
}
"comment": "If enabled, requires type be specified on member fields.",
"props": { "ignoreEnumAbstractValues": true, "severity": "INFO" },
"type": "Type"
},
{
"comment": "If enabled, mandates documentation comments on classes and interfaces.",
"props": {
"tokens": ["CLASS_DEF", "ENUM_DEF", "INTERFACE_DEF", "TYPEDEF_DEF"]
"tokens": ["CLASS_DEF", "ENUM_DEF", "INTERFACE_DEF", "TYPEDEF_DEF"],
"severity": "INFO"
},
"type": "TypeDocComment"
},
{
"comment": "Specifies a specific naming format for abstract types.",
"props": {
"ignoreExtern": true,
"format": "^[A-Z]+[a-zA-Z0-9]*$",
"tokens": []
"tokens": ["ABSTRACT"],
"severity": "WARNING"
},
"type": "TypeName"
},
{
"comment": "Specifies a specific naming format for class types.",
"props": {
"ignoreExtern": true,
"format": "^[A-Z]+[a-zA-Z0-9]*$",
"tokens": ["CLASS"],
"severity": "WARNING"
},
"type": "TypeName"
},
{
"comment": "Specifies a specific naming format for enum types.",
"props": {
"ignoreExtern": true,
"format": "^[A-Z]+[a-zA-Z0-9]*$",
"tokens": ["ENUM"],
"severity": "WARNING"
},
"type": "TypeName"
},
{
"comment": "Specifies a specific naming format for interface types.",
"props": {
"ignoreExtern": true,
"format": "^[A-Z]+[a-zA-Z0-9]*$",
"tokens": ["INTERFACE"],
"severity": "WARNING"
},
"type": "TypeName"
},
{
"comment": "Specifies a specific naming format for typedefs.",
"props": {
"ignoreExtern": true,
"format": "^[A-Z]+[a-zA-Z0-9]*$",
"tokens": ["TYPEDEF"],
"severity": "WARNING"
},
"type": "TypeName"
},
{
"props": {},
"comment": "If enabled, complains when a class with only static fields and values has a redundant constructor.",
"props": { "severity": "WARNING" },
"type": "UnnecessaryConstructor"
},
{
"props": {
"moduleTypeMap": {},
"ignoreModules": []
},
"comment": "If enabled, complains when a module contains unused imports. NOTE:Sometimes complains about required imports.",
"props": { "moduleTypeMap": {}, "ignoreModules": [], "severity": "INFO" },
"type": "UnusedImport"
},
{
"props": {
"severity": "WARNING"
},
"comment": "If enabled, complains when a local variable is unused.",
"props": { "severity": "WARNING" },
"type": "UnusedLocalVar"
},
{
"type": "VarTypeHint",
"comment": "If enabled, requires type hints for certain variables.",
"props": {
"typeHintPolicy": "enforce_all",
"ignoreEnumAbstractValues": true,
"severity": "IGNORE"
}
},
"type": "VarTypeHint"
},
{
"comment": "If enabled, complains when a class member variable is initialized at the class level rather than the constructor.",
"type": "VariableInitialisation",
"props": {
"allowFinal": false
"allowFinal": true,
"severity": "IGNORE"
}
},
{
"comment": "If enabled, mandates whitespace after certain tokens.",
"props": {
"tokens": [",", ";"],
"allowTrailingComma": false
"allowTrailingComma": false,
"severity": "INFO"
},
"type": "WhitespaceAfter"
},
{
"comment": "If enabled, mandates whitespace around certain tokens.",
"props": {
"tokens": [
"=",
@@ -672,11 +828,10 @@
"&=",
"^=",
"=>"
]
],
"severity": "INFO"
},
"type": "WhitespaceAround"
}
],
"exclude": {},
"version": 1
]
}
+1 -1
View File
@@ -60,7 +60,7 @@ This section provides guidelines to follow when [opening an issue](https://githu
## Requirements
Make sure you're playing:
- the latest version of the game (currently v0.8.1)
- the latest version of the game (currently v0.8.4)
- without any mods
- on [Newgrounds](https://www.newgrounds.com/portal/view/770371) or downloaded from [itch.io](https://ninja-muffin24.itch.io/funkin)
+2 -3
View File
@@ -8,9 +8,7 @@ Most of this functionality is only available on debug builds of the game!
- `F3`: ***SCREENSHOT***: Takes a screenshot of the game and saves it to the local `screenshots` directory. Works outside of debug builds too!
- `F4`: ***EJECT***: Forcibly switch state to the Main Menu (with no extra transition). Useful if you're stuck in a level and you need to get out!
- `F5`: ***HOT RELOAD***: Forcibly reload the game's scripts and data files, then restart the current state. If any files in the `assets` folder have been modified, the game should process the changes for you! NOTE: Known bug, this does not reset song charts or song scripts, but it should reset everything else (such as stage layout data and character animation data).
- `CTRL-ALT-SHIFT-L`: ***FORCE CRASH***: Immediately crash the game with a detailed crash log and a stack trace. (Only works in the Main Menu on debug builds).
- `CTRL-SHIFT-L`: ***FORCE CRASH***: Immediately crash the game with a detailed crash log and a stack trace.
- `CTRL-ALT-SHIFT-L`: ***FORCE CRASH***: Immediately crash the game with a detailed crash log and a stack trace.
## **Play State**
- `H`: ***HIDE UI***: Makes the user interface invisible. Works in Pause Menu, great for screenshots.
@@ -27,6 +25,7 @@ Most of this functionality is only available on debug builds of the game!
- `P`: ***SWITCH TO PICO/BF***: Switch to Pico or BF (reopens Freeplay as the other character).
- `T`: ***TEST RANK ANIMATION***: Play the Gold Perfect rank animation on the currently selected song.
- `SHIFT-ACCEPT`: ***BOTPLAY MODE***: Start a song with Botplay mode enabled.
- `CTRL-ACCEPT`: ***MIRRORED MODE***: Start a song with mirrored notes enabled.
- `CTRL-Switch Song`: Play the first unlocked alternate instrumental as the song preview.
## **Title State**
+1 -1
View File
@@ -6,7 +6,7 @@
"name": "EliteMasterEric"
}
],
"api_version": "0.7.0",
"api_version": "0.8.0",
"mod_version": "1.0.0",
"license": "Apache-2.0"
}
+1 -1
View File
@@ -6,7 +6,7 @@
"name": "EliteMasterEric"
}
],
"api_version": "0.7.0",
"api_version": "0.8.0",
"mod_version": "1.0.0",
"license": "Apache-2.0"
}
+13 -20
View File
@@ -4,7 +4,7 @@
"name": "FlxPartialSound",
"type": "git",
"dir": null,
"ref": "26ed20b9c181a576f4cbe18ccdea38912c01476e",
"ref": "2f984e244f1544ca98c0e03b9b21ae570f07ac55",
"url": "https://github.com/FunkinCrew/FlxPartialSound.git"
},
{
@@ -18,7 +18,7 @@
"name": "extension-admob",
"type": "git",
"dir": null,
"ref": "4c69bb43f1fb89fd6003dc98d2f3a9d75c5364b6",
"ref": "5c908b3f7c74115a8b52eddf1e05525f4873f26e",
"url": "https://github.com/FunkinCrew/extension-admob"
},
{
@@ -52,21 +52,21 @@
"name": "flixel",
"type": "git",
"dir": null,
"ref": "c8e79d2a42f9c11c639519ef2a6fd7ef2379a8aa",
"ref": "f7b94eebf7dbb452a929d0c67ab31a9cbd71d3a0",
"url": "https://github.com/FunkinCrew/flixel"
},
{
"name": "flixel-addons",
"type": "git",
"dir": null,
"ref": "6fa30b3f5209146c852c25f3d1003e08898083e2",
"ref": "187f93b34f93c6a405d634a42913c745e443463a",
"url": "https://github.com/FunkinCrew/flixel-addons"
},
{
"name": "flixel-animate",
"type": "git",
"dir": null,
"ref": "c61476f4b3a3d225631ab3065e4e925a4b63c076",
"ref": "c5e3393c70b71a191f20fa902114cea92042e486",
"url": "https://github.com/MaybeMaru/flixel-animate"
},
{
@@ -97,7 +97,7 @@
"name": "haxeui-core",
"type": "git",
"dir": null,
"ref": "088b153b35985f8e4419ef710057ebd5b3749513",
"ref": "09f2512564b45e92229e21433e6dd482391f7b7d",
"url": "https://github.com/FunkinCrew/haxeui-core"
},
{
@@ -107,18 +107,11 @@
"ref": "100f2c96beab619cfe72c567a058c41c71e3e998",
"url": "https://github.com/haxeui/haxeui-flixel"
},
{
"name": "hscript",
"type": "git",
"dir": null,
"ref": "dcc6f822e0866ca4fda300ed23e99559260f7bf5",
"url": "https://github.com/FunkinCrew/hscript"
},
{
"name": "hxcpp",
"type": "git",
"dir": null,
"ref": "5932340d095a7eea8635fe4d1355f1c0efd0b3c2",
"ref": "450d112e50acff57b1bc9d584dcf1374c9e33995",
"url": "https://github.com/FunkinCrew/hxcpp"
},
{
@@ -153,13 +146,13 @@
{
"name": "hxvlc",
"type": "haxelib",
"version": "2.2.5"
"version": "2.2.6"
},
{
"name": "json2object",
"type": "git",
"dir": null,
"ref": "a7e4cef3d444bea8d8244d6e59ab82f5a593f597",
"ref": "59e0467c953d1f26e3cbf2a070f140e2d2e8457d",
"url": "https://github.com/FunkinCrew/json2object"
},
{
@@ -176,7 +169,7 @@
"name": "lime",
"type": "git",
"dir": null,
"ref": "318253ea3a28a3299a167748912c40444f403777",
"ref": "58dd49b018729f86600f719a98728ffb024724e3",
"url": "https://github.com/FunkinCrew/lime"
},
{
@@ -190,15 +183,15 @@
"name": "openfl",
"type": "git",
"dir": null,
"ref": "a69a6e778816c6a57eba7a91bfb0b60295508e88",
"ref": "88534506595a32c3f02b21b3987e789a24074ae7",
"url": "https://github.com/FunkinCrew/openfl"
},
{
"name": "polymod",
"type": "git",
"dir": null,
"ref": "9824bf4f00863c152d5afe3ac4bbcac173d80684",
"url": "https://github.com/larsiusprime/polymod"
"ref": "fb123758b90127f5647727727f273d27e93cabdb",
"url": "https://github.com/FunkinCrew/polymod"
},
{
"name": "thx.core",
+282 -6
View File
@@ -1,30 +1,306 @@
{
"disableFormatting": false,
"emptyLines": {
"finalNewline": true,
"maxAnywhereInFile": 1,
"beforePackage": 0,
"afterPackage": 1,
"importAndUsing": {
"betweenImports": 0,
"betweenImportsLevel": "firstLevelPackage",
"beforeUsing": 1,
"beforeType": 1
},
"betweenTypes": 1,
"lineCommentsBetweenTypes": "keep",
"lineCommentsBetweenFunctions": "keep",
"betweenSingleLineTypes": 0,
"beforeRightCurly": "remove",
"afterLeftCurly": "remove",
"afterReturn": "remove",
"beforeBlocks": "remove",
"afterBlocks": "remove",
"enumAbstractEmptyLines": {
"beginType": 0,
"endType": 0,
"betweenVars": 0,
"afterVars": 1,
"betweenFunctions": 1,
"existingBetweenFields": "keep"
},
"classEmptyLines": {
"beginType": 0,
"endType": 0,
"betweenStaticVars": 0,
"afterStaticVars": 1,
"afterPrivateVars": 1,
"betweenVars": 0,
"afterVars": 1,
"afterStaticFunctions": 1,
"betweenStaticFunctions": 1,
"afterPrivateFunctions": 1,
"betweenFunctions": 1,
"existingBetweenFields": "keep"
},
"macroClassEmptyLines": {
"beginType": 0,
"endType": 0,
"betweenStaticVars": 0,
"afterStaticVars": 1,
"afterPrivateVars": 1,
"betweenVars": 0,
"afterVars": 1,
"afterStaticFunctions": 1,
"betweenStaticFunctions": 1,
"afterPrivateFunctions": 1,
"betweenFunctions": 1,
"existingBetweenFields": "keep"
},
"externClassEmptyLines": {
"beginType": 0,
"endType": 0,
"betweenVars": 0,
"afterVars": 0,
"betweenFunctions": 0,
"existingBetweenFields": "keep"
},
"abstractEmptyLines": {
"beginType": 0,
"endType": 0,
"betweenStaticVars": 0,
"afterStaticVars": 1,
"afterPrivateVars": 1,
"betweenVars": 0,
"afterVars": 1,
"afterStaticFunctions": 1,
"betweenStaticFunctions": 1,
"afterPrivateFunctions": 1,
"betweenFunctions": 1,
"existingBetweenFields": "keep"
},
"interfaceEmptyLines": {
"beginType": 0,
"endType": 0,
"betweenVars": 0,
"afterVars": 0,
"betweenFunctions": 0,
"existingBetweenFields": "keep"
},
"enumEmptyLines": {
"beginType": 0,
"endType": 0,
"betweenFields": 0,
"existingBetweenFields": "keep"
},
"typedefEmptyLines": {
"beginType": 0,
"endType": 0,
"betweenFields": 0,
"existingBetweenFields": "keep"
},
"conditionalsEmptyLines": {
"afterIf": 0,
"beforeElse": 0,
"afterElse": 0,
"beforeEnd": 0,
"beforeError": 0,
"afterError": 0
},
"beforeDocCommentEmptyLines": "one",
"afterFieldsWithDocComments": "one",
"afterFileHeaderComment": 1,
"betweenMultilineComments": 0
},
"indentation": {
"conditionalPolicy": "aligned",
"character": " ",
"tabWidth": 2,
"trailingWhitespace": false,
"indentObjectLiteral": true,
"indentComplexValueExpressions": false,
"indentCaseLabels": true
},
"lineEnds": {
"lineEndCharacter": "auto",
"metadataType": "none",
"metadataVar": "none",
"metadataFunction": "none",
"metadataOther": "none",
"caseColon": "after",
"sharp": "after",
"leftCurly": "both",
"rightCurly": "both",
"emptyCurly": "noBreak",
"blockCurly": {
"emptyCurly": "break",
"leftCurly": "both",
"rightCurly": "both"
},
"anonFunctionCurly": {
"emptyCurly": "break",
"leftCurly": "both",
"rightCurly": "both"
},
"anonTypeCurly": {
"emptyCurly": "break",
"leftCurly": "both",
"rightCurly": "both"
},
"objectLiteralCurly": {
"emptyCurly": "break",
"leftCurly": "after",
"rightCurly": "both"
},
"leftCurly": "both",
"rightCurly": "both"
"typedefCurly": {
"emptyCurly": "break",
"leftCurly": "both",
"rightCurly": "both"
}
},
"sameLine": {
"ifBody": "same",
"elseBody": "next",
"ifElse": "next",
"doWhile": "next",
"elseIf": "same",
"ifElseSemicolonNextLine": true,
"expressionIf": "same",
"expressionIfWithBlocks": false,
"forBody": "next",
"comprehensionFor": "same",
"whileBody": "next",
"doWhileBody": "next",
"doWhile": "same",
"tryBody": "next",
"tryCatch": "next"
"catchBody": "next",
"tryCatch": "next",
"caseBody": "next",
"expressionCase": "keep",
"expressionTry": "same",
"functionBody": "same",
"anonFunctionBody": "same",
"returnBody": "same",
"returnBodySingleLine": "same",
"untypedBody": "same"
},
"whitespace": {
"switchPolicy": "around"
}
"parenConfig": {},
"bracesConfig": {},
"bracketConfig": {},
"typeParamOpenPolicy": "none",
"typeParamClosePolicy": "none",
"typeExtensionPolicy": "after",
"commaPolicy": "onlyAfter",
"dotPolicy": "none",
"colonPolicy": "none",
"caseColonPolicy": "onlyAfter",
"objectFieldColonPolicy": "after",
"typeHintColonPolicy": "none",
"typeCheckColonPolicy": "around",
"ternaryPolicy": "around",
"semicolonPolicy": "onlyAfter",
"ifPolicy": "after",
"doPolicy": "after",
"whilePolicy": "after",
"forPolicy": "after",
"switchPolicy": "around",
"tryPolicy": "after",
"catchPolicy": "after",
"binopPolicy": "around",
"intervalPolicy": "none",
"arrowFunctionsPolicy": "around",
"functionTypeHaxe3Policy": "none",
"functionTypeHaxe4Policy": "around",
"compressSuccessiveParenthesis": true,
"formatStringInterpolation": true,
"addLineCommentSpace": true
},
"wrapping": {
"maxLineLength": 160,
"arrayWrap": {
"defaultWrap": "noWrap",
"defaultLocation": "afterLast",
"defaultAdditionalIndent": 0
},
"mapWrap": {
"defaultWrap": "noWrap",
"defaultLocation": "afterLast",
"defaultAdditionalIndent": 0
},
"typeParameter": {
"defaultWrap": "noWrap"
}
},
"excludes": [
"_Provide a list of regular expressions to exclude from formatting.",
".haxelib",
".git",
"node_modules"
]
}
+54 -54
View File
@@ -32,13 +32,13 @@ class Project extends HXProject
* REMEMBER TO CHANGE THIS WHEN THE GAME UPDATES!
* You only have to change it here, the rest of the game will query this value.
*/
static final VERSION:String = "0.8.1";
static final VERSION:String = "0.8.4";
/**
* The build's number and version code.
* Used when publishing the game to mobile app stores. Should increment with each patch.
*/
static final BUILD_NUMBER:Int = 70;
static final BUILD_NUMBER:Int = 85;
/**
* The game's name. Used as the default window title.
@@ -114,11 +114,7 @@ class Project extends HXProject
*/
static final ANDROID_TARGET_SDK_VERSION:Int = 35;
static final ANDROID_EXTENSIONS:Array<String> = [
"funkin.extensions.CallbackUtil",
"funkin.extensions.FNFCExtension",
"funkin.extensions.AudioSession"
];
static final ANDROID_EXTENSIONS:Array<String> = ["funkin.extensions.CallbackUtil", "funkin.extensions.FNFCExtension", "funkin.extensions.AudioSession"];
/**
* The team ID to use for the iOS app. Configured in XCode.
@@ -171,11 +167,7 @@ class Project extends HXProject
/**
* Asset path globs to exclude on platforms with `CENSOR_EXPLETIVES` disabled.
*/
static final EXCLUDE_ASSETS_UNCENSORED:Array<String> = [
"stressCutscene-censored.mp4",
"stressPicoCutscene-censored.mp4",
"darnellCutscene-censored.mp4"
];
static final EXCLUDE_ASSETS_UNCENSORED:Array<String> = ["stressCutscene-censored.mp4", "stressPicoCutscene-censored.mp4", "darnellCutscene-censored.mp4"];
//
// ASSET EMBEDDING
@@ -184,9 +176,7 @@ class Project extends HXProject
/**
* The songs whose audio files should be embedded inside the executable.
*/
static final EMBED_SONGS_AUDIO:Array<String> = [
"spaghetti"
];
static final EMBED_SONGS_AUDIO:Array<String> = ["spaghetti"];
//
// BUILD FLAGS
@@ -216,6 +206,13 @@ class Project extends HXProject
*/
static final EXCLUDE_ARMV7:FeatureFlag = "EXCLUDE_ARMV7";
/**
* `-DFORCE_BLEND_SHADER`
* If this flag is enabled, the game will force the use of shaders to render
* certain blend modes, even if the device supports the needed OpenGL extensions.
*/
static final FORCE_BLEND_SHADER:FeatureFlag = "FORCE_BLEND_SHADER";
/**
* `-DGITHUB_BUILD`
* If this flag is enabled, the game will use the configuration used by GitHub Actions
@@ -659,7 +656,7 @@ class Project extends HXProject
this.window.hardware = true;
this.window.vsync = false;
// force / allow high DPI
this.window.allowHighDPI = true;
this.window.allowHighDPI = !isMac();
if (isWeb())
{
@@ -855,14 +852,15 @@ class Project extends HXProject
// Should be true on mobile builds.
CENSOR_EXPLETIVES.apply(this, isMobile());
// Should be true on Android.
// Some Android devices support native blends, but it causes issues
// with other shaders, so we'll disable it for now.
FORCE_BLEND_SHADER.apply(this, isAndroid());
//
// FEATURE FLAGS
//
// Should be true on debug builds or if GITHUB_BUILD is enabled.
FEATURE_DEBUG_FUNCTIONS.apply(this, isDebug() || GITHUB_BUILD.isEnabled(this));
FEATURE_RESULTS_DEBUG.apply(this, isDebug() || GITHUB_BUILD.isEnabled(this));
FEATURE_FUNKVIS.apply(this, true);
FEATURE_LOG_TRACE.apply(this, true);
FEATURE_DEBUG_FILE_LOGGING.apply(this, FEATURE_DEBUG_FUNCTIONS.isEnabled(this));
@@ -884,7 +882,7 @@ class Project extends HXProject
// Should be true on desktop, non-tester builds.
// We don't want testers to accidentally leak songs to their Discord friends!
FEATURE_DISCORD_RPC.apply(this, isDesktop() && !FEATURE_DEBUG_FUNCTIONS.isEnabled(this));
FEATURE_DISCORD_RPC.apply(this, isDesktop() && !FEATURE_DEBUG_FUNCTIONS.isEnabled(this) && !isHashLink());
FEATURE_LOST_FOCUS_VOLUME.apply(this, isDesktop());
@@ -1123,6 +1121,13 @@ class Project extends HXProject
// Ensure all flixel-animate classes are available at runtime.
addHaxeMacro("include('animate')");
// Ensure all openfl classes are available at runtime.
addHaxeMacro("include('openfl')");
// Ensure all lime classes are available at runtime.
// Explicitly ignore tools and internal packages.
addHaxeMacro("include('lime', true, ['lime.tools.*', 'lime._internal.*'])");
// Ensure all Flixel classes are available at runtime.
// Explicitly ignore packages which require additional dependencies.
addHaxeMacro("include('flixel', true, [ 'flixel.addons.editors.spine.*', 'flixel.addons.nape.*', 'flixel.system.macros.*', 'flixel.addons.tile.FlxRayCastTilemap' ])");
@@ -1133,8 +1138,9 @@ class Project extends HXProject
*/
function configureCustomMacros()
{
// This macro allows addition of new functionality to existing Flixel. -->
// These macros allow additions of new functionality to existing Flixel. -->
addHaxeMacro("addMetadata('@:build(funkin.util.macro.FlxMacro.buildFlxBasic())', 'flixel.FlxBasic')");
addHaxeMacro("addMetadata('@:build(funkin.util.macro.FlxMacro.buildFlxSprite())', 'flixel.FlxSprite')");
}
function configureOutputDir()
@@ -1218,21 +1224,12 @@ class Project extends HXProject
intentFilter.addChild(category);
}
final intentFilterDatas:Map<String, Array<String>> = [
"android:mimeType" => ["application/zip"],
// When this is added, it makes the game show up only when it's a FNFC file.
final intentFilterDatas:Map<String,
Array<String>> = ["android:mimeType" => ["application/zip"], // When this is added, it makes the game show up only when it's a FNFC file.
// But it also for some reason make it not show up at all in ZArchiver no matter what the file is...
// "android:host" => ["*"],
"android:scheme" => ["file", "content"],
// I think having all these makes it so the extension check would work even when the files has dots like "epic-song-v2.0.fnfc"
"android:pathPattern" => [
".*\\.fnfc",
".*\\..*\\.fnfc",
".*\\..*\\..*\\.fnfc",
".*\\..*\\..*\\..*\\.fnfc",
".*\\..*\\..*\\..*\\..*\\.fnfc"
]
];
"android:scheme" => ["file", "content"], // I think having all these makes it so the extension check would work even when the files has dots like "epic-song-v2.0.fnfc"
"android:pathPattern" => [".*\\.fnfc", ".*\\..*\\.fnfc", ".*\\..*\\..*\\.fnfc", ".*\\..*\\..*\\..*\\.fnfc", ".*\\..*\\..*\\..*\\..*\\.fnfc"]];
for (key => values in intentFilterDatas)
{
@@ -1325,7 +1322,6 @@ class Project extends HXProject
addHaxelib('flixel'); // Game engine
addHaxelib('flixel-addons'); // Additional utilities for Flixel
addHaxelib('hscript'); // Scripting
if (FEATURE_HAXEUI.isEnabled(this))
{
@@ -1342,12 +1338,12 @@ class Project extends HXProject
addHaxelib('thx.core'); // General utility library, "the lodash of Haxe"
addHaxelib('thx.semver'); // Version string handling
if (isDebug())
if (isDebug() && isCPP())
{
addHaxelib('hxcpp-debug-server'); // VSCode debug support
}
if (isDesktop() || isMobile() && !isHashLink() && FEATURE_VIDEO_PLAYBACK.isEnabled(this))
if ((isDesktop() || isMobile()) && FEATURE_VIDEO_PLAYBACK.isEnabled(this))
{
// hxvlc doesn't function on HashLink or non-desktop platforms
// It's also unnecessary if video playback is disabled
@@ -1413,8 +1409,11 @@ class Project extends HXProject
function configureAssets()
{
// Delete the assets folder from the export folder before adding anything.
clearAssets();
if (!isDisplay())
{
// Delete the assets folder from the export folder before adding anything.
clearAssets();
}
var exclude = EXCLUDE_ASSETS.concat(isWeb() ? EXCLUDE_ASSETS_WEB : EXCLUDE_ASSETS_NATIVE);
var shouldPreload = PRELOAD_ALL.isEnabled(this);
@@ -1500,8 +1499,6 @@ class Project extends HXProject
addAssetLibrary("sserafim", shouldEmbed, shouldPreload);
addAssetPath("assets/sserafim", "assets/sserafim", "sserafim", ["*"], exclude, shouldEmbed, "assets");
// Art asset library (where README and CHANGELOG pull from)
var shouldEmbedArt = false;
var shouldPreloadArt = false;
@@ -1528,7 +1525,7 @@ class Project extends HXProject
var exportPath:Null<String> = app.path ?? "";
// mac target uses `macos` for the export folder instead of `mac`
var platform:String = (!isMac() ? Std.string(this.target) : 'macos');
var platform:String = isHashLink() ? 'hl' : (!isMac() ? Std.string(this.target) : 'macos');
var basePath:String = Path.join([exportPath, platform, "bin"]);
var assetsPath:String = "";
@@ -1548,6 +1545,10 @@ class Project extends HXProject
{
assetsPath = Path.join([basePath, "app", "src", "main", "assets", "assets"]);
}
else if (isIOS())
{
assetsPath = Path.join([exportPath, platform, '${this.app.file}', "assets", "assets"]);
}
else
{
return;
@@ -2092,7 +2093,7 @@ class Project extends HXProject
@SuppressWarnings('checkstyle:Dynamic')
function checkLibraries():Void
{
var diffrentLibraries:Map<String, Array<String>> = new Map<String, Array<String>>();
var differentLibraries:Map<String, Array<String>> = new Map<String, Array<String>>();
var hmmData:Dynamic = haxe.Json.parse(sys.io.File.getContent(#if ios '../../../../../' + #end 'hmm.json'));
@@ -2113,11 +2114,11 @@ class Project extends HXProject
switch (library.type)
{
case 'haxelib':
diffrentLibraries.set(libraryName, [libraryDev, libraryCurrentCommitHash, library.version, 'haxelib']);
differentLibraries.set(libraryName, [libraryDev, libraryCurrentCommitHash, library.version, 'haxelib']);
case 'git':
if (libraryCurrentCommitHash != library.ref)
{
diffrentLibraries.set(libraryName, [libraryDev, libraryCurrentCommitHash, library.ref, 'git']);
differentLibraries.set(libraryName, [libraryDev, libraryCurrentCommitHash, library.ref, 'git']);
}
}
}
@@ -2128,18 +2129,18 @@ class Project extends HXProject
case 'haxelib':
if (library.version != libraryCurrentVersion)
{
diffrentLibraries.set(libraryName, ['', libraryCurrentVersion, library.version, 'haxelib']);
differentLibraries.set(libraryName, ['', libraryCurrentVersion, library.version, 'haxelib']);
}
case 'git':
if (libraryCurrentCommitHash != library.ref)
{
diffrentLibraries.set(libraryName, ['', libraryCurrentCommitHash, library.ref, 'git']);
differentLibraries.set(libraryName, ['', libraryCurrentCommitHash, library.ref, 'git']);
}
}
}
}
if (Lambda.count(diffrentLibraries) > 0)
if (Lambda.count(differentLibraries) > 0)
{
warn("Some libraries differ from the versions defined in hmm.json.".bold().yellow());
warn("To ensure consistency, it's recommended to stop the build and run `hmm reinstall [library]`.".bold().yellow());
@@ -2147,9 +2148,9 @@ class Project extends HXProject
Sys.println('');
for (libraryName in diffrentLibraries.keys())
for (libraryName in differentLibraries.keys())
{
var infos:Null<Array<String>> = diffrentLibraries.get(libraryName);
var infos:Null<Array<String>> = differentLibraries.get(libraryName);
if (infos == null) continue;
@@ -2162,7 +2163,6 @@ class Project extends HXProject
{
Sys.println("- " + libraryName.replace(",", ".") + " (Development Build)".blue().bold());
Sys.println((" Path: " + haxe.io.Path.removeTrailingSlashes(devPath)).blue());
}
else
{
@@ -2181,7 +2181,7 @@ class Project extends HXProject
{
var path = getLibraryCurrentFile(libraryName);
if (sys.FileSystem.exists(path)) return sys.io.File.getContent(path);
if (sys.FileSystem.exists(path)) return sys.io.File.getContent(path).trim();
return '';
}
@@ -2190,7 +2190,7 @@ class Project extends HXProject
{
var path = getLibraryDevFile(libraryName);
if (sys.FileSystem.exists(path)) return sys.io.File.getContent(path);
if (sys.FileSystem.exists(path)) return sys.io.File.getContent(path).trim();
return '';
}
+49
View File
@@ -0,0 +1,49 @@
package scripts;
using DateTools;
class Postbuild
{
static function main()
{
/* trace('creating NG zip');
var binFolder:String = 'export/release/html5/bin/';
var date = Date.now();
var outputName:String = 'NG-' + date.format("%Y%m%d--%H%M") + '.zip';
var out = sys.io.File.write(outputName);
var zip = new haxe.zip.Writer(out);
zip.write(getEntries(binFolder));
trace('Finished creating ZIP');
*/
}
static function getEntries(dir:String, entries:List<haxe.zip.Entry> = null, inDir:Null<String> = null)
{
if (entries == null) entries = new List<haxe.zip.Entry>();
if (inDir == null) inDir = dir;
for (file in sys.FileSystem.readDirectory(dir))
{
var path = haxe.io.Path.join([dir, file]);
if (sys.FileSystem.isDirectory(path)) getEntries(path, entries, inDir);
else
{
var bytes:haxe.io.Bytes = haxe.io.Bytes.ofData(sys.io.File.getBytes(path).getData());
var entry:haxe.zip.Entry =
{
fileName: StringTools.replace(path, inDir, ""),
fileSize: bytes.length,
fileTime: Date.now(),
compressed: false,
dataSize: sys.FileSystem.stat(path).size,
data: bytes,
crc32: haxe.crypto.Crc32.make(bytes)
};
entries.push(entry);
}
}
return entries;
}
}
+180
View File
@@ -0,0 +1,180 @@
import haxe.Json;
import haxe.Log;
import haxe.macro.Compiler;
import sys.FileSystem;
import sys.io.File;
using StringTools;
#if !interp
package scripts;
// needs this thing to be run by interp, just for me lol!
#end
// general use of this!!
// if run in INTERP MODE:
// - scripts>haxe --main SongConverter --interp
// - song to convert: ../assets/preload/data/
// it will run through EVERY folder in there and convert the old songs to the new format!
// TODO make instructions for the C# script version!
class SongConverter
{
public static var VERSION:String = '0.1.0';
// TODO
// Update engine shit, to accomodate single file
static function main()
{
// trace(Compiler.get);
// trace(Compiler.getDefine('sysfsd'));
Sys.stdout().writeString('Please type directory you want to convert: ');
Sys.stdout().flush();
final input = Sys.stdin().readLine();
trace('Hello ${input}!');
/* Sys.stdout().writeString('What type of conversion do you need?\n\t0: Old charts to new chart\n\t1: new chart to .... new chart? lol\n>');
Sys.stdout().flush();
final deleteShitIDK = Std.parseInt(Sys.stdin().readLine());
trace(deleteShitIDK); */
var songCount:Int = 0;
for (fileThing in FileSystem.readDirectory('${input}/.'))
{
// trace(fileThing);
// trace(FileSystem.isDirectory(${input} + "/" + fileThing));
if (FileSystem.isDirectory(${input} + "/" + fileThing) && fileThing.toLowerCase() != 'smash')
{
trace('Formatting $fileThing');
formatSongs(fileThing, input);
songCount++;
}
}
trace('CONVERTED $songCount SONGS!!');
var timer:Int = 5;
while (timer > 0)
{
Sys.stdout().writeString('CLOSING IN $timer SECONDS!');
Sys.sleep(1);
Sys.print("\r");
timer -= 1;
}
}
public static function formatSongs(songName:String, root:String)
{
var existsArray:Array<Bool> = [];
var songMap:Map<String, Dynamic> = new Map();
var speedMap:Map<String, Dynamic> = new Map();
for (songFile in FileSystem.readDirectory('$root/$songName/'))
{
if (!songFile.endsWith('json') || !songFile.startsWith(songName)) continue; // ACCOMODATE FOR PICO SPEAKER EVENTUALLY!
var funnyFile:Dynamic = cast Json.parse(File.getContent('$root/$songName/$songFile'));
var songSplit:Array<String> = songFile.split('-');
var songShit:String = 'normal';
if (songSplit.length > 1)
{
if (songSplit[1] == 'new.json')
{
FileSystem.deleteFile('$root/$songName/$songFile');
trace('DELETEING $songFile');
continue;
}
songShit = songSplit[1].substr(0, songSplit[1].length - 5);
}
if (songShit != 'normal')
{
songMap[songShit] = funnyFile.song.notes;
speedMap[songShit] = funnyFile.song.speed;
}
else
{
//
if (funnyFile.song.notes is Array)
{
songMap[songShit] = funnyFile.song.notes[1];
speedMap[songShit] = funnyFile.song.speed[1];
}
else if (Type.typeof(funnyFile.song.notes) == TObject)
{
var dipshitMap:Map<String, Dynamic> = cast funnyFile.song.notes;
// songMap[songShit] = dipshitMap.get('normal');
}
else
{
songMap[songShit] = funnyFile.song.notes;
speedMap[songShit] = funnyFile.song.speed;
}
}
}
var fileNormal:Dynamic = cast Json.parse(File.getContent('$root/$songName/$songName.json'));
fileNormal.song.notes = songMap;
fileNormal.song.speed = speedMap;
fileNormal.song.hasDialogueFile = false;
fileNormal.song.stageDefault = getStage(songName);
fileNormal.version = 'FNF SongConverter $VERSION';
var daJson = Json.stringify(fileNormal, null, "\t");
// trace(daJson);
File.saveContent('$root/$songName/$songName.json', daJson);
}
static function noteCleaner(notes:Array<Dynamic>):Array<Dynamic>
{
var swagArray:Array<Dynamic> = [];
for (i in notes)
{
if (i.sectionNotes.length > 0) swagArray.push(i);
}
return swagArray;
}
/**
* Quicky lil function just for me formatting the old songs hehehe
*/
static function getStage(songName:String):String
{
switch (songName)
{
case 'spookeez' | 'monster' | 'south':
return "spooky";
case 'pico' | 'blammed' | 'philly':
return 'philly';
case "milf" | 'satin-panties' | 'high':
return 'limo';
case "cocoa" | 'eggnog':
return 'mall';
case 'winter-horrorland':
return 'mallEvil';
case 'senpai' | 'roses':
return 'school';
case 'thorns':
return 'schoolEvil';
case 'guns' | 'stress' | 'ugh':
return 'tank';
default:
return 'stage';
}
}
}
+99
View File
@@ -0,0 +1,99 @@
import csv
import re
import sys
import json
import subprocess
# This script imports a CSV file, and bulk updates the chart metadata files
#
# Requirements:
# python3 I believe
# and you need to have npm/npx, as we use that to run prettier to keep the same formatting
#
# Usage:
# In our Google Sheets, export as .csv file
#
# Then in here from within this directory, run:
# python3 sheetsToCharts.py path/to/csv/file.csv
#
# use from within this directory, as the paths to the chart metadata files are relative to this directory
# Get the command line argument, if one wasn't already provided
if len(sys.argv) < 2:
csv_file = input("Please provide the CSV file path: ")
else:
csv_file = sys.argv[1]
# Open the CSV file
with open(csv_file, 'r') as file:
reader = csv.reader(file)
# Which rows for each difficulty are we looking for
diff_rows = {}
# Iterate over each row in the CSV file
for idx, row in enumerate(reader):
# The first row has headers for the columns, stuff like "Easy - Difficulty", so we want
# to know which rows corresponde to which difficulty
if idx == 0:
pattern = r"\b(?:difficulty)\b"
diff_cols = []
diff_words = []
# Go through each column, and see if it includes the word "difficulty"
# then append the column index, and the first word of the column (usually what difficulty it is, "easy", "normal", "hard", etc.)
for colindex, column in enumerate(row):
txt = re.findall(pattern, column, flags=re.IGNORECASE)
if txt:
diff_cols.append(colindex)
diff_words.append(column.split()[0].lower())
# We then create a dictionary for use later, where the key is the difficulty, and the value is the column index
diff_rows = dict(zip(diff_words, diff_cols))
else:
# Some song title parsing, to match the filenames we used in for the chart files
song_title = row[1].lower() # we use lowercase for filenames, SOUTH -> south
song_title = song_title.replace(" ", "-") # usually we change spaces to dashes, PHILLY NICE -> philly-nice
song_title = song_title.replace(".", "") # M.I.L.F. -> milf
song_title = song_title.replace("'", "") # blazin' -> blazin
# we open the chart metadata json file for writing and reading ("r+")
with open(f"../../../assets/preload/data/songs/{song_title}/{song_title}-metadata.json", "r+") as chart_metadata_file:
json_data = json.load(chart_metadata_file) # load the file as a python data structure/dict
play_data = json_data["playData"] # we want to modify the "playData" section, as that holds the difficulty
# note to self, python equals(=) operator seems to create a reference for the variable,
# so modifying play_data will also modify json_data, so we can save json_data easily later
# if the chart metadata file doesn't already have a "ratings" dict/section, we create one here with 0 for each
if "ratings" not in play_data:
play_data["ratings"] = {'easy': 0, 'normal': 0, 'hard': 0}
ratings = play_data["ratings"]
# Now we go through our data from the csv file, and the data we kept from the columns there
# will be put into our new ratings var, if it exists
for diff, col in diff_rows.items():
if row[col] == "":
continue
if diff in ratings:
ratings[diff] = round(float(row[col])) # convert the string to a float, and then round it to nearest int
# Convert the python json_data dict back to a json string
json_output = json.dumps(json_data)
# Write the json string back to the file, and truncate the rest of the file
chart_metadata_file.seek(0)
chart_metadata_file.write(json_output)
chart_metadata_file.truncate()
chart_metadata_file.close()
# Bit hacky, but we simply run `npx prettier` using the same rules we use for FNF here
# essnetially running it via cli and passing in the songs folder and our prettier config file
# This should make the spacing and formatting consistent
command = "npx prettier ../../../assets/preload/data/songs --write --config ../../../.prettierrc.js"
subprocess.run(command, shell=True)
+5
View File
@@ -0,0 +1,5 @@
#!/bin/bash
# Find all files in OGG format and execute ffmpeg to convert them to MP3
# Skips files that are already in MP3 format
find "../assets/" -name "*.ogg" -exec sh -c 'ffmpeg -n -i {} "${0%.*}.mp3"' {} \;
+218
View File
@@ -0,0 +1,218 @@
import requests
import sys
PROJECT_ID = 5582053
TEMPLATE = 'jQuery("#new-event-name").val("{event}"); jQuery("#save-new-event").click();'
EVENT_TEMPLATES = [
"start-game",
"watch-cartoon",
"open-credits",
"start-song_{songId}-{variation}",
"blueballs_{songId}-{variation}",
"complete-song_{songId}-{variation}",
"start-level_{levelId}",
"complete-level_{levelId}",
"earn-rank_{rankName}",
]
SONG_IDS = [
{ "songId": "tutorial", "variation": "default" },
{ "songId": "tutorial", "variation": "erect" },
{ "songId": "tutorial", "variation": "pico" },
{ "songId": "bopeebo", "variation": "default" },
{ "songId": "bopeebo", "variation": "erect" },
{ "songId": "bopeebo", "variation": "pico" },
{ "songId": "fresh", "variation": "default" },
{ "songId": "fresh", "variation": "erect" },
{ "songId": "fresh", "variation": "pico" },
{ "songId": "dadbattle", "variation": "default" },
{ "songId": "dadbattle", "variation": "erect" },
{ "songId": "dadbattle", "variation": "pico" },
{ "songId": "spookeez", "variation": "default" },
{ "songId": "spookeez", "variation": "erect" },
{ "songId": "spookeez", "variation": "pico" },
{ "songId": "south", "variation": "default" },
{ "songId": "south", "variation": "erect" },
{ "songId": "south", "variation": "pico" },
{ "songId": "monster", "variation": "default" },
{ "songId": "monster", "variation": "erect" },
{ "songId": "monster", "variation": "pico" },
{ "songId": "pico", "variation": "default" },
{ "songId": "pico", "variation": "erect" },
{ "songId": "pico", "variation": "pico" },
{ "songId": "philly-nice", "variation": "default" },
{ "songId": "philly-nice", "variation": "erect" },
{ "songId": "philly-nice", "variation": "pico" },
{ "songId": "blammed", "variation": "default" },
{ "songId": "blammed", "variation": "erect" },
{ "songId": "blammed", "variation": "pico" },
{ "songId": "satin-panties", "variation": "default" },
{ "songId": "satin-panties", "variation": "erect" },
{ "songId": "satin-panties", "variation": "pico" },
{ "songId": "high", "variation": "default" },
{ "songId": "high", "variation": "erect" },
{ "songId": "high", "variation": "pico" },
{ "songId": "milf", "variation": "default" },
{ "songId": "milf", "variation": "erect" },
{ "songId": "milf", "variation": "pico" },
{ "songId": "cocoa", "variation": "default" },
{ "songId": "cocoa", "variation": "erect" },
{ "songId": "cocoa", "variation": "pico" },
{ "songId": "eggnog", "variation": "default" },
{ "songId": "eggnog", "variation": "erect" },
{ "songId": "eggnog", "variation": "pico" },
{ "songId": "winter-horrorland", "variation": "default" },
{ "songId": "winter-horrorland", "variation": "erect" },
{ "songId": "winter-horrorland", "variation": "pico" },
{ "songId": "senpai", "variation": "default" },
{ "songId": "senpai", "variation": "erect" },
{ "songId": "senpai", "variation": "pico" },
{ "songId": "roses", "variation": "default" },
{ "songId": "roses", "variation": "erect" },
{ "songId": "roses", "variation": "pico" },
{ "songId": "thorns", "variation": "default" },
{ "songId": "thorns", "variation": "erect" },
{ "songId": "thorns", "variation": "pico" },
{ "songId": "ugh", "variation": "default" },
{ "songId": "ugh", "variation": "erect" },
{ "songId": "ugh", "variation": "pico" },
{ "songId": "guns", "variation": "default" },
{ "songId": "guns", "variation": "erect" },
{ "songId": "guns", "variation": "pico" },
{ "songId": "stress", "variation": "default" },
{ "songId": "stress", "variation": "erect" },
{ "songId": "stress", "variation": "pico" },
{ "songId": "darnell", "variation": "default" },
{ "songId": "darnell", "variation": "erect" },
{ "songId": "darnell", "variation": "bf" },
{ "songId": "lit-up", "variation": "default" },
{ "songId": "lit-up", "variation": "erect" },
{ "songId": "lit-up", "variation": "bf" },
{ "songId": "2hot", "variation": "default" },
{ "songId": "2hot", "variation": "erect" },
{ "songId": "2hot", "variation": "bf" },
{ "songId": "blazin", "variation": "default" },
{ "songId": "blazin", "variation": "erect" },
{ "songId": "blazin", "variation": "bf" },
]
LEVEL_IDS = [
"tutorial",
"week1",
"week2",
"week3",
"week4",
"week5",
"week6",
"week7",
"weekend1",
"week8",
]
RANKS = [
"PERFECT_GOLD",
"PERFECT",
"EXCELLENT",
"GREAT",
"GOOD",
"SHIT",
]
def formatEventSong(event):
result = []
for song in SONG_IDS:
result.append(event.format(
songId = song["songId"],
variation = song["variation"]
))
return result
def formatEventLevel(event):
result = []
for level in LEVEL_IDS:
result.append(event.format(
levelId = level
))
return result
def formatEventRank(event):
result = []
for rank in RANKS:
result.append(event.format(
rankName = rank
))
return result
def formatEvent(event):
if "{songId}" in event or "{variation}" in event:
return formatEventSong(event)
if "{levelId}" in event:
return formatEventLevel(event)
if "{rankName}" in event:
return formatEventRank(event)
return [event]
def createEvent(event):
print(TEMPLATE.format(event=event))
def main():
event_list = []
for event in EVENT_TEMPLATES:
event_list.extend(formatEvent(event))
# Filter out duplicates then sort alphabetically
event_list = list(set(event_list))
event_list.sort()
for event in event_list:
createEvent(event)
if __name__ == "__main__":
main()
#function sleep(ms) {
# console.log("sleeping for " + ms + "ms");
# return new Promise(resolve => setTimeout(resolve, ms));
#}
#async function example() {
# jQuery("#new-event-name").val("blueballs_blazin-erect"); jQuery("#save-new-event").click();
# await sleep(1000);
# jQuery("#new-event-name").val("blueballs_blazin-erect"); jQuery("#save-new-event").click();
# await sleep(1000);
#}
#example();
@@ -0,0 +1,11 @@
@echo off
color 0a
cd ..
@echo on
echo BUILDING GAME
lime build html5 -final
echo UPLOADING TO ITCH
butler push ./export/release/html5/bin ninja-muffin24/funkin-secret:html5
butler status ninja-muffin24/funkin-secret:html5
echo ITCH SHIT UPDATED LMAOOOOO
pause
+11
View File
@@ -0,0 +1,11 @@
@echo off
color 0a
cd ..
@echo on
echo BUILDING GAME
lime build html5 -debug
echo UPLOADING TO ITCH
butler push ./export/debug/html5/bin ninja-muffin24/funkin-secret:html5
butler status ninja-muffin24/funkin-secret:html5
echo ITCH SHIT UPDATED LMAOOOOO
pause
@@ -0,0 +1,15 @@
@echo off
color 0a
cd ..
@echo on
echo BUILDING GAME
lime build windows -final -clean
echo UPLOADING 64 BIT VERSION TO ITCH
butler push ./export/release/windows/bin ninja-muffin24/funkin:windows-64bit
lime build windows -final -32
echo UPLOADING 32 BIT VERSION TO ITCH
butler push ./export/release/windows/bin ninja-muffin24/funkin:windows-32bit
butler status ninja-muffin24/funkin:windows-32bit
butler status ninja-muffin24/funkin:windows-64bit
echo ITCH SHIT UPDATED LMAOOOOO
pause
@@ -0,0 +1,11 @@
@echo off
color 0a
cd ..
@echo on
echo BUILDING GAME
lime build windows -debug
echo UPLOADING 64 BIT VERSION TO ITCH
butler push ./export/debug/windows/bin ninja-muffin24/funkin:windows-secretBeta
butler status ninja-muffin24/funkin:windows-secretBeta
echo ITCH SHIT UPDATED LMAOOOOO
pause
@@ -0,0 +1,15 @@
@echo off
color 0a
cd ..
@echo on
echo BUILDING GAME
lime build windows -release
echo UPLOADING 64 BIT VERSION TO ITCH
butler push ./export/release/windows/bin ninja-muffin24/funkin:windows-64bit
lime build windows -release -32
echo UPLOADING 32 BIT VERSION TO ITCH
butler push ./export/release/windows/bin ninja-muffin24/funkin:windows-32bit
butler status ninja-muffin24/funkin:windows-32bit
butler status ninja-muffin24/funkin:windows-64bit
echo ITCH SHIT UPDATED LMAOOOOO
pause
@@ -0,0 +1,12 @@
@echo off
color 0a
cd ..
@echo on
echo BUILDING GAME
lime build html5 -final -Dng
echo ZIPPING
cd export
7z a -tzip -r swag release\html5\bin
start .
start https://www.newgrounds.com/projects/games/1528775
pause
@@ -0,0 +1,27 @@
@echo off
cd ..
@echo on
echo REBUILDING LIME FOR EXPORT (VERBOSE)
@echo off
color 0b
@echo on
lime rebuild windows -clean -v
@echo off
color 0a
@echo on
lime rebuild switch -clean -v
@echo off
color 0e
@echo on
lime rebuild tools -clean -v
echo HOPE AND PRAY...
@echo off
color 0a
@echo on
echo BUILDING GAME
lime build switch -final -clean -v
@echo off
color 0b
@echo on
echo NSP FILE CREATED
pause
+110
View File
@@ -0,0 +1,110 @@
// Highlight keyframes in flash
// drag .jsfl script in
// will export the layer info of the first(?) element it finds?
// maybe someone can extend this to add more depth / functionality!
// see FramesJSFLParser.hx and CharSelectGF.hx for sample implementation
function splitArrayIntoChunks(array, chunkSize) {
var result = [];
for (var i = 0; i < array.length; i += chunkSize) {
var chunk = array.slice(i, i + chunkSize);
result.push(chunk);
}
return result;
}
var isJson = false;
function addField(name, variable, end)
{
return (isJson) ? addFJson(name, variable, end) : addF(variable, end);
}
function addFJson(name, variable, end) {
return "\"" + name + "\": " + variable + ((!end) ? "," : "");
}
function addF(variable, end) {
return variable + ((end)? "" : " ");
}
fl.outputPanel.clear();
var timeline = fl.getDocumentDOM().getTimeline();
var daSelection = timeline.getSelectedFrames();
var splitArrays = splitArrayIntoChunks(daSelection, 3);
var uri = undefined;
if (fl.version.substring(4).split(",")[0] < 13)
{
var macFormat = "Folder|TEXT[*.||";
var winFormat = "Folder|*.||";
var previewArea = {};
uri = fl.browseForFileURL("save", "where to save files pick folder...", previewArea, macFormat, winFormat);
}
else
uri = fl.browseForFileURL("save", "where to save files pick folder..", "Folder(*.)", "*.");
for (var i = 0; i < splitArrays.length; i+=1)
{
var curLayerInfo = splitArrays[i];
var curLayerInd = curLayerInfo[0];
var curLayer = fl.getDocumentDOM().getTimeline().layers[curLayerInd];
var layerURI = uri;
var fileName = "";
var uris = uri.split("/");
fileName = uris[uris.length - 1];
FLfile.createFolder(layerURI);
var fileData = "{\n";
if (!isJson)
fileData = "";
var selectedFrames = curLayer.frames;
var sliceLength = curLayerInfo[2] - curLayerInfo[1];
selectedFrames =selectedFrames.slice(curLayerInfo[1],curLayerInfo[2]);
if (isJson)
fileData += "\"frames\": [";
for (var frameInd = curLayerInfo[1]; frameInd < curLayerInfo[2]; frameInd+=1)
{
if (isJson)
fileData += "\n{"
var curFrame = curLayer.frames[frameInd];
if (curFrame.isEmpty)
{
continue;
}
for (var elementInd = 0; elementInd < curFrame.elements.length; elementInd+=1)
{
var curElement = curFrame.elements[elementInd];
fileData += addField("x", curElement.left, false);
fileData += addField("y", curElement.top, false);
fileData += addField("alpha", (curElement.colorAlphaPercent == undefined) ? 100 : curElement.colorAlphaPercent, false);
fileData += addField("scaleX", curElement.scaleX, false);
fileData += addField("scaleY", curElement.scaleY, true);
if (frameInd != curLayerInfo[2] - 1)
fileData += "\n";
}
if (isJson)
fileData += "},";
}
if (isJson)
fileData += "]";
if (isJson)
fileData += "\n}";
FLfile.write(layerURI + "/" + fileName + ".txt", fileData);
}
+6
View File
@@ -0,0 +1,6 @@
# README
jsfl is a scripting format with javascript syntax, I believe it's old js (no `let`, idk the spec!)
Official Adobe JSFL docuementation
[https://github.com/AdobeDocs/developers-animatesdk-docs/tree/master](https://github.com/AdobeDocs/developers-animatesdk-docs/tree/master)
+120
View File
@@ -0,0 +1,120 @@
#!/bin/bash
set -e # Exit immediately if a command exits with a non-zero status
echo "Note! This should be run from the root of the main Funkin repo, after creating a universal macOS build!"
echo "This script will assist in codesigning the Funkin.app for macOS"
echo ""
TEAM_ID="Z7G7AVNGSH"
ISSUER_ID="5205caca-2a9b-4b5e-9390-1db124cf51f4"
DEVELOPER_CERT_NAME="Developer ID Application: The Funkin' Crew Incorporated ($TEAM_ID)"
APP_PATH="export/release/macosUniversal/Funkin.app"
# Check if app exists
if [ ! -d "$APP_PATH" ]; then
echo "Error: $APP_PATH does not exist! Please build the app first."
exit 1
fi
echo "Preparing/Checking the AuthKey"
team_key_path=~/.appstoreconnect/private_keys/
# Check if directory exists, if not, create it
if [ ! -d "$team_key_path" ]; then
echo "The directory $team_key_path does not exist! Creating it now."
mkdir -p "$team_key_path"
echo ""
echo "$team_key_path created, put the private key file in there (should be called 'AuthKey_XXXXXXX.p8')"
echo "Ask Cameron for the private key file!"
echo ""
fi
# wait for the user to put the file in the directory, if it's not there
while [ ! -f "${team_key_path}"AuthKey_*.p8 ]; do
echo "Waiting for the private key file to be placed in $team_key_path... (press Ctrl+C to exit)"
sleep 5
done
key_id=$(ls "$team_key_path" | grep -oE '[A-Z0-9]{10}' | head -n 1)
if [ -z "$key_id" ]; then
echo "Error: Could not extract key ID from the AuthKey file name"
exit 1
fi
echo "Found AuthKey with key id: $key_id"
key_path="${team_key_path}AuthKey_${key_id}.p8"
cd export/release/macosUniversal || { echo "Failed to change directory"; exit 1; }
echo "Ensuring properly formatted Entitlements.plist"
if [ ! -f "Funkin.app/Contents/Entitlements.plist" ]; then
echo "Error: Entitlements.plist not found"
exit 1
fi
plutil -convert xml1 Funkin.app/Contents/Entitlements.plist
plutil -convert xml1 Funkin.app/Contents/Info.plist
plutil -lint Funkin.app/Contents/Entitlements.plist
plutil -lint Funkin.app/Contents/Info.plist
echo "Entitlements.plist and Info.plist should be properly formatted..."
echo "Codesigning - Funkin.app"
# Check the keychain for the funkin crew certificate
echo "Checking for The Funkin' Crew certificate in the keychain..."
if ! security find-identity -p codesigning | grep -q "The Funkin' Crew Incorporated"; then
echo "The Funkin' Crew Developer ID Application certificate was not found in the keychain!"
echo "Download the certificate from:"
echo "https://developer.apple.com/account/resources/certificates/download/Z62SXF29U7"
exit 1
fi
echo "Codesigning - Funkin.app"
codesign --force --deep --timestamp --sign "$DEVELOPER_CERT_NAME" --options runtime Funkin.app || {
echo "Code signing failed"
exit 1
}
echo "Codesigning - Funkin.app done!"
# Debug info to see if the app is properly signed
codesign -vv --deep --strict Funkin.app || {
echo "Code signing verification failed"
exit 1
}
echo ""
echo "Zipping Funkin.app for notarization (using ditto)..."
# Check if Funkin.app.zip already exists, if so, delete it
if [ -f Funkin.app.zip ]; then
echo "Funkin.app.zip already exists, deleting it..."
rm -rf Funkin.app.zip
fi
ditto -c -k --keepParent Funkin.app Funkin.app.zip || {
echo "Failed to create zip file"
exit 1
}
echo "Funkin.app zipped, now sending to Apple for notarization..."
xcrun notarytool submit Funkin.app.zip --issuer "$ISSUER_ID" --key-id "$key_id" --key "$key_path" --wait || {
echo "Notarization submission failed"
exit 1
}
# Clean up zip file
rm -rf Funkin.app.zip
echo "Stapling Funkin.app"
xcrun stapler staple Funkin.app || {
echo "Stapling failed"
exit 1
}
echo "Code sign information!"
codesign -dv --verbose=4 Funkin.app
echo "Notarization information (stapler):"
xcrun stapler validate Funkin.app || {
echo "Stapler validation failed"
exit 1
}
cd ../../.. || { echo "Failed to return to original directory"; exit 1; }
echo "Notarization complete! Funkin.app is now codesigned and notarized!"
+20
View File
@@ -0,0 +1,20 @@
#!/bin/sh
echo "Note! This should be run from the root of the main Funkin repo, after creating a universal macOS build!"
echo "This script will assist in creating a universal build of Funkin.app for macOS"
echo ""
lime build mac -64 -release
cd export/release
rm -rf macosUniversal
mkdir macosUniversal
cp -r macos/bin/Funkin.app macosUniversal
cd ../..
lime build mac -arm64 -release
cd export/release
cp -r macos/bin/Funkin.app/Contents/MacOS/Funkin macosUniversal/Funkin.app/Contents/MacOS/FunkinArm
cp -r macos/bin/Funkin.app/Contents/MacOS/lime.ndll macosUniversal/Funkin.app/Contents/MacOS/limeArm.ndll
cd macosUniversal/Funkin.app/Contents/MacOS
mv Funkin Funkin64
mv lime.ndll lime64.ndll
lipo -create -output lime.ndll lime64.ndll limeArm.ndll
lipo -create -output Funkin Funkin64 FunkinArm
rm FunkinArm Funkin64 lime64.ndll limeArm.ndll
+4
View File
@@ -0,0 +1,4 @@
#!/bin/bash
# Find all files in PNG format and execute oxipng to optimize file sizes
cd ../assets/ && oxipng -o 6 --strip safe --alpha {} **/*.png
+4
View File
@@ -0,0 +1,4 @@
#!/bin/bash
# Resize each health icon to 512x512
find "../art/discord/" -name "icon-*.png" -exec sh -c 'ffmpeg -i {} -vf scale=512:512 "${0%.*}2.png"' {} \;
+29 -19
View File
@@ -87,6 +87,21 @@ class Main extends Sprite
removeEventListener(Event.ADDED_TO_STAGE, init);
}
#if (sys && !mobile)
// Force-kill the game to prevent background processing.
Lib.current.stage.window.onClose.add(function()
{
trace(' EXITING '.bold().bg_red() + ' Game is exiting, cleaning up resources...');
#if hxvlc
// Clean up VLC threads to prevent memory leaks.
hxvlc.util.Handle.dispose();
#end
Sys.exit(0);
});
#end
// Manually crash the game when using a software renderer in order to give a nicer error message.
var context = stage.window.context.type;
if (context != WEBGL && context != OPENGL && context != OPENGLES)
@@ -136,7 +151,8 @@ class Main extends Sprite
#if hxvlc
// Initialize hxvlc's Handle here so the videos are loading faster.
Handle.initAsync(function(success:Bool):Void {
Handle.initAsync(function(success:Bool):Void
{
if (success)
{
trace(' HXVLC '.bold().bg_orange() + ' LibVLC instance initialized!');
@@ -148,16 +164,15 @@ class Main extends Sprite
});
#end
// Don't call anything from the preferences until the save is loaded!
#if web
// set this variable (which is a function) from the lime version at lime/_internal/backend/html5/HTML5Application.hx
// The framerate cap will more thoroughly initialize via Preferences in InitState.hx
funkin.Preferences.lockedFramerateFunction = untyped js.Syntax.code("window.requestAnimationFrame");
#end
WindowUtil.setVSyncMode(funkin.Preferences.vsyncMode);
var game:FlxGame = new FlxGame(gameWidth, gameHeight, initialState, Preferences.framerate, Preferences.framerate, skipSplash,
// Force a `FunkinCamera` to be the default camera.
// This allows the blend mode shader to work everywhere.
untyped FlxG.cameras = new funkin.graphics.FunkinCameraFrontEnd();
var framerate:Int = Preferences.unlockedFramerate ? 0 : Preferences.framerate;
var game:FlxGame = new FlxGame(gameWidth, gameHeight, initialState, framerate, framerate, skipSplash,
(FlxG.stage.window.fullscreen || Preferences.autoFullscreen));
// FlxG.game._customSoundTray wants just the class, it calls new from
@@ -169,7 +184,7 @@ class Main extends Sprite
addChild(game);
#if FEATURE_DEBUG_FUNCTIONS
game.debugger.interaction.addTool(new funkin.util.TrackerToolButtonUtil());
#if !FLX_NO_DEBUG game.debugger.interaction.addTool(new funkin.util.TrackerToolButtonUtil()); #end
funkin.util.macro.ConsoleMacro.init();
#end
@@ -231,14 +246,7 @@ class Main extends Sprite
function repositionCounters(lerp:Bool):Void
{
// Calling this so it gets scaled based on the resolution of the game and device's resolution.
var scale:Float = Math.min(FlxG.stage.stageWidth / FlxG.width, FlxG.stage.stageHeight / FlxG.height);
#if android
scale = Math.max(scale, 1);
#else
scale = Math.min(scale, 1);
#end
final thypos:Float = Math.max(FullScreenScaleMode.notchSize.x, 10);
var scale:Float = Math.max(Math.min(FlxG.stage.stageWidth / FlxG.width, FlxG.stage.stageHeight / FlxG.height), 1);
if (debugDisplay != null)
{
@@ -246,13 +254,15 @@ class Main extends Sprite
if (FlxG.game != null)
{
final thypos:Float = Math.max(FullScreenScaleMode.notchSize.x, 10);
if (lerp)
{
debugDisplay.x = flixel.math.FlxMath.lerp(debugDisplay.x, FlxG.game.x + thypos, FlxG.elapsed * 3);
}
else
{
debugDisplay.x = FlxG.game.x + FullScreenScaleMode.notchSize.x + 10;
debugDisplay.x = FlxG.game.x + thypos;
}
debugDisplay.y = FlxG.game.y + (3 * scale);
+1 -6
View File
@@ -36,12 +36,7 @@ class Postbuild
static function format(time:Float, decimals:Int = 1):String
{
var units = [
{name: "day", secs: 86400},
{name: "hour", secs: 3600},
{name: "minute", secs: 60},
{name: "second", secs: 1}
];
var units = [{name: "day", secs: 86400}, {name: "hour", secs: 3600}, {name: "minute", secs: 60}, {name: "second", secs: 1}];
var parts:Array<String> = [];
var remaining:Float = time;
+4 -2
View File
@@ -2,6 +2,8 @@ package source; // Yeah, I know...
import sys.io.File;
using tools.AnsiUtil;
/**
* A script which executes before the game is built.
*/
@@ -12,13 +14,13 @@ class Prebuild
static function main():Void
{
var start:Float = Sys.time();
// Sys.println('[INFO] Performing pre-build tasks...');
// Sys.println(' INFO '.bold().bg_blue() + " Performing pre-build tasks...");
saveBuildTime();
var end:Float = Sys.time();
var duration:Float = end - start;
// Sys.println('[INFO] Finished pre-build tasks in $duration seconds.');
// Sys.println(' INFO '.bold().bg_blue() + ' Finished pre-build tasks in $duration seconds.');
}
static function saveBuildTime():Void
+11 -20
View File
@@ -89,44 +89,35 @@ extern class Native_TracyProfiler
class Cppia_TracyProfiler
{
@:inheritDoc(cpp.vm.tracy.Native_TracyProfiler.frameMark)
public static function frameMark()
Native_TracyProfiler.frameMark();
public static function frameMark() Native_TracyProfiler.frameMark();
@:inheritDoc(cpp.vm.tracy.Native_TracyProfiler.frameMarkNamed)
public static function frameMarkNamed(_name:String)
Native_TracyProfiler.frameMarkNamed(_name);
public static function frameMarkNamed(_name:String) Native_TracyProfiler.frameMarkNamed(_name);
@:inheritDoc(cpp.vm.tracy.Native_TracyProfiler.frameMarkStart)
public static function frameMarkStart(_name:String)
Native_TracyProfiler.frameMarkStart(_name);
public static function frameMarkStart(_name:String) Native_TracyProfiler.frameMarkStart(_name);
@:inheritDoc(cpp.vm.tracy.Native_TracyProfiler.frameMarkEnd)
public static function frameMarkEnd(_name:String)
Native_TracyProfiler.frameMarkEnd(_name);
public static function frameMarkEnd(_name:String) Native_TracyProfiler.frameMarkEnd(_name);
@:inheritDoc(cpp.vm.tracy.Native_TracyProfiler.message)
public static function message(_msg:String, ?_color:Int = 0x000000)
Native_TracyProfiler.message(_msg, _color);
public static function message(_msg:String, ?_color:Int = 0x000000) Native_TracyProfiler.message(_msg, _color);
@:inheritDoc(cpp.vm.tracy.Native_TracyProfiler.messageAppInfo)
public static function messageAppInfo(_info:String)
Native_TracyProfiler.messageAppInfo(_info);
public static function messageAppInfo(_info:String) Native_TracyProfiler.messageAppInfo(_info);
@:inheritDoc(cpp.vm.tracy.Native_TracyProfiler.plot)
public static function plot(_name:String, _val:Float)
Native_TracyProfiler.plot(_name, _val);
public static function plot(_name:String, _val:Float) Native_TracyProfiler.plot(_name, _val);
@:inheritDoc(cpp.vm.tracy.Native_TracyProfiler.plotConfig)
public static function plotConfig(_name:String, _format:PlotFormatType, ?_step:Bool = false, ?_fill:Bool = false, ?_color:Int = 0x000000)
Native_TracyProfiler.plotConfig(_name, _format, _step, _fill, _color);
public static function plotConfig(_name:String, _format:PlotFormatType, ?_step:Bool = false, ?_fill:Bool = false,
?_color:Int = 0x000000) Native_TracyProfiler.plotConfig(_name, _format, _step, _fill, _color);
@:inheritDoc(cpp.vm.tracy.Native_TracyProfiler.setThreadName)
public static function setThreadName(_name:String, ?_groupHint:Int = 1)
Native_TracyProfiler.setThreadName(_name, _groupHint);
public static function setThreadName(_name:String, ?_groupHint:Int = 1) Native_TracyProfiler.setThreadName(_name, _groupHint);
@:inheritDoc(cpp.vm.tracy.Native_TracyProfiler.zoneScoped)
public static function zoneScoped(_name:String)
Native_TracyProfiler.zoneScoped(_name);
public static function zoneScoped(_name:String) Native_TracyProfiler.zoneScoped(_name);
}
typedef TracyProfiler = Cppia_TracyProfiler;
+3 -1
View File
@@ -381,7 +381,9 @@ class Conductor
/**
* The constructor.
*/
public function new() {}
public function new()
{
}
/**
* Forcibly defines the current BPM of the song.
+58 -37
View File
@@ -12,7 +12,7 @@ import lime.app.Promise;
/**
* Handles caching of textures and sounds for the game.
* TODO: Remove this once Eric finishes the memory system.
* I did this hello, this can be improved later on and I have ideas on how, but for now this functions well enough. -Zack
*/
@:nullSafety
class FunkinMemory
@@ -21,7 +21,6 @@ class FunkinMemory
static var currentCachedTextures:Map<String, FlxGraphic> = [];
static var previousCachedTextures:Map<String, FlxGraphic> = [];
// waow
static var permanentCachedSounds:Map<String, Sound> = [];
static var currentCachedSounds:Map<String, Sound> = [];
static var previousCachedSounds:Map<String, Sound> = [];
@@ -97,6 +96,7 @@ class FunkinMemory
/**
* Clears the current texture and sound caches.
* @param callGarbageCollector Whether to call the system's garbage collector after purging.
*/
public static inline function purgeCache(callGarbageCollector:Bool = false):Void
{
@@ -111,16 +111,6 @@ class FunkinMemory
///// TEXTURES /////
/**
* Determine whether the texture with the given key is cached.
* @param key The key of the texture to check.
* @return Whether the texture is cached.
*/
public static function isTextureCached(key:String):Bool
{
return FlxG.bitmap.get(key) != null;
}
/**
* Ensures a texture with the given key is cached.
* @param key The key of the texture to cache.
@@ -173,30 +163,6 @@ class FunkinMemory
currentCachedTextures = permanentCachedTextures.copy();
}
/**
* Forces the GPU to load and upload a FlxGraphic.
*/
private static function forceRender(graphic:FlxGraphic):Void
{
if (graphic == null) return;
var bmp:Null<FlxGraphic> = FlxG.bitmap.get(graphic.key);
if (bmp != null && bmp.bitmap != null) var _:Int = bmp.bitmap.width; // Trigger
// Draws sprite and actually caches it.
var sprite = new flixel.FlxSprite();
sprite.loadGraphic(graphic);
sprite.draw(); // Draw sprite and load it into game's memory.
graphic.bitmap?.getTexture(FlxG.stage.context3D); // Just in case that didn't work...
sprite.destroy();
}
/**
* Checks, if graphic with given path cached in memory.
*/
public static inline function isGraphicCached(path:String):Bool
return permanentCachedTextures.exists(path) || currentCachedTextures.exists(path) || previousCachedTextures.exists(path);
public static function getCachedGraphic(path:String):Null<FlxGraphic>
{
if (permanentCachedTextures.exists(path)) return permanentCachedTextures.get(path);
@@ -281,8 +247,42 @@ class FunkinMemory
}
}
/**
* Forces the GPU to load and upload a FlxGraphic.
* @param graphic The graphic to force render.
*/
private static function forceRender(graphic:FlxGraphic):Void
{
if (graphic == null) return;
var bmp:Null<FlxGraphic> = FlxG.bitmap.get(graphic.key);
if (bmp != null && bmp.bitmap != null) var _:Int = bmp.bitmap.width; // Trigger
// Draws sprite and actually caches it.
var sprite = new flixel.FlxSprite();
sprite.loadGraphic(graphic);
sprite.draw(); // Draw sprite and load it into game's memory.
graphic.bitmap?.getTexture(FlxG.stage.context3D); // Just in case that didn't work...
sprite.destroy();
}
/**
* Determine whether the texture with the given key is cached.
* @param key The key of the texture to check.
* @return Whether the texture is cached.
*/
public static function isTextureCached(key:String):Bool
{
return FlxG.bitmap.get(key) != null
&& (permanentCachedTextures.exists(key) || currentCachedTextures.exists(key) || previousCachedTextures.exists(key));
}
///// NOTE STYLE //////
/**
* Caches all assets for the given note style.
* @param style The note style to cache.
*/
public static function cacheNoteStyle(style:NoteStyle):Void
{
// TODO: Texture paths should fall back to the default values.
@@ -325,6 +325,10 @@ class FunkinMemory
///// SOUND //////
/**
* Caches a sound with the given key.
* @param key The key of the sound to cache.
*/
public static function cacheSound(key:String):Void
{
if (currentCachedSounds.exists(key)) return;
@@ -344,6 +348,10 @@ class FunkinMemory
currentCachedSounds.set(key, sound);
}
/**
* Permanently caches a sound with the given key.
* @param key The key of the sound to cache.
*/
public static function permanentCacheSound(key:String):Void
{
if (permanentCachedSounds.exists(key)) return;
@@ -356,6 +364,9 @@ class FunkinMemory
if (sound != null) currentCachedSounds.set(key, sound);
}
/**
* Prepares the cache for purging unused sounds.
*/
public static function preparePurgeSoundCache():Void
{
previousCachedSounds = currentCachedSounds.copy();
@@ -405,6 +416,9 @@ class FunkinMemory
///// MISC /////
/**
* Clears all Freeplay assets from memory.
*/
public static inline function clearFreeplay():Void
{
var keysToRemove:Array<String> = [];
@@ -436,6 +450,9 @@ class FunkinMemory
purgeSoundCache();
}
/**
* Clears all sticker assets from memory.
*/
public static inline function clearStickers():Void
{
var keysToRemove:Array<String> = [];
@@ -464,7 +481,11 @@ class FunkinMemory
}
}
static function log(message:String):Void
/**
* Sends a trace with fancy ANSI colors.
* @param message The message to log.
*/
private static function log(message:String):Void
{
trace(' MEMORY '.bg_bright_lilac().bold() + ' ${message}');
}
+13 -14
View File
@@ -49,20 +49,19 @@ abstract Tallies(RawTallies)
{
public function new()
{
this =
{
combo: 0,
missed: 0,
shit: 0,
bad: 0,
good: 0,
sick: 0,
totalNotes: 0,
totalNotesHit: 0,
maxCombo: 0,
score: 0,
isNewHighscore: false
}
this = {
combo: 0,
missed: 0,
shit: 0,
bad: 0,
good: 0,
sick: 0,
totalNotes: 0,
totalNotesHit: 0,
maxCombo: 0,
score: 0,
isNewHighscore: false
}
}
}
+82 -64
View File
@@ -20,6 +20,7 @@ import funkin.data.freeplay.style.FreeplayStyleRegistry;
import funkin.data.notestyle.NoteStyleRegistry;
import funkin.data.song.SongRegistry;
import funkin.data.stickers.StickerRegistry;
import funkin.play.event.SongEventHelper;
import funkin.data.event.SongEventRegistry;
import funkin.data.stage.StageRegistry;
import funkin.data.story.level.LevelRegistry;
@@ -136,9 +137,11 @@ class InitState extends FlxState
#if mobile
// Setup Mobile FNFC launcher.
funkin.mobile.util.FNFCUtil.init();
funkin.mobile.util.FNFCProvider.init();
#end
SongEventHelper.generateEaseGraphsBitmaps();
// This ain't a pixel art game! (most of the time)
FlxSprite.defaultAntialiasing = true;
@@ -185,7 +188,8 @@ class InitState extends FlxState
FlxTransitionableState.defaultTransOut = new TransitionData(FADE, FlxColor.BLACK, 0.7, new FlxPoint(0, 1), tileData,
new FlxRect(-200, -200, FlxG.width * 1.4, FlxG.height * 1.4));
FlxG.signals.gameResized.add(function(width:Int, height:Int) {
FlxG.signals.gameResized.add(function(width:Int, height:Int)
{
FlxTransitionableState.defaultTransIn = new TransitionData(FADE, FlxColor.BLACK, 1, new FlxPoint(0, -1), tileData,
new FlxRect(-200, -200, FlxG.width * 1.4, FlxG.height * 1.4));
FlxTransitionableState.defaultTransOut = new TransitionData(FADE, FlxColor.BLACK, 0.7, new FlxPoint(0, 1), tileData,
@@ -196,10 +200,12 @@ class InitState extends FlxState
// Since we don't really need VSync on Android we're gonna forcefully disable it on these signals for now
// This is fixed on SDL3 from what I've heared but that doodoo isn't working poperly for Android
#if android
FlxG.signals.focusLost.add(function() {
FlxG.signals.focusLost.add(function()
{
WindowUtil.setVSyncMode(lime.ui.WindowVSyncMode.OFF);
});
FlxG.signals.focusGained.add(function() {
FlxG.signals.focusGained.add(function()
{
WindowUtil.setVSyncMode(lime.ui.WindowVSyncMode.OFF);
});
#end
@@ -217,7 +223,8 @@ class InitState extends FlxState
#if FEATURE_DISCORD_RPC
DiscordClient.instance.init();
lime.app.Application.current.onExit.add(function(exitCode) {
lime.app.Application.current.onExit.add(function(exitCode)
{
DiscordClient.instance.shutdown();
});
#end
@@ -304,19 +311,34 @@ class InitState extends FlxState
#if FEATURE_LOST_FOCUS_VOLUME
@:noCompletion var _lastFocusVolume:Null<Float>;
function onLostFocus()
function onLostFocus():Void
{
if (FlxG.sound.muted || FlxG.sound.volume == 0 || FlxG.autoPause) return;
_lastFocusVolume = FlxG.sound.volume;
FlxG.sound.volume *= Constants.LOST_FOCUS_VOLUME_MULTIPLIER;
}
#end
function onGainFocus()
function onGainFocus():Void
{
#if !mobile
if (Preferences.unlockedFramerate)
{
FlxG.updateFramerate = 0;
FlxG.drawFramerate = 0;
}
else
{
FlxG.updateFramerate = Preferences.framerate;
FlxG.drawFramerate = Preferences.framerate;
}
#end
#if FEATURE_LOST_FOCUS_VOLUME
if (FlxG.sound.muted || FlxG.autoPause) return;
if (_lastFocusVolume != null) FlxG.sound.volume = _lastFocusVolume;
#end
}
#end
/**
* Start the game.
@@ -359,37 +381,34 @@ class InitState extends FlxState
FlxG.switchState(() -> new funkin.ui.debug.stage.StageBuilderState());
#elseif RESULTS
// -DRESULTS
FlxG.switchState(() -> new funkin.play.ResultState(
{
storyMode: true,
title: "Cum Song Erect by Kawai Sprite",
songId: "cum",
characterId: "pico",
difficultyId: "hard",
isNewHighscore: true,
scoreData:
{
score: 1_234_567,
tallies:
{
sick: 130,
good: 60,
bad: 69,
shit: 69,
missed: 69,
combo: 69,
maxCombo: 69,
totalNotesHit: 140,
totalNotes: 240
}
// 2400 total notes = 7% = LOSS
// 275 total notes = 69% = NICE
// 240 total notes = 79% = GOOD
// 230 total notes = 82% = GREAT
// 210 total notes = 91% = EXCELLENT
// 190 total notes = PERFECT
},
}));
FlxG.switchState(() -> new funkin.play.ResultState({
storyMode: true,
title: "Cum Song Erect by Kawai Sprite",
songId: "cum",
characterId: "pico",
difficultyId: "hard",
isNewHighscore: true,
scoreData: {
score: 1_234_567,
tallies: {
sick: 130,
good: 60,
bad: 69,
shit: 69,
missed: 69,
combo: 69,
maxCombo: 69,
totalNotesHit: 140,
totalNotes: 240
}
// 2400 total notes = 7% = LOSS
// 275 total notes = 69% = NICE
// 240 total notes = 79% = GOOD
// 230 total notes = 82% = GREAT
// 210 total notes = 91% = EXCELLENT
// 190 total notes = PERFECT
},
}));
#elseif ANIMDEBUG
// -DANIMDEBUG
FlxG.switchState(() -> new funkin.ui.debug.anim.DebugBoundingState());
@@ -407,15 +426,13 @@ class InitState extends FlxState
function startGameNormally():Void
{
var params:CLIParams = CLIUtil.processArgs();
trace('Command line args: ${params}');
if (params.chart.shouldLoadChart)
{
#if FEATURE_CHART_EDITOR
FlxG.switchState(() -> new ChartEditorState(
{
fnfcTargetPath: params.chart.chartPath,
}));
FlxG.switchState(() -> new ChartEditorState({
fnfcTargetPath: params.chart.chartPath,
}));
#else
FlxG.switchState(() -> new TitleState());
#end
@@ -423,10 +440,9 @@ class InitState extends FlxState
else if (params.stage.shouldLoadStage)
{
#if FEATURE_STAGE_EDITOR
FlxG.switchState(() -> new StageEditorState(
{
fnfsTargetPath: params.stage.stagePath,
}));
FlxG.switchState(() -> new StageEditorState({
fnfsTargetPath: params.stage.stagePath,
}));
#else
FlxG.switchState(() -> new TitleState());
#end
@@ -443,7 +459,8 @@ class InitState extends FlxState
{
// FlxG.sound.cache(Paths.music('freakyMenu/freakyMenu'));
#if mobile
funkin.mobile.util.FNFCUtil.onFNFCOpen.add(function(fnfcFile:String) {
funkin.mobile.util.FNFCProvider.onFNFCOpen.add(function(fnfcFile:String)
{
flixel.tweens.FlxTween.globalManager.clear();
flixel.util.FlxTimer.globalManager.clear();
@:nullSafety(Off)
@@ -456,7 +473,7 @@ class InitState extends FlxState
FlxG.switchState(() -> new ChartPlaytestMenu(fnfcFile));
});
final fnfcFile = funkin.mobile.util.FNFCUtil.queryFNFC();
final fnfcFile = funkin.mobile.util.FNFCProvider.queryFNFC();
if (fnfcFile != null)
{
trace('launching FNFC from $fnfcFile');
@@ -517,11 +534,10 @@ class InitState extends FlxState
}
@:nullSafety(Off) // Cannot unify?
LoadingState.loadPlayState(
{
targetSong: songData,
targetDifficulty: difficultyId,
});
LoadingState.loadPlayState({
targetSong: songData,
targetDifficulty: difficultyId,
});
}
/**
@@ -560,11 +576,10 @@ class InitState extends FlxState
}
@:nullSafety(Off)
LoadingState.loadPlayState(
{
targetSong: targetSong,
targetDifficulty: difficultyId,
});
LoadingState.loadPlayState({
targetSong: targetSong,
targetDifficulty: difficultyId,
});
}
@:nullSafety(Off) // Meh, remove when flixel.system.debug.log.LogStyle is null safe
@@ -573,7 +588,7 @@ class InitState extends FlxState
//
// FLIXEL DEBUG SETUP
//
#if FEATURE_DEBUG_FUNCTIONS
#if (FEATURE_DEBUG_FUNCTIONS && !FLX_NO_DEBUG)
trace('Initializing Flixel debugger...');
#if !debug
@@ -592,7 +607,8 @@ class InitState extends FlxState
// Adds a red button to the debugger.
// This pauses the game AND the music! This ensures the Conductor stops.
FlxG.debugger.addButton(CENTER, new BitmapData(20, 20, true, 0xFFCC2233), function() {
FlxG.debugger.addButton(CENTER, new BitmapData(20, 20, true, 0xFFCC2233), function()
{
if (FlxG.vcr.paused)
{
FlxG.vcr.resume();
@@ -619,7 +635,8 @@ class InitState extends FlxState
// Adds a blue button to the debugger.
// This skips forward in the song.
FlxG.debugger.addButton(CENTER, new BitmapData(20, 20, true, 0xFF2222CC), function() {
FlxG.debugger.addButton(CENTER, new BitmapData(20, 20, true, 0xFF2222CC), function()
{
FlxG.game.debugger.vcr.onStep();
for (snd in FlxG.sound.list)
@@ -636,7 +653,8 @@ class InitState extends FlxState
// This big obnoxious white button is for MOBILE, so that you can press it
// easily with your finger when debug bullshit pops up during testing lol!
#if mobile
FlxG.debugger.addButton(LEFT, new BitmapData(200, 200), function() {
FlxG.debugger.addButton(LEFT, new BitmapData(200, 200), function()
{
FlxG.debugger.visible = false;
// Make errors and warnings less annoying.
+12 -13
View File
@@ -193,19 +193,18 @@ class Paths implements ConsoleClass
graphicKey = Paths.animateAtlas(key);
}
var validatedSettings:AtlasSpriteSettings =
{
swfMode: settings?.swfMode ?? false,
cacheOnLoad: settings?.cacheOnLoad ?? false,
filterQuality: settings?.filterQuality ?? MEDIUM,
spritemaps: settings?.spritemaps ?? null,
metadataJson: settings?.metadataJson ?? null,
cacheKey: settings?.cacheKey ?? null,
uniqueInCache: settings?.uniqueInCache ?? false,
onSymbolCreate: settings?.onSymbolCreate ?? null,
applyStageMatrix: settings?.applyStageMatrix ?? false,
useRenderTexture: settings?.useRenderTexture ?? false
};
var validatedSettings:AtlasSpriteSettings = {
swfMode: settings?.swfMode ?? false,
cacheOnLoad: settings?.cacheOnLoad ?? false,
filterQuality: settings?.filterQuality ?? MEDIUM,
spritemaps: settings?.spritemaps ?? null,
metadataJson: settings?.metadataJson ?? null,
cacheKey: settings?.cacheKey ?? null,
uniqueInCache: settings?.uniqueInCache ?? false,
onSymbolCreate: settings?.onSymbolCreate ?? null,
applyStageMatrix: settings?.applyStageMatrix ?? false,
useRenderTexture: settings?.useRenderTexture ?? false
};
// Validate asset path.
if (!Assets.exists('${graphicKey}/Animation.json'))
+1 -1
View File
@@ -98,7 +98,7 @@ class PlayerSettings
*/
function new(id:Int)
{
trace('loading player settings for id: $id');
trace('Loading player settings for id: $id');
this.id = id;
this.controls = new Controls('player$id', None);
+56 -34
View File
@@ -41,12 +41,23 @@ class Preferences
{
#if web
return 60;
#elseif mobile
var refreshRate:Int = FlxG.stage.window.displayMode.refreshRate;
if (refreshRate < 60) refreshRate = 60;
return refreshRate;
#else
var save:Save = Save.instance;
save.options.framerate = value;
Save.system.flush();
FlxG.updateFramerate = value;
FlxG.drawFramerate = value;
if (!unlockedFramerate)
{
FlxG.updateFramerate = value;
FlxG.drawFramerate = value;
}
return value;
#end
}
@@ -69,13 +80,13 @@ class Preferences
static function set_naughtyness(value:Bool):Bool
{
#if NO_FEATURE_NAUGHTYNESS
value = false;
#end
return false;
#else
var save:Save = Save.instance;
save.options.naughtyness = value;
Save.system.flush();
return value;
#end
}
/**
@@ -146,19 +157,33 @@ class Preferences
{
#if NO_FEATURE_DEBUG_DISPLAY
return DebugDisplayMode.Off;
#else
#if hl
// Account for when debugDisplay used to be a boolean
var options:Null<SaveDataOptions> = Save.instance?.options;
if (options != null && Std.isOfType(options.debugDisplay, Bool))
{
var convertedDebugDisplay = cast(options.debugDisplay, Bool) ? DebugDisplayMode.Simple : DebugDisplayMode.Off;
options.debugDisplay = convertedDebugDisplay;
Save.system.flush();
}
#end
return Save?.instance?.options?.debugDisplay ?? 'Off';
#end
}
static function set_debugDisplay(value:DebugDisplayMode):DebugDisplayMode
{
#if NO_FEATURE_DEBUG_DISPLAY
return DebugDisplayMode.Off;
#else
if (value != Save.instance.options.debugDisplay) setDebugDisplayMode(value);
var save = Save.instance;
save.options.debugDisplay = value;
Save.system.flush();
return value;
#end
}
/**
@@ -253,18 +278,23 @@ class Preferences
{
#if mobile
return false;
#end
#else
return Save?.instance?.options?.autoPause ?? true;
#end
}
static function set_autoPause(value:Bool):Bool
{
#if mobile
return false;
#else
if (value != Save.instance.options.autoPause) FlxG.autoPause = value;
var save:Save = Save.instance;
save.options.autoPause = value;
Save.system.flush();
return value;
#end
}
/**
@@ -314,6 +344,9 @@ class Preferences
static function get_vsyncMode():lime.ui.WindowVSyncMode
{
#if (mobile || web)
return lime.ui.WindowVSyncMode.OFF;
#else
var value = Save?.instance?.options?.vsyncMode ?? "Off";
return switch (value)
@@ -327,10 +360,14 @@ class Preferences
default:
lime.ui.WindowVSyncMode.OFF;
};
#end
}
static function set_vsyncMode(value:lime.ui.WindowVSyncMode):lime.ui.WindowVSyncMode
{
#if (mobile || web)
return lime.ui.WindowVSyncMode.OFF;
#else
var string;
switch (value)
@@ -351,50 +388,37 @@ class Preferences
save.options.vsyncMode = string;
Save.system.flush();
return value;
#end
}
public static var unlockedFramerate(get, set):Bool;
static function get_unlockedFramerate():Bool
{
#if (mobile || web)
return false;
#else
return Save?.instance?.options?.unlockedFramerate ?? false;
#end
}
static function set_unlockedFramerate(value:Bool):Bool
{
#if (mobile || web)
return false;
#else
if (value != Save.instance.options.unlockedFramerate)
{
#if web
toggleFramerateCap(value);
#end
}
var save:Save = Save.instance;
save.options.unlockedFramerate = value;
Save.system.flush();
return value;
#end
}
#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
/**
* If >0, the game will display a semi-opaque background under the notes.
* `0` for no background, `100` for solid black if you're freaky like that
@@ -484,9 +508,7 @@ class Preferences
setDebugDisplayMode(Preferences.debugDisplay);
setDebugDisplayBGOpacity(Preferences.debugDisplayBGOpacity / 100);
#if web
toggleFramerateCap(Preferences.unlockedFramerate);
#end
#if mobile
// Apply the allowScreenTimeout setting.
@@ -496,9 +518,9 @@ class Preferences
static function toggleFramerateCap(unlocked:Bool):Void
{
#if web
var framerateFunction = unlocked ? unlockedFramerateFunction : lockedFramerateFunction;
untyped js.Syntax.code("window.requestAnimationFrame = framerateFunction;");
#if !(mobile || web)
FlxG.drawFramerate = unlocked ? 0 : framerate;
FlxG.updateFramerate = unlocked ? 0 : framerate;
#end
}
+4 -2
View File
@@ -51,7 +51,8 @@ class Leaderboards
var leaderboardData:Null<LeaderboardData> = listLeaderboardData().get(leaderboard.getId());
if (leaderboardData != null)
{
leaderboardData.postScore(score, function(outcome:Outcome<CallError>):Void {
leaderboardData.postScore(score, function(outcome:Outcome<CallError>):Void
{
switch (outcome)
{
case SUCCESS:
@@ -82,7 +83,8 @@ class Leaderboards
if ((params?.useCurrentUser ?? false) && NewgroundsClient.instance.isLoggedIn()) user = NewgroundsClient.instance.user;
leaderboardData.requestScores(params?.limit ?? 10, params?.skip ?? 0, params?.period ?? ALL, params?.social ?? false, params?.tag, user,
function(outcome:Outcome<CallError>):Void {
function(outcome:Outcome<CallError>):Void
{
switch (outcome)
{
case SUCCESS:
+6 -24
View File
@@ -58,7 +58,8 @@ class Medals
// Play the medal unlock animation, but only if the user has not already unlocked it.
#if html5
// Web builds support parsing the bitmap data from the URL directly.
BitmapData.loadFromFile("https:" + medalData.icon).onComplete(function(bmp:BitmapData) {
BitmapData.loadFromFile("https:" + medalData.icon).onComplete(function(bmp:BitmapData)
{
var medalGraphic = FlxGraphic.fromBitmapData(bmp);
medalGraphic.persist = true;
NewgroundsMedalPlugin.play(medalData.value, medalData.name, medalGraphic);
@@ -68,7 +69,8 @@ class Medals
// We have to use a medal image from the game files. We use a Base64 encoded image that NG spits out.
// TODO: Wait, don't they give us the medal icon?
var localMedalData:Null<MedalJSON> = medalJSON.filter(function(jsonMedal) {
var localMedalData:Null<MedalJSON> = medalJSON.filter(function(jsonMedal)
{
#if FEATURE_NEWGROUNDS_TESTING_MEDALS
return medal == jsonMedal.idTest;
#else
@@ -436,27 +438,7 @@ enum abstract Medal(Int) from Int to Int
*/
public static function getAllMedals():Array<Medal>
{
return [
StartGame,
StoryTutorial,
StoryWeek1,
StoryWeek2,
StoryWeek3,
StoryWeek4,
StoryWeek5,
StoryWeek6,
StoryWeek7,
StoryWeekend1,
CharSelect,
FreeplayPicoMix,
FreeplayStressPico,
LossRating,
PerfectRatingHard,
GoldPerfectRatingHard,
ErectDifficulty,
GoldPerfectRatingNightmare,
FridayNight,
Nice
];
return
[StartGame, StoryTutorial, StoryWeek1, StoryWeek2, StoryWeek3, StoryWeek4, StoryWeek5, StoryWeek6, StoryWeek7, StoryWeekend1, CharSelect, FreeplayPicoMix, FreeplayStressPico, LossRating, PerfectRatingHard, GoldPerfectRatingHard, ErectDifficulty, GoldPerfectRatingNightmare, FridayNight, Nice];
}
}
+6 -3
View File
@@ -58,7 +58,8 @@ class NGSaveSlot
try
{
ngSaveSlot?.save(encodedData, function(outcome:Outcome<CallError>) {
ngSaveSlot?.save(encodedData, function(outcome:Outcome<CallError>)
{
switch (outcome)
{
case SUCCESS:
@@ -80,7 +81,8 @@ class NGSaveSlot
{
try
{
ngSaveSlot?.load(function(outcome:SaveSlotOutcome):Void {
ngSaveSlot?.load(function(outcome:SaveSlotOutcome):Void
{
switch (outcome)
{
case SUCCESS(value):
@@ -122,7 +124,8 @@ class NGSaveSlot
{
try
{
ngSaveSlot?.clear(function(outcome:Outcome<CallError>) {
ngSaveSlot?.clear(function(outcome:Outcome<CallError>)
{
switch (outcome)
{
case SUCCESS:
@@ -113,14 +113,16 @@ class NewgroundsClient
return;
}
var passportHandler:String->Void = function(passportUrl:String) {
var passportHandler:String->Void = function(passportUrl:String)
{
// This exists so we can create a popup on mobile but with a WebView instead.
#if FEATURE_MOBILE_WEBVIEW
if (passportUrl != null)
{
NG.core.logVerbose('Loading passport from WebView: ${passportUrl}');
WebViewUtil.openURL(passportUrl, function():Void {
WebViewUtil.openURL(passportUrl, function():Void
{
NG.core.cancelLoginRequest();
});
@@ -151,7 +153,8 @@ class NewgroundsClient
return;
}
var dummyPassport:String->Void = function(_) {
var dummyPassport:String->Void = function(_)
{
// just a dummy passport, so we don't create a popup
// otherwise `NG.core.requestLogin()` will automatically attempt to open a tab at the beginning of the game
// users should go to the Options Menu to login to NG
+2 -1
View File
@@ -23,7 +23,8 @@ class Referral
{
NG.core?.calls.loader.loadReferral(false)
.addComponentParameter("referral_name", referralName)
.addResponseHandler(response -> {
.addResponseHandler(response ->
{
trace(response);
if (response.success)
{
+8 -4
View File
@@ -42,7 +42,8 @@ class FunkinSound extends FlxSound implements ICloneable<FunkinSound>
if (_onVolumeChanged == null)
{
_onVolumeChanged = new FlxTypedSignal<Float->Void>();
FlxG.sound.onVolumeChange.add(function(volume:Float) {
FlxG.sound.onVolumeChange.add(function(volume:Float)
{
_onVolumeChanged.dispatch(volume);
});
}
@@ -350,7 +351,8 @@ class FunkinSound extends FlxSound implements ICloneable<FunkinSound>
partialQueue.push(music);
@:nullSafety(Off)
music.future.onComplete(function(partialMusic:Null<FunkinSound>) {
music.future.onComplete(function(partialMusic:Null<FunkinSound>)
{
FlxG.sound.music = partialMusic;
FlxG.sound.list.remove(FlxG.sound.music);
@@ -496,11 +498,13 @@ class FunkinSound extends FlxSound implements ICloneable<FunkinSound>
}
else
{
promise.future.onError(function(e) {
promise.future.onError(function(e)
{
soundRequest.error("Sound loading was errored or cancelled");
});
soundRequest.future.onComplete(function(partialSound) {
soundRequest.future.onComplete(function(partialSound)
{
var snd = FunkinSound.load(partialSound, volume, looped, autoDestroy, autoPlay, false, onComplete, onLoad);
promise.complete(snd);
});
+27 -13
View File
@@ -58,7 +58,8 @@ class SoundGroup extends FlxTypedGroup<FunkinSound>
{
var error:Float = 0;
forEachAlive(function(snd) {
forEachAlive(function(snd)
{
if (targetTime == null) targetTime = snd.time;
else
{
@@ -85,7 +86,8 @@ class SoundGroup extends FlxTypedGroup<FunkinSound>
// result.pause();
result.time = this.time;
result.onComplete = function() {
result.onComplete = function()
{
this.onComplete();
}
@@ -96,14 +98,17 @@ class SoundGroup extends FlxTypedGroup<FunkinSound>
return result;
}
public dynamic function onComplete():Void {}
public dynamic function onComplete():Void
{
}
/**
* Pause all the sounds in the group.
*/
public function pause()
{
forEachAlive(function(sound:FunkinSound) {
forEachAlive(function(sound:FunkinSound)
{
sound.pause();
});
}
@@ -113,7 +118,8 @@ class SoundGroup extends FlxTypedGroup<FunkinSound>
*/
public function play(forceRestart:Bool = false, startTime:Float = 0.0, ?endTime:Float)
{
forEachAlive(function(sound:FunkinSound) {
forEachAlive(function(sound:FunkinSound)
{
if (sound.length < startTime)
{
// trace('Queuing sound (${sound.toString()} past its length! Skipping...)');
@@ -128,7 +134,8 @@ class SoundGroup extends FlxTypedGroup<FunkinSound>
*/
public function resume()
{
forEachAlive(function(sound:FunkinSound) {
forEachAlive(function(sound:FunkinSound)
{
sound.resume();
});
}
@@ -139,7 +146,8 @@ class SoundGroup extends FlxTypedGroup<FunkinSound>
@:nullSafety(Off)
public function fadeIn(duration:Float, ?from:Float = 0.0, ?to:Float = 1.0, ?onComplete:FlxTween->Void):Void
{
forEachAlive(function(sound:FunkinSound) {
forEachAlive(function(sound:FunkinSound)
{
sound.fadeIn(duration, from, to, onComplete);
});
}
@@ -150,7 +158,8 @@ class SoundGroup extends FlxTypedGroup<FunkinSound>
@:nullSafety(Off)
public function fadeOut(duration:Float, ?to:Float = 0.0, ?onComplete:FlxTween->Void):Void
{
forEachAlive(function(sound:FunkinSound) {
forEachAlive(function(sound:FunkinSound)
{
sound.fadeOut(duration, to, onComplete);
});
}
@@ -162,7 +171,8 @@ class SoundGroup extends FlxTypedGroup<FunkinSound>
{
if (members != null)
{
forEachAlive(function(sound:FunkinSound) {
forEachAlive(function(sound:FunkinSound)
{
sound.stop();
});
}
@@ -198,7 +208,8 @@ class SoundGroup extends FlxTypedGroup<FunkinSound>
function set_time(time:Float):Float
{
forEachAlive(function(snd:FunkinSound) {
forEachAlive(function(snd:FunkinSound)
{
// account for different offsets per sound?
snd.time = time;
});
@@ -233,7 +244,8 @@ class SoundGroup extends FlxTypedGroup<FunkinSound>
// in PlayState, adjust the code so that it only mutes the player1 vocal tracks?
function set_volume(volume:Float):Float
{
forEachAlive(function(snd:FunkinSound) {
forEachAlive(function(snd:FunkinSound)
{
snd.volume = volume;
});
@@ -249,7 +261,8 @@ class SoundGroup extends FlxTypedGroup<FunkinSound>
function set_muted(muted:Bool):Bool
{
forEachAlive(function(snd:FunkinSound) {
forEachAlive(function(snd:FunkinSound)
{
snd.muted = muted;
});
@@ -269,7 +282,8 @@ class SoundGroup extends FlxTypedGroup<FunkinSound>
{
#if FLX_PITCH
trace('Setting audio pitch to ' + val);
forEachAlive(function(snd:FunkinSound) {
forEachAlive(function(snd:FunkinSound)
{
snd.pitch = val;
});
#end
+21 -7
View File
@@ -6,6 +6,13 @@ import funkin.audio.waveform.WaveformData;
@:nullSafety
class VoicesGroup extends SoundGroup
{
/**
* Whenever or not the game is using the legacy vocals system (shared Voices.ogg)
*/
public var legacyVoiceSystem:Bool = false;
public var legacyVoiceUsesPlayer:Bool = false;
var playerVoices:Null<FlxTypedGroup<FunkinSound>>;
var opponentVoices:Null<FlxTypedGroup<FunkinSound>>;
@@ -47,7 +54,8 @@ class VoicesGroup extends SoundGroup
function set_playerVolume(volume:Float):Float
{
playerVoices?.forEachAlive(function(voice:FunkinSound) {
playerVoices?.forEachAlive(function(voice:FunkinSound)
{
voice.volume = volume;
});
return playerVolume = volume;
@@ -55,15 +63,18 @@ class VoicesGroup extends SoundGroup
override function set_time(time:Float):Float
{
forEachAlive(function(snd) {
forEachAlive(function(snd)
{
// account for different offsets per sound?
snd.time = time;
});
playerVoices?.forEachAlive(function(voice:FunkinSound) {
playerVoices?.forEachAlive(function(voice:FunkinSound)
{
voice.time -= playerVoicesOffset;
});
opponentVoices?.forEachAlive(function(voice:FunkinSound) {
opponentVoices?.forEachAlive(function(voice:FunkinSound)
{
voice.time -= opponentVoicesOffset;
});
@@ -72,7 +83,8 @@ class VoicesGroup extends SoundGroup
function set_playerVoicesOffset(offset:Float):Float
{
playerVoices?.forEachAlive(function(voice:FunkinSound) {
playerVoices?.forEachAlive(function(voice:FunkinSound)
{
voice.time += playerVoicesOffset;
voice.time -= offset;
});
@@ -81,7 +93,8 @@ class VoicesGroup extends SoundGroup
function set_opponentVoicesOffset(offset:Float):Float
{
opponentVoices?.forEachAlive(function(voice:FunkinSound) {
opponentVoices?.forEachAlive(function(voice:FunkinSound)
{
voice.time += opponentVoicesOffset;
voice.time -= offset;
});
@@ -99,7 +112,8 @@ class VoicesGroup extends SoundGroup
function set_opponentVolume(volume:Float):Float
{
opponentVoices?.forEachAlive(function(voice:FunkinSound) {
opponentVoices?.forEachAlive(function(voice:FunkinSound)
{
voice.volume = volume;
});
return opponentVolume = volume;
@@ -69,7 +69,8 @@ class SpectogramSprite extends FlxTypedSpriteGroup<FlxSprite>
default:
}
forEach(spr -> {
forEach(spr ->
{
spr.visible = spr.ID % wavOptimiz == 0;
});
+5 -6
View File
@@ -40,7 +40,8 @@ class VisShit
// helpers, note that spectrum indexes suppose non-negative frequencies
final binSize = fs / fftN;
final indexToFreq = function(k:Int) {
final indexToFreq = function(k:Int)
{
var powShit:Float = FlxMath.remapToRange(k, 0, halfN, 0, MathUtil.logBase(10, halfN)); // 4.3 is almost the log of 20Khz or so. Close enuf lol
return 1.0 * (Math.pow(10, powShit)); // we need the `1.0` to avoid overflows
@@ -49,7 +50,8 @@ class VisShit
// "melodic" band-pass filter
final minFreq = 20.70;
final maxFreq = 4000.01;
final melodicBandPass = function(k:Int, s:Float) {
final melodicBandPass = function(k:Int, s:Float)
{
final freq = indexToFreq(k);
final filter = freq > minFreq - binSize && freq < maxFreq + binSize ? 1 : 0;
return s;
@@ -62,10 +64,7 @@ class VisShit
while (c < samples.length)
{
// take a chunk (zero-padded if needed) and apply the window
final chunk = [
for (n in 0...fftN)
(c + n < samples.length ? samples[c + n] : 0.0) * window(n)
];
final chunk = [for (n in 0...fftN) (c + n < samples.length ? samples[c + n] : 0.0) * window(n)];
// compute positive spectrum with sampling correction and BP filter
final freqs = FFT.rfft(chunk).map(z -> z.scale(1 / fftN).magnitude).mapi(melodicBandPass);
+11 -22
View File
@@ -10,58 +10,48 @@ abstract Complex({
final imag:Float;
})
{
public inline function new(real:Float, imag:Float)
this = {real: real, imag: imag};
public inline function new(real:Float, imag:Float) this = {real: real, imag: imag};
/**
Makes a Complex number with the given Float as its real part and a zero imag part.
**/
@:from
public static inline function fromReal(r:Float)
return new Complex(r, 0);
public static inline function fromReal(r:Float) return new Complex(r, 0);
/**
Complex argument, in radians.
**/
public var angle(get, never):Float;
inline function get_angle()
return Math.atan2(this.imag, this.real);
inline function get_angle() return Math.atan2(this.imag, this.real);
/**
Complex module.
**/
public var magnitude(get, never):Float;
inline function get_magnitude()
return Math.sqrt(this.real * this.real + this.imag * this.imag);
inline function get_magnitude() return Math.sqrt(this.real * this.real + this.imag * this.imag);
@:op(A + B)
public inline function add(rhs:Complex):Complex
return new Complex(this.real + rhs.real, this.imag + rhs.imag);
public inline function add(rhs:Complex):Complex return new Complex(this.real + rhs.real, this.imag + rhs.imag);
@:op(A - B)
public inline function sub(rhs:Complex):Complex
return new Complex(this.real - rhs.real, this.imag - rhs.imag);
public inline function sub(rhs:Complex):Complex return new Complex(this.real - rhs.real, this.imag - rhs.imag);
@:op(A * B)
public inline function mult(rhs:Complex):Complex
return new Complex(this.real * rhs.real - this.imag * rhs.imag, this.real * rhs.imag + this.imag * rhs.real);
public inline function mult(rhs:Complex):Complex return new Complex(this.real * rhs.real - this.imag * rhs.imag, this.real * rhs.imag + this.imag * rhs.real);
/**
Returns the complex conjugate, does not modify this object.
**/
public inline function conj():Complex
return new Complex(this.real, -this.imag);
public inline function conj():Complex return new Complex(this.real, -this.imag);
/**
Multiplication by a real factor, does not modify this object.
**/
public inline function scale(k:Float):Complex
return new Complex(this.real * k, this.imag * k);
public inline function scale(k:Float):Complex return new Complex(this.real * k, this.imag * k);
public inline function copy():Complex
return new Complex(this.real, this.imag);
public inline function copy():Complex return new Complex(this.real, this.imag);
/**
The imaginary unit.
@@ -76,6 +66,5 @@ abstract Complex({
/**
Computes the complex exponential `e^(iw)`.
**/
public static inline function exp(w:Float)
return new Complex(Math.cos(w), Math.sin(w));
public static inline function exp(w:Float) return new Complex(Math.cos(w), Math.sin(w));
}
+2 -4
View File
@@ -19,8 +19,7 @@ class FFT
samples from the Discrete-Time Fourier Transform (DTFT) - which is Fs-periodic -
with a spacing of Fs/N Hz between them and a scaling factor of Fs.
**/
public static function fft(input:Array<Complex>):Array<Complex>
return do_fft(input, false);
public static function fft(input:Array<Complex>):Array<Complex> return do_fft(input, false);
/**
Like `fft`, but for a real (Float) sequence input.
@@ -41,8 +40,7 @@ class FFT
from each other, the result will consist of N data points as sampled
from a time signal at intervals of 1/Fs with a scaling factor of 1/Fs.
**/
public static function ifft(input:Array<Complex>):Array<Complex>
return do_fft(input, true);
public static function ifft(input:Array<Complex>):Array<Complex> return do_fft(input, true);
// Handles padding and scaling for forwards and inverse FFTs.
static function do_fft(input:Array<Complex>, inverse:Bool):Array<Complex>
@@ -12,35 +12,28 @@ abstract OffsetArray<T>({
final offset:Int;
})
{
public inline function new(array:Array<T>, offset:Int)
this = {array: array, offset: offset};
public inline function new(array:Array<T>, offset:Int) this = {array: array, offset: offset};
public var length(get, never):Int;
inline function get_length()
return this.array.length;
inline function get_length() return this.array.length;
@:arrayAccess
public inline function get(index:Int):T
return this.array[index - this.offset];
public inline function get(index:Int):T return this.array[index - this.offset];
@:arrayAccess
public inline function set(index:Int, value:T):Void
this.array[index - this.offset] = value;
public inline function set(index:Int, value:T):Void this.array[index - this.offset] = value;
/**
Iterates through items in their original order while providing the altered indexes as keys.
**/
public inline function keyValueIterator():KeyValueIterator<Int, T>
return new OffsetArrayIterator(this.array, this.offset);
public inline function keyValueIterator():KeyValueIterator<Int, T> return new OffsetArrayIterator(this.array, this.offset);
@:from
static inline function fromArray<T>(array:Array<T>)
return new OffsetArray(array, 0);
static inline function fromArray<T>(array:Array<T>) return new OffsetArray(array, 0);
@:to
inline function toArray()
return this.array;
inline function toArray() return this.array;
/**
Makes a shifted version of the given `array`, where elements are in the
@@ -76,12 +69,12 @@ private class OffsetArrayIterator<T>
this.enumeration = 0;
}
public inline function next():{key:Int, value:T}
public inline function next():
{key:Int, value:T}
{
final i = this.enumeration++;
return {key: i + this.offset, value: this.array[i]};
}
public inline function hasNext():Bool
return this.enumeration < this.array.length;
public inline function hasNext():Bool return this.enumeration < this.array.length;
}
+5 -10
View File
@@ -86,30 +86,25 @@ class Signal
/**
Returns the average value of an array.
**/
public static function mean(y:Array<Float>):Float
return sum(y) / y.length;
public static function mean(y:Array<Float>):Float return sum(y) / y.length;
/**
Returns the global maximum.
**/
public static function max(y:Array<Float>):Float
return y.fold(Math.max, y[0]);
public static function max(y:Array<Float>):Float return y.fold(Math.max, y[0]);
/**
Returns the global maximum's index.
**/
public static function maxi(y:Array<Float>):Int
return y.foldi((yi, m, i) -> yi > y[m] ? i : m, 0);
public static function maxi(y:Array<Float>):Int return y.foldi((yi, m, i) -> yi > y[m] ? i : m, 0);
/**
Returns the global minimum.
**/
public static function min(y:Array<Float>):Float
return y.fold(Math.min, y[0]);
public static function min(y:Array<Float>):Float return y.fold(Math.min, y[0]);
/**
Returns the global minimum's index.
**/
public static function mini(y:Array<Float>):Int
return y.foldi((yi, m, i) -> yi < y[m] ? i : m, 0);
public static function mini(y:Array<Float>):Int return y.foldi((yi, m, i) -> yi < y[m] ? i : m, 0);
}
@@ -3,10 +3,14 @@ package funkin.audio.waveform;
@:nullSafety
class WaveformDataParser
{
@:native("int16_max")
static final INT16_MAX:Int = 32767;
@:native("int16_min")
static final INT16_MIN:Int = -32768;
@:native("int8_max")
static final INT8_MAX:Int = 127;
@:native("int8_min")
static final INT8_MIN:Int = -128;
public static function interpretFlxSound(sound:Null<flixel.sound.FlxSound>):Null<WaveformData>
@@ -2,6 +2,7 @@ package funkin.audio.waveform;
import funkin.graphics.rendering.MeshRender;
import flixel.util.FlxColor;
import funkin.play.character.BaseCharacter.CharacterType;
/**
* A sprite which displays the waveform of audio data.
@@ -17,6 +18,8 @@ class WaveformSprite extends MeshRender
static final DEFAULT_WIDTH:Float = 100.0;
static final DEFAULT_HEIGHT:Float = 100.0;
public var iconId:CharacterType;
/**
* Set this to true to tell the waveform to rebuild itself.
* Do this any time the data or drawable area of the waveform changes.
+2 -1
View File
@@ -109,7 +109,8 @@ abstract class BaseRegistry<T:(IRegistryEntry<J> & Constructible<EntryConstructo
// UNSCRIPTED ENTRIES
//
var entryIdList:Array<String> = DataAssets.listDataFilesInPath('${dataFilePath}/');
var unscriptedEntryIds:Array<String> = entryIdList.filter(function(entryId:String):Bool {
var unscriptedEntryIds:Array<String> = entryIdList.filter(function(entryId:String):Bool
{
return !entries.exists(entryId);
});
log(' INFO '.info() + 'Parsing ${unscriptedEntryIds.length} unscripted entries...');
+1 -1
View File
@@ -53,7 +53,7 @@ class DataError
case TEnum(c):
trace(' ERROR '.error() + '(${Type.getEnumName(c)}) ${e.toString()}');
default:
trace(' ERROR '.error() + '(${Type.typeof(e)}) ${e.toString()}');
trace(' ERROR '.error() + '(${Type.typeof(e)}) ${Std.string(e)}');
}
}
+4 -5
View File
@@ -243,11 +243,10 @@ class DataParse
switch (json.value)
{
case JObject(fields):
var result:LegacyNoteSection =
{
mustHitSection: false,
sectionNotes: [],
};
var result:LegacyNoteSection = {
mustHitSection: false,
sectionNotes: [],
};
for (field in fields)
{
switch (field.name)
+3 -1
View File
@@ -6,4 +6,6 @@ package funkin.data;
* @see `funkin.data.BaseRegistry`
*/
@:autoBuild(funkin.util.macro.RegistryMacro.buildRegistry())
interface DefaultRegistryImpl {}
interface DefaultRegistryImpl
{
}
@@ -147,4 +147,20 @@ typedef UnnamedAnimationData =
@:default("framelabel")
@:optional
var animType:String;
/**
* The render type of the animation.
* Only available for multi-sparrow and multi-animateatlas characters.
* Options: "sparrow", "animateatlas"
*/
@:default("")
@:optional
var renderType:String;
/**
* Various settings for the sprite.
* Only available for texture atlases.
*/
@:optional
var atlasSettings:funkin.data.stage.StageData.TextureAtlasData;
}
+34 -33
View File
@@ -57,7 +57,8 @@ class CharacterDataParser
// UNSCRIPTED CHARACTERS
//
var charIdList:Array<String> = DataAssets.listDataFilesInPath('characters/');
var unscriptedCharIds:Array<String> = charIdList.filter(function(charId:String):Bool {
var unscriptedCharIds:Array<String> = charIdList.filter(function(charId:String):Bool
{
return !characterCache.exists(charId);
});
log('Fetching data for ${unscriptedCharIds.length} characters...');
@@ -93,7 +94,7 @@ class CharacterDataParser
{
try
{
var character:SparrowCharacter = ScriptedSparrowCharacter.init(charCls, DEFAULT_CHAR_ID);
var character:SparrowCharacter = ScriptedSparrowCharacter.scriptInit(charCls, DEFAULT_CHAR_ID);
log('Loaded character ${character.characterName} (scripted: $charCls)');
characterScriptedClass.set(character.characterId, charCls);
}
@@ -113,7 +114,7 @@ class CharacterDataParser
{
try
{
var character:PackerCharacter = ScriptedPackerCharacter.init(charCls, DEFAULT_CHAR_ID);
var character:PackerCharacter = ScriptedPackerCharacter.scriptInit(charCls, DEFAULT_CHAR_ID);
log('Loaded character ${character.characterName} (scripted: $charCls)');
characterScriptedClass.set(character.characterId, charCls);
}
@@ -133,7 +134,7 @@ class CharacterDataParser
{
try
{
var character:MultiSparrowCharacter = ScriptedMultiSparrowCharacter.init(charCls, DEFAULT_CHAR_ID);
var character:MultiSparrowCharacter = ScriptedMultiSparrowCharacter.scriptInit(charCls, DEFAULT_CHAR_ID);
log('Loaded character ${character.characterName} (scripted: $charCls)');
characterScriptedClass.set(character.characterId, charCls);
}
@@ -153,7 +154,7 @@ class CharacterDataParser
{
try
{
var character:AnimateAtlasCharacter = ScriptedAnimateAtlasCharacter.init(charCls, DEFAULT_CHAR_ID);
var character:AnimateAtlasCharacter = ScriptedAnimateAtlasCharacter.scriptInit(charCls, DEFAULT_CHAR_ID);
log('Loaded character ${character.characterName} (scripted: $charCls)');
characterScriptedClass.set(character.characterId, charCls);
}
@@ -173,7 +174,7 @@ class CharacterDataParser
{
try
{
var character:MultiAnimateAtlasCharacter = ScriptedMultiAnimateAtlasCharacter.init(charCls, DEFAULT_CHAR_ID);
var character:MultiAnimateAtlasCharacter = ScriptedMultiAnimateAtlasCharacter.scriptInit(charCls, DEFAULT_CHAR_ID);
log('Loaded character ${character.characterName} (scripted: $charCls)');
characterScriptedClass.set(character.characterId, charCls);
}
@@ -188,7 +189,8 @@ class CharacterDataParser
// NOTE: Only instantiate the ones not populated above.
// ScriptedBaseCharacter.listScriptClasses() will pick up scripts extending the other classes.
var scriptedCharClassNames:Array<String> = ScriptedBaseCharacter.listScriptClasses();
scriptedCharClassNames = scriptedCharClassNames.filter(function(charCls:String):Bool {
scriptedCharClassNames = scriptedCharClassNames.filter(function(charCls:String):Bool
{
return !(scriptedCharClassNames1.contains(charCls)
|| scriptedCharClassNames2.contains(charCls)
|| scriptedCharClassNames3.contains(charCls)
@@ -201,7 +203,7 @@ class CharacterDataParser
log('Instantiating ${scriptedCharClassNames.length} (Base) scripted characters...');
for (charCls in scriptedCharClassNames)
{
var character:BaseCharacter = ScriptedBaseCharacter.init(charCls, DEFAULT_CHAR_ID, Custom);
var character:BaseCharacter = ScriptedBaseCharacter.scriptInit(charCls, DEFAULT_CHAR_ID, Custom);
if (character == null)
{
log(' ERROR '.error() + 'Failed to initialize scripted character: $charCls');
@@ -245,18 +247,18 @@ class CharacterDataParser
if (charData != null) switch (charData.renderType)
{
case CharacterRenderType.AnimateAtlas:
char = ScriptedAnimateAtlasCharacter.init(charScriptClass, charId);
char = ScriptedAnimateAtlasCharacter.scriptInit(charScriptClass, charId);
case CharacterRenderType.MultiSparrow:
char = ScriptedMultiSparrowCharacter.init(charScriptClass, charId);
char = ScriptedMultiSparrowCharacter.scriptInit(charScriptClass, charId);
case CharacterRenderType.Sparrow:
char = ScriptedSparrowCharacter.init(charScriptClass, charId);
char = ScriptedSparrowCharacter.scriptInit(charScriptClass, charId);
case CharacterRenderType.Packer:
char = ScriptedPackerCharacter.init(charScriptClass, charId);
char = ScriptedPackerCharacter.scriptInit(charScriptClass, charId);
case CharacterRenderType.MultiAnimateAtlas:
char = ScriptedMultiAnimateAtlasCharacter.init(charScriptClass, charId);
char = ScriptedMultiAnimateAtlasCharacter.scriptInit(charScriptClass, charId);
default:
// We're going to assume that the script class does the rendering.
char = ScriptedBaseCharacter.init(charScriptClass, charId, CharacterRenderType.Custom);
char = ScriptedBaseCharacter.scriptInit(charScriptClass, charId, CharacterRenderType.Custom);
}
}
else
@@ -353,7 +355,8 @@ class CharacterDataParser
{
var frames = Paths.getSparrowAtlas(charPath);
var idleFrame:Null<FlxFrame> = frames.frames.find(function(frame:FlxFrame):Bool {
var idleFrame:Null<FlxFrame> = frames.frames.find(function(frame:FlxFrame):Bool
{
return frame.name.startsWith('idle');
});
@@ -463,14 +466,13 @@ class CharacterDataParser
public static final DEFAULT_STARTINGANIM:String = 'idle';
public static final DEFAULT_APPLYSTAGEMATRIX:Bool = false;
public static final DEFAULT_ANIMTYPE:String = "framelabel";
public static final DEFAULT_ATLASSETTINGS:funkin.data.stage.StageData.TextureAtlasData =
{
swfMode: true,
cacheOnLoad: false,
filterQuality: 1,
applyStageMatrix: false,
useRenderTexture: false
};
public static final DEFAULT_ATLASSETTINGS:funkin.data.stage.StageData.TextureAtlasData = {
swfMode: true,
cacheOnLoad: false,
filterQuality: 1,
applyStageMatrix: false,
useRenderTexture: false
};
/**
* Set unspecified parameters to their defaults.
@@ -528,14 +530,13 @@ class CharacterDataParser
if (input.healthIcon == null)
{
input.healthIcon =
{
id: null,
scale: null,
flipX: null,
isPixel: null,
offsets: null
};
input.healthIcon = {
id: null,
scale: null,
flipX: null,
isPixel: null,
offsets: null
};
}
if (input.healthIcon.id == null)
@@ -705,7 +706,7 @@ enum abstract CharacterRenderType(String) from String to String
typedef CharacterData =
{
/**
* The sematic version number of the character data JSON format.
* The semantic version number of the character data JSON format.
*/
var version:String;
@@ -723,7 +724,7 @@ typedef CharacterData =
/**
* Behavior varies by render type:
* - SPARROW: Path to retrieve both the spritesheet and the XML data from.
* - PACKER: Path to retrieve both the spritsheet and the TXT data from.
* - PACKER: Path to retrieve both the spritesheet and the TXT data from.
*/
var assetPath:String;
@@ -23,4 +23,6 @@ class SpeakerRegistry extends BaseRegistry<Speaker, SpeakerData, SpeakerEntryPar
}
}
typedef SpeakerEntryParams = {}
typedef SpeakerEntryParams =
{
}
+56 -17
View File
@@ -1,9 +1,13 @@
package funkin.data.event;
import funkin.play.event.SongEvent;
import flixel.util.FlxSort;
import funkin.data.song.SongData.SongEventData;
import funkin.util.macro.ClassMacro;
import funkin.modding.events.ScriptEvent;
import funkin.modding.events.ScriptEventDispatcher;
import funkin.play.event.ScriptedSongEvent;
import funkin.play.event.SongEvent;
import funkin.util.SortUtil;
import funkin.util.macro.ClassMacro;
/**
* This class statically handles the parsing of internal and scripted song event handlers.
@@ -64,7 +68,7 @@ class SongEventRegistry
for (eventCls in scriptedEventClassNames)
{
var event:SongEvent = ScriptedSongEvent.init(eventCls, "UKNOWN");
var event:SongEvent = ScriptedSongEvent.scriptInit(eventCls, "UKNOWN");
if (event != null)
{
@@ -108,8 +112,7 @@ class SongEventRegistry
public static function handleEvent(data:SongEventData):Void
{
var eventKind:String = data.eventKind;
var eventHandler:Null<SongEvent> = eventCache.get(eventKind);
var eventHandler:Null<SongEvent> = getEvent(data.eventKind);
if (eventHandler != null)
{
@@ -117,7 +120,7 @@ class SongEventRegistry
}
else
{
trace('WARNING: No event handler for event with kind: ${eventKind}');
trace('WARNING: No event handler for event with kind: ${data.eventKind}');
}
data.activated = true;
@@ -132,20 +135,40 @@ class SongEventRegistry
}
/**
* Given a list of song events and the current timestamp,
* return a list of events that should be handled.
* Caching the index for the next event to query greatly reduces lag.
* Kinda nasty that it's tied to a static class though.
*/
public static function queryEvents(events:Array<SongEventData>, currentTime:Float):Array<SongEventData>
static var nextEventIndex:Int = 0;
/**
* Retrieve the list of events to activate this frame.
*
* @param events The list of available song events.
* @param currentTime The current time in milliseconds.
* @param startIndex The index to start querying from.
* Defaults to the index of the last event handled.
* @return The list of events which haven't been handled yet.
*/
public static function queryEvents(events:Array<SongEventData>, currentTime:Float, ?startIndex:Int):Array<SongEventData>
{
return events.filter(function(event:SongEventData):Bool {
// If the event is already activated, don't activate it again.
if (event.activated) return false;
startIndex ??= nextEventIndex;
// If the event is in the future, don't activate it.
if (event.time > currentTime) return false;
var result:Array<SongEventData> = [];
return true;
});
for (i in startIndex...events.length)
{
if (events[i].activated) continue;
if (events[i].time > currentTime)
{
nextEventIndex = i;
return result;
}
result.push(events[i]);
}
return result;
}
/**
@@ -176,10 +199,26 @@ class SongEventRegistry
*/
public static function resetEvents(events:Array<SongEventData>):Void
{
events.sort(SortUtil.eventDataByTime.bind(FlxSort.ASCENDING));
nextEventIndex = 0;
allEventHandlers.resize(0);
for (event in events)
{
event.activated = false;
// TODO: Add an onReset() method to SongEvent?
var handler:Null<SongEvent> = getEvent(event.eventKind);
if (handler != null && !allEventHandlers.contains(handler)) allEventHandlers.push(handler);
}
}
static var allEventHandlers:Array<SongEvent> = [];
public static inline function callEvent(scriptEvent:ScriptEvent):Void
{
for (event in allEventHandlers)
{
ScriptEventDispatcher.callEvent(event, scriptEvent);
}
}
}
@@ -49,4 +49,10 @@ typedef AlbumData =
@:optional
@:default([])
public var albumTitleAnimations:Array<AnimationData>;
/**
* An optional override for the Freeplay OST text.
*/
@:optional
public var albumOSTName:String;
}
@@ -14,7 +14,7 @@ class AlbumRegistry extends BaseRegistry<Album, AlbumData, AlbumEntryParams> imp
* Handle breaking changes by incrementing this value
* and adding migration to the `migrateAlbumData()` function.
*/
public static final ALBUM_DATA_VERSION:thx.semver.Version = '1.0.0';
public static final ALBUM_DATA_VERSION:thx.semver.Version = '1.0.3';
public static final ALBUM_DATA_VERSION_RULE:thx.semver.VersionRule = '1.0.x';
@@ -24,4 +24,6 @@ class AlbumRegistry extends BaseRegistry<Album, AlbumData, AlbumEntryParams> imp
}
}
typedef AlbumEntryParams = {}
typedef AlbumEntryParams =
{
}
@@ -5,5 +5,17 @@ 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.3]
### Added
- Added `albumOSTName` to change the OST at the top right of the Freeplay menu.
## [1.0.2]
### Added
- Added `albumTitleOffsets` to change the horizontal and vertical position of the album title.
## [1.0.1]
### Added
- Added `albumTitleAnimations` to modify animation data for the album art.
## [1.0.0]
Initial release.
@@ -129,10 +129,10 @@ class PlayerFreeplayDJData
var charSelect:Null<PlayerFreeplayDJCharSelectData>;
@:optional
var cartoon:Null<PlayerFreeplayDJCartoonData>;
var fistPump:Null<PlayerFreeplayDJFistPumpData>;
@:optional
var fistPump:Null<PlayerFreeplayDJFistPumpData>;
public var atlasSettings:funkin.data.stage.StageData.TextureAtlasData;
@:optional
@:default("animateatlas")
@@ -142,12 +142,20 @@ class PlayerFreeplayDJData
@:default("")
public var scriptClass:Null<String>;
@:optional
@:default(false)
public var useAnimatePosition:Bool;
@:optional
@:default([0, 0])
var offsets:Array<Float>;
public function new()
{
animationMap = new Map();
}
function mapAnimations()
function mapAnimations():Void
{
if (animationMap == null) animationMap = new Map();
if (prefixToOffsetsMap == null) prefixToOffsetsMap = new Map();
@@ -161,17 +169,39 @@ class PlayerFreeplayDJData
}
}
public inline function getAssetPath():String
return assetPath; // return assetPath;
public inline function getAssetPath():String return assetPath; // return assetPath;
public inline function getAnimationsList():Array<AnimationData>
return animations;
public inline function getAnimationsList():Array<AnimationData> return animations;
public function useApplyStageMatrix():Bool
{
return applyStageMatrix;
}
public function getGlobalOffsets():Array<Float>
{
return offsets;
}
/**
* Normally, we'd let `FunkinSprite` handle the settings validation, but
* Freeplay DJs have a special case where the turntable lights use a movieclip
* that remains static without SWF mode enabled!
* So we have to manually validate the settings to have SWF mode enabled by default.
*
* @return The configuration for the texture atlas.
*/
public function getAtlasSettings():funkin.graphics.FunkinSprite.AtlasSpriteSettings
{
return {
swfMode: atlasSettings?.swfMode ?? true,
cacheOnLoad: atlasSettings?.cacheOnLoad ?? false,
filterQuality: cast atlasSettings?.filterQuality ?? animate.FlxAnimateFrames.FilterQuality.MEDIUM,
applyStageMatrix: atlasSettings?.applyStageMatrix ?? false,
useRenderTexture: atlasSettings?.useRenderTexture ?? false
}
}
public function getFreeplayDJText(index:Int):String
{
switch (index)
@@ -208,33 +238,6 @@ class PlayerFreeplayDJData
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;
@@ -406,15 +409,6 @@ 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)
@@ -148,4 +148,6 @@ class PlayerRegistry extends BaseRegistry<PlayableCharacter, PlayerData, PlayerE
}
}
typedef PlayerEntryParams = {}
typedef PlayerEntryParams =
{
}
@@ -25,4 +25,6 @@ class FreeplayStyleRegistry extends BaseRegistry<FreeplayStyle, FreeplayStyleDat
}
}
typedef FreeplayStyleEntryParams = {}
typedef FreeplayStyleEntryParams =
{
}
+11 -3
View File
@@ -219,9 +219,17 @@ typedef NoteStyleData_Countdown =
var audioPath:String;
}
typedef NoteStyleData_HoldNote = {}
typedef NoteStyleData_Judgement = {}
typedef NoteStyleData_ComboNum = {}
typedef NoteStyleData_HoldNote =
{
}
typedef NoteStyleData_Judgement =
{
}
typedef NoteStyleData_ComboNum =
{
}
/**
* Data on animations for each direction of the strumline.
@@ -31,4 +31,6 @@ class NoteStyleRegistry extends BaseRegistry<NoteStyle, NoteStyleData, NoteStyle
}
}
typedef NoteStyleEntryParams = {}
typedef NoteStyleEntryParams =
{
}
+35 -17
View File
@@ -1,11 +1,14 @@
package funkin.data.song;
import funkin.ui.debug.charting.ChartEditorState;
import funkin.data.event.SongEventRegistry;
import funkin.play.event.SongEvent;
import funkin.data.event.SongEventSchema;
import funkin.data.song.SongRegistry;
import thx.semver.Version;
import funkin.util.tools.ICloneable;
import funkin.play.notes.notekind.NoteKind;
import funkin.play.notes.notekind.NoteKindManager;
/**
* Data containing information about a song.
@@ -19,7 +22,6 @@ class SongMetadata implements ICloneable<SongMetadata>
* A semantic versioning string for the song data format.
*
*/
// @:default(funkin.data.song.SongRegistry.SONG_METADATA_VERSION)
@:jcustomparse(funkin.data.DataParse.semverVersion)
@:jcustomwrite(funkin.data.DataWrite.semverVersion)
public var version:Version;
@@ -53,7 +55,6 @@ class SongMetadata implements ICloneable<SongMetadata>
*/
public var playData:SongPlayData;
@:default(funkin.data.song.SongRegistry.DEFAULT_GENERATEDBY)
public var generatedBy:String;
@:optional
@@ -121,6 +122,18 @@ class SongMetadata implements ICloneable<SongMetadata>
// Update generatedBy and version before writing.
updateVersionToLatest();
// This might not be a very wise hack, but it works.
#if FEATURE_CHART_EDITOR
if (Std.isOfType(FlxG.state, ChartEditorState))
{
var state:ChartEditorState = cast(FlxG.state, ChartEditorState);
final songLength:Float = @:privateAccess state.songLengthInMs;
if (playData.previewStart > 1) playData.previewStart /= songLength;
if (playData.previewEnd > 1) playData.previewEnd /= songLength;
}
#end
var ignoreNullOptionals = true;
var writer = new json2object.JsonWriter<SongMetadata>(ignoreNullOptionals);
// I believe @:jignored should be ignored by the writer?
@@ -352,7 +365,6 @@ class SongMusicData implements ICloneable<SongMusicData>
* A semantic versioning string for the song data format.
*
*/
// @:default(funkin.data.song.SongRegistry.SONG_METADATA_VERSION)
@:jcustomparse(funkin.data.DataParse.semverVersion)
@:jcustomwrite(funkin.data.DataWrite.semverVersion)
public var version:Version;
@@ -463,6 +475,7 @@ class SongPlayData implements ICloneable<SongPlayData>
*/
@:optional
@:default(['normal' => 0])
@:order(funkin.util.Constants.DEFAULT_DIFFICULTY_LIST_FULL)
public var ratings:Map<String, Int>;
/**
@@ -485,17 +498,17 @@ class SongPlayData implements ICloneable<SongPlayData>
* @since `2.2.2`
*/
@:optional
@:default(0)
public var previewStart:Int;
@:default(funkin.util.Constants.DEFAULT_PREVIEW_START_TIME)
public var previewStart:Float;
/**
* The end time for the audio preview in Freeplay.
* Defaults to 15 seconds in.
* Defaults to 20% seconds in.
* @since `2.2.2`
*/
@:optional
@:default(15000)
public var previewEnd:Int;
@:default(funkin.util.Constants.DEFAULT_PREVIEW_END_TIME)
public var previewEnd:Float;
public function new()
{
@@ -568,7 +581,7 @@ class SongCharacterData implements ICloneable<SongCharacterData>
this.opponent = opponent;
this.instrumental = instrumental;
this.altInstrumentals = altInstrumentals;
this.altInstrumentals = altInstrumentals ?? [];
this.opponentVocals = opponentVocals;
this.playerVocals = playerVocals;
@@ -595,16 +608,16 @@ class SongCharacterData implements ICloneable<SongCharacterData>
class SongChartData implements ICloneable<SongChartData>
{
@:default(funkin.data.song.SongRegistry.SONG_CHART_DATA_VERSION)
@:jcustomparse(funkin.data.DataParse.semverVersion)
@:jcustomwrite(funkin.data.DataWrite.semverVersion)
public var version:Version;
@:order(funkin.util.Constants.DEFAULT_DIFFICULTY_LIST_FULL)
public var scrollSpeed:Map<String, Float>;
public var events:Array<SongEventData>;
@:order(funkin.util.Constants.DEFAULT_DIFFICULTY_LIST_FULL)
public var notes:Map<String, Array<SongNoteData>>;
@:default(funkin.data.song.SongRegistry.DEFAULT_GENERATEDBY)
public var generatedBy:String;
/**
@@ -782,7 +795,9 @@ class SongEventDataRaw implements ICloneable<SongEventDataRaw>
public function valueAsStruct(?defaultKey:String = "key"):Dynamic
{
if (this.value == null) return {};
if (this.value == null) return
{
};
if (Std.isOfType(this.value, Array))
{
var result:haxe.DynamicAccess<Dynamic> = {};
@@ -848,7 +863,7 @@ class SongEventDataRaw implements ICloneable<SongEventDataRaw>
public function getInt(key:String):Null<Int>
{
if (this.value == null) return null;
var result = Reflect.field(this.value, key);
var result:Any = Reflect.field(this.value, key);
if (result == null) return null;
if (Std.isOfType(result, Int)) return result;
if (Std.isOfType(result, String)) return Std.parseInt(cast result);
@@ -863,7 +878,7 @@ class SongEventDataRaw implements ICloneable<SongEventDataRaw>
public function getFloat(key:String):Null<Float>
{
if (this.value == null) return null;
var result = Reflect.field(this.value, key);
var result:Any = Reflect.field(this.value, key);
if (result == null) return null;
if (Std.isOfType(result, Float)) return result;
if (Std.isOfType(result, String)) return Std.parseFloat(cast result);
@@ -1303,12 +1318,15 @@ class SongNoteDataRaw implements ICloneable<SongNoteDataRaw>
*/
public function buildTooltip():String
{
if ((this.kind?.length ?? 0) == 0) return "";
if ((this.kind?.length ?? 0) == 0) return '';
var result:String = 'Kind: ${this.kind}';
var noteKind:Null<NoteKind> = NoteKindManager.getNoteKind(this.kind);
var noteKindDesc:String = noteKind?.description ?? this.kind;
var result:String = 'Kind: $noteKindDesc';
if (this.params.length == 0) return result;
result += "\nParams:";
result += '\nParams:';
for (param in params)
{
+87 -15
View File
@@ -24,7 +24,8 @@ class SongDataUtils
*/
public static function offsetSongNoteData(notes:Array<SongNoteData>, offset:Float):Array<SongNoteData>
{
var offsetNote = function(note:SongNoteData):SongNoteData {
var offsetNote = function(note:SongNoteData):SongNoteData
{
var time:Float = note.time + offset;
var data:Int = note.data;
var length:Float = note.length;
@@ -46,7 +47,8 @@ class SongDataUtils
*/
public static function offsetSongEventData(events:Array<SongEventData>, offset:Float):Array<SongEventData>
{
return events.map(function(event:SongEventData):SongEventData {
return events.map(function(event:SongEventData):SongEventData
{
return new SongEventData(event.time + offset, event.eventKind, event.value);
});
}
@@ -61,7 +63,8 @@ class SongDataUtils
*/
public static function clampSongNoteData(notes:Array<SongNoteData>, startTime:Float, endTime:Float):Array<SongNoteData>
{
return notes.filter(function(note:SongNoteData):Bool {
return notes.filter(function(note:SongNoteData):Bool
{
return note.time >= startTime && note.time <= endTime;
});
}
@@ -76,7 +79,8 @@ class SongDataUtils
*/
public static function clampSongEventData(events:Array<SongEventData>, startTime:Float, endTime:Float):Array<SongEventData>
{
return events.filter(function(event:SongEventData):Bool {
return events.filter(function(event:SongEventData):Bool
{
return event.time >= startTime && event.time <= endTime;
});
}
@@ -92,7 +96,8 @@ class SongDataUtils
{
if (notes.length == 0 || subtrahend.length == 0) return notes;
var result = notes.filter(function(note:SongNoteData):Bool {
var result = notes.filter(function(note:SongNoteData):Bool
{
for (x in subtrahend)
{
// The currently iterated note is in the subtrahend array.
@@ -117,7 +122,8 @@ class SongDataUtils
{
if (events.length == 0 || subtrahend.length == 0) return events;
return events.filter(function(event:SongEventData):Bool {
return events.filter(function(event:SongEventData):Bool
{
for (x in subtrahend)
{
// The currently iterated event is in the subtrahend array.
@@ -134,7 +140,8 @@ class SongDataUtils
*/
public static function flipNotes(notes:Array<SongNoteData>, strumlineSize:Int = 4):Array<SongNoteData>
{
return notes.map(function(note:SongNoteData):SongNoteData {
return notes.map(function(note:SongNoteData):SongNoteData
{
var newData = note.data;
if (newData < strumlineSize) newData += strumlineSize;
@@ -145,6 +152,63 @@ class SongDataUtils
});
}
/**
* Create an array of notes whose note data is mirrored.
* Does not mutate the original array.
*
* @param flip Flip the notes if the notes given are in both strumlines, so that result isn't inverted when mirrored.
* @param mirrorX Mirror along the X axis, aka the directions of the notes.
* @param mirrorY Mirror along the Y axis, aka the time of the notes.
*/
public static function mirrorNotes(notes:Array<SongNoteData>, strumlineSize:Int = 4, flip:Bool = false, mirrorX:Bool = true,
mirrorY:Bool = true):Array<SongNoteData>
{
var minTime = notes[0].time;
var maxTime = notes[0].time;
var minStrumline = notes[0].data;
var maxStrumline = notes[0].data;
for (note in notes)
{
// Find the maximum and minimum time and strumline positions
// I wish there was a better way of doing this
if (flip)
{
if (note.data < minStrumline) minStrumline = note.data;
else if (note.data > maxStrumline) maxStrumline = note.data;
}
if (note.time < minTime) minTime = note.time;
else if (note.time > maxTime) maxTime = note.time;
}
var timeDiff = minTime + (maxTime - minTime) / 2;
if (flip && minStrumline < strumlineSize && strumlineSize < maxStrumline)
{
// Flip the notes if one of the notes is on the other strum
// Otherwise they'll be inverted when mirrored
notes = flipNotes(notes);
}
return notes.map(function(note:SongNoteData):SongNoteData
{
var newData = note.data;
var newTime = note.time;
if (mirrorX)
{
if (newData < strumlineSize) newData = strumlineSize - 1 - newData;
else
newData = strumlineSize + strumlineSize * 2 - 1 - newData;
}
if (mirrorY)
{
if (newTime < timeDiff) newTime += (timeDiff - newTime) * 2;
else if (newTime > timeDiff) newTime -= (newTime - timeDiff) * 2;
}
return new SongNoteData(newTime, newData, note.length, note.kind);
});
}
/**
* Prepare an array of notes to be used as the clipboard data.
*
@@ -175,7 +239,8 @@ class SongDataUtils
public static function sortNotes(notes:Array<SongNoteData>, desc:Bool = false):Array<SongNoteData>
{
// TODO: Modifies the array in place. Is this okay?
notes.sort(function(a:SongNoteData, b:SongNoteData):Int {
notes.sort(function(a:SongNoteData, b:SongNoteData):Int
{
return FlxSort.byValues(desc ? FlxSort.DESCENDING : FlxSort.ASCENDING, a.time, b.time);
});
return notes;
@@ -187,7 +252,8 @@ class SongDataUtils
public static function sortEvents(events:Array<SongEventData>, desc:Bool = false):Array<SongEventData>
{
// TODO: Modifies the array in place. Is this okay?
events.sort(function(a:SongEventData, b:SongEventData):Int {
events.sort(function(a:SongEventData, b:SongEventData):Int
{
return FlxSort.byValues(desc ? FlxSort.DESCENDING : FlxSort.ASCENDING, a.time, b.time);
});
return events;
@@ -199,7 +265,8 @@ class SongDataUtils
public static function sortTimeChanges(timeChanges:Array<SongTimeChange>, desc:Bool = false):Array<SongTimeChange>
{
// TODO: Modifies the array in place. Is this okay?
timeChanges.sort(function(a:SongTimeChange, b:SongTimeChange):Int {
timeChanges.sort(function(a:SongTimeChange, b:SongTimeChange):Int
{
return FlxSort.byValues(desc ? FlxSort.DESCENDING : FlxSort.ASCENDING, a.timeStamp, b.timeStamp);
});
return timeChanges;
@@ -256,7 +323,8 @@ class SongDataUtils
*/
public static function getNotesInTimeRange(notes:Array<SongNoteData>, start:Float, end:Float):Array<SongNoteData>
{
return notes.filter(function(note:SongNoteData):Bool {
return notes.filter(function(note:SongNoteData):Bool
{
return note.time >= start && note.time <= end;
});
}
@@ -266,7 +334,8 @@ class SongDataUtils
*/
public static function getEventsInTimeRange(events:Array<SongEventData>, start:Float, end:Float):Array<SongEventData>
{
return events.filter(function(event:SongEventData):Bool {
return events.filter(function(event:SongEventData):Bool
{
return event.time >= start && event.time <= end;
});
}
@@ -276,7 +345,8 @@ class SongDataUtils
*/
public static function getNotesInDataRange(notes:Array<SongNoteData>, start:Int, end:Int):Array<SongNoteData>
{
return notes.filter(function(note:SongNoteData):Bool {
return notes.filter(function(note:SongNoteData):Bool
{
return note.data >= start && note.data <= end;
});
}
@@ -286,7 +356,8 @@ class SongDataUtils
*/
public static function getNotesWithData(notes:Array<SongNoteData>, data:Array<Int>):Array<SongNoteData>
{
return notes.filter(function(note:SongNoteData):Bool {
return notes.filter(function(note:SongNoteData):Bool
{
return data.indexOf(note.data) != -1;
});
}
@@ -296,7 +367,8 @@ class SongDataUtils
*/
public static function getEventsWithKind(events:Array<SongEventData>, kinds:Array<String>):Array<SongEventData>
{
return events.filter(function(event:SongEventData):Bool {
return events.filter(function(event:SongEventData):Bool
{
return kinds.indexOf(event.eventKind) != -1;
});
}
+6 -2
View File
@@ -85,10 +85,12 @@ using funkin.data.song.migrator.SongDataMigrator;
//
// UNSCRIPTED ENTRIES
//
var entryIdList:Array<String> = DataAssets.listDataFilesInPath('songs/', '-metadata.json').map(function(songDataPath:String):String {
var entryIdList:Array<String> = DataAssets.listDataFilesInPath('songs/', '-metadata.json').map(function(songDataPath:String):String
{
return songDataPath.split('/')[0];
});
var unscriptedEntryIds:Array<String> = entryIdList.filter(function(entryId:String):Bool {
var unscriptedEntryIds:Array<String> = entryIdList.filter(function(entryId:String):Bool
{
return !entries.exists(entryId);
});
log('Parsing ${unscriptedEntryIds.length} unscripted entries...');
@@ -563,6 +565,8 @@ using funkin.data.song.migrator.SongDataMigrator;
}
}
allDifficulties.sort(funkin.util.SortUtil.defaultsThenAlphabetically.bind(Constants.DEFAULT_DIFFICULTY_LIST_FULL));
if (allDifficulties.length == 0)
{
trace(' WARNING '.bold().bg_yellow() + ' No difficulties found. Returning default difficulty list.');
@@ -12,7 +12,6 @@ class ChartManifestData
public static final invalidIdRegex:EReg = ~/[\/\\:*?"<>|]/g;
@:default(funkin.data.song.importer.ChartManifestData.CHART_MANIFEST_DATA_VERSION)
@:jcustomparse(funkin.data.DataParse.semverVersion)
@:jcustomwrite(funkin.data.DataWrite.semverVersion)
public var version:thx.semver.Version;
@@ -27,7 +27,9 @@ class LegacySongData
public var notes:Either<Array<LegacyNoteSection>, LegacyNoteData>;
public var song:String; // Song name
public function new() {}
public function new()
{
}
public function toString():String
{
@@ -9,6 +9,7 @@ typedef OsuManiaData =
var General:
{
var PreviewTime:Int;
var Mode:Int; // Should only be 3 if you are sure this is a mania beatmap
};
var Editor:
{
@@ -31,7 +31,8 @@ class OsuManiaImporter
currentSection = sectionRegex.matched(1);
if (nonCSVLikeSections.contains(currentSection))
{
Reflect.setField(result, currentSection, {});
Reflect.setField(result, currentSection, {
});
}
else
{
@@ -45,8 +46,9 @@ class OsuManiaImporter
{
var parts:Array<String> = line.split(":");
var key:String = StringTools.trim(parts.shift());
var value:String = StringTools.trim(parts.join(":"));
if (Reflect.field(result, currentSection) == null) Reflect.setField(result, currentSection, {});
var value:Any = parseValue(StringTools.trim(parts.join(":")));
if (Reflect.field(result, currentSection) == null) Reflect.setField(result, currentSection, {
});
Reflect.setField(Reflect.field(result, currentSection), key, value);
}
// For CSV-like sections
@@ -163,7 +165,8 @@ class OsuManiaImporter
static function parseTimingPoints(timingLines:Array<String>):Array<TimingPoint>
{
return timingLines.map(function(line:String):TimingPoint {
return timingLines.map(function(line:String):TimingPoint
{
var parts = line.split(",");
var time = Std.parseFloat(parts[0]);
var beatLength = Std.parseFloat(parts[1]);
@@ -180,7 +183,8 @@ class OsuManiaImporter
static function parseManiaHitObjects(hitObjectsLines:Array<String>, ?columns:Int = 4):Array<ManiaHitObject>
{
return hitObjectsLines.map(function(line:String):ManiaHitObject {
return hitObjectsLines.map(function(line:String):ManiaHitObject
{
var parts = line.split(",");
var x:Int = Std.parseInt(parts[0]);
@@ -196,4 +200,22 @@ class OsuManiaImporter
return new ManiaHitObject(time, noteD, holdDuration);
});
}
static function parseValue(v:String):Any
{
var result:Null<Any>;
if (v.contains('.'))
{
result = Std.parseFloat(v);
if (!Math.isNaN(result)) return result;
}
else
{
result = Std.parseInt(v);
if (result != null) return result;
}
return v;
}
}
@@ -10,7 +10,6 @@ typedef StepManiaData =
var Credit:String;
var Banner:String;
var Background:String;
var Offset:Float;
var SampleStart:Float;
};
@@ -19,13 +18,15 @@ typedef StepManiaData =
var Difficulties:Array<StepDifficulty>;
}
enum StepManiaChartType {
enum StepManiaChartType
{
DanceSingle;
DanceDouble;
Unknown;
}
enum StepManiaNoteType {
enum StepManiaNoteType
{
Tap;
Head;
Tail;
@@ -44,7 +45,8 @@ class StepNote
{
this.beat = beat;
this.column = column;
switch (t) {
switch (t)
{
case "2":
this.type = StepManiaNoteType.Head;
case "3":
@@ -72,7 +74,8 @@ class StepDifficulty
public function parseChartType(chartTypeStr:String):StepManiaChartType
{
switch (chartTypeStr) {
switch (chartTypeStr)
{
case "dance-single":
return StepManiaChartType.DanceSingle;
case "dance-double":
@@ -5,7 +5,6 @@ import funkin.data.song.SongData.SongChartData;
import funkin.data.song.SongData.SongCharacterData;
import funkin.data.song.SongData.SongNoteData;
import funkin.data.song.SongData.SongTimeChange;
import funkin.data.song.importer.StepManiaData.StepTimingPoint;
import funkin.data.song.importer.StepManiaData.StepDifficulty;
import funkin.data.song.importer.StepManiaData.StepManiaChartType;
@@ -223,7 +222,6 @@ class StepManiaImporter
tp.endTimestamp = tp.startTimestamp;
tpIndex++;
}
}
}
else
@@ -324,7 +322,7 @@ class StepManiaImporter
SampleStart: 0
},
TimingPoints: [],
Stops: [],
Stops: [],
Difficulties: []
};
@@ -430,7 +428,6 @@ class StepManiaImporter
measure.push(line);
}
}
}
if (workingDiff != null && workingDiff.notes.length > 0)
@@ -484,8 +481,8 @@ class StepManiaImporter
return (time * 1000) - (offset * 1000); // convert to ms
}
static function convertStepNotes(offset:Float, type:StepManiaChartType, stepNotes:Array<StepNote>,
stepTimingPoints:Array<StepTimingPoint>, stepStops:Array<StepStop>):Array<SongNoteData>
static function convertStepNotes(offset:Float, type:StepManiaChartType, stepNotes:Array<StepNote>, stepTimingPoints:Array<StepTimingPoint>,
stepStops:Array<StepStop>):Array<SongNoteData>
{
var result:Array<SongNoteData> = [];
var holdArray:Array<Float> = [];
@@ -539,7 +536,6 @@ class StepManiaImporter
result.push(snd);
}
return result;
}
/**
@@ -592,7 +588,8 @@ class StepManiaImporter
* @param songData The StepManiaData to migrate.
* @return SongChartData The migrated SongChartData.
*/
public static function migrateChartData(songData:StepManiaData):SongChartData {
public static function migrateChartData(songData:StepManiaData):SongChartData
{
var scrollsMap:Map<String, Float> = new Map<String, Float>();
var stepNoteMap:Map<String, Array<SongNoteData>> = new Map<String, Array<SongNoteData>>();
@@ -49,7 +49,9 @@ class SongMetadata_v2_0_0
public var timeChanges:Array<SongData.SongTimeChange>;
public function new() {}
public function new()
{
}
/**
* Produces a string representation suitable for debugging.
@@ -88,7 +90,9 @@ class SongPlayData_v2_0_0
public var stage:String;
public function new() {}
public function new()
{
}
/**
* Produces a string representation suitable for debugging.
@@ -100,7 +100,9 @@ class SongPlayData_v2_1_0
public var characters:SongData.SongCharacterData;
public var stage:String;
public function new() {}
public function new()
{
}
/**
* Produces a string representation suitable for debugging.
+18 -21
View File
@@ -33,27 +33,24 @@ class StageData
function makeDefaultCharacters():StageDataCharacters
{
return {
bf:
{
zIndex: 0,
scale: 1,
position: [0, 0],
cameraOffsets: [-100, -100]
},
dad:
{
zIndex: 0,
scale: 1,
position: [0, 0],
cameraOffsets: [100, -100]
},
gf:
{
zIndex: 0,
scale: 1,
position: [0, 0],
cameraOffsets: [0, 0]
}
bf: {
zIndex: 0,
scale: 1,
position: [0, 0],
cameraOffsets: [-100, -100]
},
dad: {
zIndex: 0,
scale: 1,
position: [0, 0],
cameraOffsets: [100, -100]
},
gf: {
zIndex: 0,
scale: 1,
position: [0, 0],
cameraOffsets: [0, 0]
}
};
}
+3 -1
View File
@@ -23,4 +23,6 @@ class StageRegistry extends BaseRegistry<Stage, StageData, StageEntryParams> imp
}
}
typedef StageEntryParams = {}
typedef StageEntryParams =
{
}
@@ -82,7 +82,7 @@ class StickerRegistry extends BaseRegistry<StickerPack, StickerData, StickerEntr
function createScriptedEntry(clsName:String):StickerPack
{
return ScriptedStickerPack.init(clsName, 'unknown');
return ScriptedStickerPack.scriptInit(clsName, 'unknown');
}
function getScriptedClassNames():Array<String>
@@ -91,4 +91,6 @@ class StickerRegistry extends BaseRegistry<StickerPack, StickerData, StickerEntr
}
}
typedef StickerEntryParams = {}
typedef StickerEntryParams =
{
}
@@ -5,7 +5,12 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [1.0.2]
### Added
- Added `capsule` field to change the Level's capsule name on the Freeplay menu.
## [1.0.1]
### Added
- Added `visible` attribute.
## [1.0.0]
@@ -21,6 +21,13 @@ typedef LevelData =
*/
var name:String;
/**
* Optional data for how a level title is labeled on a capsule.
* Used when displaying songs in Freeplay.
*/
@:optional
var capsule:Null<LevelCapsuleData>;
/**
* The graphic for the level, as seen in the scrolling list.
*/
@@ -56,6 +63,24 @@ typedef LevelData =
var background:String;
}
/**
* Data for a level capsule text.
*/
typedef LevelCapsuleData =
{
/**
* The label for the capsule text.
*/
@:optional
var name:String;
/**
* The offset on the position to render the capsule text at.
*/
@:optional
var offsets:Array<Float>;
}
/**
* Data for a single prop for a story mode level.
*/
@@ -129,4 +154,11 @@ typedef LevelPropData =
@:default(false)
@:optional
var flipX:Null<Bool>;
/**
* Flips the sprite on Y axis.
*/
@:default(false)
@:optional
var flipY:Null<Bool>;
}
@@ -14,7 +14,7 @@ class LevelRegistry extends BaseRegistry<Level, LevelData, LevelEntryParams> imp
* Handle breaking changes by incrementing this value
* and adding migration to the `migrateLevelData()` function.
*/
public static final LEVEL_DATA_VERSION:thx.semver.Version = "1.0.1";
public static final LEVEL_DATA_VERSION:thx.semver.Version = "1.0.2";
public static final LEVEL_DATA_VERSION_RULE:thx.semver.VersionRule = ">=1.0.0 <1.1.0";
@@ -31,18 +31,7 @@ class LevelRegistry extends BaseRegistry<Level, LevelData, LevelEntryParams> imp
{
// This MUST be hard-coded (overriding the auto-generated method)
// because the auto-generated method spits out values in alphabetical order.
return [
'tutorial',
'week1',
'week2',
'week3',
'week4',
'week5',
'week6',
'week7',
'weekend1',
'sserafim'
];
return ['tutorial', 'week1', 'week2', 'week3', 'week4', 'week5', 'week6', 'week7', 'weekend1', 'sserafim'];
}
/**
@@ -58,4 +47,6 @@ class LevelRegistry extends BaseRegistry<Level, LevelData, LevelEntryParams> imp
}
}
typedef LevelEntryParams = {}
typedef LevelEntryParams =
{
}
+1 -1
View File
@@ -23,7 +23,7 @@ class FunkTrail extends FlxTrail
* @param alpha The alpha value for the very first trailsprite.
* @param diff How much lower the alpha of the next trailsprite is.
*/
public function new(target:FlxSprite, ?graphic:FlxGraphicAsset, length:Int = 10, delay:Int = 3, alpha:Float = 0.4, diff:Float = 0.05)
public function new(target:FlxSprite, ?graphic:FlxGraphicAsset, length:Int = 10, delay:Float = 0.1, alpha:Float = 0.4, diff:Float = 0.05)
{
super(target, graphic, length, delay, alpha, diff);
}
+3 -1
View File
@@ -236,5 +236,7 @@ class IntervalShake implements IFlxDestroyable
* Internal constructor. Use static methods.
*/
@:keep
function new() {}
function new()
{
}
}
+8 -4
View File
@@ -14,7 +14,8 @@ class RetroCameraFade
var steps:Int = 0;
var stepsTotal:Int = camSteps;
new FlxTimer().start(time / stepsTotal, _ -> {
new FlxTimer().start(time / stepsTotal, _ ->
{
var V:Float = (1 / stepsTotal) * steps;
if (steps == stepsTotal) V = 1;
@@ -42,7 +43,8 @@ class RetroCameraFade
];
camera.filters = [new ColorMatrixFilter(matrixDerp)];
new FlxTimer().start(time / stepsTotal, _ -> {
new FlxTimer().start(time / stepsTotal, _ ->
{
var V:Float = (1 / stepsTotal) * steps;
if (steps == stepsTotal) V = 1;
@@ -62,7 +64,8 @@ class RetroCameraFade
var steps:Int = 0;
var stepsTotal:Int = camSteps;
new FlxTimer().start(time / stepsTotal, _ -> {
new FlxTimer().start(time / stepsTotal, _ ->
{
var V:Float = (1 / stepsTotal) * steps;
if (steps == stepsTotal) V = 1;
@@ -90,7 +93,8 @@ class RetroCameraFade
];
camera.filters = [new ColorMatrixFilter(matrixDerp)];
new FlxTimer().start(time / stepsTotal, _ -> {
new FlxTimer().start(time / stepsTotal, _ ->
{
var V:Float = (1 / stepsTotal) * steps;
if (steps == stepsTotal) V = 1;
+3 -1
View File
@@ -66,7 +66,9 @@ class CallbackUtil #if (lime >= "8.0.0") implements JNISafety #end
}
@:noCompletion
private function new() {}
private function new()
{
}
@:noCompletion
@:keep

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