diff --git a/.gitignore b/.gitignore index 5f82e547..7dbb7d60 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ export/ -.vscode/ \ No newline at end of file +.vscode/ +APIStuff.hx \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 3898230a..875bc460 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,14 +1,16 @@ # Changelog All notable changes will be documented in this file. -## [Unreleased] +## [1.1.0] ### Added - 32bit support - Controller (dancepads) support - Pause screen - Main Menu overhaul - Cool intro screen thing +- Uh lots of bullshit +- Remind me to actually add this later lmaooo -## [0.1.0] - 2020-10-05 +## [1.0.0] - 2020-10-05 ### Added - Uh, everything. This the game's initial gamejam release. We put it out \ No newline at end of file diff --git a/Project.xml b/Project.xml index 06de8f4a..24bf5739 100644 --- a/Project.xml +++ b/Project.xml @@ -97,5 +97,6 @@ - + + diff --git a/art/FNF_main_menu_assets.fla b/art/FNF_main_menu_assets.fla index 8046fc5f..af724a86 100644 Binary files a/art/FNF_main_menu_assets.fla and b/art/FNF_main_menu_assets.fla differ diff --git a/art/Start_Screen_Assets.fla b/art/Start_Screen_Assets.fla new file mode 100644 index 00000000..e329a225 Binary files /dev/null and b/art/Start_Screen_Assets.fla differ diff --git a/art/build-Itch-HTML-RELEASE.bat b/art/build-Itch-HTML-RELEASE.bat new file mode 100644 index 00000000..4024c8c6 --- /dev/null +++ b/art/build-Itch-HTML-RELEASE.bat @@ -0,0 +1,11 @@ +@echo off +color 0a +cd .. +@echo on +echo BUILDING GAME +lime build html5 -release +echo UPLOADING TO ITCH +butler push ./export/release/html5/bin ninja-muffin24/funkin:html5 +butler status ninja-muffin24/funkin:html5 +echo ITCH SHIT UPDATED LMAOOOOO +pause \ No newline at end of file diff --git a/art/build-Itch-WINDOWS.bat b/art/build-Itch-WINDOWS.bat index f5dd696d..b2a07448 100644 --- a/art/build-Itch-WINDOWS.bat +++ b/art/build-Itch-WINDOWS.bat @@ -3,12 +3,12 @@ color 0a cd .. @echo on echo BUILDING GAME -lime build hl -debug +lime build windows -release echo UPLOADING 64 BIT VERSION TO ITCH -butler push ./export/debug/hl/bin ninja-muffin24/funkin:windows-64bit -lime build hl -debug -32 +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/debug/hl/bin ninja-muffin24/funkin:windows-32bit +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 diff --git a/art/thumbnailNewer.png b/art/thumbnailNewer.png new file mode 100644 index 00000000..a4196738 Binary files /dev/null and b/art/thumbnailNewer.png differ diff --git a/assets/data/bopeebo/bopeebo-easy.json b/assets/data/bopeebo/bopeebo-easy.json new file mode 100644 index 00000000..02ee15fd --- /dev/null +++ b/assets/data/bopeebo/bopeebo-easy.json @@ -0,0 +1 @@ +{"song":{"player2":"dad","player1":"bf","speed":1,"needsVoices":true,"sectionLengths":[],"song":"Bopeebo","notes":[{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[0,2,0],[600,3,450],[1050,3,600]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[2400,2,0],[3000,3,450],[3450,3,600]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[4800,1,300],[5400,0,300],[6000,3,300]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[7200,1,300],[7800,0,300],[8400,3,300]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[9600,1,150],[10200,3,0],[10500,0,0],[10800,1,450]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[12000,1,150],[12600,3,0],[12900,0,0],[13200,1,450]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[14400,3,0],[14700,1,0],[15300,0,0],[15600,2,300]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[16800,3,0],[17100,1,0],[17700,0,0],[18000,2,300]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[19200,0,0],[19500,3,0],[19800,1,750]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[21600,0,0],[21900,3,0],[22200,1,750]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[24000,1,0],[24300,3,0],[24600,0,750]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[26700,3,0],[27000,0,750],[26400,1,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[28800,2,0],[29100,3,0],[29400,0,1050]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[31200,2,0],[31500,3,0],[31800,0,1050]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[33600,0,0],[33900,3,0],[34500,2,0],[34800,1,450]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[36000,0,0],[36300,3,0],[36900,2,0],[37200,1,450]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[38400,2,450],[39000,3,300],[39600,0,450]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[40800,2,450],[41400,3,300],[42000,0,450]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[43200,1,0],[43800,2,0],[44400,1,0],[44550,1,0],[44700,1,0],[45000,2,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[45600,1,0],[46200,2,0],[46800,1,0],[46950,1,0],[47100,1,0],[47400,2,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[48000,2,450],[48600,3,300],[49200,0,450]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[50400,2,450],[51000,3,300],[51600,0,450]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[52800,3,1650]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[55200,3,1650],[55650,4,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[57600,2,0],[57900,3,0],[58200,0,1050]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[60000,2,0],[60300,3,0],[60600,0,1050],[62100,6,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[62400,0,0],[62700,3,0],[63300,2,0],[63600,1,450],[64500,6,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[64800,0,0],[65100,3,0],[65700,2,0],[66000,1,450]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[67200,2,0],[67500,3,0],[67800,0,0],[68100,2,0],[68400,1,450]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[69600,2,0],[69900,3,0],[70200,0,0],[70500,2,0],[70800,1,450],[71700,6,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[72000,0,0],[72300,3,0],[72900,2,0],[73200,1,450],[74100,6,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[74400,0,0],[74700,3,0],[75300,2,0],[75600,1,450]]},{"lengthInSteps":16,"bpm":100,"changeBPM":false,"mustHitSection":true,"sectionNotes":[],"typeOfSection":0}],"bpm":100,"sections":0},"bpm":100,"sections":33,"notes":[{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[0,2,0],[600,3,450],[1050,3,600]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[2400,2,0],[3000,3,450],[3450,3,600]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[4800,1,300],[5400,0,300],[6000,3,300]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[7200,1,300],[7800,0,300],[8400,3,300]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[9600,1,150],[10200,3,0],[10500,0,0],[10800,1,450]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[12000,1,150],[12600,3,0],[12900,0,0],[13200,1,450]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[14400,3,0],[14700,1,0],[15300,0,0],[15600,2,300]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[16800,3,0],[17100,1,0],[17700,0,0],[18000,2,300]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[19200,0,0],[19500,3,0],[19800,1,750]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[21600,0,0],[21900,3,0],[22200,1,750]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[24000,1,0],[24300,3,0],[24600,0,750]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[26700,3,0],[27000,0,750],[26400,1,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[28800,2,0],[29100,3,0],[29400,0,1050]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[31200,2,0],[31500,3,0],[31800,0,1050]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[33600,0,0],[33900,3,0],[34500,2,0],[34800,1,450]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[36000,0,0],[36300,3,0],[36900,2,0],[37200,1,450]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[38400,2,450],[39000,3,300],[39600,0,450]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[40800,2,450],[41400,3,300],[42000,0,450]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[43200,1,0],[43800,2,0],[44400,1,0],[44550,1,0],[44700,1,0],[45000,2,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[45600,1,0],[46200,2,0],[46800,1,0],[46950,1,0],[47100,1,0],[47400,2,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[48000,2,450],[48600,3,300],[49200,0,450]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[50400,2,450],[51000,3,300],[51600,0,450]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[52800,3,1650]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[55200,3,1650],[55650,4,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[57600,2,0],[57900,3,0],[58200,0,1050]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[60000,2,0],[60300,3,0],[60600,0,1050],[62100,6,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[62400,0,0],[62700,3,0],[63300,2,0],[63600,1,450],[64500,6,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[64800,0,0],[65100,3,0],[65700,2,0],[66000,1,450]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[67200,2,0],[67500,3,0],[67800,0,0],[68100,2,0],[68400,1,450]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[69600,2,0],[69900,3,0],[70200,0,0],[70500,2,0],[70800,1,450],[71700,6,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[72000,0,0],[72300,3,0],[72900,2,0],[73200,1,450],[74100,6,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[74400,0,0],[74700,3,0],[75300,2,0],[75600,1,450]]},{"lengthInSteps":16,"bpm":100,"changeBPM":false,"mustHitSection":true,"sectionNotes":[],"typeOfSection":0}]} \ No newline at end of file diff --git a/assets/data/bopeebo/bopeebo-hard.json b/assets/data/bopeebo/bopeebo-hard.json new file mode 100644 index 00000000..7c3d942d --- /dev/null +++ b/assets/data/bopeebo/bopeebo-hard.json @@ -0,0 +1 @@ +{"song":{"player2":"dad","player1":"bf","speed":1.6,"needsVoices":true,"sectionLengths":[],"song":"Bopeebo","notes":[{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[0,2,0],[600,3,450],[1050,3,600]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[2400,2,0],[3000,3,450],[3450,3,600]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[4800,1,300],[5400,0,300],[6000,3,300]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[7200,1,300],[7800,0,300],[8400,3,300]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[9600,1,150],[10200,3,0],[10500,0,0],[10800,1,450]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[12000,1,150],[12600,3,0],[12900,0,0],[13200,1,450]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[14400,3,0],[14700,1,0],[15300,0,0],[15600,2,300]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[16800,3,0],[17100,1,0],[17700,0,0],[18000,2,300]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[19200,0,0],[19500,3,0],[19800,1,750]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[21600,0,0],[21900,3,0],[22200,1,750]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[24000,1,0],[24300,3,0],[24600,0,750]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[26700,3,0],[27000,0,750],[26400,1,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[28800,2,0],[29100,3,0],[29400,0,1050]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[31200,2,0],[31500,3,0],[31800,0,1050]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[33600,0,0],[33900,3,0],[34500,2,0],[34800,1,450]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[36000,0,0],[36300,3,0],[36900,2,0],[37200,1,450]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[38400,2,450],[39000,3,300],[39600,0,450]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[40800,2,450],[41400,3,300],[42000,0,450]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[43200,1,0],[43800,2,0],[44400,1,0],[44550,1,0],[44700,1,0],[45000,2,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[45600,1,0],[46200,2,0],[46800,1,0],[46950,1,0],[47100,1,0],[47400,2,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[48000,2,450],[48600,3,300],[49200,0,450]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[50400,2,450],[51000,3,300],[51600,0,450]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[52800,3,1650]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[55200,3,1650],[55650,4,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[57600,2,0],[57900,3,0],[58200,0,1050]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[60000,2,0],[60300,3,0],[60600,0,1050],[62100,6,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[62400,0,0],[62700,3,0],[63300,2,0],[63600,1,450],[64500,6,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[64800,0,0],[65100,3,0],[65700,2,0],[66000,1,450]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[67200,2,0],[67500,3,0],[67800,0,0],[68100,2,0],[68400,1,450]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[69600,2,0],[69900,3,0],[70200,0,0],[70500,2,0],[70800,1,450],[71700,6,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[72000,0,0],[72300,3,0],[72900,2,0],[73200,1,450],[74100,6,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[74400,0,0],[74700,3,0],[75300,2,0],[75600,1,450]]},{"lengthInSteps":16,"bpm":100,"changeBPM":false,"mustHitSection":true,"sectionNotes":[],"typeOfSection":0}],"bpm":100,"sections":0},"bpm":100,"sections":33,"notes":[{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[0,2,0],[600,3,450],[1050,3,600]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[2400,2,0],[3000,3,450],[3450,3,600]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[4800,1,300],[5400,0,300],[6000,3,300]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[7200,1,300],[7800,0,300],[8400,3,300]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[9600,1,150],[10200,3,0],[10500,0,0],[10800,1,450]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[12000,1,150],[12600,3,0],[12900,0,0],[13200,1,450]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[14400,3,0],[14700,1,0],[15300,0,0],[15600,2,300]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[16800,3,0],[17100,1,0],[17700,0,0],[18000,2,300]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[19200,0,0],[19500,3,0],[19800,1,750]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[21600,0,0],[21900,3,0],[22200,1,750]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[24000,1,0],[24300,3,0],[24600,0,750]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[26700,3,0],[27000,0,750],[26400,1,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[28800,2,0],[29100,3,0],[29400,0,1050]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[31200,2,0],[31500,3,0],[31800,0,1050]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[33600,0,0],[33900,3,0],[34500,2,0],[34800,1,450]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[36000,0,0],[36300,3,0],[36900,2,0],[37200,1,450]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[38400,2,450],[39000,3,300],[39600,0,450]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[40800,2,450],[41400,3,300],[42000,0,450]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[43200,1,0],[43800,2,0],[44400,1,0],[44550,1,0],[44700,1,0],[45000,2,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[45600,1,0],[46200,2,0],[46800,1,0],[46950,1,0],[47100,1,0],[47400,2,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[48000,2,450],[48600,3,300],[49200,0,450]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[50400,2,450],[51000,3,300],[51600,0,450]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[52800,3,1650]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[55200,3,1650],[55650,4,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[57600,2,0],[57900,3,0],[58200,0,1050]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[60000,2,0],[60300,3,0],[60600,0,1050],[62100,6,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[62400,0,0],[62700,3,0],[63300,2,0],[63600,1,450],[64500,6,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[64800,0,0],[65100,3,0],[65700,2,0],[66000,1,450]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[67200,2,0],[67500,3,0],[67800,0,0],[68100,2,0],[68400,1,450]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[69600,2,0],[69900,3,0],[70200,0,0],[70500,2,0],[70800,1,450],[71700,6,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[72000,0,0],[72300,3,0],[72900,2,0],[73200,1,450],[74100,6,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[74400,0,0],[74700,3,0],[75300,2,0],[75600,1,450]]},{"lengthInSteps":16,"bpm":100,"changeBPM":false,"mustHitSection":true,"sectionNotes":[],"typeOfSection":0}]} \ No newline at end of file diff --git a/assets/data/south/south-easy.json b/assets/data/south/south-easy.json new file mode 100644 index 00000000..d64df96e --- /dev/null +++ b/assets/data/south/south-easy.json @@ -0,0 +1 @@ +{"song":{"song":"South","notes":[{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[11636.818181818182,3,0],[11999.818181818182,3,0],[12363.818181818182,0,0],[12726.818181818182,2,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[13101.818181818182,0,0],[13454.818181818182,1,0],[13817.818181818182,3,0],[13999.818181818182,3,0],[14181.818181818182,3,200]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[14545.818181818182,3,0],[14908.818181818182,3,0],[15272.818181818182,3,0],[15636.818181818182,0,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[16008.818181818182,0,0],[16363.818181818182,0,0],[16726.818181818184,2,0],[17090.818181818184,0,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[17455,3,0],[17818,3,0],[18182,0,0],[18545,2,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[18920,0,0],[19273,1,0],[19636,3,0],[19818,3,0],[20000,3,200]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[20364,3,0],[20727,3,0],[21091,3,0],[21455,0,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[21827,0,0],[22182,0,0],[22545,2,0],[22909,0,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[23273,2,0],[23636,0,0],[23818,0,0],[24000,2,0],[24364,2,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[24734,2,0],[25091,2,0],[25455,2,0],[25818,0,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[26193,0,0],[26545,0,0],[26727,0,0],[26909,3,0],[27273,1,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[27648,2,0],[28000,2,0],[28364,2,0],[28545,3,0],[28727,0,0],[28909,1,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[29091.181818181816,2,0],[29454.181818181816,0,0],[29636.181818181816,0,0],[29818.181818181816,2,0],[30182.181818181816,2,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[30552.181818181816,2,0],[30909.181818181816,2,0],[31273.181818181816,2,0],[31636.181818181816,0,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[32011.181818181816,0,0],[32363.181818181816,0,0],[32545.181818181816,0,0],[32727.181818181816,3,0],[33091.181818181816,1,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[33466.181818181816,2,0],[33818.181818181816,2,0],[34182.181818181816,2,0],[34363.181818181816,3,0],[34545.181818181816,0,0],[34727.181818181816,1,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[34918,2,0],[35273,0,0],[35455,2,0],[35636,3,0],[35818,0,0],[36000,2,0],[36182,3,0],[35091,3,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[36380,0,0],[36545,2,0],[36727,3,0],[36909,0,0],[37273,3,0],[37455,0,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[37834,2,0],[38000,3,0],[38182,0,0],[38364,2,0],[38545,3,0],[38727,0,0],[38909,2,0],[39091,3,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[39284,0,0],[39727,3,0],[39909,0,0],[40000,3,0],[40182,0,0],[40364,3,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[40736.181818181816,2,0],[40909.181818181816,3,0],[41091.181818181816,0,0],[41273.181818181816,2,0],[41454.181818181816,3,0],[41636.181818181816,0,0],[41818.181818181816,2,0],[42000.181818181816,3,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[42198.181818181816,0,0],[42363.181818181816,2,0],[42545.181818181816,3,0],[42727.181818181816,0,0],[42909.181818181816,0,0],[43091.181818181816,3,0],[43273.181818181816,0,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[43652.181818181816,2,0],[43818.181818181816,3,0],[44000.181818181816,0,0],[44182.181818181816,2,0],[44363.181818181816,3,0],[44545.181818181816,0,0],[44727.181818181816,2,0],[44909.181818181816,3,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[45102.181818181816,0,0],[45545.181818181816,3,0],[45727.181818181816,0,0],[45818.181818181816,3,0],[46000.181818181816,0,0],[46182.181818181816,3,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[46554.818181818184,0,0],[46908.818181818184,1,0],[47181.818181818184,0,0],[47454.818181818184,1,0],[47726.818181818184,2,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[48011.818181818184,0,0],[48181.818181818184,2,0],[48363.818181818184,3,0],[48545.818181818184,0,0],[48726.818181818184,3,0],[48908.818181818184,2,0],[49090.818181818184,0,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[49455,0,0],[49818,3,0],[50000,0,0],[50364,3,0],[50727,2,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[50914,1,0],[51273,0,0],[51455,3,0],[51727,2,0],[52091,0,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[52373,0,0],[52727,1,0],[53000,0,0],[53273,1,0],[53545,2,0],[53727,3,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[53830,0,0],[54000,2,0],[54182,3,0],[54364,0,0],[54545,3,0],[54727,2,0],[54909,0,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[55273.181818181816,0,0],[55636.181818181816,3,0],[55818.181818181816,0,0],[56182.181818181816,3,0],[56545.181818181816,2,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[56732.181818181816,1,0],[57091.181818181816,0,0],[57273.181818181816,3,0],[57545.181818181816,2,0],[57909.181818181816,0,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[58182.27272727273,3,0],[58545.27272727273,3,0],[58909.27272727273,0,0],[59272.27272727273,2,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[59647.27272727273,0,0],[60363.27272727273,3,0],[60545.27272727273,3,0],[60727.27272727273,3,200]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[61091.27272727273,3,0],[61454.27272727273,3,0],[62182.27272727273,0,0],[61727,2,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[62550,0,0],[63000,0,0],[63364,0,0],[63364,7,0],[63636,5,0],[63636,3,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[64000.454545454544,3,0],[64363.454545454544,3,0],[64727.454545454544,0,0],[65090.454545454544,2,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[65465.454545454544,0,0],[66181.45454545454,3,0],[66363.45454545454,3,0],[66545.45454545454,3,200]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[66909.45454545454,3,0],[67272.45454545454,3,0],[68000.45454545454,0,0],[67545.18181818182,2,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[68368.18181818182,0,0],[68818.18181818182,0,0],[69182.18181818182,0,0],[69454.18181818182,3,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[69818.45454545454,2,0],[70181.45454545454,0,0],[70363.45454545454,0,0],[70545.45454545454,2,0],[70909.45454545454,2,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[71279.45454545454,2,0],[71636.45454545454,2,0],[72000.45454545454,2,0],[72363.45454545454,0,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[72738.45454545454,0,0],[73090.45454545454,0,0],[73272.45454545454,0,0],[73454.45454545454,3,0],[73818.45454545454,1,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[74195,2,0],[74364,3,0],[74727,0,0],[74909,1,0],[75273,0,0],[75455,3,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[75636.63636363637,2,0],[75999.63636363637,0,0],[76181.63636363637,0,0],[76363.63636363637,2,0],[76727.63636363637,2,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[77097.63636363637,2,0],[77454.63636363637,2,0],[77818.63636363637,2,0],[78181.63636363637,0,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[78556.63636363637,0,0],[78908.63636363637,0,0],[79090.63636363637,0,0],[79272.63636363637,3,0],[79636.63636363637,1,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[80013.18181818182,2,0],[80182.18181818182,3,0],[80545.18181818182,0,0],[80727.18181818182,1,0],[81091.18181818182,0,0],[81273.18181818182,3,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[]},{"lengthInSteps":16,"bpm":165,"changeBPM":false,"mustHitSection":true,"sectionNotes":[],"typeOfSection":0},{"lengthInSteps":16,"bpm":165,"changeBPM":false,"mustHitSection":true,"sectionNotes":[],"typeOfSection":0},{"lengthInSteps":16,"bpm":165,"changeBPM":false,"mustHitSection":true,"sectionNotes":[],"typeOfSection":0}],"bpm":165,"sections":0,"needsVoices":true,"player1":"bf","player2":"spooky","sectionLengths":[],"speed":1.1},"bpm":165,"sections":63,"notes":[{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[11636.818181818182,3,0],[11999.818181818182,3,0],[12363.818181818182,0,0],[12726.818181818182,2,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[13101.818181818182,0,0],[13454.818181818182,1,0],[13817.818181818182,3,0],[13999.818181818182,3,0],[14181.818181818182,3,200]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[14545.818181818182,3,0],[14908.818181818182,3,0],[15272.818181818182,3,0],[15636.818181818182,0,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[16008.818181818182,0,0],[16363.818181818182,0,0],[16726.818181818184,2,0],[17090.818181818184,0,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[17455,3,0],[17818,3,0],[18182,0,0],[18545,2,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[18920,0,0],[19273,1,0],[19636,3,0],[19818,3,0],[20000,3,200]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[20364,3,0],[20727,3,0],[21091,3,0],[21455,0,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[21827,0,0],[22182,0,0],[22545,2,0],[22909,0,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[23273,2,0],[23636,0,0],[23818,0,0],[24000,2,0],[24364,2,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[24734,2,0],[25091,2,0],[25455,2,0],[25818,0,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[26193,0,0],[26545,0,0],[26727,0,0],[26909,3,0],[27273,1,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[27648,2,0],[28000,2,0],[28364,2,0],[28545,3,0],[28727,0,0],[28909,1,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[29091.181818181816,2,0],[29454.181818181816,0,0],[29636.181818181816,0,0],[29818.181818181816,2,0],[30182.181818181816,2,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[30552.181818181816,2,0],[30909.181818181816,2,0],[31273.181818181816,2,0],[31636.181818181816,0,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[32011.181818181816,0,0],[32363.181818181816,0,0],[32545.181818181816,0,0],[32727.181818181816,3,0],[33091.181818181816,1,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[33466.181818181816,2,0],[33818.181818181816,2,0],[34182.181818181816,2,0],[34363.181818181816,3,0],[34545.181818181816,0,0],[34727.181818181816,1,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[34918,2,0],[35273,0,0],[35455,2,0],[35636,3,0],[35818,0,0],[36000,2,0],[36182,3,0],[35091,3,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[36380,0,0],[36545,2,0],[36727,3,0],[36909,0,0],[37273,3,0],[37455,0,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[37834,2,0],[38000,3,0],[38182,0,0],[38364,2,0],[38545,3,0],[38727,0,0],[38909,2,0],[39091,3,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[39284,0,0],[39727,3,0],[39909,0,0],[40000,3,0],[40182,0,0],[40364,3,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[40736.181818181816,2,0],[40909.181818181816,3,0],[41091.181818181816,0,0],[41273.181818181816,2,0],[41454.181818181816,3,0],[41636.181818181816,0,0],[41818.181818181816,2,0],[42000.181818181816,3,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[42198.181818181816,0,0],[42363.181818181816,2,0],[42545.181818181816,3,0],[42727.181818181816,0,0],[42909.181818181816,0,0],[43091.181818181816,3,0],[43273.181818181816,0,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[43652.181818181816,2,0],[43818.181818181816,3,0],[44000.181818181816,0,0],[44182.181818181816,2,0],[44363.181818181816,3,0],[44545.181818181816,0,0],[44727.181818181816,2,0],[44909.181818181816,3,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[45102.181818181816,0,0],[45545.181818181816,3,0],[45727.181818181816,0,0],[45818.181818181816,3,0],[46000.181818181816,0,0],[46182.181818181816,3,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[46554.818181818184,0,0],[46908.818181818184,1,0],[47181.818181818184,0,0],[47454.818181818184,1,0],[47726.818181818184,2,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[48011.818181818184,0,0],[48181.818181818184,2,0],[48363.818181818184,3,0],[48545.818181818184,0,0],[48726.818181818184,3,0],[48908.818181818184,2,0],[49090.818181818184,0,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[49455,0,0],[49818,3,0],[50000,0,0],[50364,3,0],[50727,2,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[50914,1,0],[51273,0,0],[51455,3,0],[51727,2,0],[52091,0,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[52373,0,0],[52727,1,0],[53000,0,0],[53273,1,0],[53545,2,0],[53727,3,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[53830,0,0],[54000,2,0],[54182,3,0],[54364,0,0],[54545,3,0],[54727,2,0],[54909,0,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[55273.181818181816,0,0],[55636.181818181816,3,0],[55818.181818181816,0,0],[56182.181818181816,3,0],[56545.181818181816,2,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[56732.181818181816,1,0],[57091.181818181816,0,0],[57273.181818181816,3,0],[57545.181818181816,2,0],[57909.181818181816,0,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[58182.27272727273,3,0],[58545.27272727273,3,0],[58909.27272727273,0,0],[59272.27272727273,2,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[59647.27272727273,0,0],[60363.27272727273,3,0],[60545.27272727273,3,0],[60727.27272727273,3,200]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[61091.27272727273,3,0],[61454.27272727273,3,0],[62182.27272727273,0,0],[61727,2,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[62550,0,0],[63000,0,0],[63364,0,0],[63364,7,0],[63636,5,0],[63636,3,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[64000.454545454544,3,0],[64363.454545454544,3,0],[64727.454545454544,0,0],[65090.454545454544,2,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[65465.454545454544,0,0],[66181.45454545454,3,0],[66363.45454545454,3,0],[66545.45454545454,3,200]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[66909.45454545454,3,0],[67272.45454545454,3,0],[68000.45454545454,0,0],[67545.18181818182,2,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[68368.18181818182,0,0],[68818.18181818182,0,0],[69182.18181818182,0,0],[69454.18181818182,3,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[69818.45454545454,2,0],[70181.45454545454,0,0],[70363.45454545454,0,0],[70545.45454545454,2,0],[70909.45454545454,2,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[71279.45454545454,2,0],[71636.45454545454,2,0],[72000.45454545454,2,0],[72363.45454545454,0,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[72738.45454545454,0,0],[73090.45454545454,0,0],[73272.45454545454,0,0],[73454.45454545454,3,0],[73818.45454545454,1,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[74195,2,0],[74364,3,0],[74727,0,0],[74909,1,0],[75273,0,0],[75455,3,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[75636.63636363637,2,0],[75999.63636363637,0,0],[76181.63636363637,0,0],[76363.63636363637,2,0],[76727.63636363637,2,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[77097.63636363637,2,0],[77454.63636363637,2,0],[77818.63636363637,2,0],[78181.63636363637,0,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[78556.63636363637,0,0],[78908.63636363637,0,0],[79090.63636363637,0,0],[79272.63636363637,3,0],[79636.63636363637,1,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[80013.18181818182,2,0],[80182.18181818182,3,0],[80545.18181818182,0,0],[80727.18181818182,1,0],[81091.18181818182,0,0],[81273.18181818182,3,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[]},{"lengthInSteps":16,"bpm":165,"changeBPM":false,"mustHitSection":true,"sectionNotes":[],"typeOfSection":0},{"lengthInSteps":16,"bpm":165,"changeBPM":false,"mustHitSection":true,"sectionNotes":[],"typeOfSection":0},{"lengthInSteps":16,"bpm":165,"changeBPM":false,"mustHitSection":true,"sectionNotes":[],"typeOfSection":0}]} \ No newline at end of file diff --git a/assets/data/south/south-hard.json b/assets/data/south/south-hard.json new file mode 100644 index 00000000..b6fd4351 --- /dev/null +++ b/assets/data/south/south-hard.json @@ -0,0 +1 @@ +{"song":{"song":"South","notes":[{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[11636.818181818182,3,0],[11999.818181818182,3,0],[12363.818181818182,0,0],[12545.818181818182,3,0],[12726.818181818182,2,0],[12908.818181818182,3,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[13101.818181818182,0,0],[13454.818181818182,1,0],[13817.818181818182,3,0],[13999.818181818182,3,0],[14181.818181818182,3,200]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[14545.818181818182,3,0],[14908.818181818182,3,0],[15272.818181818182,3,0],[15454.818181818182,2,0],[15636.818181818182,0,0],[15817.818181818182,1,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[16008.818181818182,0,0],[16363.818181818182,0,0],[16726.818181818184,2,0],[17090.818181818184,0,0],[17272.818181818184,3,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[17455,3,0],[17818,3,0],[18182,0,0],[18364,3,0],[18545,2,0],[18727,3,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[18920,0,0],[19273,1,0],[19636,3,0],[19818,3,0],[20000,3,200]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[20364,3,0],[20727,3,0],[21091,3,0],[21273,2,0],[21455,0,0],[21636,1,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[21827,0,0],[22182,0,0],[22545,2,0],[22909,0,0],[23091,3,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[23273,2,0],[23455,1,0],[23636,0,0],[23818,0,0],[23909,3,0],[24000,2,0],[24182,0,0],[24364,2,0],[24545,1,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[24734,2,0],[25091,2,0],[25455,2,0],[25636,1,0],[25818,0,0],[26000,3,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[26193,0,0],[26545,0,0],[26727,0,0],[26818,2,0],[26909,3,0],[27000,0,0],[27273,1,0],[27455,3,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[27648,2,0],[28000,2,0],[28364,2,0],[28545,3,0],[28727,0,0],[28909,1,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[29091.181818181816,2,0],[29273.181818181816,1,0],[29454.181818181816,0,0],[29636.181818181816,0,0],[29727.181818181816,3,0],[29818.181818181816,2,0],[30000.181818181816,0,0],[30182.181818181816,2,0],[30363.181818181816,1,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[30552.181818181816,2,0],[30909.181818181816,2,0],[31273.181818181816,2,0],[31454.181818181816,1,0],[31636.181818181816,0,0],[31818.181818181816,3,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[32011.181818181816,0,0],[32363.181818181816,0,0],[32545.181818181816,0,0],[32636.181818181816,2,0],[32727.181818181816,3,0],[32818.181818181816,0,0],[33091.181818181816,1,0],[33273.181818181816,3,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[33466.181818181816,2,0],[33818.181818181816,2,0],[34182.181818181816,2,0],[34363.181818181816,3,0],[34545.181818181816,0,0],[34727.181818181816,1,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[34918,2,0],[35091,3,0],[35273,0,0],[35455,2,0],[35636,3,0],[35818,0,0],[36000,2,0],[36182,3,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[36380,0,0],[36545,2,0],[36727,3,0],[36909,0,0],[37091,0,0],[37273,3,0],[37455,0,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[37834,2,0],[38000,3,0],[38182,0,0],[38364,2,0],[38545,3,0],[38727,0,0],[38909,2,0],[39091,3,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[39284,0,0],[39727,3,0],[39909,0,0],[40000,3,0],[40182,0,0],[40364,3,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[40736.181818181816,2,0],[40909.181818181816,3,0],[41091.181818181816,0,0],[41273.181818181816,2,0],[41454.181818181816,3,0],[41636.181818181816,0,0],[41818.181818181816,2,0],[42000.181818181816,3,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[42198.181818181816,0,0],[42363.181818181816,2,0],[42545.181818181816,3,0],[42727.181818181816,0,0],[42909.181818181816,0,0],[43091.181818181816,3,0],[43273.181818181816,0,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[43652.181818181816,2,0],[43818.181818181816,3,0],[44000.181818181816,0,0],[44182.181818181816,2,0],[44363.181818181816,3,0],[44545.181818181816,0,0],[44727.181818181816,2,0],[44909.181818181816,3,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[45102.181818181816,0,0],[45545.181818181816,3,0],[45727.181818181816,0,0],[45818.181818181816,3,0],[46000.181818181816,0,0],[46182.181818181816,3,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[46554.818181818184,0,0],[46817.818181818184,3,0],[46908.818181818184,1,0],[47181.818181818184,0,0],[47363.818181818184,3,0],[47454.818181818184,1,0],[47726.818181818184,2,0],[47908.818181818184,3,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[48011.818181818184,0,0],[48181.818181818184,2,0],[48363.818181818184,3,0],[48545.818181818184,0,0],[48726.818181818184,3,0],[48908.818181818184,2,0],[49090.818181818184,0,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[49545,3,0],[49455,0,0],[49636,2,0],[49818,3,0],[50000,0,0],[50182,2,0],[50364,3,0],[50545,0,0],[50636,3,0],[50727,2,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[50914,1,0],[51273,0,0],[51455,3,0],[51727,2,0],[51909,3,0],[52091,0,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[52373,0,0],[52636,3,0],[52727,1,0],[53000,0,0],[53182,3,0],[53273,1,0],[53545,2,0],[53727,3,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[53830,0,0],[54000,2,0],[54182,3,0],[54364,0,0],[54545,3,0],[54727,2,0],[54909,0,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[55363.181818181816,3,0],[55273.181818181816,0,0],[55454.181818181816,2,0],[55636.181818181816,3,0],[55818.181818181816,0,0],[56000.181818181816,2,0],[56182.181818181816,3,0],[56363.181818181816,0,0],[56454.181818181816,3,0],[56545.181818181816,2,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[56732.181818181816,1,0],[57091.181818181816,0,0],[57273.181818181816,3,0],[57545.181818181816,2,0],[57727.181818181816,3,0],[57909.181818181816,0,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[58182,3,0],[58545,3,0],[59000,2,0],[59091,0,0],[58727,1,0],[59364,1,0],[59455,3,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[59657,0,272.7272727272727],[60000,2,0],[60364,2,0],[60545,2,0],[60727,2,181.8181818181818]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[61100,2,0],[61455,2,0],[61636,3,0],[61818,1,0],[62000,0,0],[62182,3,0],[62364,0,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[62550,0,0],[63000,0,0],[63727,0,0],[63364,0,0],[63364,7,0],[63545,3,0],[63818,2,0],[63636,5,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[64000.181818181816,3,0],[64363.181818181816,3,0],[64818.181818181816,2,0],[64909.181818181816,0,0],[64545.181818181816,1,0],[65182.181818181816,1,0],[65273.181818181816,3,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[65475.181818181816,0,272.7272727272727],[65818.18181818182,2,0],[66182.18181818182,2,0],[66363.18181818182,2,0],[66545.18181818182,2,181.8181818181818]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[66918.18181818182,2,0],[67273.18181818182,2,0],[67454.18181818182,3,0],[67636.18181818182,1,0],[67818.18181818182,0,0],[68000.18181818182,3,0],[68182.18181818182,0,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[68368.18181818182,0,0],[68818.18181818182,0,0],[69545.18181818182,0,0],[69182.18181818182,0,0],[69182.18181818182,7,0],[69363.18181818182,3,0],[69636.18181818182,2,0],[69454.18181818182,5,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[69825,2,0],[70000,3,0],[70273,0,0],[70364,3,0],[70545,2,0],[70636,0,0],[71000,2,0],[70727,3,0],[71091,3,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[71280,2,0],[71636,2,0],[71818,0,0],[72091,2,0],[72273,3,0],[72364,0,0],[72545,2,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[72732,0,0],[73091,0,0],[73273,0,0],[73455,2,0],[73364,3,0],[73636,3,0],[73818,2,0],[74000,0,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[74195,2,0],[74364,3,0],[74545,2,0],[74727,0,0],[74909,1,0],[75091,3,0],[75273,0,0],[75455,3,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[75643.18181818182,2,0],[75818.18181818182,3,0],[76091.18181818182,0,0],[76182.18181818182,3,0],[76363.18181818182,2,0],[76454.18181818182,0,0],[76818.18181818182,2,0],[76545.18181818182,3,0],[76909.18181818182,3,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[77098.18181818182,2,0],[77454.18181818182,2,0],[77636.18181818182,0,0],[77909.18181818182,2,0],[78091.18181818182,3,0],[78182.18181818182,0,0],[78363.18181818182,2,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[78550.18181818182,0,0],[78909.18181818182,0,0],[79091.18181818182,0,0],[79273.18181818182,2,0],[79182.18181818182,3,0],[79454.18181818182,3,0],[79636.18181818182,2,0],[79818.18181818182,0,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[80013.18181818182,2,0],[80182.18181818182,3,0],[80363.18181818182,2,0],[80545.18181818182,0,0],[80727.18181818182,1,0],[80909.18181818182,3,0],[81091.18181818182,0,0],[81273.18181818182,3,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[]},{"lengthInSteps":16,"bpm":165,"changeBPM":false,"mustHitSection":true,"sectionNotes":[],"typeOfSection":0},{"lengthInSteps":16,"bpm":165,"changeBPM":false,"mustHitSection":true,"sectionNotes":[],"typeOfSection":0}],"bpm":165,"sections":0,"needsVoices":true,"player1":"bf","player2":"spooky","sectionLengths":[],"speed":2.200000000000001},"bpm":165,"sections":62,"notes":[{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[11636.818181818182,3,0],[11999.818181818182,3,0],[12363.818181818182,0,0],[12545.818181818182,3,0],[12726.818181818182,2,0],[12908.818181818182,3,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[13101.818181818182,0,0],[13454.818181818182,1,0],[13817.818181818182,3,0],[13999.818181818182,3,0],[14181.818181818182,3,200]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[14545.818181818182,3,0],[14908.818181818182,3,0],[15272.818181818182,3,0],[15454.818181818182,2,0],[15636.818181818182,0,0],[15817.818181818182,1,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[16008.818181818182,0,0],[16363.818181818182,0,0],[16726.818181818184,2,0],[17090.818181818184,0,0],[17272.818181818184,3,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[17455,3,0],[17818,3,0],[18182,0,0],[18364,3,0],[18545,2,0],[18727,3,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[18920,0,0],[19273,1,0],[19636,3,0],[19818,3,0],[20000,3,200]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[20364,3,0],[20727,3,0],[21091,3,0],[21273,2,0],[21455,0,0],[21636,1,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[21827,0,0],[22182,0,0],[22545,2,0],[22909,0,0],[23091,3,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[23273,2,0],[23455,1,0],[23636,0,0],[23818,0,0],[23909,3,0],[24000,2,0],[24182,0,0],[24364,2,0],[24545,1,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[24734,2,0],[25091,2,0],[25455,2,0],[25636,1,0],[25818,0,0],[26000,3,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[26193,0,0],[26545,0,0],[26727,0,0],[26818,2,0],[26909,3,0],[27000,0,0],[27273,1,0],[27455,3,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[27648,2,0],[28000,2,0],[28364,2,0],[28545,3,0],[28727,0,0],[28909,1,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[29091.181818181816,2,0],[29273.181818181816,1,0],[29454.181818181816,0,0],[29636.181818181816,0,0],[29727.181818181816,3,0],[29818.181818181816,2,0],[30000.181818181816,0,0],[30182.181818181816,2,0],[30363.181818181816,1,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[30552.181818181816,2,0],[30909.181818181816,2,0],[31273.181818181816,2,0],[31454.181818181816,1,0],[31636.181818181816,0,0],[31818.181818181816,3,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[32011.181818181816,0,0],[32363.181818181816,0,0],[32545.181818181816,0,0],[32636.181818181816,2,0],[32727.181818181816,3,0],[32818.181818181816,0,0],[33091.181818181816,1,0],[33273.181818181816,3,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[33466.181818181816,2,0],[33818.181818181816,2,0],[34182.181818181816,2,0],[34363.181818181816,3,0],[34545.181818181816,0,0],[34727.181818181816,1,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[34918,2,0],[35091,3,0],[35273,0,0],[35455,2,0],[35636,3,0],[35818,0,0],[36000,2,0],[36182,3,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[36380,0,0],[36545,2,0],[36727,3,0],[36909,0,0],[37091,0,0],[37273,3,0],[37455,0,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[37834,2,0],[38000,3,0],[38182,0,0],[38364,2,0],[38545,3,0],[38727,0,0],[38909,2,0],[39091,3,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[39284,0,0],[39727,3,0],[39909,0,0],[40000,3,0],[40182,0,0],[40364,3,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[40736.181818181816,2,0],[40909.181818181816,3,0],[41091.181818181816,0,0],[41273.181818181816,2,0],[41454.181818181816,3,0],[41636.181818181816,0,0],[41818.181818181816,2,0],[42000.181818181816,3,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[42198.181818181816,0,0],[42363.181818181816,2,0],[42545.181818181816,3,0],[42727.181818181816,0,0],[42909.181818181816,0,0],[43091.181818181816,3,0],[43273.181818181816,0,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[43652.181818181816,2,0],[43818.181818181816,3,0],[44000.181818181816,0,0],[44182.181818181816,2,0],[44363.181818181816,3,0],[44545.181818181816,0,0],[44727.181818181816,2,0],[44909.181818181816,3,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[45102.181818181816,0,0],[45545.181818181816,3,0],[45727.181818181816,0,0],[45818.181818181816,3,0],[46000.181818181816,0,0],[46182.181818181816,3,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[46554.818181818184,0,0],[46817.818181818184,3,0],[46908.818181818184,1,0],[47181.818181818184,0,0],[47363.818181818184,3,0],[47454.818181818184,1,0],[47726.818181818184,2,0],[47908.818181818184,3,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[48011.818181818184,0,0],[48181.818181818184,2,0],[48363.818181818184,3,0],[48545.818181818184,0,0],[48726.818181818184,3,0],[48908.818181818184,2,0],[49090.818181818184,0,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[49545,3,0],[49455,0,0],[49636,2,0],[49818,3,0],[50000,0,0],[50182,2,0],[50364,3,0],[50545,0,0],[50636,3,0],[50727,2,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[50914,1,0],[51273,0,0],[51455,3,0],[51727,2,0],[51909,3,0],[52091,0,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[52373,0,0],[52636,3,0],[52727,1,0],[53000,0,0],[53182,3,0],[53273,1,0],[53545,2,0],[53727,3,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[53830,0,0],[54000,2,0],[54182,3,0],[54364,0,0],[54545,3,0],[54727,2,0],[54909,0,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[55363.181818181816,3,0],[55273.181818181816,0,0],[55454.181818181816,2,0],[55636.181818181816,3,0],[55818.181818181816,0,0],[56000.181818181816,2,0],[56182.181818181816,3,0],[56363.181818181816,0,0],[56454.181818181816,3,0],[56545.181818181816,2,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[56732.181818181816,1,0],[57091.181818181816,0,0],[57273.181818181816,3,0],[57545.181818181816,2,0],[57727.181818181816,3,0],[57909.181818181816,0,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[58182,3,0],[58545,3,0],[59000,2,0],[59091,0,0],[58727,1,0],[59364,1,0],[59455,3,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[59657,0,272.7272727272727],[60000,2,0],[60364,2,0],[60545,2,0],[60727,2,181.8181818181818]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[61100,2,0],[61455,2,0],[61636,3,0],[61818,1,0],[62000,0,0],[62182,3,0],[62364,0,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[62550,0,0],[63000,0,0],[63727,0,0],[63364,0,0],[63364,7,0],[63545,3,0],[63818,2,0],[63636,5,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[64000.181818181816,3,0],[64363.181818181816,3,0],[64818.181818181816,2,0],[64909.181818181816,0,0],[64545.181818181816,1,0],[65182.181818181816,1,0],[65273.181818181816,3,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[65475.181818181816,0,272.7272727272727],[65818.18181818182,2,0],[66182.18181818182,2,0],[66363.18181818182,2,0],[66545.18181818182,2,181.8181818181818]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[66918.18181818182,2,0],[67273.18181818182,2,0],[67454.18181818182,3,0],[67636.18181818182,1,0],[67818.18181818182,0,0],[68000.18181818182,3,0],[68182.18181818182,0,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[68368.18181818182,0,0],[68818.18181818182,0,0],[69545.18181818182,0,0],[69182.18181818182,0,0],[69182.18181818182,7,0],[69363.18181818182,3,0],[69636.18181818182,2,0],[69454.18181818182,5,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[69825,2,0],[70000,3,0],[70273,0,0],[70364,3,0],[70545,2,0],[70636,0,0],[71000,2,0],[70727,3,0],[71091,3,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[71280,2,0],[71636,2,0],[71818,0,0],[72091,2,0],[72273,3,0],[72364,0,0],[72545,2,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[72732,0,0],[73091,0,0],[73273,0,0],[73455,2,0],[73364,3,0],[73636,3,0],[73818,2,0],[74000,0,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[74195,2,0],[74364,3,0],[74545,2,0],[74727,0,0],[74909,1,0],[75091,3,0],[75273,0,0],[75455,3,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[75643.18181818182,2,0],[75818.18181818182,3,0],[76091.18181818182,0,0],[76182.18181818182,3,0],[76363.18181818182,2,0],[76454.18181818182,0,0],[76818.18181818182,2,0],[76545.18181818182,3,0],[76909.18181818182,3,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[77098.18181818182,2,0],[77454.18181818182,2,0],[77636.18181818182,0,0],[77909.18181818182,2,0],[78091.18181818182,3,0],[78182.18181818182,0,0],[78363.18181818182,2,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[78550.18181818182,0,0],[78909.18181818182,0,0],[79091.18181818182,0,0],[79273.18181818182,2,0],[79182.18181818182,3,0],[79454.18181818182,3,0],[79636.18181818182,2,0],[79818.18181818182,0,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[80013.18181818182,2,0],[80182.18181818182,3,0],[80363.18181818182,2,0],[80545.18181818182,0,0],[80727.18181818182,1,0],[80909.18181818182,3,0],[81091.18181818182,0,0],[81273.18181818182,3,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[]},{"lengthInSteps":16,"bpm":165,"changeBPM":false,"mustHitSection":true,"sectionNotes":[],"typeOfSection":0},{"lengthInSteps":16,"bpm":165,"changeBPM":false,"mustHitSection":true,"sectionNotes":[],"typeOfSection":0}]} \ No newline at end of file diff --git a/assets/data/spookeez/spookeez-easy.json b/assets/data/spookeez/spookeez-easy.json new file mode 100644 index 00000000..13bad470 --- /dev/null +++ b/assets/data/spookeez/spookeez-easy.json @@ -0,0 +1 @@ +{"song":{"song":"Spookeez","notes":[{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[6400,0,0],[6800,3,0],[7200,3,0],[7600,2,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[8000,1,0],[8400,3,0],[9300,0,0],[9400,3,0],[8800,2,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[9600,0,0],[10000,3,0],[10400,3,0],[10800,2,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[11200,1,0],[11600,3,0],[12500,0,0],[12600,3,0],[12000,2,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[12800,2,0],[13200,0,0],[13700,2,0],[13900,0,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[15100,1,0],[14400,1,0],[14800,3,0],[15700,2,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[16000,2,0],[16400,0,0],[16900,2,0],[17100,0,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[19000,4,0],[19100,7,0],[18300,1,0],[17600,1,0],[18000,3,0],[18900,2,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[20000,3,0],[20600,3,0],[19700,3,0],[20400,3,0],[19200,2,0],[19500,1,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[20800,2,0],[21100,1,0],[21300,3,0],[21600,3,0],[22000,3,0],[21900,1,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[22900,3,0],[23200,3,0],[23600,3,0],[23800,3,0],[22700,1,0],[22400,2,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[24500,3,0],[24300,1,0],[24000,2,0],[25200,2,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[26400,3,0],[27000,3,0],[26100,3,0],[26800,3,0],[25600,2,0],[25900,1,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[27200,2,0],[27500,1,0],[27700,3,0],[28000,3,0],[28400,3,0],[28300,1,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[29300,3,0],[29600,3,0],[30000,3,0],[30200,3,0],[29100,1,0],[28800,2,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[30900,3,0],[30700,1,0],[30400,2,0],[31600,2,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[32000,0,0],[32400,3,0],[32800,3,0],[33200,2,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[33600,1,0],[34000,3,0],[34900,0,0],[34400,2,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[35200,0,0],[35600,3,0],[36000,3,0],[36400,2,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[36800,1,0],[37200,3,0],[38100,0,0],[37600,2,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[38400,2,0],[38800,0,0],[39000,0,0],[39400,3,0],[39600,1,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[40700,1,0],[40000,1,0],[40400,3,0],[40900,0,0],[41300,2,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[41600,2,0],[42000,0,0],[42200,0,0],[42600,3,0],[42800,1,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[44600,4,0],[44700,7,0],[43900,1,0],[43200,1,0],[43600,3,0],[44100,0,0],[44500,2,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[45600,3,0],[45300,3,0],[46000,3,0],[44800,2,0],[45100,1,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[46400,2,0],[46700,1,0],[46900,3,0],[47300,1,0],[47500,0,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[48500,3,0],[48800,3,0],[49200,3,0],[49400,3,0],[48300,1,0],[48000,2,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[50100,3,0],[49900,1,0],[49600,2,0],[50400,3,0],[50800,4,0],[51000,7,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[52000,3,0],[51700,3,0],[52400,3,0],[51200,2,0],[51500,1,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[52800,2,0],[53100,1,0],[53300,3,0],[53700,1,0],[53900,0,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[54900,3,0],[55200,3,0],[55600,3,0],[55800,3,0],[54700,1,0],[54400,2,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[56500,3,0],[56300,1,0],[56000,2,0],[56800,3,0],[56900,4,0],[56800,4,0],[56700,4,0],[57100,4,0],[57300,5,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[57600,2,300],[58000,3,400],[58500,1,200],[58800,2,200]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[59200,2,100],[59600,0,300],[60000,1,300],[60400,2,200]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[60800,1,0],[61200,1,0],[61800,3,0],[62000,0,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[62400,1,0],[62800,1,0],[63400,3,0],[63600,0,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[64000,2,300],[64400,3,400],[64900,1,200],[65200,2,200]]},{"lengthInSteps":16,"bpm":150,"changeBPM":false,"mustHitSection":true,"sectionNotes":[[65600,2,100],[66000,0,300],[66400,1,300],[66800,2,200]],"typeOfSection":0},{"lengthInSteps":16,"bpm":150,"changeBPM":false,"mustHitSection":true,"sectionNotes":[[67200,1,0],[67600,1,0],[68200,3,0],[68400,0,0]],"typeOfSection":0},{"lengthInSteps":16,"bpm":150,"changeBPM":false,"mustHitSection":true,"sectionNotes":[[68800,1,0],[69200,1,0],[69800,3,0],[70000,0,0]],"typeOfSection":0},{"lengthInSteps":16,"bpm":150,"changeBPM":false,"mustHitSection":false,"sectionNotes":[[70400,2,0],[71000,2,0],[71400,3,0],[71700,1,0],[70600,2,0]],"typeOfSection":0},{"lengthInSteps":16,"bpm":150,"changeBPM":false,"mustHitSection":false,"sectionNotes":[[72000,2,0],[72600,2,0],[73000,3,0],[73300,1,0],[72200,2,0]],"typeOfSection":0},{"lengthInSteps":16,"bpm":150,"changeBPM":false,"mustHitSection":false,"sectionNotes":[[73600,2,0],[74200,2,0],[74600,3,0],[74900,1,0],[73800,2,0]],"typeOfSection":0},{"lengthInSteps":16,"bpm":157,"changeBPM":false,"mustHitSection":false,"sectionNotes":[[75200,2,0],[75800,2,0],[76200,3,0],[76500,1,0],[75400,2,0],[75200,4,300],[75600,5,300],[76000,7,300],[76400,5,300]],"typeOfSection":0},{"lengthInSteps":16,"bpm":150,"changeBPM":false,"mustHitSection":true,"sectionNotes":[[76800,2,0],[77400,2,0],[77800,3,0],[78100,1,0],[77000,2,0]],"typeOfSection":0},{"lengthInSteps":16,"bpm":150,"changeBPM":false,"mustHitSection":true,"sectionNotes":[[78400,2,0],[79000,2,0],[79400,3,0],[79700,1,0],[78600,2,0]],"typeOfSection":0},{"lengthInSteps":16,"bpm":150,"changeBPM":false,"mustHitSection":true,"sectionNotes":[[80000,2,0],[80600,2,0],[81000,3,0],[81300,1,0],[80200,2,0]],"typeOfSection":0},{"lengthInSteps":16,"bpm":150,"changeBPM":false,"mustHitSection":true,"sectionNotes":[[81600,2,0],[82200,2,0],[82600,3,0],[82900,1,0],[81800,2,0],[81600,4,300],[82000,5,300],[82400,7,300],[82800,5,300]],"typeOfSection":0},{"lengthInSteps":16,"bpm":150,"changeBPM":false,"mustHitSection":false,"sectionNotes":[[83200,2,0],[83800,2,0],[84200,3,0],[84500,1,0],[83400,2,0]],"typeOfSection":0},{"lengthInSteps":16,"bpm":150,"changeBPM":false,"mustHitSection":false,"sectionNotes":[[84800,2,0],[85400,2,0],[85800,3,0],[86100,1,0],[85000,2,0]],"typeOfSection":0},{"lengthInSteps":16,"bpm":150,"changeBPM":false,"mustHitSection":false,"sectionNotes":[[86400,2,0],[87000,2,0],[87400,3,0],[87700,1,0],[86600,2,0]],"typeOfSection":0},{"lengthInSteps":16,"bpm":150,"changeBPM":false,"mustHitSection":false,"sectionNotes":[[88000,2,0],[88600,2,0],[89000,3,0],[89300,1,0],[88200,2,0],[88000,4,300],[88400,5,300],[88800,7,300],[89200,5,300]],"typeOfSection":0},{"lengthInSteps":16,"bpm":150,"changeBPM":false,"mustHitSection":true,"sectionNotes":[[89600,2,0],[90200,2,0],[90600,3,0],[90900,1,0],[89800,2,0]],"typeOfSection":0},{"lengthInSteps":16,"bpm":150,"changeBPM":false,"mustHitSection":true,"sectionNotes":[[91200,2,0],[91800,2,0],[92200,3,0],[92500,1,0],[91400,2,0],[91200,2,0],[91800,2,0],[92200,3,0],[92500,1,0],[91400,2,0]],"typeOfSection":0},{"lengthInSteps":16,"bpm":150,"changeBPM":false,"mustHitSection":true,"sectionNotes":[[92800,2,0],[93400,2,0],[93800,3,0],[94100,1,0],[93000,2,0]],"typeOfSection":0},{"lengthInSteps":16,"bpm":150,"changeBPM":false,"mustHitSection":true,"sectionNotes":[[94400,2,0],[95000,2,0],[95400,3,0],[95700,1,0],[94600,2,0]],"typeOfSection":0},{"lengthInSteps":16,"bpm":150,"changeBPM":false,"mustHitSection":true,"sectionNotes":[],"typeOfSection":0},{"lengthInSteps":16,"bpm":150,"changeBPM":false,"mustHitSection":true,"sectionNotes":[],"typeOfSection":0},{"lengthInSteps":16,"bpm":150,"changeBPM":false,"mustHitSection":true,"sectionNotes":[],"typeOfSection":0}],"bpm":150,"sections":0,"needsVoices":true,"player1":"bf","player2":"spooky","sectionLengths":[],"speed":1},"bpm":150,"sections":63,"notes":[{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[6400,0,0],[6800,3,0],[7200,3,0],[7600,2,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[8000,1,0],[8400,3,0],[9300,0,0],[9400,3,0],[8800,2,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[9600,0,0],[10000,3,0],[10400,3,0],[10800,2,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[11200,1,0],[11600,3,0],[12500,0,0],[12600,3,0],[12000,2,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[12800,2,0],[13200,0,0],[13700,2,0],[13900,0,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[15100,1,0],[14400,1,0],[14800,3,0],[15700,2,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[16000,2,0],[16400,0,0],[16900,2,0],[17100,0,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[19000,4,0],[19100,7,0],[18300,1,0],[17600,1,0],[18000,3,0],[18900,2,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[20000,3,0],[20600,3,0],[19700,3,0],[20400,3,0],[19200,2,0],[19500,1,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[20800,2,0],[21100,1,0],[21300,3,0],[21600,3,0],[22000,3,0],[21900,1,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[22900,3,0],[23200,3,0],[23600,3,0],[23800,3,0],[22700,1,0],[22400,2,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[24500,3,0],[24300,1,0],[24000,2,0],[25200,2,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[26400,3,0],[27000,3,0],[26100,3,0],[26800,3,0],[25600,2,0],[25900,1,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[27200,2,0],[27500,1,0],[27700,3,0],[28000,3,0],[28400,3,0],[28300,1,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[29300,3,0],[29600,3,0],[30000,3,0],[30200,3,0],[29100,1,0],[28800,2,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[30900,3,0],[30700,1,0],[30400,2,0],[31600,2,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[32000,0,0],[32400,3,0],[32800,3,0],[33200,2,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[33600,1,0],[34000,3,0],[34900,0,0],[34400,2,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[35200,0,0],[35600,3,0],[36000,3,0],[36400,2,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[36800,1,0],[37200,3,0],[38100,0,0],[37600,2,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[38400,2,0],[38800,0,0],[39000,0,0],[39400,3,0],[39600,1,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[40700,1,0],[40000,1,0],[40400,3,0],[40900,0,0],[41300,2,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[41600,2,0],[42000,0,0],[42200,0,0],[42600,3,0],[42800,1,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[44600,4,0],[44700,7,0],[43900,1,0],[43200,1,0],[43600,3,0],[44100,0,0],[44500,2,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[45600,3,0],[45300,3,0],[46000,3,0],[44800,2,0],[45100,1,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[46400,2,0],[46700,1,0],[46900,3,0],[47300,1,0],[47500,0,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[48500,3,0],[48800,3,0],[49200,3,0],[49400,3,0],[48300,1,0],[48000,2,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[50100,3,0],[49900,1,0],[49600,2,0],[50400,3,0],[50800,4,0],[51000,7,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[52000,3,0],[51700,3,0],[52400,3,0],[51200,2,0],[51500,1,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[52800,2,0],[53100,1,0],[53300,3,0],[53700,1,0],[53900,0,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[54900,3,0],[55200,3,0],[55600,3,0],[55800,3,0],[54700,1,0],[54400,2,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[56500,3,0],[56300,1,0],[56000,2,0],[56800,3,0],[56900,4,0],[56800,4,0],[56700,4,0],[57100,4,0],[57300,5,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[57600,2,300],[58000,3,400],[58500,1,200],[58800,2,200]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[59200,2,100],[59600,0,300],[60000,1,300],[60400,2,200]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[60800,1,0],[61200,1,0],[61800,3,0],[62000,0,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[62400,1,0],[62800,1,0],[63400,3,0],[63600,0,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[64000,2,300],[64400,3,400],[64900,1,200],[65200,2,200]]},{"lengthInSteps":16,"bpm":150,"changeBPM":false,"mustHitSection":true,"sectionNotes":[[65600,2,100],[66000,0,300],[66400,1,300],[66800,2,200]],"typeOfSection":0},{"lengthInSteps":16,"bpm":150,"changeBPM":false,"mustHitSection":true,"sectionNotes":[[67200,1,0],[67600,1,0],[68200,3,0],[68400,0,0]],"typeOfSection":0},{"lengthInSteps":16,"bpm":150,"changeBPM":false,"mustHitSection":true,"sectionNotes":[[68800,1,0],[69200,1,0],[69800,3,0],[70000,0,0]],"typeOfSection":0},{"lengthInSteps":16,"bpm":150,"changeBPM":false,"mustHitSection":false,"sectionNotes":[[70400,2,0],[71000,2,0],[71400,3,0],[71700,1,0],[70600,2,0]],"typeOfSection":0},{"lengthInSteps":16,"bpm":150,"changeBPM":false,"mustHitSection":false,"sectionNotes":[[72000,2,0],[72600,2,0],[73000,3,0],[73300,1,0],[72200,2,0]],"typeOfSection":0},{"lengthInSteps":16,"bpm":150,"changeBPM":false,"mustHitSection":false,"sectionNotes":[[73600,2,0],[74200,2,0],[74600,3,0],[74900,1,0],[73800,2,0]],"typeOfSection":0},{"lengthInSteps":16,"bpm":157,"changeBPM":false,"mustHitSection":false,"sectionNotes":[[75200,2,0],[75800,2,0],[76200,3,0],[76500,1,0],[75400,2,0],[75200,4,300],[75600,5,300],[76000,7,300],[76400,5,300]],"typeOfSection":0},{"lengthInSteps":16,"bpm":150,"changeBPM":false,"mustHitSection":true,"sectionNotes":[[76800,2,0],[77400,2,0],[77800,3,0],[78100,1,0],[77000,2,0]],"typeOfSection":0},{"lengthInSteps":16,"bpm":150,"changeBPM":false,"mustHitSection":true,"sectionNotes":[[78400,2,0],[79000,2,0],[79400,3,0],[79700,1,0],[78600,2,0]],"typeOfSection":0},{"lengthInSteps":16,"bpm":150,"changeBPM":false,"mustHitSection":true,"sectionNotes":[[80000,2,0],[80600,2,0],[81000,3,0],[81300,1,0],[80200,2,0]],"typeOfSection":0},{"lengthInSteps":16,"bpm":150,"changeBPM":false,"mustHitSection":true,"sectionNotes":[[81600,2,0],[82200,2,0],[82600,3,0],[82900,1,0],[81800,2,0],[81600,4,300],[82000,5,300],[82400,7,300],[82800,5,300]],"typeOfSection":0},{"lengthInSteps":16,"bpm":150,"changeBPM":false,"mustHitSection":false,"sectionNotes":[[83200,2,0],[83800,2,0],[84200,3,0],[84500,1,0],[83400,2,0]],"typeOfSection":0},{"lengthInSteps":16,"bpm":150,"changeBPM":false,"mustHitSection":false,"sectionNotes":[[84800,2,0],[85400,2,0],[85800,3,0],[86100,1,0],[85000,2,0]],"typeOfSection":0},{"lengthInSteps":16,"bpm":150,"changeBPM":false,"mustHitSection":false,"sectionNotes":[[86400,2,0],[87000,2,0],[87400,3,0],[87700,1,0],[86600,2,0]],"typeOfSection":0},{"lengthInSteps":16,"bpm":150,"changeBPM":false,"mustHitSection":false,"sectionNotes":[[88000,2,0],[88600,2,0],[89000,3,0],[89300,1,0],[88200,2,0],[88000,4,300],[88400,5,300],[88800,7,300],[89200,5,300]],"typeOfSection":0},{"lengthInSteps":16,"bpm":150,"changeBPM":false,"mustHitSection":true,"sectionNotes":[[89600,2,0],[90200,2,0],[90600,3,0],[90900,1,0],[89800,2,0]],"typeOfSection":0},{"lengthInSteps":16,"bpm":150,"changeBPM":false,"mustHitSection":true,"sectionNotes":[[91200,2,0],[91800,2,0],[92200,3,0],[92500,1,0],[91400,2,0],[91200,2,0],[91800,2,0],[92200,3,0],[92500,1,0],[91400,2,0]],"typeOfSection":0},{"lengthInSteps":16,"bpm":150,"changeBPM":false,"mustHitSection":true,"sectionNotes":[[92800,2,0],[93400,2,0],[93800,3,0],[94100,1,0],[93000,2,0]],"typeOfSection":0},{"lengthInSteps":16,"bpm":150,"changeBPM":false,"mustHitSection":true,"sectionNotes":[[94400,2,0],[95000,2,0],[95400,3,0],[95700,1,0],[94600,2,0]],"typeOfSection":0},{"lengthInSteps":16,"bpm":150,"changeBPM":false,"mustHitSection":true,"sectionNotes":[],"typeOfSection":0},{"lengthInSteps":16,"bpm":150,"changeBPM":false,"mustHitSection":true,"sectionNotes":[],"typeOfSection":0},{"lengthInSteps":16,"bpm":150,"changeBPM":false,"mustHitSection":true,"sectionNotes":[],"typeOfSection":0}]} \ No newline at end of file diff --git a/assets/data/spookeez/spookeez-hard.json b/assets/data/spookeez/spookeez-hard.json new file mode 100644 index 00000000..8411fc2d --- /dev/null +++ b/assets/data/spookeez/spookeez-hard.json @@ -0,0 +1 @@ +{"song":{"song":"Spookeez","notes":[{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[6400,0,0],[6600,1,0],[6800,3,0],[7200,3,0],[7600,2,0],[7800,3,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[8000,1,0],[8200,3,0],[8400,3,0],[9300,0,0],[9400,3,0],[8800,2,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[9600,0,0],[9800,1,0],[10000,3,0],[10400,3,0],[10800,2,0],[11000,3,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[11200,1,0],[11400,3,0],[11600,3,0],[12500,0,0],[12600,3,0],[12000,2,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[12800,2,0],[13000,3,0],[13100,1,0],[13200,0,0],[13400,0,0],[13500,1,0],[13700,2,0],[13800,3,0],[13900,0,0],[14000,1,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[14700,1,0],[15100,1,0],[14400,1,0],[14600,0,0],[14800,3,0],[15000,3,0],[15300,0,0],[15500,0,0],[15700,2,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[16000,2,0],[16200,3,0],[16300,1,0],[16400,0,0],[16600,0,0],[16700,1,0],[16900,2,0],[17000,3,0],[17100,0,0],[17200,1,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[17900,1,0],[18300,1,0],[17600,1,0],[17800,0,0],[18000,3,0],[18200,3,0],[18500,0,0],[18700,0,0],[18900,2,0],[19000,4,0],[19100,7,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[20000,3,0],[20600,3,0],[19700,3,0],[20400,3,0],[19200,2,0],[19300,0,0],[19400,3,0],[19500,1,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[20800,2,0],[21100,1,0],[20900,3,0],[21000,0,0],[21300,3,0],[21600,3,0],[21900,1,0],[22000,3,0],[22200,3,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[22900,3,0],[23200,3,0],[23600,3,0],[23800,3,0],[22700,1,0],[22400,2,0],[22500,0,0],[22600,3,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[24500,3,0],[24300,1,0],[24000,2,0],[24200,0,0],[24100,3,0],[24800,1,0],[25200,2,0],[25400,2,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[26400,3,0],[27000,3,0],[26100,3,0],[26800,3,0],[25600,2,0],[25700,0,0],[25800,3,0],[25900,1,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[27200,2,0],[27500,1,0],[27300,3,0],[27400,0,0],[27700,3,0],[28000,3,0],[28300,1,0],[28400,3,0],[28600,3,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[29300,3,0],[29600,3,0],[30000,3,0],[30200,3,0],[29100,1,0],[28800,2,0],[28900,0,0],[29000,3,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[30900,3,0],[30700,1,0],[30400,2,0],[30600,0,0],[30500,3,0],[31200,1,0],[31600,2,0],[31800,2,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[32000,0,0],[32200,1,0],[32400,3,0],[32800,3,0],[33200,2,0],[33400,3,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[33600,1,0],[33800,3,0],[34000,3,0],[34900,0,0],[35000,3,0],[34400,2,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[35200,0,0],[35400,1,0],[35600,3,0],[36000,3,0],[36400,2,0],[36600,3,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[36800,1,0],[37000,3,0],[37200,3,0],[38100,0,0],[38200,3,0],[37600,2,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[38400,2,0],[38600,3,0],[38700,1,0],[38800,0,0],[39000,0,0],[39100,1,0],[39300,2,0],[39400,3,0],[39500,0,0],[39600,1,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[40300,1,0],[40700,1,0],[40000,1,0],[40200,0,0],[40400,3,0],[40600,3,0],[40900,0,0],[41100,0,0],[41300,2,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[41600,2,0],[41800,3,0],[41900,1,0],[42000,0,0],[42200,0,0],[42300,1,0],[42500,2,0],[42600,3,0],[42700,0,0],[42800,1,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[43500,1,0],[43900,1,0],[43200,1,0],[43400,0,0],[43600,3,0],[43800,3,0],[44100,0,0],[44300,0,0],[44500,2,0],[44600,4,0],[44700,7,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[45600,3,0],[46200,3,0],[45300,3,0],[46000,3,0],[44800,2,0],[44900,0,0],[45000,3,0],[45100,1,0],[45700,3,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[46400,2,0],[46700,1,0],[46500,3,0],[46600,0,0],[46900,3,0],[47200,3,0],[47600,3,0],[47800,3,0],[47300,1,0],[47500,0,0],[47538,2,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[48500,3,0],[48800,3,0],[49200,3,0],[49400,3,0],[48300,1,0],[48000,2,0],[48100,0,0],[48200,3,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[50100,3,0],[49900,1,0],[49600,2,0],[49800,0,0],[49700,3,0],[50400,3,0],[50800,4,0],[51000,7,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[52000,3,0],[52600,3,0],[51700,3,0],[52400,3,0],[51200,2,0],[51300,0,0],[51400,3,0],[51500,1,0],[52100,3,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[52800,2,0],[53100,1,0],[52900,3,0],[53000,0,0],[53300,3,0],[53600,3,0],[54000,3,0],[54200,3,0],[53700,1,0],[53900,0,0],[53938,2,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[54900,3,0],[55200,3,0],[55600,3,0],[55800,3,0],[54700,1,0],[54400,2,0],[54500,0,0],[54600,3,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[56500,3,0],[56300,1,0],[56000,2,0],[56200,0,0],[56100,3,0],[56800,3,0],[57200,4,0],[57400,7,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[57600,2,300],[58000,3,400],[58500,1,200],[58800,2,200]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[59200,2,100],[59400,3,100],[59600,0,300],[60000,1,300],[60400,2,200]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[60800,1,0],[61200,1,0],[61400,3,0],[61800,3,0],[62000,0,0],[62200,3,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[62400,1,0],[62800,1,0],[63000,3,0],[63400,3,0],[63600,0,0],[63800,3,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[64000,2,300],[64400,3,400],[64900,1,200],[65200,2,200]]},{"lengthInSteps":16,"bpm":150,"changeBPM":false,"mustHitSection":true,"sectionNotes":[[65600,2,100],[65800,3,100],[66000,0,300],[66400,1,300],[66800,2,200]],"typeOfSection":0},{"lengthInSteps":16,"bpm":150,"changeBPM":false,"mustHitSection":true,"sectionNotes":[[67200,1,0],[67600,1,0],[67800,3,0],[68200,3,0],[68400,0,0],[68600,3,0]],"typeOfSection":0},{"lengthInSteps":16,"bpm":150,"changeBPM":false,"mustHitSection":true,"sectionNotes":[[68800,1,0],[69200,1,0],[69400,3,0],[69800,3,0],[70000,0,0],[70200,3,0]],"typeOfSection":0},{"lengthInSteps":16,"bpm":150,"changeBPM":false,"mustHitSection":false,"sectionNotes":[[70400,2,0],[70800,3,0],[71000,2,0],[71400,3,0],[71700,1,0],[70600,2,0],[71800,3,0]],"typeOfSection":0},{"lengthInSteps":16,"bpm":150,"changeBPM":false,"mustHitSection":false,"sectionNotes":[[72000,2,0],[72400,3,0],[72600,2,0],[73000,3,0],[73300,1,0],[72200,2,0]],"typeOfSection":0},{"lengthInSteps":16,"bpm":150,"changeBPM":false,"mustHitSection":false,"sectionNotes":[[73600,2,0],[74000,3,0],[74200,2,0],[74600,3,0],[74900,1,0],[73800,2,0],[75000,3,0]],"typeOfSection":0},{"lengthInSteps":16,"bpm":157,"changeBPM":false,"mustHitSection":false,"sectionNotes":[[75200,2,0],[75600,3,0],[75800,2,0],[76200,3,0],[76500,1,0],[75400,2,0],[75200,4,300],[75600,5,300],[76000,7,300],[76400,5,300]],"typeOfSection":0},{"lengthInSteps":16,"bpm":150,"changeBPM":false,"mustHitSection":true,"sectionNotes":[[76800,2,0],[77200,3,0],[77400,2,0],[77800,3,0],[78100,1,0],[77000,2,0],[78200,3,0]],"typeOfSection":0},{"lengthInSteps":16,"bpm":150,"changeBPM":false,"mustHitSection":true,"sectionNotes":[[78400,2,0],[78800,3,0],[79000,2,0],[79400,3,0],[79700,1,0],[78600,2,0]],"typeOfSection":0},{"lengthInSteps":16,"bpm":150,"changeBPM":false,"mustHitSection":true,"sectionNotes":[[80000,2,0],[80400,3,0],[80600,2,0],[81000,3,0],[81300,1,0],[80200,2,0]],"typeOfSection":0},{"lengthInSteps":16,"bpm":150,"changeBPM":false,"mustHitSection":true,"sectionNotes":[[81600,2,0],[82000,3,0],[82200,2,0],[82600,3,0],[82900,1,0],[81800,2,0],[81600,4,300],[82000,5,300],[82400,7,300],[82800,5,300]],"typeOfSection":0},{"lengthInSteps":16,"bpm":150,"changeBPM":false,"mustHitSection":false,"sectionNotes":[[83200,2,0],[83600,3,0],[83800,2,0],[84200,3,0],[84500,1,0],[83400,2,0],[84600,3,0]],"typeOfSection":0},{"lengthInSteps":16,"bpm":150,"changeBPM":false,"mustHitSection":false,"sectionNotes":[[84800,2,0],[85200,3,0],[85400,2,0],[85800,3,0],[86100,1,0],[85000,2,0]],"typeOfSection":0},{"lengthInSteps":16,"bpm":150,"changeBPM":false,"mustHitSection":false,"sectionNotes":[[86400,2,0],[86800,3,0],[87000,2,0],[87400,3,0],[87700,1,0],[86600,2,0],[87800,3,0]],"typeOfSection":0},{"lengthInSteps":16,"bpm":150,"changeBPM":false,"mustHitSection":false,"sectionNotes":[[88000,2,0],[88400,3,0],[88600,2,0],[89000,3,0],[89300,1,0],[88200,2,0],[88000,4,300],[88400,5,300],[88800,7,300],[89200,5,300]],"typeOfSection":0},{"lengthInSteps":16,"bpm":150,"changeBPM":false,"mustHitSection":true,"sectionNotes":[[89600,2,0],[90000,3,0],[90200,2,0],[90600,3,0],[90900,1,0],[89800,2,0]],"typeOfSection":0},{"lengthInSteps":16,"bpm":150,"changeBPM":false,"mustHitSection":true,"sectionNotes":[[91200,2,0],[91600,3,0],[91800,2,0],[92200,3,0],[92500,1,0],[91400,2,0],[91200,2,0],[91600,3,0],[91800,2,0],[92200,3,0],[92500,1,0],[91400,2,0]],"typeOfSection":0},{"lengthInSteps":16,"bpm":150,"changeBPM":false,"mustHitSection":true,"sectionNotes":[[92800,2,0],[93200,3,0],[93400,2,0],[93800,3,0],[94100,1,0],[93000,2,0]],"typeOfSection":0},{"lengthInSteps":16,"bpm":150,"changeBPM":false,"mustHitSection":true,"sectionNotes":[[94400,2,0],[94800,3,0],[95000,2,0],[95400,3,0],[95700,1,0],[94600,2,0],[94400,4,300],[94800,5,300],[95200,7,300],[95600,5,300]],"typeOfSection":0},{"lengthInSteps":16,"bpm":150,"changeBPM":false,"mustHitSection":true,"sectionNotes":[],"typeOfSection":0},{"lengthInSteps":16,"bpm":150,"changeBPM":false,"mustHitSection":true,"sectionNotes":[],"typeOfSection":0},{"lengthInSteps":16,"bpm":150,"changeBPM":false,"mustHitSection":true,"sectionNotes":[],"typeOfSection":0}],"bpm":150,"sections":0,"needsVoices":true,"player1":"bf","player2":"spooky","sectionLengths":[],"speed":2.4000000000000012},"bpm":150,"sections":63,"notes":[{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[6400,0,0],[6600,1,0],[6800,3,0],[7200,3,0],[7600,2,0],[7800,3,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[8000,1,0],[8200,3,0],[8400,3,0],[9300,0,0],[9400,3,0],[8800,2,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[9600,0,0],[9800,1,0],[10000,3,0],[10400,3,0],[10800,2,0],[11000,3,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[11200,1,0],[11400,3,0],[11600,3,0],[12500,0,0],[12600,3,0],[12000,2,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[12800,2,0],[13000,3,0],[13100,1,0],[13200,0,0],[13400,0,0],[13500,1,0],[13700,2,0],[13800,3,0],[13900,0,0],[14000,1,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[14700,1,0],[15100,1,0],[14400,1,0],[14600,0,0],[14800,3,0],[15000,3,0],[15300,0,0],[15500,0,0],[15700,2,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[16000,2,0],[16200,3,0],[16300,1,0],[16400,0,0],[16600,0,0],[16700,1,0],[16900,2,0],[17000,3,0],[17100,0,0],[17200,1,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[17900,1,0],[18300,1,0],[17600,1,0],[17800,0,0],[18000,3,0],[18200,3,0],[18500,0,0],[18700,0,0],[18900,2,0],[19000,4,0],[19100,7,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[20000,3,0],[20600,3,0],[19700,3,0],[20400,3,0],[19200,2,0],[19300,0,0],[19400,3,0],[19500,1,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[20800,2,0],[21100,1,0],[20900,3,0],[21000,0,0],[21300,3,0],[21600,3,0],[21900,1,0],[22000,3,0],[22200,3,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[22900,3,0],[23200,3,0],[23600,3,0],[23800,3,0],[22700,1,0],[22400,2,0],[22500,0,0],[22600,3,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[24500,3,0],[24300,1,0],[24000,2,0],[24200,0,0],[24100,3,0],[24800,1,0],[25200,2,0],[25400,2,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[26400,3,0],[27000,3,0],[26100,3,0],[26800,3,0],[25600,2,0],[25700,0,0],[25800,3,0],[25900,1,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[27200,2,0],[27500,1,0],[27300,3,0],[27400,0,0],[27700,3,0],[28000,3,0],[28300,1,0],[28400,3,0],[28600,3,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[29300,3,0],[29600,3,0],[30000,3,0],[30200,3,0],[29100,1,0],[28800,2,0],[28900,0,0],[29000,3,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[30900,3,0],[30700,1,0],[30400,2,0],[30600,0,0],[30500,3,0],[31200,1,0],[31600,2,0],[31800,2,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[32000,0,0],[32200,1,0],[32400,3,0],[32800,3,0],[33200,2,0],[33400,3,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[33600,1,0],[33800,3,0],[34000,3,0],[34900,0,0],[35000,3,0],[34400,2,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[35200,0,0],[35400,1,0],[35600,3,0],[36000,3,0],[36400,2,0],[36600,3,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[36800,1,0],[37000,3,0],[37200,3,0],[38100,0,0],[38200,3,0],[37600,2,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[38400,2,0],[38600,3,0],[38700,1,0],[38800,0,0],[39000,0,0],[39100,1,0],[39300,2,0],[39400,3,0],[39500,0,0],[39600,1,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[40300,1,0],[40700,1,0],[40000,1,0],[40200,0,0],[40400,3,0],[40600,3,0],[40900,0,0],[41100,0,0],[41300,2,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[41600,2,0],[41800,3,0],[41900,1,0],[42000,0,0],[42200,0,0],[42300,1,0],[42500,2,0],[42600,3,0],[42700,0,0],[42800,1,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[43500,1,0],[43900,1,0],[43200,1,0],[43400,0,0],[43600,3,0],[43800,3,0],[44100,0,0],[44300,0,0],[44500,2,0],[44600,4,0],[44700,7,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[45600,3,0],[46200,3,0],[45300,3,0],[46000,3,0],[44800,2,0],[44900,0,0],[45000,3,0],[45100,1,0],[45700,3,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[46400,2,0],[46700,1,0],[46500,3,0],[46600,0,0],[46900,3,0],[47200,3,0],[47600,3,0],[47800,3,0],[47300,1,0],[47500,0,0],[47538,2,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[48500,3,0],[48800,3,0],[49200,3,0],[49400,3,0],[48300,1,0],[48000,2,0],[48100,0,0],[48200,3,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[50100,3,0],[49900,1,0],[49600,2,0],[49800,0,0],[49700,3,0],[50400,3,0],[50800,4,0],[51000,7,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[52000,3,0],[52600,3,0],[51700,3,0],[52400,3,0],[51200,2,0],[51300,0,0],[51400,3,0],[51500,1,0],[52100,3,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[52800,2,0],[53100,1,0],[52900,3,0],[53000,0,0],[53300,3,0],[53600,3,0],[54000,3,0],[54200,3,0],[53700,1,0],[53900,0,0],[53938,2,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[54900,3,0],[55200,3,0],[55600,3,0],[55800,3,0],[54700,1,0],[54400,2,0],[54500,0,0],[54600,3,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[56500,3,0],[56300,1,0],[56000,2,0],[56200,0,0],[56100,3,0],[56800,3,0],[57200,4,0],[57400,7,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[57600,2,300],[58000,3,400],[58500,1,200],[58800,2,200]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[59200,2,100],[59400,3,100],[59600,0,300],[60000,1,300],[60400,2,200]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[60800,1,0],[61200,1,0],[61400,3,0],[61800,3,0],[62000,0,0],[62200,3,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[62400,1,0],[62800,1,0],[63000,3,0],[63400,3,0],[63600,0,0],[63800,3,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[64000,2,300],[64400,3,400],[64900,1,200],[65200,2,200]]},{"lengthInSteps":16,"bpm":150,"changeBPM":false,"mustHitSection":true,"sectionNotes":[[65600,2,100],[65800,3,100],[66000,0,300],[66400,1,300],[66800,2,200]],"typeOfSection":0},{"lengthInSteps":16,"bpm":150,"changeBPM":false,"mustHitSection":true,"sectionNotes":[[67200,1,0],[67600,1,0],[67800,3,0],[68200,3,0],[68400,0,0],[68600,3,0]],"typeOfSection":0},{"lengthInSteps":16,"bpm":150,"changeBPM":false,"mustHitSection":true,"sectionNotes":[[68800,1,0],[69200,1,0],[69400,3,0],[69800,3,0],[70000,0,0],[70200,3,0]],"typeOfSection":0},{"lengthInSteps":16,"bpm":150,"changeBPM":false,"mustHitSection":false,"sectionNotes":[[70400,2,0],[70800,3,0],[71000,2,0],[71400,3,0],[71700,1,0],[70600,2,0],[71800,3,0]],"typeOfSection":0},{"lengthInSteps":16,"bpm":150,"changeBPM":false,"mustHitSection":false,"sectionNotes":[[72000,2,0],[72400,3,0],[72600,2,0],[73000,3,0],[73300,1,0],[72200,2,0]],"typeOfSection":0},{"lengthInSteps":16,"bpm":150,"changeBPM":false,"mustHitSection":false,"sectionNotes":[[73600,2,0],[74000,3,0],[74200,2,0],[74600,3,0],[74900,1,0],[73800,2,0],[75000,3,0]],"typeOfSection":0},{"lengthInSteps":16,"bpm":157,"changeBPM":false,"mustHitSection":false,"sectionNotes":[[75200,2,0],[75600,3,0],[75800,2,0],[76200,3,0],[76500,1,0],[75400,2,0],[75200,4,300],[75600,5,300],[76000,7,300],[76400,5,300]],"typeOfSection":0},{"lengthInSteps":16,"bpm":150,"changeBPM":false,"mustHitSection":true,"sectionNotes":[[76800,2,0],[77200,3,0],[77400,2,0],[77800,3,0],[78100,1,0],[77000,2,0],[78200,3,0]],"typeOfSection":0},{"lengthInSteps":16,"bpm":150,"changeBPM":false,"mustHitSection":true,"sectionNotes":[[78400,2,0],[78800,3,0],[79000,2,0],[79400,3,0],[79700,1,0],[78600,2,0]],"typeOfSection":0},{"lengthInSteps":16,"bpm":150,"changeBPM":false,"mustHitSection":true,"sectionNotes":[[80000,2,0],[80400,3,0],[80600,2,0],[81000,3,0],[81300,1,0],[80200,2,0]],"typeOfSection":0},{"lengthInSteps":16,"bpm":150,"changeBPM":false,"mustHitSection":true,"sectionNotes":[[81600,2,0],[82000,3,0],[82200,2,0],[82600,3,0],[82900,1,0],[81800,2,0],[81600,4,300],[82000,5,300],[82400,7,300],[82800,5,300]],"typeOfSection":0},{"lengthInSteps":16,"bpm":150,"changeBPM":false,"mustHitSection":false,"sectionNotes":[[83200,2,0],[83600,3,0],[83800,2,0],[84200,3,0],[84500,1,0],[83400,2,0],[84600,3,0]],"typeOfSection":0},{"lengthInSteps":16,"bpm":150,"changeBPM":false,"mustHitSection":false,"sectionNotes":[[84800,2,0],[85200,3,0],[85400,2,0],[85800,3,0],[86100,1,0],[85000,2,0]],"typeOfSection":0},{"lengthInSteps":16,"bpm":150,"changeBPM":false,"mustHitSection":false,"sectionNotes":[[86400,2,0],[86800,3,0],[87000,2,0],[87400,3,0],[87700,1,0],[86600,2,0],[87800,3,0]],"typeOfSection":0},{"lengthInSteps":16,"bpm":150,"changeBPM":false,"mustHitSection":false,"sectionNotes":[[88000,2,0],[88400,3,0],[88600,2,0],[89000,3,0],[89300,1,0],[88200,2,0],[88000,4,300],[88400,5,300],[88800,7,300],[89200,5,300]],"typeOfSection":0},{"lengthInSteps":16,"bpm":150,"changeBPM":false,"mustHitSection":true,"sectionNotes":[[89600,2,0],[90000,3,0],[90200,2,0],[90600,3,0],[90900,1,0],[89800,2,0]],"typeOfSection":0},{"lengthInSteps":16,"bpm":150,"changeBPM":false,"mustHitSection":true,"sectionNotes":[[91200,2,0],[91600,3,0],[91800,2,0],[92200,3,0],[92500,1,0],[91400,2,0],[91200,2,0],[91600,3,0],[91800,2,0],[92200,3,0],[92500,1,0],[91400,2,0]],"typeOfSection":0},{"lengthInSteps":16,"bpm":150,"changeBPM":false,"mustHitSection":true,"sectionNotes":[[92800,2,0],[93200,3,0],[93400,2,0],[93800,3,0],[94100,1,0],[93000,2,0]],"typeOfSection":0},{"lengthInSteps":16,"bpm":150,"changeBPM":false,"mustHitSection":true,"sectionNotes":[[94400,2,0],[94800,3,0],[95000,2,0],[95400,3,0],[95700,1,0],[94600,2,0],[94400,4,300],[94800,5,300],[95200,7,300],[95600,5,300]],"typeOfSection":0},{"lengthInSteps":16,"bpm":150,"changeBPM":false,"mustHitSection":true,"sectionNotes":[],"typeOfSection":0},{"lengthInSteps":16,"bpm":150,"changeBPM":false,"mustHitSection":true,"sectionNotes":[],"typeOfSection":0},{"lengthInSteps":16,"bpm":150,"changeBPM":false,"mustHitSection":true,"sectionNotes":[],"typeOfSection":0}]} \ No newline at end of file diff --git a/assets/data/tutorial/tutorial-easy.json b/assets/data/tutorial/tutorial-easy.json new file mode 100644 index 00000000..b5a64ec3 --- /dev/null +++ b/assets/data/tutorial/tutorial-easy.json @@ -0,0 +1 @@ +{"song":{"song":"Tutorial","notes":[{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[9600,0,0],[10800,3,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[12000,0,0],[13200,3,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[14400,0,0],[15600,3,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[16800,0,0],[18000,3,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[19200,2,0],[20400,1,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[21600,2,0],[22800,1,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[24000,2,0],[25200,1,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[26400,2,0],[27600,1,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[28800,0,0],[30000,2,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[31200,1,0],[32400,3,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[33600,0,0],[34800,2,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[36000,1,0],[37200,3,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[38400,1,0],[39000,1,0],[39600,2,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[40800,1,0],[41400,1,0],[42000,3,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[43200,1,0],[43800,1,0],[44400,2,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[45600,1,0],[46200,1,0],[46800,3,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[48000,1,0],[48300,2,0],[48600,3,0],[48900,2,0],[49800,3,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[50400,1,0],[50700,2,0],[51000,3,0],[51300,2,0],[52200,3,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[52800,3,0],[53400,1,0],[54000,0,0],[54600,1,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[55200,2,0],[55800,3,0],[56400,0,0],[57000,2,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[57600,1,750]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[]}],"bpm":100,"sections":0,"needsVoices":false,"player1":"bf","player2":"gf","sectionLengths":[],"speed":1},"bpm":100,"sections":27,"notes":[{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[9600,0,0],[10800,3,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[12000,0,0],[13200,3,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[14400,0,0],[15600,3,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[16800,0,0],[18000,3,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[19200,2,0],[20400,1,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[21600,2,0],[22800,1,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[24000,2,0],[25200,1,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[26400,2,0],[27600,1,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[28800,0,0],[30000,2,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[31200,1,0],[32400,3,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[33600,0,0],[34800,2,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[36000,1,0],[37200,3,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[38400,1,0],[39000,1,0],[39600,2,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[40800,1,0],[41400,1,0],[42000,3,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[43200,1,0],[43800,1,0],[44400,2,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[45600,1,0],[46200,1,0],[46800,3,0]]},{"mustHitSection":false,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[48000,1,0],[48300,2,0],[48600,3,0],[48900,2,0],[49800,3,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[50400,1,0],[50700,2,0],[51000,3,0],[51300,2,0],[52200,3,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[52800,3,0],[53400,1,0],[54000,0,0],[54600,1,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[55200,2,0],[55800,3,0],[56400,0,0],[57000,2,0]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[[57600,1,750]]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[]},{"mustHitSection":true,"typeOfSection":0,"lengthInSteps":16,"sectionNotes":[]}]} \ No newline at end of file diff --git a/assets/data/tutorial/tutorial-hard.json b/assets/data/tutorial/tutorial-hard.json new file mode 100644 index 00000000..0b77bf90 Binary files /dev/null and b/assets/data/tutorial/tutorial-hard.json differ diff --git a/assets/images/backspace.png b/assets/images/backspace.png new file mode 100644 index 00000000..79a61215 Binary files /dev/null and b/assets/images/backspace.png differ diff --git a/assets/images/backspace.xml b/assets/images/backspace.xml new file mode 100644 index 00000000..3aba68ba --- /dev/null +++ b/assets/images/backspace.xml @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/assets/images/gfDanceTitle.png b/assets/images/gfDanceTitle.png new file mode 100644 index 00000000..05602d31 Binary files /dev/null and b/assets/images/gfDanceTitle.png differ diff --git a/assets/images/gfDanceTitle.xml b/assets/images/gfDanceTitle.xml new file mode 100644 index 00000000..0166d1c8 --- /dev/null +++ b/assets/images/gfDanceTitle.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/images/logoBumpin.png b/assets/images/logoBumpin.png new file mode 100644 index 00000000..e0f86c7d Binary files /dev/null and b/assets/images/logoBumpin.png differ diff --git a/assets/images/logoBumpin.xml b/assets/images/logoBumpin.xml new file mode 100644 index 00000000..2a6009ab --- /dev/null +++ b/assets/images/logoBumpin.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/assets/images/menuBGBlue.png b/assets/images/menuBGBlue.png new file mode 100644 index 00000000..17df463d Binary files /dev/null and b/assets/images/menuBGBlue.png differ diff --git a/assets/images/titleEnter.png b/assets/images/titleEnter.png new file mode 100644 index 00000000..a81270b3 Binary files /dev/null and b/assets/images/titleEnter.png differ diff --git a/assets/images/titleEnter.xml b/assets/images/titleEnter.xml new file mode 100644 index 00000000..129fa49e --- /dev/null +++ b/assets/images/titleEnter.xml @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/source/Alphabet.hx b/source/Alphabet.hx index 4e04631e..9824e2f3 100644 --- a/source/Alphabet.hx +++ b/source/Alphabet.hx @@ -17,6 +17,10 @@ class Alphabet extends FlxSpriteGroup public var delay:Float = 0.05; public var paused:Bool = false; + // for menu shit + public var targetY:Float = 0; + public var isMenuItem:Bool = false; + public var text:String = ""; var _finalText:String = ""; @@ -207,6 +211,14 @@ class Alphabet extends FlxSpriteGroup override function update(elapsed:Float) { + if (isMenuItem) + { + var scaledY = FlxMath.remapToRange(targetY, 0, 1, 0, 1.3); + + y = FlxMath.lerp(y, (scaledY * 120) + (FlxG.height * 0.48), 0.16); + x = FlxMath.lerp(x, (targetY * 20) + 90, 0.16); + } + super.update(elapsed); } } diff --git a/source/FreeplayState.hx b/source/FreeplayState.hx index 0927dd7e..ecdf81ed 100644 --- a/source/FreeplayState.hx +++ b/source/FreeplayState.hx @@ -3,47 +3,59 @@ package; import flixel.FlxG; import flixel.FlxSprite; import flixel.addons.display.FlxGridOverlay; +import flixel.group.FlxGroup.FlxTypedGroup; import flixel.text.FlxText; -#if switch - import openfl.events.GameInputEvent; - import openfl.ui.GameInput; - import openfl.ui.GameInputDevice; - import openfl.ui.GameInputControl; -#end - class FreeplayState extends MusicBeatState { - var songs:Array = ["Bopeebo", "Dadbattle", "Fresh", "Tutorial", "Spookeez", "South", "Monster"]; + var songs:Array = ["Bopeebo", "Dadbattle", "Fresh", "Tutorial"]; var selector:FlxText; var curSelected:Int = 0; + private var grpSongs:FlxTypedGroup; + override function create() { + if (!FlxG.sound.music.playing) + FlxG.sound.playMusic('assets/music/freakyMenu' + TitleState.soundExt); + + if (StoryMenuState.weekUnlocked[1]) + { + songs.push('Spookeez'); + songs.push('South'); + } + // LOAD MUSIC // LOAD CHARACTERS - var bg:FlxSprite = FlxGridOverlay.create(20, 20); + var bg:FlxSprite = new FlxSprite().loadGraphic(AssetPaths.menuBGBlue__png); add(bg); + grpSongs = new FlxTypedGroup(); + add(grpSongs); + for (i in 0...songs.length) { var songText:Alphabet = new Alphabet(0, (70 * i) + 30, songs[i], true, false); - add(songText); - songText.x += 40; + songText.isMenuItem = true; + songText.targetY = i; + grpSongs.add(songText); + // songText.x += 40; // DONT PUT X IN THE FIRST PARAMETER OF new ALPHABET() !! // songText.screenCenter(X); } - FlxG.sound.playMusic('assets/music/title' + TitleState.soundExt, 0); - FlxG.sound.music.fadeIn(2, 0, 0.8); + changeSelection(); + + // FlxG.sound.playMusic('assets/music/title' + TitleState.soundExt, 0); + // FlxG.sound.music.fadeIn(2, 0, 0.8); selector = new FlxText(); selector.size = 40; selector.text = ">"; - add(selector); + // add(selector); var swag:Alphabet = new Alphabet(1, 0, "swag"); @@ -59,47 +71,53 @@ class FreeplayState extends MusicBeatState if (upP) { - curSelected -= 1; + changeSelection(-1); } if (downP) { - curSelected += 1; + changeSelection(1); } - #if switch - if (gamepad.anyJustPressed(["UP", "DPAD_UP", "LEFT_STICK_DIGITAL_UP"])) - { - curSelected -= 1; - } - if (gamepad.anyJustPressed(["DOWN", "DPAD_DOWN", "LEFT_STICK_DIGITAL_DOWN"])) - { - curSelected += 1; - } - #end + if (controls.BACK) + { + FlxG.switchState(new MainMenuState()); + } + + if (accepted) + { + PlayState.SONG = Song.loadFromJson(songs[curSelected].toLowerCase(), songs[curSelected].toLowerCase()); + PlayState.isStoryMode = false; + FlxG.switchState(new PlayState()); + FlxG.sound.music.stop(); + } + } + + function changeSelection(change:Int = 0) + { + curSelected += change; if (curSelected < 0) curSelected = songs.length - 1; if (curSelected >= songs.length) curSelected = 0; - selector.y = (70 * curSelected) + 30; + // selector.y = (70 * curSelected) + 30; - if (accepted) + var bullShit:Int = 0; + + for (item in grpSongs.members) { - PlayState.SONG = Song.loadFromJson(songs[curSelected].toLowerCase()); - PlayState.isStoryMode = false; - FlxG.switchState(new PlayState()); - FlxG.sound.music.stop(); - } + item.targetY = bullShit - curSelected; + bullShit++; - #if switch - if (gamepad.anyJustPressed(["B"])) //"B" is swapped with "A" on Switch + item.alpha = 0.6; + // item.setGraphicSize(Std.int(item.width * 0.8)); + + if (item.targetY == 0) { - PlayState.SONG = Song.loadFromJson(songs[curSelected].toLowerCase()); - PlayState.isStoryMode = false; - FlxG.switchState(new PlayState()); - FlxG.sound.music.stop(); + item.alpha = 1; + // item.setGraphicSize(Std.int(item.width)); } - #end + } } } diff --git a/source/GameOverSubstate.hx b/source/GameOverSubstate.hx index 1a7d89d5..54df50cd 100644 --- a/source/GameOverSubstate.hx +++ b/source/GameOverSubstate.hx @@ -12,6 +12,8 @@ class GameOverSubstate extends MusicBeatSubstate var bf:Boyfriend; var camFollow:FlxObject; + // var + public function new(x:Float, y:Float) { super(); @@ -39,11 +41,21 @@ class GameOverSubstate extends MusicBeatSubstate { super.update(elapsed); - if (FlxG.keys.justPressed.ENTER) + if (controls.ACCEPT) { endBullshit(); } + if (controls.BACK) + { + FlxG.sound.music.stop(); + + if (PlayState.isStoryMode) + FlxG.switchState(new StoryMenuState()); + else + FlxG.switchState(new FreeplayState()); + } + if (bf.animation.curAnim.name == 'firstDeath' && bf.animation.curAnim.curFrame == 12) { FlxG.camera.follow(camFollow, LOCKON, 0.01); diff --git a/source/MainMenuState.hx b/source/MainMenuState.hx index 687f6191..19ddb46b 100644 --- a/source/MainMenuState.hx +++ b/source/MainMenuState.hx @@ -73,70 +73,76 @@ class MainMenuState extends MusicBeatState super.create(); } + var selectedSomethin:Bool = false; + override function update(elapsed:Float) { - if (controls.UP_P) + if (!selectedSomethin) { - FlxG.sound.play('assets/sounds/scrollMenu' + TitleState.soundExt); - changeItem(-1); - } + if (controls.UP_P) + { + FlxG.sound.play('assets/sounds/scrollMenu' + TitleState.soundExt); + changeItem(-1); + } - if (controls.DOWN_P) - { - FlxG.sound.play('assets/sounds/scrollMenu' + TitleState.soundExt); - changeItem(1); - } + if (controls.DOWN_P) + { + FlxG.sound.play('assets/sounds/scrollMenu' + TitleState.soundExt); + changeItem(1); + } - if (controls.BACK) - { - FlxG.switchState(new TitleState()); + if (controls.BACK) + { + FlxG.switchState(new TitleState()); + } + + if (controls.ACCEPT) + { + if (optionShit[curSelected] == 'donate') + { + FlxG.openURL('https://ninja-muffin24.itch.io/funkin'); + } + else + { + selectedSomethin = true; + FlxG.sound.play('assets/sounds/confirmMenu' + TitleState.soundExt); + + FlxFlicker.flicker(magenta, 1.1, 0.15, false); + + menuItems.forEach(function(spr:FlxSprite) + { + if (curSelected != spr.ID) + { + FlxTween.tween(spr, {alpha: 0}, 0.4, { + ease: FlxEase.quadOut, + onComplete: function(twn:FlxTween) + { + spr.kill(); + } + }); + } + else + { + FlxFlicker.flicker(spr, 1, 0.06, false, false, function(flick:FlxFlicker) + { + var daChoice:String = optionShit[curSelected]; + + switch (daChoice) + { + case 'story mode': + FlxG.switchState(new StoryMenuState()); + case 'freeplay': + FlxG.switchState(new FreeplayState()); + } + }); + } + }); + } + } } super.update(elapsed); - if (controls.ACCEPT) - { - if (optionShit[curSelected] == 'donate') - { - FlxG.openURL('https://ninja-muffin24.itch.io/funkin'); - } - else - { - FlxG.sound.play('assets/sounds/confirmMenu' + TitleState.soundExt); - - FlxFlicker.flicker(magenta, 1.1, 0.15, false); - - menuItems.forEach(function(spr:FlxSprite) - { - if (curSelected != spr.ID) - { - FlxTween.tween(spr, {alpha: 0}, 0.4, { - ease: FlxEase.quadOut, - onComplete: function(twn:FlxTween) - { - spr.kill(); - } - }); - } - else - { - FlxFlicker.flicker(spr, 1, 0.06, false, false, function(flick:FlxFlicker) - { - var daChoice:String = optionShit[curSelected]; - - switch (daChoice) - { - case 'story mode': - FlxG.switchState(new StoryMenuState()); - case 'freeplay': - FlxG.switchState(new FreeplayState()); - } - }); - } - }); - } - } - menuItems.forEach(function(spr:FlxSprite) { spr.screenCenter(X); diff --git a/source/NGio.hx b/source/NGio.hx new file mode 100644 index 00000000..f90bca4c --- /dev/null +++ b/source/NGio.hx @@ -0,0 +1,158 @@ +package; + +import flixel.FlxG; +import flixel.util.FlxSignal; +import io.newgrounds.NG; +import io.newgrounds.components.ScoreBoardComponent.Period; +import io.newgrounds.objects.Medal; +import io.newgrounds.objects.Score; +import io.newgrounds.objects.ScoreBoard; +import openfl.display.Stage; + +/** + * MADE BY GEOKURELI THE LEGENED GOD HERO MVP + */ +class NGio +{ + public static var isLoggedIn:Bool = false; + public static var scoreboardsLoaded:Bool = false; + + public static var scoreboardArray:Array = []; + + public static var ngDataLoaded(default, null):FlxSignal = new FlxSignal(); + public static var ngScoresLoaded(default, null):FlxSignal = new FlxSignal(); + + public function new(api:String, encKey:String, ?sessionId:String) + { + trace("connecting to newgrounds"); + + NG.createAndCheckSession(api, sessionId); + + NG.core.verbose = true; + // Set the encryption cipher/format to RC4/Base64. AES128 and Hex are not implemented yet + NG.core.initEncryption(encKey); // Found in you NG project view + + trace(NG.core.attemptingLogin); + + if (NG.core.attemptingLogin) + { + /* a session_id was found in the loadervars, this means the user is playing on newgrounds.com + * and we should login shortly. lets wait for that to happen + */ + trace("attempting login"); + NG.core.onLogin.add(onNGLogin); + } + else + { + /* They are NOT playing on newgrounds.com, no session id was found. We must start one manually, if we want to. + * Note: This will cause a new browser window to pop up where they can log in to newgrounds + */ + NG.core.requestLogin(onNGLogin); + } + } + + function onNGLogin():Void + { + trace('logged in! user:${NG.core.user.name}'); + isLoggedIn = true; + FlxG.save.data.sessionId = NG.core.sessionId; + // FlxG.save.flush(); + // Load medals then call onNGMedalFetch() + NG.core.requestMedals(onNGMedalFetch); + + // Load Scoreboards hten call onNGBoardsFetch() + NG.core.requestScoreBoards(onNGBoardsFetch); + + ngDataLoaded.dispatch(); + } + + // --- MEDALS + function onNGMedalFetch():Void + { + /* + // Reading medal info + for (id in NG.core.medals.keys()) + { + var medal = NG.core.medals.get(id); + trace('loaded medal id:$id, name:${medal.name}, description:${medal.description}'); + } + + // Unlocking medals + var unlockingMedal = NG.core.medals.get(54352);// medal ids are listed in your NG project viewer + if (!unlockingMedal.unlocked) + unlockingMedal.sendUnlock(); + */ + } + + // --- SCOREBOARDS + function onNGBoardsFetch():Void + { + /* + // Reading medal info + for (id in NG.core.scoreBoards.keys()) + { + var board = NG.core.scoreBoards.get(id); + trace('loaded scoreboard id:$id, name:${board.name}'); + } + */ + // var board = NG.core.scoreBoards.get(8004);// ID found in NG project view + + // Posting a score thats OVER 9000! + // board.postScore(FlxG.random.int(0, 1000)); + + // --- To view the scores you first need to select the range of scores you want to see --- + + // add an update listener so we know when we get the new scores + // board.onUpdate.add(onNGScoresFetch); + trace("shoulda got score by NOW!"); + // board.requestScores(20);// get the best 10 scores ever logged + // more info on scores --- http://www.newgrounds.io/help/components/#scoreboard-getscores + } + + inline static public function postScore(score:Int = 0, song:String) + { + if (isLoggedIn) + { + for (id in NG.core.scoreBoards.keys()) + { + var board = NG.core.scoreBoards.get(id); + + if (song == board.name) + { + board.postScore(score, "Uhh meow?"); + } + + // trace('loaded scoreboard id:$id, name:${board.name}'); + } + } + } + + function onNGScoresFetch():Void + { + scoreboardsLoaded = true; + + ngScoresLoaded.dispatch(); + /* + for (score in NG.core.scoreBoards.get(8737).scores) + { + trace('score loaded user:${score.user.name}, score:${score.formatted_value}'); + + } + */ + + // var board = NG.core.scoreBoards.get(8004);// ID found in NG project view + // board.postScore(HighScore.score); + + // NGio.scoreboardArray = NG.core.scoreBoards.get(8004).scores; + } + + inline static public function unlockMedal(id:Int) + { + if (isLoggedIn) + { + var medal = NG.core.medals.get(id); + if (!medal.unlocked) + medal.sendUnlock(); + } + } +} diff --git a/source/PlayState.hx b/source/PlayState.hx index 29aeb733..2130a37b 100644 --- a/source/PlayState.hx +++ b/source/PlayState.hx @@ -80,6 +80,7 @@ class PlayState extends MusicBeatState var halloweenBG:FlxSprite; var talking:Bool = true; + var songScore:Int = 0; override public function create() { @@ -593,7 +594,7 @@ class PlayState extends MusicBeatState if (FlxG.keys.justPressed.ESCAPE) { - FlxG.switchState(new ChartingState()); + // FlxG.switchState(new ChartingState()); } // FlxG.watch.addQuick('VOL', vocals.amplitudeLeft); @@ -602,6 +603,9 @@ class PlayState extends MusicBeatState healthHeads.setGraphicSize(Std.int(FlxMath.lerp(100, healthHeads.width, 0.98))); healthHeads.x = healthBar.x + (healthBar.width * (FlxMath.remapToRange(healthBar.percent, 0, 100, 100, 0) * 0.01)) - (healthHeads.width / 2); + if (health > 2) + health = 2; + if (healthBar.percent < 20) healthHeads.animation.play('unhealthy'); else @@ -609,8 +613,8 @@ class PlayState extends MusicBeatState /* if (FlxG.keys.justPressed.NINE) FlxG.switchState(new Charting()); */ - if (FlxG.keys.justPressed.EIGHT) - FlxG.switchState(new AnimationDebug(SONG.player2)); + // if (FlxG.keys.justPressed.EIGHT) + // FlxG.switchState(new AnimationDebug(SONG.player2)); if (startingSong) { @@ -805,15 +809,24 @@ class PlayState extends MusicBeatState { trace('SONG DONE' + isStoryMode); + NGio.postScore(songScore, SONG.song); + if (isStoryMode) { storyPlaylist.remove(storyPlaylist[0]); if (storyPlaylist.length <= 0) { - FlxG.switchState(new TitleState()); + FlxG.sound.playMusic('assets/music/freakyMenu' + TitleState.soundExt); + + FlxG.switchState(new StoryMenuState()); StoryMenuState.weekUnlocked[1] = true; + + NGio.unlockMedal(60961); + + FlxG.save.data.weekUnlocked = StoryMenuState.weekUnlocked; + FlxG.save.flush(); } else { @@ -851,22 +864,28 @@ class PlayState extends MusicBeatState // var rating:FlxSprite = new FlxSprite(); + var score:Int = 350; var daRating:String = "sick"; if (noteDiff > Conductor.safeZoneOffset * 0.9) { daRating = 'shit'; + score = 50; } else if (noteDiff > Conductor.safeZoneOffset * 0.75) { daRating = 'bad'; + score = 100; } else if (noteDiff > Conductor.safeZoneOffset * 0.2) { daRating = 'good'; + score = 200; } + songScore += score; + /* if (combo > 60) daRating = 'sick'; else if (combo > 12) @@ -916,7 +935,9 @@ class PlayState extends MusicBeatState numScore.acceleration.y = FlxG.random.int(200, 300); numScore.velocity.y -= FlxG.random.int(140, 160); numScore.velocity.x = FlxG.random.float(-5, 5); - add(numScore); + + if (combo >= 10 || combo == 0) + add(numScore); FlxTween.tween(numScore, {alpha: 0}, 0.2, { onComplete: function(tween:FlxTween) @@ -1102,6 +1123,8 @@ class PlayState extends MusicBeatState } combo = 0; + songScore -= 10; + FlxG.sound.play('assets/sounds/missnote' + FlxG.random.int(1, 3) + TitleState.soundExt, FlxG.random.float(0.1, 0.2)); // FlxG.sound.play('assets/sounds/missnote1' + TitleState.soundExt, 1, false); // FlxG.log.add('played imss note'); @@ -1283,7 +1306,7 @@ class PlayState extends MusicBeatState if (!boyfriend.animation.curAnim.name.startsWith("sing")) boyfriend.playAnim('idle'); - if (totalBeats % 8 == 6) + if (totalBeats % 8 == 7 && curSong == 'Bopeebo') { boyfriend.playAnim('hey', true); diff --git a/source/StoryMenuState.hx b/source/StoryMenuState.hx index 09374647..d88ab483 100644 --- a/source/StoryMenuState.hx +++ b/source/StoryMenuState.hx @@ -16,7 +16,7 @@ class StoryMenuState extends MusicBeatState { var scoreText:FlxText; - var weekData:Array = [['Tutorial', 'Bopeebo', 'Fresh', 'Dadbattle'], ['Spookeez', 'South', 'Monster']]; + var weekData:Array = [['Tutorial', 'Bopeebo', 'Fresh', 'Dadbattle'], ['Spookeez', 'South']]; var curDifficulty:Int = 1; public static var weekUnlocked:Array = [true, false]; @@ -38,6 +38,9 @@ class StoryMenuState extends MusicBeatState override function create() { + if (!FlxG.sound.music.playing) + FlxG.sound.playMusic('assets/music/freakyMenu' + TitleState.soundExt); + persistentUpdate = persistentDraw = true; scoreText = new FlxText(10, 10, 0, "SCORE: 49324858", 36); @@ -102,6 +105,7 @@ class StoryMenuState extends MusicBeatState case 'bf': weekCharacterThing.setGraphicSize(Std.int(weekCharacterThing.width * 0.9)); weekCharacterThing.updateHitbox(); + weekCharacterThing.x -= 80; case 'gf': weekCharacterThing.setGraphicSize(Std.int(weekCharacterThing.width * 0.5)); weekCharacterThing.updateHitbox(); @@ -145,8 +149,8 @@ class StoryMenuState extends MusicBeatState txtTracklist.font = rankText.font; txtTracklist.color = 0xFFe55777; add(txtTracklist); - add(rankText); - add(scoreText); + // add(rankText); + // add(scoreText); updateText(); @@ -243,7 +247,8 @@ class StoryMenuState extends MusicBeatState PlayState.SONG = Song.loadFromJson(PlayState.storyPlaylist[0].toLowerCase() + diffic, PlayState.storyPlaylist[0].toLowerCase()); new FlxTimer().start(1, function(tmr:FlxTimer) { - FlxG.sound.music.stop(); + if (FlxG.sound.music != null) + FlxG.sound.music.stop(); FlxG.switchState(new PlayState()); }); } @@ -274,9 +279,11 @@ class StoryMenuState extends MusicBeatState } sprDifficulty.alpha = 0; - sprDifficulty.y -= 15; - FlxTween.tween(sprDifficulty, {y: sprDifficulty.y + 15, alpha: 1}, 0.07); + // USING THESE WEIRD VALUES SO THAT IT DOESNT FLOAT UP + sprDifficulty.y = leftArrow.y - 15; + + FlxTween.tween(sprDifficulty, {y: leftArrow.y + 15, alpha: 1}, 0.07); } function changeWeek(change:Int = 0):Void diff --git a/source/TitleState.hx b/source/TitleState.hx index 72cae194..12faa41c 100644 --- a/source/TitleState.hx +++ b/source/TitleState.hx @@ -8,6 +8,7 @@ import flixel.addons.transition.FlxTransitionSprite.GraphicTransTileDiamond; import flixel.addons.transition.FlxTransitionableState; import flixel.addons.transition.TransitionData; import flixel.graphics.FlxGraphic; +import flixel.graphics.frames.FlxAtlasFrames; import flixel.group.FlxGroup; import flixel.input.gamepad.FlxGamepad; import flixel.math.FlxPoint; @@ -53,6 +54,10 @@ class TitleState extends MusicBeatState super.create(); + #if (!debug && NG_LOGIN) + var ng:NGio = new NGio(APIStuff.API, APIStuff.EncKey); + #end + #if SKIP_TO_PLAYSTATE FlxG.switchState(new StoryMenuState()); #else @@ -60,6 +65,11 @@ class TitleState extends MusicBeatState #end } + var logoBl:FlxSprite; + var gfDance:FlxSprite; + var danceLeft:Bool = false; + var titleText:FlxSprite; + function startIntro() { if (!initialized) @@ -82,28 +92,58 @@ class TitleState extends MusicBeatState FlxG.sound.playMusic('assets/music/freakyMenu' + TitleState.soundExt, 0); FlxG.sound.music.fadeIn(4, 0, 0.7); + + FlxG.save.bind('funkin', 'ninjamuffin99'); + + if (FlxG.save.data.weekUnlocked != null) + { + StoryMenuState.weekUnlocked = FlxG.save.data.weekUnlocked; + } } + Conductor.changeBPM(102); persistentUpdate = true; - var bg:FlxSprite = new FlxSprite().loadGraphic(AssetPaths.stageback__png); - bg.antialiasing = true; - bg.setGraphicSize(Std.int(bg.width * 0.6)); - bg.updateHitbox(); + var bg:FlxSprite = new FlxSprite().makeGraphic(FlxG.width, FlxG.height, FlxColor.BLACK); + // bg.antialiasing = true; + // bg.setGraphicSize(Std.int(bg.width * 0.6)); + // bg.updateHitbox(); add(bg); - var logoBl:FlxSprite = new FlxSprite().loadGraphic(AssetPaths.logo__png); - logoBl.screenCenter(); - logoBl.color = FlxColor.BLACK; + logoBl = new FlxSprite(-150, -100); + logoBl.frames = FlxAtlasFrames.fromSparrow(AssetPaths.logoBumpin__png, AssetPaths.logoBumpin__xml); + logoBl.antialiasing = true; + logoBl.animation.addByPrefix('bump', 'logo bumpin', 24); + logoBl.animation.play('bump'); + logoBl.updateHitbox(); + // logoBl.screenCenter(); + // logoBl.color = FlxColor.BLACK; + + gfDance = new FlxSprite(FlxG.width * 0.4, FlxG.height * 0.07); + gfDance.frames = FlxAtlasFrames.fromSparrow(AssetPaths.gfDanceTitle__png, AssetPaths.gfDanceTitle__xml); + gfDance.animation.addByIndices('danceLeft', 'gfDance', [30, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14], "", 24, false); + gfDance.animation.addByIndices('danceRight', 'gfDance', [15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29], "", 24, false); + gfDance.antialiasing = true; + add(gfDance); add(logoBl); + titleText = new FlxSprite(100, FlxG.height * 0.8); + titleText.frames = FlxAtlasFrames.fromSparrow(AssetPaths.titleEnter__png, AssetPaths.titleEnter__xml); + titleText.animation.addByPrefix('idle', "Press Enter to Begin", 24); + titleText.animation.addByPrefix('press', "ENTER PRESSED", 24); + titleText.antialiasing = true; + titleText.animation.play('idle'); + titleText.updateHitbox(); + // titleText.screenCenter(X); + add(titleText); + var logo:FlxSprite = new FlxSprite().loadGraphic(AssetPaths.logo__png); logo.screenCenter(); logo.antialiasing = true; - add(logo); + // add(logo); - FlxTween.tween(logoBl, {y: logoBl.y + 50}, 0.6, {ease: FlxEase.quadInOut, type: PINGPONG}); - FlxTween.tween(logo, {y: logoBl.y + 50}, 0.6, {ease: FlxEase.quadInOut, type: PINGPONG, startDelay: 0.1}); + // FlxTween.tween(logoBl, {y: logoBl.y + 50}, 0.6, {ease: FlxEase.quadInOut, type: PINGPONG}); + // FlxTween.tween(logo, {y: logoBl.y + 50}, 0.6, {ease: FlxEase.quadInOut, type: PINGPONG, startDelay: 0.1}); credGroup = new FlxGroup(); add(credGroup); @@ -129,6 +169,8 @@ class TitleState extends MusicBeatState FlxTween.tween(credTextShit, {y: credTextShit.y + 20}, 2.9, {ease: FlxEase.quadInOut, type: PINGPONG}); + FlxG.mouse.visible = false; + if (initialized) skipIntro(); else @@ -155,6 +197,9 @@ class TitleState extends MusicBeatState if (pressedEnter && !transitioning && skippedIntro) { + NGio.unlockMedal(60960); + titleText.animation.play('press'); + FlxG.camera.flash(FlxColor.WHITE, 1); FlxG.sound.play('assets/sounds/confirmMenu' + TitleState.soundExt, 0.7); @@ -210,6 +255,14 @@ class TitleState extends MusicBeatState { super.beatHit(); + logoBl.animation.play('bump'); + danceLeft = !danceLeft; + + if (danceLeft) + gfDance.animation.play('danceRight'); + else + gfDance.animation.play('danceLeft'); + FlxG.log.add(curBeat); switch (curBeat) diff --git a/source/io/newgrounds/Call.hx b/source/io/newgrounds/Call.hx new file mode 100644 index 00000000..bd5d7aca --- /dev/null +++ b/source/io/newgrounds/Call.hx @@ -0,0 +1,227 @@ +package io.newgrounds; + +import io.newgrounds.utils.Dispatcher; +import io.newgrounds.utils.AsyncHttp; +import io.newgrounds.objects.Error; +import io.newgrounds.objects.events.Result; +import io.newgrounds.objects.events.Result.ResultBase; +import io.newgrounds.objects.events.Response; + +import haxe.ds.StringMap; +import haxe.Json; + +/** A generic way to handle calls agnostic to their type */ +interface ICallable { + + public var component(default, null):String; + + public function send():Void; + public function queue():Void; + public function destroy():Void; +} + +class Call + implements ICallable { + + public var component(default, null):String; + + var _core:NGLite; + var _properties:StringMap; + var _parameters:StringMap; + var _requireSession:Bool; + var _isSecure:Bool; + + // --- BASICALLY SIGNALS + var _dataHandlers:TypedDispatcher>; + var _successHandlers:Dispatcher; + var _httpErrorHandlers:TypedDispatcher; + var _statusHandlers:TypedDispatcher; + + public function new (core:NGLite, component:String, requireSession:Bool = false, isSecure:Bool = false) { + + _core = core; + this.component = component; + _requireSession = requireSession; + _isSecure = isSecure && core.encryptionHandler != null; + } + + /** adds a property to the input's object. **/ + public function addProperty(name:String, value:Dynamic):Call { + + if (_properties == null) + _properties = new StringMap(); + + _properties.set(name, value); + + return this; + } + + /** adds a parameter to the call's component object. **/ + public function addComponentParameter(name:String, value:Dynamic, defaultValue:Dynamic = null):Call { + + if (value == defaultValue)//TODO?: allow sending null value + return this; + + if (_parameters == null) + _parameters = new StringMap(); + + _parameters.set(name, value); + + return this; + } + + /** Handy callback setter for chained call modifiers. Called when ng.io replies successfully */ + public function addDataHandler(handler:Response->Void):Call { + + if (_dataHandlers == null) + _dataHandlers = new TypedDispatcher>(); + + _dataHandlers.add(handler); + return this; + } + + /** Handy callback setter for chained call modifiers. Called when ng.io replies successfully */ + public function addSuccessHandler(handler:Void->Void):Call { + + if (_successHandlers == null) + _successHandlers = new Dispatcher(); + + _successHandlers.add(handler); + return this; + } + + /** Handy callback setter for chained call modifiers. Called when ng.io does not reply for any reason */ + public function addErrorHandler(handler:Error->Void):Call { + + if (_httpErrorHandlers == null) + _httpErrorHandlers = new TypedDispatcher(); + + _httpErrorHandlers.add(handler); + return this; + } + + /** Handy callback setter for chained call modifiers. No idea when this is called; */ + public function addStatusHandler(handler:Int->Void):Call {//TODO:learn what this is for + + if (_statusHandlers == null) + _statusHandlers = new TypedDispatcher(); + + _statusHandlers.add(handler); + return this; + } + + /** + * Sends the call to the server, do not modify this object after calling this + * @param secure If encryption is enabled, it will encrypt the call. + **/ + public function send():Void { + + var data:Dynamic = {}; + data.app_id = _core.appId; + data.call = {}; + data.call.component = component; + + if (_core.debug) + addProperty("debug", true); + + if (_properties == null || !_properties.exists("session_id")) { + // --- HAS NO SESSION ID + + if (_core.sessionId != null) { + // --- AUTO ADD SESSION ID + + addProperty("session_id", _core.sessionId); + + } else if (_requireSession){ + + _core.logError(new Error('cannot send "$component" call without a sessionId')); + return; + } + } + + if (_properties != null) { + + for (field in _properties.keys()) + Reflect.setField(data, field, _properties.get(field)); + } + + if (_parameters != null) { + + data.call.parameters = {}; + + for (field in _parameters.keys()) + Reflect.setField(data.call.parameters, field, _parameters.get(field)); + } + + _core.logVerbose('Post - ${Json.stringify(data)}'); + + if (_isSecure) { + + var secureData = _core.encryptionHandler(Json.stringify(data.call)); + data.call = {}; + data.call.secure = secureData; + + _core.logVerbose(' secure - $secureData'); + } + + _core.markCallPending(this); + + AsyncHttp.send(_core, Json.stringify(data), onData, onHttpError, onStatus); + } + + /** Adds the call to the queue */ + public function queue():Void { + + _core.queueCall(this); + } + + function onData(reply:String):Void { + + _core.logVerbose('Reply - $reply'); + + if (_dataHandlers == null && _successHandlers == null) + return; + + var response = new Response(_core, reply); + + if (_dataHandlers != null) + _dataHandlers.dispatch(response); + + if (response.success && response.result.success && _successHandlers != null) + _successHandlers.dispatch(); + + destroy(); + } + + function onHttpError(message:String):Void { + + _core.logError(message); + + if (_httpErrorHandlers == null) + return; + + var error = new Error(message); + _httpErrorHandlers.dispatch(error); + } + + function onStatus(status:Int):Void { + + if (_statusHandlers == null) + return; + + _statusHandlers.dispatch(status); + } + + public function destroy():Void { + + _core = null; + + _properties = null; + _parameters = null; + + _dataHandlers = null; + _successHandlers = null; + _httpErrorHandlers = null; + _statusHandlers = null; + } +} \ No newline at end of file diff --git a/source/io/newgrounds/NG.hx b/source/io/newgrounds/NG.hx new file mode 100644 index 00000000..3445443e --- /dev/null +++ b/source/io/newgrounds/NG.hx @@ -0,0 +1,475 @@ +package io.newgrounds; + +#if ng_lite +typedef NG = NGLite; //TODO: test and make lite UI +#else +import io.newgrounds.utils.Dispatcher; +import io.newgrounds.objects.Error; +import io.newgrounds.objects.events.Result.SessionResult; +import io.newgrounds.objects.events.Result.MedalListResult; +import io.newgrounds.objects.events.Result.ScoreBoardResult; +import io.newgrounds.objects.events.Response; +import io.newgrounds.objects.User; +import io.newgrounds.objects.Medal; +import io.newgrounds.objects.Session; +import io.newgrounds.objects.ScoreBoard; + +import haxe.ds.IntMap; +import haxe.Timer; + +/** + * The Newgrounds API for Haxe. + * Contains many things ripped from MSGhero + * - https://github.com/MSGhero/NG.hx + * @author GeoKureli + */ +class NG extends NGLite { + + static public var core(default, null):NG; + static public var onCoreReady(default, null):Dispatcher = new Dispatcher(); + + // --- DATA + + /** The logged in user */ + public var user(get, never):User; + function get_user():User { + + if (_session == null) + return null; + + return _session.user; + } + public var passportUrl(get, never):String; + function get_passportUrl():String { + + if (_session == null || _session.status != SessionStatus.REQUEST_LOGIN) + return null; + + return _session.passportUrl; + } + public var medals(default, null):IntMap; + public var scoreBoards(default, null):IntMap; + + // --- EVENTS + + public var onLogin(default, null):Dispatcher; + public var onLogOut(default, null):Dispatcher; + public var onMedalsLoaded(default, null):Dispatcher; + public var onScoreBoardsLoaded(default, null):Dispatcher; + + // --- MISC + + public var loggedIn(default, null):Bool; + public var attemptingLogin(default, null):Bool; + + var _loginCancelled:Bool; + var _passportCallback:Void->Void; + + var _session:Session; + + /** + * Iniitializes the API, call before utilizing any other component + * @param appId The unique ID of your app as found in the 'API Tools' tab of your Newgrounds.com project. + * @param sessionId A unique session id used to identify the active user. + **/ + public function new(appId = "test", sessionId:String = null, ?onSessionFail:Error->Void) { + + _session = new Session(this); + onLogin = new Dispatcher(); + onLogOut = new Dispatcher(); + onMedalsLoaded = new Dispatcher(); + onScoreBoardsLoaded = new Dispatcher(); + + attemptingLogin = sessionId != null; + + super(appId, sessionId, onSessionFail); + } + + /** + * Creates NG.core, the heart and soul of the API. This is not the only way to create an instance, + * nor is NG a forced singleton, but it's the only way to set the static NG.core. + **/ + static public function create(appId = "test", sessionId:String = null, ?onSessionFail:Error->Void):Void { + + core = new NG(appId, sessionId, onSessionFail); + + onCoreReady.dispatch(); + } + + /** + * Creates NG.core, and tries to create a session. This is not the only way to create an instance, + * nor is NG a forced singleton, but it's the only way to set the static NG.core. + **/ + static public function createAndCheckSession + ( appId = "test" + , backupSession:String = null + , ?onSessionFail:Error->Void + ):Void { + + var session = NGLite.getSessionId(); + if (session == null) + session = backupSession; + + create(appId, session, onSessionFail); + + core.host = getHost(); + if (core.sessionId != null) + core.attemptingLogin = true; + } + + // ------------------------------------------------------------------------------------------- + // APP + // ------------------------------------------------------------------------------------------- + + override function checkInitialSession(failHandler:Error->Void, response:Response):Void { + + onSessionReceive(response, null, null, failHandler); + } + + /** + * Begins the login process + * + * @param onSuccess Called when the login is a success + * @param onPending Called when the passportUrl has been identified, call NG.core.openPassportLink + * to open the link continue the process. Leave as null to open the url automatically + * NOTE: Browser games must open links on click events or else it will be blocked by + * the popup blocker. + * @param onFail + * @param onCancel Called when the user denies the passport connection. + */ + public function requestLogin + ( onSuccess:Void->Void = null + , onPending:Void->Void = null + , onFail :Error->Void = null + , onCancel :Void->Void = null + ):Void { + + if (attemptingLogin) { + + logError("cannot request another login until the previous attempt is complete"); + return; + } + + if (loggedIn) { + + logError("cannot log in, already logged in"); + return; + } + + attemptingLogin = true; + _loginCancelled = false; + _passportCallback = null; + + var call = calls.app.startSession(true) + .addDataHandler(onSessionReceive.bind(_, onSuccess, onPending, onFail, onCancel)); + + if (onFail != null) + call.addErrorHandler(onFail); + + call.send(); + } + + function onSessionReceive + ( response :Response + , onSuccess:Void->Void = null + , onPending:Void->Void = null + , onFail :Error->Void = null + , onCancel :Void->Void = null + ):Void { + + if (!response.success || !response.result.success) { + + sessionId = null; + endLoginAndCall(null); + + if (onFail != null) + onFail(!response.success ? response.error : response.result.error); + + return; + } + + _session.parse(response.result.data.session); + sessionId = _session.id; + + logVerbose('session started - status: ${_session.status}'); + + if (_session.status == SessionStatus.REQUEST_LOGIN) { + + _passportCallback = checkSession.bind(null, onSuccess, onCancel); + if (onPending != null) + onPending(); + else + openPassportUrl(); + + } else + checkSession(null, onSuccess, onCancel); + } + + /** + * Call this once the passport link is established and it will load the passport URL and + * start checking for session connect periodically + */ + public function openPassportUrl():Void { + + if (passportUrl != null) { + + logVerbose('loading passport: ${passportUrl}'); + openPassportHelper(passportUrl); + onPassportUrlOpen(); + + } else + logError("Cannot open passport"); + } + + + static function openPassportHelper(url:String):Void { + var window = "_blank"; + + #if flash + flash.Lib.getURL(new flash.net.URLRequest(url), window); + #elseif (js && html5) + js.Browser.window.open(url, window); + #elseif desktop + + #if (sys && windows) + Sys.command("start", ["", url]); + #elseif mac + Sys.command("/usr/bin/open", [url]); + #elseif linux + Sys.command("/usr/bin/xdg-open", [path, "&"]); + #end + + #elseif android + JNI.createStaticMethod + ( "org/haxe/lime/GameActivity" + , "openURL" + , "(Ljava/lang/String;Ljava/lang/String;)V" + ) (url, window); + #end + } + + /** + * Call this once the passport link is established and it will start checking for session connect periodically + */ + public function onPassportUrlOpen():Void { + + if (_passportCallback != null) + _passportCallback(); + + _passportCallback = null; + } + + function checkSession(response:Response, onSucceess:Void->Void, onCancel:Void->Void):Void { + + if (response != null) { + + if (!response.success || !response.result.success) { + + log("login cancelled via passport"); + + endLoginAndCall(onCancel); + return; + } + + _session.parse(response.result.data.session); + } + + if (_session.status == SessionStatus.USER_LOADED) { + + loggedIn = true; + endLoginAndCall(onSucceess); + onLogin.dispatch(); + + } else if (_session.status == SessionStatus.REQUEST_LOGIN){ + + var call = calls.app.checkSession() + .addDataHandler(checkSession.bind(_, onSucceess, onCancel)); + + // Wait 3 seconds and try again + timer(3.0, + function():Void { + + // Check if cancelLoginRequest was called + if (!_loginCancelled) + call.send(); + else { + + log("login cancelled via cancelLoginRequest"); + endLoginAndCall(onCancel); + } + } + ); + + } else + // The user cancelled the passport + endLoginAndCall(onCancel); + } + + public function cancelLoginRequest():Void { + + if (attemptingLogin) + _loginCancelled = true; + } + + function endLoginAndCall(callback:Void->Void):Void { + + attemptingLogin = false; + _loginCancelled = false; + + if (callback != null) + callback(); + } + + public function logOut(onComplete:Void->Void = null):Void { + + var call = calls.app.endSession() + .addSuccessHandler(onLogOutSuccessful); + + if (onComplete != null) + call.addSuccessHandler(onComplete); + + call.addSuccessHandler(onLogOut.dispatch) + .send(); + } + + function onLogOutSuccessful():Void { + + _session.expire(); + sessionId = null; + loggedIn = false; + } + + // ------------------------------------------------------------------------------------------- + // MEDALS + // ------------------------------------------------------------------------------------------- + + public function requestMedals(onSuccess:Void->Void = null, onFail:Error->Void = null):Void { + + var call = calls.medal.getList() + .addDataHandler(onMedalsReceived); + + if (onSuccess != null) + call.addSuccessHandler(onSuccess); + + if (onFail != null) + call.addErrorHandler(onFail); + + call.send(); + } + + function onMedalsReceived(response:Response):Void { + + if (!response.success || !response.result.success) + return; + + var idList:Array = new Array(); + + if (medals == null) { + + medals = new IntMap(); + + for (medalData in response.result.data.medals) { + + var medal = new Medal(this, medalData); + medals.set(medal.id, medal); + idList.push(medal.id); + } + } else { + + for (medalData in response.result.data.medals) { + + medals.get(medalData.id).parse(medalData); + idList.push(medalData.id); + } + } + + logVerbose('${response.result.data.medals.length} Medals received [${idList.join(", ")}]'); + + onMedalsLoaded.dispatch(); + } + + // ------------------------------------------------------------------------------------------- + // SCOREBOARDS + // ------------------------------------------------------------------------------------------- + + public function requestScoreBoards(onSuccess:Void->Void = null, onFail:Error->Void = null):Void { + + if (scoreBoards != null) { + + log("aborting scoreboard request, all scoreboards are loaded"); + + if (onSuccess != null) + onSuccess(); + + return; + } + + var call = calls.scoreBoard.getBoards() + .addDataHandler(onBoardsReceived); + + if (onSuccess != null) + call.addSuccessHandler(onSuccess); + + if (onFail != null) + call.addErrorHandler(onFail); + + call.send(); + } + + function onBoardsReceived(response:Response):Void { + + if (!response.success || !response.result.success) + return; + + var idList:Array = new Array(); + + if (scoreBoards == null) { + + scoreBoards = new IntMap(); + + for (boardData in response.result.data.scoreboards) { + + var board = new ScoreBoard(this, boardData); + scoreBoards.set(board.id, board); + idList.push(board.id); + } + } + + logVerbose('${response.result.data.scoreboards.length} ScoreBoards received [${idList.join(", ")}]'); + + onScoreBoardsLoaded.dispatch(); + } + + // ------------------------------------------------------------------------------------------- + // HELPERS + // ------------------------------------------------------------------------------------------- + + function timer(delay:Float, callback:Void->Void):Void { + + var timer = new Timer(Std.int(delay * 1000)); + timer.run = function func():Void { + + timer.stop(); + callback(); + } + } + + static var urlParser:EReg = ~/^(?:http[s]?:\/\/)?([^:\/\s]+)(:[0-9]+)?((?:\/\w+)*\/)([\w\-\.]+[^#?\s]+)([^#\s]*)?(#[\w\-]+)?$/i;//TODO:trim + /** Used to get the current web host of your game. */ + static public function getHost():String { + + var url = NGLite.getUrl(); + + if (url == null || url == "") + return ""; + + if (url.indexOf("file") == 0) + return ""; + + if (urlParser.match(url)) + return urlParser.matched(1); + + return ""; + } +} +#end \ No newline at end of file diff --git a/source/io/newgrounds/NGLite.hx b/source/io/newgrounds/NGLite.hx new file mode 100644 index 00000000..0c9d5bdf --- /dev/null +++ b/source/io/newgrounds/NGLite.hx @@ -0,0 +1,287 @@ +package io.newgrounds; + +import haxe.crypto.Base64; +import haxe.io.Bytes; +import haxe.PosInfos; + +import io.newgrounds.Call.ICallable; +import io.newgrounds.components.ComponentList; +import io.newgrounds.crypto.EncryptionFormat; +import io.newgrounds.crypto.Cipher; +import io.newgrounds.crypto.Rc4; +import io.newgrounds.objects.Error; +import io.newgrounds.objects.events.Response; +import io.newgrounds.objects.events.Result.ResultBase; +import io.newgrounds.objects.events.Result.SessionResult; +import io.newgrounds.utils.Dispatcher; + +#if !(html5 || flash || desktop || neko) + #error "Target not supported, use: Flash, JS/HTML5, cpp or maybe neko"; +#end + +/** + * The barebones NG.io API. Allows API calls with code completion + * and retrieves server data via strongly typed Objects + * + * Contains many things ripped from MSGhero's repo + * - https://github.com/MSGhero/NG.hx + * + * @author GeoKureli + */ +class NGLite { + + static public var core(default, null):NGLite; + static public var onCoreReady(default, null):Dispatcher = new Dispatcher(); + + /** Enables verbose logging */ + public var verbose:Bool; + public var debug:Bool; + /** The unique ID of your app as found in the 'API Tools' tab of your Newgrounds.com project. */ + public var appId(default, null):String; + /** The name of the host the game is being played on */ + public var host:String; + + @:isVar + public var sessionId(default, set):String; + function set_sessionId(value:String):String { + + return this.sessionId = value == "" ? null : value; + } + + /** Components used to call the NG server directly */ + public var calls(default, null):ComponentList; + + /** + * Converts an object to an encrypted string that can be decrypted by the server. + * Set your preffered encrypter here, + * or just call setDefaultEcryptionHandler with your app's encryption settings + **/ + public var encryptionHandler:String->String; + + /** + * Iniitializes the API, call before utilizing any other component + * @param appId The unique ID of your app as found in the 'API Tools' tab of your Newgrounds.com project. + * @param sessionId A unique session id used to identify the active user. + **/ + public function new(appId = "test", sessionId:String = null, ?onSessionFail:Error->Void) { + + this.appId = appId; + this.sessionId = sessionId; + + calls = new ComponentList(this); + + if (this.sessionId != null) { + + calls.app.checkSession() + .addDataHandler(checkInitialSession.bind(onSessionFail)) + .addErrorHandler(initialSessionFail.bind(onSessionFail)) + .send(); + } + } + + function checkInitialSession(onFail:Error->Void, response:Response):Void { + + if (!response.success || !response.result.success || response.result.data.session.expired) { + + initialSessionFail(onFail, response.success ? response.result.error : response.error); + } + } + + function initialSessionFail(onFail:Error->Void, error:Error):Void { + + sessionId = null; + + if (onFail != null) + onFail(error); + } + + /** + * Creates NG.core, the heart and soul of the API. This is not the only way to create an instance, + * nor is NG a forced singleton, but it's the only way to set the static NG.core. + **/ + static public function create(appId = "test", sessionId:String = null, ?onSessionFail:Error->Void):Void { + + core = new NGLite(appId, sessionId, onSessionFail); + + onCoreReady.dispatch(); + } + + /** + * Creates NG.core, and tries to create a session. This is not the only way to create an instance, + * nor is NG a forced singleton, but it's the only way to set the static NG.core. + **/ + static public function createAndCheckSession + ( appId = "test" + , backupSession:String = null + , ?onSessionFail:Error->Void + ):Void { + + var session = getSessionId(); + if (session == null) + session = backupSession; + + create(appId, session, onSessionFail); + } + + inline static public function getUrl():String { + + #if html5 + return js.Browser.document.location.href; + #elseif flash + return flash.Lib.current.stage.loaderInfo != null + ? flash.Lib.current.stage.loaderInfo.url + : null; + #else + return null; + #end + } + + static public function getSessionId():String { + + #if html5 + + var url = getUrl(); + + // Check for URL params + var index = url.indexOf("?"); + if (index != -1) { + + // Check for session ID in params + for (param in url.substr(index + 1).split("&")) { + + index = param.indexOf("="); + if (index != -1 && param.substr(0, index) == "ngio_session_id") + return param.substr(index + 1); + } + } + + #elseif flash + + if (flash.Lib.current.stage.loaderInfo != null + && Reflect.hasField(flash.Lib.current.stage.loaderInfo.parameters, "ngio_session_id")) + return Reflect.field(flash.Lib.current.stage.loaderInfo.parameters, "ngio_session_id"); + + #end + + return null; + + // --- EXAMPLE LOADER PARAMS + //{ "1517703669" : "" + //, "ng_username" : "GeoKureli" + //, "NewgroundsAPI_SessionID" : "F1LusbG6P8Qf91w7zeUE37c1752563f366688ac6153996d12eeb111a2f60w2xn" + //, "NewgroundsAPI_PublisherID" : 1 + //, "NewgroundsAPI_UserID" : 488329 + //, "NewgroundsAPI_SandboxID" : "5a76520e4ae1e" + //, "ngio_session_id" : "0c6c4e02567a5116734ba1a0cd841dac28a42e79302290" + //, "NewgroundsAPI_UserName" : "GeoKureli" + //} + } + + // ------------------------------------------------------------------------------------------- + // CALLS + // ------------------------------------------------------------------------------------------- + + var _queuedCalls:Array = new Array(); + var _pendingCalls:Array = new Array(); + + @:allow(io.newgrounds.Call) + @:generic + function queueCall(call:Call):Void { + + logVerbose('queued - ${call.component}'); + + _queuedCalls.push(call); + checkQueue(); + } + + @:allow(io.newgrounds.Call) + @:generic + function markCallPending(call:Call):Void { + + _pendingCalls.push(call); + + call.addDataHandler(function (_):Void { onCallComplete(call); }); + call.addErrorHandler(function (_):Void { onCallComplete(call); }); + } + + function onCallComplete(call:ICallable):Void { + + _pendingCalls.remove(call); + checkQueue(); + } + + function checkQueue():Void { + + if (_pendingCalls.length == 0 && _queuedCalls.length > 0) + _queuedCalls.shift().send(); + } + + // ------------------------------------------------------------------------------------------- + // LOGGING / ERRORS + // ------------------------------------------------------------------------------------------- + + /** Called internally, set this to your preferred logging method */ + dynamic public function log(any:Dynamic, ?pos:PosInfos):Void {//TODO: limit access via @:allow + + haxe.Log.trace('[Newgrounds API] :: ${any}', pos); + } + + /** used internally, logs if verbose is true */ + inline public function logVerbose(any:Dynamic, ?pos:PosInfos):Void {//TODO: limit access via @:allow + + if (verbose) + log(any, pos); + } + + /** Used internally. Logs by default, set this to your preferred error handling method */ + dynamic public function logError(any:Dynamic, ?pos:PosInfos):Void {//TODO: limit access via @:allow + + log('Error: $any', pos); + } + + /** used internally, calls log error if the condition is false. EX: if (assert(data != null, "null data")) */ + inline public function assert(condition:Bool, msg:Dynamic, ?pos:PosInfos):Bool {//TODO: limit access via @:allow + if (!condition) + logError(msg, pos); + + return condition; + } + + // ------------------------------------------------------------------------------------------- + // ENCRYPTION + // ------------------------------------------------------------------------------------------- + + /** Sets */ + public function initEncryption + ( key :String + , cipher:Cipher = Cipher.RC4 + , format:EncryptionFormat = EncryptionFormat.BASE_64 + ):Void { + + if (cipher == Cipher.NONE) + encryptionHandler = null; + else if (cipher == Cipher.RC4) + encryptionHandler = encryptRc4.bind(key, format); + else + throw "aes not yet implemented"; + } + + function encryptRc4(key:String, format:EncryptionFormat, data:String):String { + + if (format == EncryptionFormat.HEX) + throw "hex format not yet implemented"; + + var keyBytes:Bytes; + if (format == EncryptionFormat.BASE_64) + keyBytes = Base64.decode(key); + else + keyBytes = null;//TODO + + var dataBytes = new Rc4(keyBytes).crypt(Bytes.ofString(data)); + + if (format == EncryptionFormat.BASE_64) + return Base64.encode(dataBytes); + + return null; + } +} \ No newline at end of file diff --git a/source/io/newgrounds/components/AppComponent.hx b/source/io/newgrounds/components/AppComponent.hx new file mode 100644 index 00000000..1ea5b8b1 --- /dev/null +++ b/source/io/newgrounds/components/AppComponent.hx @@ -0,0 +1,44 @@ +package io.newgrounds.components; + +import io.newgrounds.objects.events.Result; +import io.newgrounds.objects.events.Result.SessionResult; +import io.newgrounds.NGLite; + +class AppComponent extends Component { + + public function new (core:NGLite) { super(core); } + + public function startSession(force:Bool = false):Call { + + return new Call(_core, "App.startSession") + .addComponentParameter("force", force, false); + } + + public function checkSession():Call { + + return new Call(_core, "App.checkSession", true); + } + + public function endSession():Call { + + return new Call(_core, "App.endSession", true); + } + + public function getCurrentVersion(version:String):Call { + + return new Call(_core, "App.getCurrentVersion") + .addComponentParameter("version", version); + } + + public function getHostLicense():Call { + + return new Call(_core, "App.getHostLicense") + .addComponentParameter("host", _core.host); + } + + public function logView():Call { + + return new Call(_core, "App.logView") + .addComponentParameter("host", _core.host); + } +} \ No newline at end of file diff --git a/source/io/newgrounds/components/Component.hx b/source/io/newgrounds/components/Component.hx new file mode 100644 index 00000000..3c588ff1 --- /dev/null +++ b/source/io/newgrounds/components/Component.hx @@ -0,0 +1,13 @@ +package io.newgrounds.components; + +import io.newgrounds.NGLite; + +class Component { + + var _core:NGLite; + + public function new(core:NGLite) { + + this._core = core; + } +} \ No newline at end of file diff --git a/source/io/newgrounds/components/ComponentList.hx b/source/io/newgrounds/components/ComponentList.hx new file mode 100644 index 00000000..315abf4e --- /dev/null +++ b/source/io/newgrounds/components/ComponentList.hx @@ -0,0 +1,25 @@ +package io.newgrounds.components; +class ComponentList { + + var _core:NGLite; + + // --- COMPONENTS + public var medal : MedalComponent; + public var app : AppComponent; + public var event : EventComponent; + public var scoreBoard: ScoreBoardComponent; + public var loader : LoaderComponent; + public var gateway : GatewayComponent; + + public function new(core:NGLite) { + + _core = core; + + medal = new MedalComponent (_core); + app = new AppComponent (_core); + event = new EventComponent (_core); + scoreBoard = new ScoreBoardComponent(_core); + loader = new LoaderComponent (_core); + gateway = new GatewayComponent (_core); + } +} diff --git a/source/io/newgrounds/components/EventComponent.hx b/source/io/newgrounds/components/EventComponent.hx new file mode 100644 index 00000000..2e631773 --- /dev/null +++ b/source/io/newgrounds/components/EventComponent.hx @@ -0,0 +1,16 @@ +package io.newgrounds.components; + +import io.newgrounds.objects.events.Result.LogEventResult; +import io.newgrounds.NGLite; + +class EventComponent extends Component { + + public function new (core:NGLite){ super(core); } + + public function logEvent(eventName:String):Call { + + return new Call(_core, "Event.logEvent") + .addComponentParameter("event_name", eventName) + .addComponentParameter("host", _core.host); + } +} \ No newline at end of file diff --git a/source/io/newgrounds/components/GatewayComponent.hx b/source/io/newgrounds/components/GatewayComponent.hx new file mode 100644 index 00000000..4f0ece61 --- /dev/null +++ b/source/io/newgrounds/components/GatewayComponent.hx @@ -0,0 +1,25 @@ +package io.newgrounds.components; + +import io.newgrounds.objects.events.Result; +import io.newgrounds.NGLite; + +class GatewayComponent extends Component { + + public function new (core:NGLite){ super(core); } + + public function getDatetime():Call { + + return new Call(_core, "Gateway.getDatetime"); + } + + public function getVersion():Call { + + return new Call(_core, "Gateway.getVersion"); + } + + public function ping():Call { + + return new Call(_core, "Gateway.ping"); + } + +} \ No newline at end of file diff --git a/source/io/newgrounds/components/LoaderComponent.hx b/source/io/newgrounds/components/LoaderComponent.hx new file mode 100644 index 00000000..717cc2eb --- /dev/null +++ b/source/io/newgrounds/components/LoaderComponent.hx @@ -0,0 +1,44 @@ +package io.newgrounds.components; + +import io.newgrounds.objects.events.Result; +import io.newgrounds.NGLite; + +class LoaderComponent extends Component { + + public function new (core:NGLite){ super(core); } + + public function loadAuthorUrl(redirect:Bool = false):Call { + + return new Call(_core, "Loader.loadAuthorUrl") + .addComponentParameter("host", _core.host) + .addComponentParameter("redirect", redirect, true); + } + + public function loadMoreGames(redirect:Bool = false):Call { + + return new Call(_core, "Loader.loadMoreGames") + .addComponentParameter("host", _core.host) + .addComponentParameter("redirect", redirect, true); + } + + public function loadNewgrounds(redirect:Bool = false):Call { + + return new Call(_core, "Loader.loadNewgrounds") + .addComponentParameter("host", _core.host) + .addComponentParameter("redirect", redirect, true); + } + + public function loadOfficialUrl(redirect:Bool = false):Call { + + return new Call(_core, "Loader.loadOfficialUrl") + .addComponentParameter("host", _core.host) + .addComponentParameter("redirect", redirect, true); + } + + public function loadReferral(redirect:Bool = false):Call { + + return new Call(_core, "Loader.loadReferral") + .addComponentParameter("host", _core.host) + .addComponentParameter("redirect", redirect, true); + } +} \ No newline at end of file diff --git a/source/io/newgrounds/components/MedalComponent.hx b/source/io/newgrounds/components/MedalComponent.hx new file mode 100644 index 00000000..7e56621c --- /dev/null +++ b/source/io/newgrounds/components/MedalComponent.hx @@ -0,0 +1,21 @@ +package io.newgrounds.components; + +import io.newgrounds.objects.events.Result; +import io.newgrounds.Call; +import io.newgrounds.NGLite; + +class MedalComponent extends Component { + + public function new(core:NGLite):Void { super(core); } + + public function unlock(id:Int):Call { + + return new Call(_core, "Medal.unlock", true, true) + .addComponentParameter("id", id); + } + + public function getList():Call { + + return new Call(_core, "Medal.getList"); + } +} \ No newline at end of file diff --git a/source/io/newgrounds/components/ScoreBoardComponent.hx b/source/io/newgrounds/components/ScoreBoardComponent.hx new file mode 100644 index 00000000..7417e67c --- /dev/null +++ b/source/io/newgrounds/components/ScoreBoardComponent.hx @@ -0,0 +1,114 @@ +package io.newgrounds.components; + +import io.newgrounds.objects.User; +import io.newgrounds.objects.events.Response; +import io.newgrounds.objects.events.Result; +import io.newgrounds.objects.events.Result.ScoreBoardResult; +import io.newgrounds.objects.events.Result.ScoreResult; +import io.newgrounds.NGLite; +import io.newgrounds.objects.ScoreBoard; + +import haxe.ds.IntMap; + +class ScoreBoardComponent extends Component { + + public var allById:IntMap; + + public function new (core:NGLite){ super(core); } + + // ------------------------------------------------------------------------------------------- + // GET SCORES + // ------------------------------------------------------------------------------------------- + + public function getBoards():Call { + + return new Call(_core, "ScoreBoard.getBoards"); + } + + /*function onBoardsReceive(response:Response):Void { + + if (!response.result.success) + return; + + allById = new IntMap(); + + for (boardData in response.result.scoreboards) + createBoard(boardData); + + _core.log('${response.result.scoreboards.length} ScoreBoards loaded'); + }*/ + + // ------------------------------------------------------------------------------------------- + // GET SCORES + // ------------------------------------------------------------------------------------------- + + public function getScores + ( id :Int + , limit :Int = 10 + , skip :Int = 0 + , period:Period = Period.DAY + , social:Bool = false + , tag :String = null + , user :Dynamic = null + ):Call { + + if (user != null && !Std.is(user, String) && !Std.is(user, Int)) + user = user.id; + + return new Call(_core, "ScoreBoard.getScores") + .addComponentParameter("id" , id ) + .addComponentParameter("limit" , limit , 10) + .addComponentParameter("skip" , skip , 0) + .addComponentParameter("period", period, Period.DAY) + .addComponentParameter("social", social, false) + .addComponentParameter("tag" , tag , null) + .addComponentParameter("user" , user , null); + } + + // ------------------------------------------------------------------------------------------- + // POST SCORE + // ------------------------------------------------------------------------------------------- + + public function postScore(id:Int, value:Int, tag:String = null):Call { + + return new Call(_core, "ScoreBoard.postScore", true, true) + .addComponentParameter("id" , id) + .addComponentParameter("value", value) + .addComponentParameter("tag" , tag , null); + } + + /*function onScorePosted(response:Response):Void { + + if (!response.result.success) + return; + + allById = new IntMap(); + + //createBoard(data.data.scoreBoard).parseScores(data.data.scores); + }*/ + + inline function createBoard(data:Dynamic):ScoreBoard { + + var board = new ScoreBoard(_core, data); + _core.logVerbose('created $board'); + + allById.set(board.id, board); + + return board; + } +} + +@:enum +abstract Period(String) to String from String{ + + /** Indicates scores are from the current day. */ + var DAY = "D"; + /** Indicates scores are from the current week. */ + var WEEK = "W"; + /** Indicates scores are from the current month. */ + var MONTH = "M"; + /** Indicates scores are from the current year. */ + var YEAR = "Y"; + /** Indicates scores are from all-time. */ + var ALL = "A"; +} \ No newline at end of file diff --git a/source/io/newgrounds/crypto/Cipher.hx b/source/io/newgrounds/crypto/Cipher.hx new file mode 100644 index 00000000..2f4c0075 --- /dev/null +++ b/source/io/newgrounds/crypto/Cipher.hx @@ -0,0 +1,8 @@ +package io.newgrounds.crypto; + +@:enum +abstract Cipher(String) to String{ + var NONE = "none"; + var AES_128 = "aes128"; + var RC4 = "rc4"; +} \ No newline at end of file diff --git a/source/io/newgrounds/crypto/EncryptionFormat.hx b/source/io/newgrounds/crypto/EncryptionFormat.hx new file mode 100644 index 00000000..6e8f17fd --- /dev/null +++ b/source/io/newgrounds/crypto/EncryptionFormat.hx @@ -0,0 +1,7 @@ +package io.newgrounds.crypto; + +@:enum +abstract EncryptionFormat(String) to String { + var BASE_64 = "base64"; + var HEX = "hex"; +} \ No newline at end of file diff --git a/source/io/newgrounds/crypto/Rc4.hx b/source/io/newgrounds/crypto/Rc4.hx new file mode 100644 index 00000000..54dafa74 --- /dev/null +++ b/source/io/newgrounds/crypto/Rc4.hx @@ -0,0 +1,68 @@ +package io.newgrounds.crypto; + +import haxe.io.Bytes; + +/** + * The following was straight-up ganked from https://github.com/iskolbin/rc4hx + * + * You da real MVP iskolbin... + * + * The MIT License (MIT) + * + * Copyright (c) 2015 iskolbin + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. +**/ +class Rc4 { + var perm = Bytes.alloc( 256 ); + var index1: Int = 0; + var index2: Int = 0; + + public function new( key: Bytes ) { + for ( i in 0...256 ) { + perm.set( i, i ); + } + + var j: Int = 0; + for ( i in 0...256 ) { + j = ( j + perm.get( i ) + key.get( i % key.length )) % 256; + swap( i, j ); + } + } + + inline function swap( i: Int, j: Int ): Void { + var temp = perm.get( i ); + perm.set( i, perm.get( j )); + perm.set( j, temp ); + } + + public function crypt( input: Bytes ): Bytes { + var output = Bytes.alloc( input.length ); + + for ( i in 0...input.length ) { + index1 = ( index1 + 1 ) % 256; + index2 = ( index2 + perm.get( index1 )) % 256; + swap( index1, index2 ); + var j = ( perm.get( index1 ) + perm.get( index2 )) % 256; + output.set( i, input.get( i ) ^ perm.get( j )); + } + + return output; + } +} \ No newline at end of file diff --git a/source/io/newgrounds/objects/Error.hx b/source/io/newgrounds/objects/Error.hx new file mode 100644 index 00000000..6e82e4e2 --- /dev/null +++ b/source/io/newgrounds/objects/Error.hx @@ -0,0 +1,20 @@ +package io.newgrounds.objects; +class Error { + + public var code(default, null):Int; + public var message(default, null):String; + + public function new (message:String, code:Int = 0) { + + this.message = message; + this.code = code; + } + + public function toString():String { + + if (code > 0) + return '#$code - $message'; + + return message; + } +} diff --git a/source/io/newgrounds/objects/Medal.hx b/source/io/newgrounds/objects/Medal.hx new file mode 100644 index 00000000..3cecc7a6 --- /dev/null +++ b/source/io/newgrounds/objects/Medal.hx @@ -0,0 +1,118 @@ +package io.newgrounds.objects; + +import io.newgrounds.objects.events.Response; +import io.newgrounds.objects.events.Result.MedalUnlockResult; +import io.newgrounds.utils.Dispatcher; +import io.newgrounds.NGLite; + +class Medal extends Object { + + inline static public var EASY :Int = 1; + inline static public var MODERATE :Int = 2; + inline static public var CHALLENGING:Int = 3; + inline static public var DIFFICULT :Int = 4; + inline static public var BRUTAL :Int = 5; + + static var difficultyNames:Array = + [ "Easy" + , "Moderate" + , "Challenging" + , "Difficult" + , "Brutal" + ]; + // --- FROM SERVER + public var id (default, null):Int; + public var name (default, null):String; + public var description(default, null):String; + public var icon (default, null):String; + public var value (default, null):Int; + public var difficulty (default, null):Int; + public var secret (default, null):Bool; + public var unlocked (default, null):Bool; + // --- HELPERS + public var difficultyName(get, never):String; + + public var onUnlock:Dispatcher; + + public function new(core:NGLite, data:Dynamic = null):Void { + + onUnlock = new Dispatcher(); + + super(core, data); + } + + @:allow(io.newgrounds.NG) + override function parse(data:Dynamic):Void { + + var wasLocked = !unlocked; + + id = data.id; + name = data.name; + description = data.description; + icon = data.icon; + value = data.value; + difficulty = data.difficulty; + secret = data.secret == 1; + unlocked = data.unlocked; + + super.parse(data); + + if (wasLocked && unlocked) + onUnlock.dispatch(); + + } + + public function sendUnlock():Void { + + if (_core.sessionId == null) { + // --- Unlock regardless, show medal popup to encourage NG signup + unlocked = true; + onUnlock.dispatch(); + //TODO: save unlock in local save + } + + _core.calls.medal.unlock(id) + .addDataHandler(onUnlockResponse) + .send(); + } + + function onUnlockResponse(response:Response):Void { + + if (response.success && response.result.success) { + + parse(response.result.data.medal); + + // --- Unlock response doesn't include unlock=true, so parse won't change it. + if (!unlocked) { + + unlocked = true; + onUnlock.dispatch(); + } + } + } + + /** Locks the medal on the client and sends an unlock request, Server responds the same either way. */ + public function sendDebugUnlock():Void { + + if (NG.core.sessionId == null) { + + onUnlock.dispatch(); + + } else { + + unlocked = false; + + sendUnlock(); + } + } + + public function get_difficultyName():String { + + return difficultyNames[difficulty - 1]; + } + + public function toString():String { + + return 'Medal: $id@$name (${unlocked ? "unlocked" : "locked"}, $value pts, $difficultyName).'; + } +} \ No newline at end of file diff --git a/source/io/newgrounds/objects/Object.hx b/source/io/newgrounds/objects/Object.hx new file mode 100644 index 00000000..32abd0fe --- /dev/null +++ b/source/io/newgrounds/objects/Object.hx @@ -0,0 +1,33 @@ +package io.newgrounds.objects; + +import io.newgrounds.utils.Dispatcher; +import io.newgrounds.NGLite; + +class Object { + + var _core:NGLite; + + public var onUpdate(default, null):Dispatcher; + + public function new(core:NGLite, data:Dynamic = null) { + + this._core = core; + + onUpdate = new Dispatcher(); + + if (data != null) + parse(data); + } + + @:allow(io.newgrounds.NGLite) + function parse(data:Dynamic):Void { + + onUpdate.dispatch(); + } + + + public function destroy():Void { + + _core = null; + } +} \ No newline at end of file diff --git a/source/io/newgrounds/objects/Score.hx b/source/io/newgrounds/objects/Score.hx new file mode 100644 index 00000000..0eb69826 --- /dev/null +++ b/source/io/newgrounds/objects/Score.hx @@ -0,0 +1,17 @@ +package io.newgrounds.objects; + +/** We don't want to serialize scores since there's a bajillion of them. */ +typedef Score = { + + /** The value value in the format selected in your scoreboard settings. */ + var formatted_value:String; + + /** The tag attached to this value (if any). */ + var tag:String; + + /** The user who earned value. If this property is absent, the value belongs to the active user. */ + var user:User; + + /** The integer value of the value. */ + var value:Int; +} \ No newline at end of file diff --git a/source/io/newgrounds/objects/ScoreBoard.hx b/source/io/newgrounds/objects/ScoreBoard.hx new file mode 100644 index 00000000..1859b080 --- /dev/null +++ b/source/io/newgrounds/objects/ScoreBoard.hx @@ -0,0 +1,76 @@ +package io.newgrounds.objects; + +import io.newgrounds.components.ScoreBoardComponent.Period; +import io.newgrounds.objects.events.Response; +import io.newgrounds.objects.events.Result; +import io.newgrounds.objects.events.Result.ScoreResult; +import io.newgrounds.NGLite; + +class ScoreBoard extends Object { + + public var scores(default, null):Array; + + /** The numeric ID of the scoreboard.*/ + public var id(default, null):Int; + + /** The name of the scoreboard. */ + public var name(default, null):String; + + public function new(core:NGLite, data:Dynamic):Void {super(core, data); } + + override function parse(data:Dynamic):Void { + + id = data.id; + name = data.name; + + super.parse(data); + } + + /** + * Fetches score data from the server, this removes all of the existing scores cached + * + * We don't unify the old and new scores because a user's rank or score may change between requests + */ + public function requestScores + ( limit :Int = 10 + , skip :Int = 0 + , period:Period = Period.ALL + , social:Bool = false + , tag :String = null + , user :Dynamic = null + ):Void { + + _core.calls.scoreBoard.getScores(id, limit, skip, period, social, tag, user) + .addDataHandler(onScoresReceived) + .send(); + } + + function onScoresReceived(response:Response):Void { + + if (!response.success || !response.result.success) + return; + + scores = response.result.data.scores; + _core.logVerbose('received ${scores.length} scores'); + + onUpdate.dispatch(); + } + + public function postScore(value :Int, tag:String = null):Void { + + _core.calls.scoreBoard.postScore(id, value, tag) + .addDataHandler(onScorePosted) + .send(); + } + + function onScorePosted(response:Response):Void { + + + } + + public function toString():String { + + return 'ScoreBoard: $id@$name'; + } + +} \ No newline at end of file diff --git a/source/io/newgrounds/objects/Session.hx b/source/io/newgrounds/objects/Session.hx new file mode 100644 index 00000000..887df792 --- /dev/null +++ b/source/io/newgrounds/objects/Session.hx @@ -0,0 +1,65 @@ +package io.newgrounds.objects; + +class Session extends Object { + + /** If true, the session_id is expired. Use App.startSession to get a new one.*/ + public var expired(default, null):Bool; + + /** A unique session identifier */ + public var id(default, null):String; + + /** If the session has no associated user but is not expired, this property will provide a URL that can be used to sign the user in. */ + public var passportUrl(default, null):String; + + /** If true, the user would like you to remember their session id. */ + public var remember(default, null):Bool; + + /** If the user has not signed in, or granted access to your app, this will be null */ + public var user(default, null):User; + + //TODO:desciption + public var status(get, never):SessionStatus; + + public function new(core:NGLite, data:Dynamic = null) { super(core, data); } + + override public function parse(data:Dynamic):Void { + + id = data.id; + expired = data.expired; + passportUrl = data.passport_url; + remember = data.remember; + + // --- KEEP THE SAME INSTANCE + if (user == null) + user = data.user; + // TODO?: update original user instance with new data. (probly not) + + super.parse(data); + } + + public function get_status():SessionStatus { + + if (expired || id == null || id == "") + return SessionStatus.SESSION_EXPIRED; + + if (user != null && user.name != null && user.name != "") + return SessionStatus.USER_LOADED; + + return SessionStatus.REQUEST_LOGIN; + } + + public function expire():Void { + + expired = true; + id = null; + user = null; + } +} + +@:enum +abstract SessionStatus(String) { + + var SESSION_EXPIRED = "session-expired"; + var REQUEST_LOGIN = "request-login"; + var USER_LOADED = "user-loaded"; +} \ No newline at end of file diff --git a/source/io/newgrounds/objects/User.hx b/source/io/newgrounds/objects/User.hx new file mode 100644 index 00000000..1ff7ce00 --- /dev/null +++ b/source/io/newgrounds/objects/User.hx @@ -0,0 +1,19 @@ +package io.newgrounds.objects; + +typedef User = { + + /** The user's icon images. */ + var icons:UserIcons; + + /** The user's numeric ID. */ + var id:Int; + + /** The user's textual name. */ + var name:String; + + /** Returns true if the user has a Newgrounds Supporter upgrade. */ + var supporter:Bool; + + /** The user's NG profile url. */ + var url:String; +} diff --git a/source/io/newgrounds/objects/UserIcons.hx b/source/io/newgrounds/objects/UserIcons.hx new file mode 100644 index 00000000..b5e56b22 --- /dev/null +++ b/source/io/newgrounds/objects/UserIcons.hx @@ -0,0 +1,14 @@ +package io.newgrounds.objects; + +typedef UserIcons = { + + /**The URL of the user's large icon. */ + var large:String; + + /** The URL of the user's medium icon. */ + var medium:String; + + /** The URL of the user's small icon. */ + var small:String; +} + diff --git a/source/io/newgrounds/objects/events/Response.hx b/source/io/newgrounds/objects/events/Response.hx new file mode 100644 index 00000000..107dc2be --- /dev/null +++ b/source/io/newgrounds/objects/events/Response.hx @@ -0,0 +1,43 @@ +package io.newgrounds.objects.events; + +import io.newgrounds.objects.events.Result.ResultBase; +import haxe.Json; +import io.newgrounds.objects.Error; + +typedef DebugResponse = { + + var exec_time:Int; + var input:Dynamic; +} + +class Response { + + public var success(default, null):Bool; + public var error(default, null):Error; + public var debug(default, null):DebugResponse; + public var result(default, null):Result; + + public function new (core:NGLite, reply:String) { + + var data:Dynamic; + + try { + data = Json.parse(reply); + + } catch (e:Dynamic) { + + data = Json.parse('{"success":false,"error":{"message":"${Std.string(reply)}","code":0}}'); + } + + success = data.success; + debug = data.debug; + + if (!success) { + error = new Error(data.error.message, data.error.code); + core.logError('Call unseccessful: $error'); + return; + } + + result = new Result(core, data.result); + } +} diff --git a/source/io/newgrounds/objects/events/Result.hx b/source/io/newgrounds/objects/events/Result.hx new file mode 100644 index 00000000..eaf87261 --- /dev/null +++ b/source/io/newgrounds/objects/events/Result.hx @@ -0,0 +1,109 @@ +package io.newgrounds.objects.events; + +class Result { + + public var echo(default, null):String; + public var component(default, null):String; + + public var data(default, null):T; + public var success(default, null):Bool; + public var debug(default, null):Bool; + public var error(default, null):Error; + + public function new(core:NGLite, data:Dynamic) { + + echo = data.echo; + component = data.component; + + data = data.data; + success = data.success; + debug = data.debug; + + if(!data.success) { + + error = new Error(data.error.message, data.error.code); + core.logError('$component fail: $error'); + + } else + this.data = data; + } +} + +typedef ResultBase = { }; + +typedef SessionResult = { + > ResultBase, + + var session:Dynamic; +} + +typedef GetHostResult = { + > ResultBase, + + var host_approved:Bool; +} + +typedef GetCurrentVersionResult = { + > ResultBase, + + var current_version:String; + var client_deprecated:Bool; +} + +typedef LogEventResult = { + > ResultBase, + + var event_name:String; +} + +typedef GetDateTimeResult = { + > ResultBase, + + var datetime:String; +} + +typedef GetVersionResult = { + > ResultBase, + + var version:String; +} + +typedef PingResult = { + > ResultBase, + + var pong:String; +} + +typedef MedalListResult = { + > ResultBase, + + var medals:Array; +} + +typedef MedalUnlockResult = { + > ResultBase, + + var medal_score:String; + var medal:Dynamic; +} + +typedef ScoreBoardResult = { + > ResultBase, + + var scoreboards:Array; +} + +typedef ScoreResult = { + > ResultBase, + + var scores:Array; + var scoreboard:Dynamic; +} + +typedef PostScoreResult = { + > ResultBase, + + var tag:String; + var scoreboard:Dynamic; + var score:Score; +} \ No newline at end of file diff --git a/source/io/newgrounds/swf/LoadingBar.hx b/source/io/newgrounds/swf/LoadingBar.hx new file mode 100644 index 00000000..9c7c590a --- /dev/null +++ b/source/io/newgrounds/swf/LoadingBar.hx @@ -0,0 +1,23 @@ +package io.newgrounds.swf; + +import openfl.display.MovieClip; + +class LoadingBar extends MovieClip { + + public var bar(default, null):MovieClip; + + public function new() { + super(); + + setProgress(0.0); + } + + /** + * + * @param value The ratio of bytes loaded to bytes total + */ + public function setProgress(value:Float):Void { + + bar.gotoAndStop(1 + Std.int(value * (bar.totalFrames - 1))); + } +} diff --git a/source/io/newgrounds/swf/MedalPopup.hx b/source/io/newgrounds/swf/MedalPopup.hx new file mode 100644 index 00000000..f55ef426 --- /dev/null +++ b/source/io/newgrounds/swf/MedalPopup.hx @@ -0,0 +1,151 @@ +package io.newgrounds.swf; + +import io.newgrounds.swf.common.BaseAsset; +import io.newgrounds.objects.Medal; + +import openfl.text.TextFieldAutoSize; +import openfl.text.TextField; +import openfl.display.DisplayObject; +import openfl.display.Loader; +import openfl.display.MovieClip; +import openfl.net.URLRequest; +import openfl.events.Event; + +class MedalPopup extends BaseAsset { + + static inline var FRAME_HIDDEN:String = "hidden"; + static inline var FRAME_MEDAL_UNLOCKED:String = "medalUnlocked"; + static inline var FRAME_INTRO_COMPLETE:String = "introComplete"; + static inline var FRAME_UNLOCK_COMPLETE:String = "unlockComplete"; + static inline var MIN_TEXT_SIZE:Int = 12; + + public var medalIcon(default, null):MovieClip; + public var medalName(default, null):MovieClip; + public var medalPoints(default, null):MovieClip; + + public var alwaysOnTop:Bool; + #if !ng_lite + public var requiresSession:Bool; + #end + + var _animQueue = new ArrayVoid>(); + var _scrollSpeed:Float; + + public function new() { + super(); + + mouseEnabled = false; + mouseChildren = false; + + hide(); + addFrameScript(totalFrames - 1, onUnlockAnimComplete); + } + + function hide():Void { + + visible = false; + gotoAndStop(FRAME_HIDDEN); + } + + #if !ng_lite + override function onReady():Void { + super.onReady(); + + if (NG.core.medals != null) + onMedalsLoaded(); + else + NG.core.onLogin.addOnce(NG.core.requestMedals.bind(onMedalsLoaded)); + } + + function onMedalsLoaded():Void { + + for (medal in NG.core.medals) + medal.onUnlock.add(onMedalOnlock.bind(medal)); + } + + function onMedalOnlock(medal:Medal):Void { + + if (requiresSession && !NG.core.loggedIn) + return; + + var loader = new Loader(); + loader.load(new URLRequest(medal.icon)); + + playAnim(loader, medal.name, medal.value); + } + + #end + + public function playAnim(icon:DisplayObject, name:String, value:Int):Void { + + if (currentLabel == FRAME_HIDDEN) + playNextAnim(icon, name, value); + else + _animQueue.push(playNextAnim.bind(icon, name, value)); + } + + function playNextAnim(icon:DisplayObject, name:String, value:Int):Void { + + visible = true; + gotoAndPlay(FRAME_MEDAL_UNLOCKED); + + if (alwaysOnTop && parent != null) { + + parent.setChildIndex(this, parent.numChildren - 1); + } + + while(medalIcon.numChildren > 0) + medalIcon.removeChildAt(0); + + cast(medalPoints.getChildByName("field"), TextField).text = Std.string(value); + + var field:TextField = cast medalName.getChildByName("field"); + field.autoSize = TextFieldAutoSize.LEFT; + field.x = 0; + field.text = ""; + var oldWidth = medalName.width; + field.text = name; + + _scrollSpeed = 0; + if (field.width > oldWidth + 4) { + + field.x = oldWidth + 4; + initScroll(field); + } + + medalIcon.addChild(icon); + } + + function initScroll(field:TextField):Void { + //TODO: Find out why scrollrect didn't work + + var animDuration = 0; + + for (frame in currentLabels){ + + if (frame.name == FRAME_INTRO_COMPLETE ) + animDuration -= frame.frame; + else if (frame.name == FRAME_UNLOCK_COMPLETE) + animDuration += frame.frame; + } + + _scrollSpeed = (field.width + field.x + 4) / animDuration; + field.addEventListener(Event.ENTER_FRAME, updateScroll); + } + + function updateScroll(e:Event):Void{ + + if (currentLabel == FRAME_INTRO_COMPLETE) + cast (e.currentTarget, TextField).x -= _scrollSpeed; + } + + function onUnlockAnimComplete():Void { + + cast (medalName.getChildByName("field"), TextField).removeEventListener(Event.ENTER_FRAME, updateScroll); + + if (_animQueue.length == 0) + hide(); + else + (_animQueue.shift())(); + } +} diff --git a/source/io/newgrounds/swf/ScoreBrowser.hx b/source/io/newgrounds/swf/ScoreBrowser.hx new file mode 100644 index 00000000..c4232c22 --- /dev/null +++ b/source/io/newgrounds/swf/ScoreBrowser.hx @@ -0,0 +1,250 @@ +package io.newgrounds.swf; + +import openfl.events.Event; +import io.newgrounds.swf.common.DropDown; +import io.newgrounds.objects.Score; +import io.newgrounds.objects.events.Result.ScoreBoardResult; +import io.newgrounds.objects.events.Result.ScoreResult; +import io.newgrounds.objects.events.Response; +import io.newgrounds.swf.common.BaseAsset; +import io.newgrounds.swf.common.Button; +import io.newgrounds.components.ScoreBoardComponent.Period; + +import openfl.display.MovieClip; +import openfl.text.TextField; + +class ScoreBrowser extends BaseAsset { + + public var prevButton (default, null):MovieClip; + public var nextButton (default, null):MovieClip; + public var reloadButton (default, null):MovieClip; + public var listBox (default, null):MovieClip; + public var loadingIcon (default, null):MovieClip; + public var errorIcon (default, null):MovieClip; + public var scoreContainer(default, null):MovieClip; + public var titleField (default, null):TextField; + public var pageField (default, null):TextField; + + public var period(get, set):Period; + function get_period():Period { return _periodDropDown.value; } + function set_period(value:Period):Period { return _periodDropDown.value = value; } + + public var title(get, set):String; + function get_title():String { return titleField.text; } + function set_title(value:String):String { return titleField.text = value; } + + public var tag(default, set):String; + function set_tag(value:String):String { + + if (this.tag != value) { + + this.tag = value; + delayReload(); + } + + return value; + } + + public var social(default, set):Bool; + function set_social(value:Bool):Bool { + + if (this.social != value) { + + this.social = value; + delayReload(); + } + + return value; + } + + public var boardId(default, set):Int; + function set_boardId(value:Int):Int { + + _boardIDSet = true; + + if (this.boardId != value) { + + this.boardId = value; + delayReload(); + } + + return value; + } + + public var page(default, set):Int; + function set_page(value:Int):Int { + + if (this.page != value) { + + this.page = value; + delayReload(); + } + + return value; + } + + var _scores:Array; + var _limit:Int = 0; + var _periodDropDown:DropDown; + var _boardIDSet:Bool; + + public function new() { super(); } + + override function setDefaults():Void { + super.setDefaults(); + + boardId = -1; + _boardIDSet = false; + + scoreContainer.visible = false; + loadingIcon.visible = false; + reloadButton.visible = false; + errorIcon.visible = false; + errorIcon.addFrameScript(errorIcon.totalFrames - 1, errorIcon.stop); + + //TODO: prevent memory leaks? + new Button(prevButton, onPrevClick); + new Button(nextButton, onNextClick); + new Button(reloadButton, reload); + _periodDropDown = new DropDown(listBox, delayReload); + _periodDropDown.addItem("Current day" , Period.DAY ); + _periodDropDown.addItem("Current week" , Period.WEEK ); + _periodDropDown.addItem("Current month", Period.MONTH); + _periodDropDown.addItem("Current year" , Period.YEAR ); + _periodDropDown.addItem("All time" , Period.ALL ); + _periodDropDown.value = Period.ALL; + + _scores = new Array(); + while(true) { + + var score:MovieClip = cast scoreContainer.getChildByName('score${_scores.length}'); + if (score == null) + break; + + new Button(score); + _scores.push(score); + } + + _limit = _scores.length; + } + + override function onReady():Void { + super.onReady(); + + if (boardId == -1 && !_boardIDSet) { + + #if ng_lite + NG.core.calls.scoreBoard.getBoards() + .addDataHandler(onBoardsRecieved) + .queue(); + #else + if (NG.core.scoreBoards != null) + onBoardsLoaded(); + else + NG.core.requestScoreBoards(onBoardsLoaded); + #end + } + + reload(); + } + + #if ng_lite + function onBoardsRecieved(response:Response):Void { + + if (response.success && response.result.success) { + + for (board in response.result.data.scoreboards) { + + NG.core.log('No boardId specified defaulting to ${board.name}'); + boardId = board.id; + return; + } + } + } + #else + function onBoardsLoaded():Void { + + for (board in NG.core.scoreBoards) { + + NG.core.log('No boardId specified defaulting to ${board.name}'); + boardId = board.id; + return; + } + } + #end + + /** Used internally to avoid multiple server requests from various property changes in a small time-frame. **/ + function delayReload():Void { + + addEventListener(Event.EXIT_FRAME, onDelayComplete); + } + + function onDelayComplete(e:Event):Void { reload(); } + + public function reload():Void { + removeEventListener(Event.EXIT_FRAME, onDelayComplete); + + errorIcon.visible = false; + scoreContainer.visible = false; + pageField.text = 'page ${page + 1}'; + + if (_coreReady && boardId != -1 && _limit > 0 && period != null) { + + loadingIcon.visible = true; + + NG.core.calls.scoreBoard.getScores(boardId, _limit, _limit * page, period, social, tag) + .addDataHandler(onScoresReceive) + .send(); + } + } + + function onScoresReceive(response:Response):Void { + + loadingIcon.visible = false; + + if (response.success && response.result.success) { + + scoreContainer.visible = true; + + var i = _limit; + while(i > 0) { + i--; + + if (i < response.result.data.scores.length) + drawScore(i, response.result.data.scores[i], _scores[i]); + else + drawScore(i, null, _scores[i]); + } + + } else { + + errorIcon.visible = true; + errorIcon.gotoAndPlay(1); + reloadButton.visible = true; + } + } + + inline function drawScore(rank:Int, score:Score, asset:MovieClip):Void { + + if (score == null) + asset.visible = false; + else { + + asset.visible = true; + cast (asset.getChildByName("nameField" ), TextField).text = score.user.name; + cast (asset.getChildByName("scoreField"), TextField).text = score.formatted_value; + cast (asset.getChildByName("rankField" ), TextField).text = Std.string(rank + 1); + } + } + + function onPrevClick():Void { + + if (page > 0) + page--; + } + + function onNextClick():Void { + + page++; + } +} diff --git a/source/io/newgrounds/swf/common/BaseAsset.hx b/source/io/newgrounds/swf/common/BaseAsset.hx new file mode 100644 index 00000000..da1f6126 --- /dev/null +++ b/source/io/newgrounds/swf/common/BaseAsset.hx @@ -0,0 +1,35 @@ +package io.newgrounds.swf.common; + +import openfl.events.Event; +import openfl.display.MovieClip; + +class BaseAsset extends MovieClip { + + var _coreReady:Bool = false; + + public function new() { + super(); + + setDefaults(); + + if (stage != null) + onAdded(null); + else + addEventListener(Event.ADDED_TO_STAGE, onAdded); + } + + function setDefaults():Void { } + + function onAdded(e:Event):Void { + + if (NG.core != null) + onReady(); + else + NG.onCoreReady.add(onReady); + } + + function onReady():Void { + + _coreReady = true; + } +} diff --git a/source/io/newgrounds/swf/common/Button.hx b/source/io/newgrounds/swf/common/Button.hx new file mode 100644 index 00000000..5f461752 --- /dev/null +++ b/source/io/newgrounds/swf/common/Button.hx @@ -0,0 +1,151 @@ +package io.newgrounds.swf.common; + +import openfl.display.Stage; +import openfl.events.Event; +import openfl.events.MouseEvent; +import openfl.display.MovieClip; + +class Button { + + var _enabled:Bool; + public var enabled(get, set):Bool; + function get_enabled():Bool { return _enabled; } + function set_enabled(value:Bool):Bool { + + if (value != _enabled) { + + _enabled = value; + updateEnabled(); + } + + return value; + } + + public var onClick:Void->Void; + public var onOver:Void->Void; + public var onOut:Void->Void; + + var _target:MovieClip; + var _down:Bool; + var _over:Bool; + var _foundLabels:Array; + + public function new(target:MovieClip, onClick:Void->Void = null, onOver:Void->Void = null, onOut:Void->Void = null) { + + _target = target; + this.onClick = onClick; + this.onOver = onOver; + this.onOut = onOut; + + _foundLabels = new Array(); + for (label in _target.currentLabels) + _foundLabels.push(label.name); + + _target.stop(); + _target.addEventListener(Event.ADDED_TO_STAGE, onAdded); + if (target.stage != null) + onAdded(null); + + enabled = true; + } + + function onAdded(e:Event):Void { + + var stage = _target.stage; + stage.addEventListener(MouseEvent.MOUSE_UP, mouseHandler); + _target.addEventListener(MouseEvent.MOUSE_OVER, mouseHandler); + _target.addEventListener(MouseEvent.MOUSE_OUT, mouseHandler); + _target.addEventListener(MouseEvent.MOUSE_DOWN, mouseHandler); + _target.addEventListener(MouseEvent.CLICK, mouseHandler); + + function selfRemoveEvent(e:Event):Void { + + _target.removeEventListener(Event.REMOVED_FROM_STAGE, selfRemoveEvent); + onRemove(e, stage); + } + _target.addEventListener(Event.REMOVED_FROM_STAGE, selfRemoveEvent); + } + + function onRemove(e:Event, stage:Stage):Void { + + stage.removeEventListener(MouseEvent.MOUSE_UP, mouseHandler); + _target.removeEventListener(MouseEvent.MOUSE_OVER, mouseHandler); + _target.removeEventListener(MouseEvent.MOUSE_OUT, mouseHandler); + _target.removeEventListener(MouseEvent.MOUSE_DOWN, mouseHandler); + _target.removeEventListener(MouseEvent.CLICK, mouseHandler); + } + + function mouseHandler(event:MouseEvent):Void { + + switch(event.type) { + + case MouseEvent.MOUSE_OVER: + + _over = true; + + if (onOver != null) + onOver(); + + case MouseEvent.MOUSE_OUT: + + _over = false; + + if (onOut != null) + onOut(); + + case MouseEvent.MOUSE_DOWN: + + _down = true; + + case MouseEvent.MOUSE_UP: + + _down = false; + + case MouseEvent.CLICK: + + if (enabled && onClick != null) + onClick(); + } + updateState(); + } + + function updateEnabled():Void { + + updateState(); + + _target.useHandCursor = enabled; + _target.buttonMode = enabled; + } + + function updateState():Void { + + var state = determineState(); + + if (_target.currentLabel != state && _foundLabels.indexOf(state) != -1) + _target.gotoAndStop(state); + } + + function determineState():String { + + if (enabled) { + + if (_over) + return _down ? "down" : "over"; + + return "up"; + + } + return "disabled"; + } + + public function destroy():Void { + + _target.removeEventListener(Event.ADDED_TO_STAGE, onAdded); + + _target = null; + onClick = null; + onOver = null; + onOut = null; + _foundLabels = null; + } +} diff --git a/source/io/newgrounds/swf/common/DropDown.hx b/source/io/newgrounds/swf/common/DropDown.hx new file mode 100644 index 00000000..a882cf39 --- /dev/null +++ b/source/io/newgrounds/swf/common/DropDown.hx @@ -0,0 +1,88 @@ +package io.newgrounds.swf.common; + + +import haxe.ds.StringMap; + +import openfl.display.MovieClip; +import openfl.display.Sprite; +import openfl.text.TextField; + +class DropDown { + + public var value(default, set):String; + function set_value(v:String):String { + + if (this.value == v) + return v; + + this.value = v; + _selectedLabel.text = _values.get(v); + + if (_onChange != null) + _onChange(); + + return v; + } + + var _choiceContainer:Sprite; + var _selectedLabel:TextField; + var _onChange:Void->Void; + var _values:StringMap; + var _unusedChoices:Array; + + public function new(target:MovieClip, label:String = "", onChange:Void->Void = null) { + + _onChange = onChange; + + _selectedLabel = cast cast(target.getChildByName("currentItem"), MovieClip).getChildByName("label"); + _selectedLabel.text = label; + + _values = new StringMap(); + + new Button(cast target.getChildByName("button"), onClickExpand); + new Button(cast target.getChildByName("currentItem"), onClickExpand); + _choiceContainer = new Sprite(); + _choiceContainer.visible = false; + target.addChild(_choiceContainer); + + _unusedChoices = new Array(); + while(true) { + + var item:MovieClip = cast target.getChildByName('item${_unusedChoices.length}'); + if (item == null) + break; + + target.removeChild(item); + _unusedChoices.push(item); + } + } + + public function addItem(name:String, value:String):Void { + + _values.set(value, name); + + if (_unusedChoices.length == 0) { + + NG.core.logError('cannot create another dropBox item max=${_choiceContainer.numChildren}'); + return; + } + + var button = _unusedChoices.shift(); + cast(button.getChildByName("label"), TextField).text = name; + _choiceContainer.addChild(button); + + new Button(button, onChoiceClick.bind(value)); + } + + function onClickExpand():Void { + + _choiceContainer.visible = !_choiceContainer.visible; + } + + function onChoiceClick(name:String):Void { + + value = name; + + _choiceContainer.visible = false; + } +} \ No newline at end of file diff --git a/source/io/newgrounds/utils/AsyncHttp.hx b/source/io/newgrounds/utils/AsyncHttp.hx new file mode 100644 index 00000000..4fbe1438 --- /dev/null +++ b/source/io/newgrounds/utils/AsyncHttp.hx @@ -0,0 +1,203 @@ +package io.newgrounds.utils; + +import io.newgrounds.NGLite; + +import haxe.Http; +import haxe.Timer; + +#if neko +import neko.vm.Thread; +#elseif java +import java.vm.Thread; +#elseif cpp +import cpp.vm.Thread; +#end + +/** + * Uses Threading to turn hxcpp's synchronous http requests into asynchronous processes + * + * @author GeoKureli + */ +class AsyncHttp { + + inline static var PATH:String = "https://newgrounds.io/gateway_v3.php"; + + static public function send + ( core:NGLite + , data:String + , onData:String->Void + , onError:String->Void + , onStatus:Int->Void + ) { + + core.logVerbose('sending: $data'); + + #if (neko || java || cpp) + sendAsync(core, data, onData, onError, onStatus); + #else + sendSync(core, data, onData, onError, onStatus); + #end + } + + static function sendSync + ( core:NGLite + , data:String + , onData:String->Void + , onError:String->Void + , onStatus:Int->Void + ):Void { + + var http = new Http(PATH); + http.setParameter("input", data); + http.onData = onData; + http.onError = onError; + http.onStatus = onStatus; + // #if js http.async = async; #end + http.request(true); + } + + #if (neko || java || cpp) + static var _deadPool:Array = []; + static var _livePool:Array = []; + static var _map:Map = new Map(); + static var _timer:Timer; + + static var _count:Int = 0; + + var _core:NGLite; + var _key:Int; + var _onData:String->Void; + var _onError:String->Void; + var _onStatus:Int->Void; + var _worker:Thread; + + public function new (core:NGLite) { + + _core = core; + _worker = Thread.create(sendThreaded); + _key = _count++; + _map[_key] = this; + _core.logVerbose('async http created: $_key'); + } + + function start(data:String, onData:String->Void, onError:String->Void, onStatus:Int->Void) { + + _core.logVerbose('async http started: $_key'); + + if (_livePool.length == 0) + startTimer(); + + _deadPool.remove(this); + _livePool.push(this); + + _onData = onData; + _onError = onError; + _onStatus = onStatus; + _worker.sendMessage({ source:Thread.current(), args:data, key:_key, core:_core }); + } + + function handleMessage(data:ReplyData):Void { + + _core.logVerbose('handling message: $_key'); + + if (data.status != null) { + + _core.logVerbose('\t- status: ${data.status}'); + _onStatus(cast data.status); + return; + } + + var tempFunc:Void->Void; + if (data.data != null) { + + _core.logVerbose('\t- data'); + tempFunc = _onData.bind(data.data); + + } else { + + _core.logVerbose('\t- error'); + tempFunc = _onError.bind(data.error); + } + + cleanUp(); + // Delay the call until destroy so that we're more likely to use a single + // thread on daisy-chained calls + tempFunc(); + } + + inline function cleanUp():Void { + + _onData = null; + _onError = null; + + _deadPool.push(this); + _livePool.remove(this); + + if (_livePool.length == 0) + stopTimer(); + } + + static function sendAsync + ( core:NGLite + , data:String + , onData:String->Void + , onError:String->Void + , onStatus:Int->Void + ):Void { + + var http:AsyncHttp; + if (_deadPool.length == 0) + http = new AsyncHttp(core); + else + http = _deadPool[0]; + + http.start(data, onData, onError, onStatus); + } + + static function startTimer():Void { + + if (_timer != null) + return; + + _timer = new Timer(1000 / 60.0); + _timer.run = update; + } + + static function stopTimer():Void { + + _timer.stop(); + _timer = null; + } + + static public function update():Void { + + var message:ReplyData = cast Thread.readMessage(false); + if (message != null) + _map[message.key].handleMessage(message); + } + + static function sendThreaded():Void { + + while(true) { + + var data:LoaderData = cast Thread.readMessage(true); + data.core.logVerbose('start message received: ${data.key}'); + + sendSync + ( data.core + , data.args + , function(reply ) { data.source.sendMessage({ key:data.key, data :reply }); } + , function(error ) { data.source.sendMessage({ key:data.key, error :error }); } + , function(status) { data.source.sendMessage({ key:data.key, status:status }); } + ); + } + } + + #end +} + + +#if (neko || java || cpp) +typedef LoaderData = { source:Thread, key:Int, args:String, core:NGLite }; +typedef ReplyData = { key:Int, ?data:String, ?error:String, ?status:Null }; +#end \ No newline at end of file diff --git a/source/io/newgrounds/utils/Dispatcher.hx b/source/io/newgrounds/utils/Dispatcher.hx new file mode 100644 index 00000000..699da01d --- /dev/null +++ b/source/io/newgrounds/utils/Dispatcher.hx @@ -0,0 +1,118 @@ +package io.newgrounds.utils; + +/** + * Basically shitty signals, but I didn't want to have external references. +**/ +class Dispatcher { + + var _list:ArrayVoid>; + var _once:ArrayVoid>; + + public function new() { + + _list = new ArrayVoid>(); + _once = new ArrayVoid>(); + } + + public function add(handler:Void->Void, once:Bool = false):Bool { + + if (_list.indexOf(handler) != -1) { + + // ---- REMOVE ONCE + if (!once && _once.indexOf(handler) != -1) + _once.remove(handler); + + return false; + } + + _list.unshift(handler); + if (once) + _once.unshift(handler); + + return true; + } + + inline public function addOnce(handler:Void->Void):Bool { + + return add(handler, true); + } + + public function remove(handler:Void->Void):Bool { + + _once.remove(handler); + return _list.remove(handler); + } + + public function dispatch():Void { + + var i = _list.length - 1; + while(i >= 0) { + + var handler = _list[i]; + + if (_once.remove(handler)) + _list.remove(handler); + + handler(); + + i--; + } + } +} + +class TypedDispatcher { + + var _list:ArrayVoid>; + var _once:ArrayVoid>; + + public function new() { + + _list = new ArrayVoid>(); + _once = new ArrayVoid>(); + } + + public function add(handler:T->Void, once:Bool = false):Bool { + + if (_list.indexOf(handler) != -1) { + + // ---- REMOVE ONCE + if (!once && _once.indexOf(handler) != -1) + _once.remove(handler); + + return false; + } + + _list.unshift(handler); + if (once) + _once.unshift(handler); + + return true; + } + + inline public function addOnce(handler:T->Void):Bool { + + return add(handler, true); + } + + public function remove(handler:T->Void):Bool { + + _once.remove(handler); + return _list.remove(handler); + } + + public function dispatch(arg:T):Void { + + var i = _list.length - 1; + while(i >= 0) { + + var handler = _list[i]; + + if (_once.remove(handler)) + _list.remove(handler); + + handler(arg); + + i--; + } + } +} \ No newline at end of file