├── .gitattributes ├── LICENSE ├── README.md ├── assets ├── eventArrowModchart.png ├── eventArrowModchart.xml └── pathTest.txt ├── documentation └── ModchartVariables.txt ├── examples ├── customPath.txt ├── leather │ ├── modchart.lua │ └── modifiers.hx ├── modchart editor testing │ └── fusion-reactor │ │ ├── customMods │ │ ├── IncomingAngleCurve.hx │ │ ├── IncomingAngleSmooth.hx │ │ ├── InvertIncomingAngle.hx │ │ └── MoveYWaveShit.hx │ │ ├── fusion-reactor-canon.json │ │ └── modchart.json ├── psych │ └── script.lua └── readme.txt ├── haxelib.json ├── include.xml ├── readme ├── custommods.gif ├── modifiers.gif └── sustains.gif └── source ├── flixel ├── addons │ └── effects │ │ └── FlxSkewedSprite.hx └── tweens │ └── misc │ ├── BezierPathNumTween.hx │ └── BezierPathTween.hx ├── import.hx ├── managers └── TweenManager.hx └── modcharting ├── ModTable.hx ├── ModchartEditorState.hx ├── ModchartEvent.hx ├── ModchartEventManager.hx ├── ModchartFile.hx ├── ModchartFuncs.hx ├── ModchartMusicBeatState.hx ├── ModchartUtil.hx ├── Modifier.hx ├── NoteMovement.hx ├── NotePositionData.hx ├── Playfield.hx ├── PlayfieldRenderer.hx ├── SimpleQuaternion.hx └── SustainStrip.hx /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # FNF Modcharting Tools 2 | Just a thing I made to make modcharting easier, should be easy to add to most engines. 3 | Still very WIP and not everything is supported yet! 4 | 5 | ## Features 6 | ### Modifier system for easing in and out effects 7 | ![](https://github.com/TheZoroForce240/FNF-Modcharting-Tools/blob/main/readme/modifiers.gif) 8 | ### Custom Sustain Renderer (using FlxStrip for stretchy sustains) 9 | ### Multiple playfields that can have their own positions and modifiers 10 | ![](https://github.com/TheZoroForce240/FNF-Modcharting-Tools/blob/main/readme/sustains.gif) 11 | ### Custom Modifier Support via Hscript 12 | ![](https://github.com/TheZoroForce240/FNF-Modcharting-Tools/blob/main/readme/custommods.gif) 13 | ### Support for multiple engines 14 | - Base Game (not tested) 15 | - [Psych Engine](https://github.com/ShadowMario/FNF-PsychEngine) (working 0.6.3 and 0.7.x, includes lua functions) 16 | - [Leather Engine](https://github.com/Leather128/LeatherEngine) (working 0.5.0) 17 | - [Kade Engine](https://github.com/KadeDev/Kade-Engine) (not tested) 18 | - [Yoshi Engine](https://github.com/YoshiCrafter29/YoshiCrafterEngine) (not tested) 19 | - [Forever Engine Legacy](https://github.com/Yoshubs/Forever-Engine-Legacy) (not tested) 20 | - [FPS Plus](https://github.com/ThatRozebudDude/FPS-Plus-Public) (not tested) 21 | 22 | 23 | ## Credits 24 | - [Original FNF Team](https://github.com/ninjamuffin99/Funkin) - They made the game 25 | - [NotITG](https://www.noti.tg/) - Inspiration (made me love modcharts lol) 26 | - [OpenITG](https://github.com/openitg/openitg) - Math used for some modifiers 27 | - [TheZoroForce240](https://github.com/TheZoroForce240/FNF-Modcharting-Tools) - Creator of modcharting tools base 28 | - [Vortex2Oblivion](https://github.com/Vortex2Oblivion) - Helper from modcharting tools 29 | - [Manu614](https://github.com/Manu614) - Helper from modcharting tools 30 | - [UncertainProd](https://github.com/UncertainProd) - Helper from modcharting tools 31 | - [Joalor64GH](https://github.com/Joalor64GH) - Helper from modcharting tools 32 | - [Edwhak_KB](https://github.com/EdwhakKB) - Added some modifiers and fixed stuff + skewNotes 33 | - [Glowsoony](https://github.com/glowsoony) - Help with some 0.7.X stuff! + skewNotes too 34 | - [Slushi_Github](https://github.com/Slushi-Github) - Help with reorganisation with haxelib edition 35 | - [2JENO](https://github.com/2JENO) - Help with the Import.hx, GPU thing (fixes some things so thanks!) 36 | 37 | ## Installation 38 | 1. You need the most recent version of HaxeFlixel for it to work. (5.5.0 as of writing) 39 | 2. If your running any (engine or psych) that uses SScript (For Custom Modifiers) then I really recommened using versions 6.1.80 and up. NO LOWER VERSIONS! (If you use older versions, sorry but SScript in older version apperantly has many memory leaks when it comes to any scripts (even without modchartingTools). -glowsoony 40 | ### With Source: 41 | 1. Install the haxelib by typing `haxelib git fnf-modcharting-tools https://github.com/EdwhakKB/FNF-Modcharting-Tools` in the console 42 | 2. Now you only need to make a few small additions to get everything working, 43 | - In MusicBeatState.hx: 44 | ```haxe 45 | class MusicBeatState extends modcharting.ModchartMusicBeatState 46 | { 47 | 48 | ``` 49 | - In PlayState.hx: 50 | ```haxe 51 | import modcharting.ModchartFuncs; 52 | import modcharting.NoteMovement; 53 | import modcharting.PlayfieldRenderer; 54 | 55 | ``` 56 | ```haxe 57 | override public function create() 58 | { 59 | //Add this before function create() (For Psych 0.7.1+) 60 | var backupGpu:Bool; 61 | //Add this before generateSong(); (For Psych 0.7.1+) 62 | backupGpu = ClientPrefs.data.cacheOnGPU; 63 | ClientPrefs.data.cacheOnGPU = false; 64 | //Add this before camfollow stuff and after strumLineNotes and notes have been made 65 | playfieldRenderer = new PlayfieldRenderer(strumLineNotes, notes, this); 66 | playfieldRenderer.cameras = [camHUD]; 67 | add(playfieldRenderer); 68 | add(grpNoteSplashes); /*place splashes in front (add this if the engine has splashes). 69 | If you have added this: remove(or something) the add(grpNoteSplashes); which is by default below the add(strumLineNotes);*/ 70 | //if you use PSYCH 0.6.3 use this code 71 | ModchartFuncs.loadLuaFunctions(); //add this if you want lua functions in scripts 72 | //being used in psych engine as an example 73 | callOnLuas('onCreatePost', []); 74 | 75 | //Find this line and then add it 76 | public function startCountdown():Void 77 | { 78 | generateStaticArrows(0); 79 | generateStaticArrows(1); 80 | 81 | //add after generating strums 82 | NoteMovement.getDefaultStrumPos(this); 83 | //Find this line and then add it (For Psych 0.7.1+) 84 | override function destroy() { 85 | ClientPrefs.data.cacheOnGPU = backupGpu; 86 | ``` 87 | 88 | - In StrumNote.hx: 89 | ```haxe 90 | //Import FlxSkewedSprite at the top 91 | import flixel.addons.effects.FlxSkewedSprite; 92 | //change "FlxSprite" to "FlxSkewedSprite" 93 | class StrumNote extends FlxSkewedSprite 94 | ``` 95 | 96 | - In Note.hx: 97 | ```haxe 98 | //Import FlxSkewedSprite at the top 99 | import flixel.addons.effects.FlxSkewedSprite; 100 | //change "FlxSprite" to "FlxSkewedSprite" 101 | class Note extends FlxSkewedSprite 102 | { 103 | //add these 2 variables for the renderer 104 | public var mesh:modcharting.SustainStrip = null; 105 | public var z:Float = 0; 106 | ``` 107 | 108 | - In ModchartUtilities.hx (Leather Exclusive): 109 | 110 | ```haxe 111 | // at the start of the HX 112 | import modcharting.ModchartFuncs; //to fix any crash lmao 113 | // (at the bottom of create()) 114 | #if desktop DiscordClient.addLuaCallbacks(this); #end 115 | ModchartFuncs.loadLuaFunctions(this); //add this if you want lua functions in scripts 116 | //being used in leather engine as an example 117 | callOnLuas('onCreate', []); 118 | ``` 119 | 120 | - In FunkinLua.hx (Found in psychlua folder) (0.7.X exclusive!): 121 | ```haxe 122 | //at the start of the HX 123 | import modcharting.ModchartFuncs; //to fix any crash lmao 124 | class FunkinLua 125 | { 126 | //add this variable bellow "public var closed:Bool = false;" 127 | public static var instance:FunkinLua = null; 128 | #if desktop DiscordClient.addLuaCallbacks(this); #end 129 | ModchartFuncs.loadLuaFunctions(this); //add this if you want lua functions in scripts 130 | being used in psych engine as an example 131 | ``` 132 | - In HScript (Found in psychlua folder) (0.7.X exclusive!) 133 | ``` haxe 134 | //under the function (PRESET!) 135 | //copy and paste this code if you use under SScript 6.1.80 136 | override function preset() 137 | { 138 | set('Math', Math); 139 | set('ModchartEditorState', modcharting.ModchartEditorState); 140 | set('ModchartEvent', modcharting.ModchartEvent); 141 | set('ModchartEventManager', modcharting.ModchartEventManager); 142 | set('ModchartFile', modcharting.ModchartFile); 143 | set('ModchartFuncs', modcharting.ModchartFuncs); 144 | set('ModchartMusicBeatState', modcharting.ModchartMusicBeatState); 145 | set('ModchartUtil', modcharting.ModchartUtil); 146 | for (i in ['mod', 'Modifier']) 147 | set(i, modcharting.Modifier); //the game crashes without this???????? what??????????? -- fue glow 148 | set('ModifierSubValue', modcharting.Modifier.ModifierSubValue); 149 | set('ModTable', modcharting.ModTable); 150 | set('NoteMovement', modcharting.NoteMovement); 151 | set('NotePositionData', modcharting.NotePositionData); 152 | set('Playfield', modcharting.Playfield); 153 | set('PlayfieldRenderer', modcharting.PlayfieldRenderer); 154 | set('SimpleQuaternion', modcharting.SimpleQuaternion); 155 | set('SustainStrip', modcharting.SustainStrip); 156 | 157 | modcharting.ModchartFuncs.loadHScriptFunctions(this); 158 | //--(else if you use SScript above or equal to version 6.1.80)-- 159 | override function preset() 160 | { 161 | set('Math', Math); 162 | setClass(modcharting.ModchartEditorState); 163 | setClass(modcharting.ModchartEvent); 164 | setClass(modcharting.ModchartEventManager); 165 | setClass(modcharting.ModchartFile); 166 | setClass(modcharting.ModchartFuncs); 167 | setClass(modcharting.ModchartMusicBeatState); 168 | setClass(modcharting.ModchartUtil); 169 | setClass(modcharting.Modifier); //the game crashes without this???????? what??????????? -- fue glow 170 | setClass(modcharting.Modifier.ModifierSubValue); 171 | setClass(modcharting.ModTable); 172 | setClass(modcharting.NoteMovement); 173 | setClass(modcharting.NotePositionData); 174 | setClass(modcharting.Playfield); 175 | setClass(modcharting.PlayfieldRenderer); 176 | setClass(modcharting.SimpleQuaternion); 177 | setClass(modcharting.SustainStrip); 178 | modcharting.ModchartFuncs.loadHScriptFunctions(this); 179 | //Function initMod -- Init's the mods functions for Hscript (found in psychlua) 180 | //Place this function anywhere in the HScript class! 181 | public function initMod(mod:modcharting.Modifier) 182 | { 183 | call("initMod", [mod]); 184 | } 185 | ``` 186 | - In Import.hx, you should copy what mine adds and paste it there 187 | 188 | - In Project.xml: 189 | ```xml 190 | 191 | 192 | 193 | 194 | 195 | ``` 196 | You need to define which engine you're using to fix compiling issues, or it would default to base game settings (downscroll won't work etc). 197 | Available ones: PSYCH, KADE(notTested), LEATHER, FOREVER_LEGACY(notTested), YOSHI(notTested), FPSPLUS(notTested) 198 | 199 | Note: If you use psych engine you should add this (have in mind "ver" is the version you want to use, do not add the text, use the brain) 200 | (just in case minimal ver is 0.6.0 to 0.7.3) 201 | and no if psych 0.7.4 or more releases i won't port this due some changes Psych has (they break MT to it max so srry :D) 202 | 203 | ```xml 204 | 205 | 206 | 207 | ``` 208 | 209 | to get 0.7.X and up add a higher version than 0.7 (example 0.7.3), 210 | leave it as another value to use 0.6.3 edition 211 | 212 | 213 | 3. Now if your game compiles successfully then you should be all good to go. 214 | -------------------------------------------------------------------------------- /assets/eventArrowModchart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EdwhakKB/FNF-Modcharting-Tools/47a411c67e7deaa39c4e29d8640c8b2f4e36ea7d/assets/eventArrowModchart.png -------------------------------------------------------------------------------- /assets/eventArrowModchart.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /assets/pathTest.txt: -------------------------------------------------------------------------------- 1 | -5.32266902923584;1.5246357917785645;-8.777054786682129;1.0 2 | -5.234609603881836;1.7484805583953857;-8.783271789550781;1.0 3 | -4.900301456451416;2.3798604011535645;-8.810586929321289;1.0 4 | -4.539057731628418;2.6687521934509277;-8.846787452697754;1.0 5 | -3.8826723098754883;2.9988062381744385;-8.915874481201172;1.0 6 | -3.499480724334717;3.0214765071868896;-8.959095001220703;1.0 7 | -3.3510608673095703;2.920449733734131;-8.977700233459473;1.0 8 | -3.23814058303833;2.734546661376953;-8.9937105178833;1.0 9 | -3.2129225730895996;2.4665908813476562;-9.00113296508789;1.0 10 | -3.3027024269104004;2.1242594718933105;-8.996732711791992;1.0 11 | -3.628297805786133;1.5280909538269043;-8.969809532165527;1.0 12 | -3.9624013900756836;1.1121773719787598;-8.938857078552246;1.0 13 | -4.432987213134766;0.7346479296684265;-8.89172077178955;1.0 14 | -4.989719390869141;0.47027212381362915;-8.832858085632324;1.0 15 | -5.33845329284668;0.40233945846557617;-8.794328689575195;1.0 16 | -5.050148010253906;0.45850127935409546;-8.82618236541748;1.0 17 | -5.029303073883057;0.5452755093574524;-8.827080726623535;1.0 18 | -4.391894817352295;2.143267869949341;-8.872462272644043;1.0 19 | -4.3830060958862305;2.175076484680176;-8.872934341430664;1.0 20 | -5.2553277015686035;0.3583762049674988;-8.804534912109375;1.0 21 | -5.1723856925964355;-0.4300546944141388;-8.82736873626709;1.0 22 | -5.1723856925964355;-0.4300546944141388;-8.82736873626709;1.0 23 | -5.05217981338501;0.43756574392318726;-8.826306343078613;1.0 24 | -4.981097221374512;0.47317057847976685;-8.83379077911377;1.0 25 | -4.445980548858643;0.7297149300575256;-8.890326499938965;1.0 26 | -4.422902584075928;0.6993982195854187;-8.893467903137207;1.0 27 | -4.289186954498291;0.33815646171569824;-8.914822578430176;1.0 28 | -3.974761962890625;-0.13148707151412964;-8.95858383178711;1.0 29 | -3.7403483390808105;-0.294700026512146;-8.988033294677734;1.0 30 | -3.6869254112243652;-0.2799406349658966;-8.993861198425293;1.0 31 | -3.5333566665649414;0.07199054956436157;-9.005355834960938;1.0 32 | -3.3668928146362305;0.2654244303703308;-9.021012306213379;1.0 33 | -3.148952007293701;0.4384259581565857;-9.042874336242676;1.0 34 | -2.9370603561401367;0.688578188419342;-9.062736511230469;1.0 35 | -2.8379602432250977;0.8949999213218689;-9.070507049560547;1.0 36 | -2.75022554397583;1.138371467590332;-9.07635498046875;1.0 37 | -2.7764339447021484;1.2986266613006592;-9.070649147033691;1.0 38 | -2.8319082260131836;1.3400392532348633;-9.06363296508789;1.0 39 | -2.9218978881835938;1.3355627059936523;-9.053467750549316;1.0 40 | -3.004868507385254;1.2715349197387695;-9.045114517211914;1.0 41 | -3.1828699111938477;1.093257188796997;-9.027887344360352;1.0 42 | -3.3691816329956055;0.7088391184806824;-9.013216972351074;1.0 43 | -3.422018527984619;0.3504212498664856;-9.01329517364502;1.0 44 | -3.3937621116638184;0.13399535417556763;-9.020188331604004;1.0 45 | -3.328347682952881;0.08581626415252686;-9.028450965881348;1.0 46 | -3.1835060119628906;0.07486605644226074;-9.045119285583496;1.0 47 | -2.993687152862549;0.16841357946395874;-9.065130233764648;1.0 48 | -2.8458547592163086;0.32340675592422485;-9.079319953918457;1.0 49 | -2.653045654296875;0.5828946232795715;-9.09685230255127;1.0 50 | -2.5239481925964355;0.7908092141151428;-9.108009338378906;1.0 51 | -2.2325916290283203;1.3958618640899658;-9.130884170532227;1.0 52 | -2.1974499225616455;1.4157617092132568;-9.13454532623291;1.0 53 | -2.442473888397217;0.7718679308891296;-9.11760425567627;1.0 54 | -2.5173850059509277;0.256844162940979;-9.117829322814941;1.0 55 | -2.412655830383301;0.2293778657913208;-9.13021469116211;1.0 56 | -2.3232898712158203;0.25984084606170654;-9.139866828918457;1.0 57 | -2.179804801940918;0.39222943782806396;-9.153944969177246;1.0 58 | -2.002357244491577;0.709648072719574;-9.168745040893555;1.0 59 | -1.702239751815796;1.4730639457702637;-9.189926147460938;1.0 60 | -1.635328769683838;1.507857322692871;-9.196949005126953;1.0 61 | -1.62910795211792;1.452498435974121;-9.198596954345703;1.0 62 | -1.8891115188598633;0.7055982947349548;-9.181700706481934;1.0 63 | -1.865096092224121;0.3752055764198303;-9.190047264099121;1.0 64 | -1.7820234298706055;0.3478724956512451;-9.199965476989746;1.0 65 | -1.7135133743286133;0.37427324056625366;-9.207313537597656;1.0 66 | -1.570199966430664;0.48486971855163574;-9.221742630004883;1.0 67 | -1.4240710735321045;0.7396168112754822;-9.23404312133789;1.0 68 | -1.1689012050628662;1.1940202713012695;-9.255358695983887;1.0 69 | -1.050473690032959;1.5260505676269531;-9.26319408416748;1.0 70 | -1.0765066146850586;1.7080979347229004;-9.2571382522583;1.0 71 | -1.1446678638458252;1.7252795696258545;-9.249089241027832;1.0 72 | -1.2324354648590088;1.6864259243011475;-9.239762306213379;1.0 73 | -1.2838106155395508;1.615495204925537;-9.235121726989746;1.0 74 | -1.3679986000061035;1.398923397064209;-9.229220390319824;1.0 75 | -1.3923673629760742;1.163543939590454;-9.230446815490723;1.0 76 | -1.3569157123565674;0.9093559384346008;-9.238801002502441;1.0 77 | -1.279334306716919;0.8200300335884094;-9.249147415161133;1.0 78 | -1.154201865196228;0.8444053530693054;-9.262971878051758;1.0 79 | -1.0420336723327637;0.9141233563423157;-9.274552345275879;1.0 80 | -0.8950022459030151;1.0733113288879395;-9.288578987121582;1.0 81 | -0.7072662115097046;1.4275479316711426;-9.303923606872559;1.0 82 | -0.5383337736129761;1.7215492725372314;-9.31815242767334;1.0 83 | -0.39519548416137695;1.8103539943695068;-9.332931518554688;1.0 84 | -0.33005672693252563;1.8317453861236572;-9.339981079101562;1.0 85 | -0.25195416808128357;1.8077962398529053;-9.349276542663574;1.0 86 | -0.21208593249320984;1.6893668174743652;-9.35582447052002;1.0 87 | -0.2257145494222641;1.443023920059204;-9.35845947265625;1.0 88 | -0.3607226014137268;1.0163805484771729;-9.350346565246582;1.0 89 | -0.4754299521446228;0.7329409718513489;-9.342108726501465;1.0 90 | -0.6449167132377625;0.578081488609314;-9.32545280456543;1.0 91 | -0.7376539707183838;0.5426102876663208;-9.315503120422363;1.0 92 | -0.8489514589309692;0.5818514823913574;-9.302170753479004;1.0 93 | -0.878355860710144;0.758889377117157;-9.295815467834473;1.0 94 | -0.8644500970840454;0.9356613755226135;-9.294394493103027;1.0 95 | -0.8468254804611206;1.161024570465088;-9.292571067810059;1.0 96 | -0.8468254804611206;1.161024570465088;-9.292571067810059;1.0 97 | -0.7261083126068115;1.0496416091918945;-9.308199882507324;1.0 98 | -0.7112677097320557;0.9263364672660828;-9.31198501586914;1.0 99 | -0.633686363697052;0.8370113968849182;-9.322330474853516;1.0 100 | -0.5215896964073181;0.7935743927955627;-9.33582592010498;1.0 101 | -0.31783077120780945;0.8593752980232239;-9.357893943786621;1.0 102 | -0.10308815538883209;1.0491602420806885;-9.379106521606445;1.0 103 | 0.11527067422866821;1.3789005279541016;-9.398353576660156;1.0 104 | 0.3083258867263794;1.7733361721038818;-9.413619995117188;1.0 105 | 0.3854227662086487;1.936307430267334;-9.419624328613281;1.0 106 | 0.3845199942588806;2.0318660736083984;-9.41789722442627;1.0 107 | 0.40919923782348633;1.9931573867797852;-9.42136287689209;1.0 108 | 0.45660877227783203;1.8805487155914307;-9.428672790527344;1.0 109 | 0.5648127794265747;1.7667279243469238;-9.44291877746582;1.0 110 | 0.56011962890625;1.700540542602539;-9.443509101867676;1.0 111 | 0.3671293258666992;0.8970697522163391;-9.435200691223145;1.0 112 | 0.4065456986427307;0.8264201283454895;-9.440886497497559;1.0 113 | 0.5124216079711914;0.8383412957191467;-9.45273208618164;1.0 114 | 0.5950434803962708;0.858787477016449;-9.461787223815918;1.0 115 | 0.9431252479553223;1.3704533576965332;-9.492703437805176;1.0 116 | 1.0598821640014648;1.5977203845977783;-9.502127647399902;1.0 117 | 1.4972403049468994;2.9213738441467285;-9.529407501220703;1.0 118 | 1.5103371143341064;2.9343698024749756;-9.530677795410156;1.0 119 | 0.9662704467773438;0.9311016201972961;-9.502802848815918;1.0 120 | 0.9534022808074951;0.9259839653968811;-9.501425743103027;1.0 121 | 0.9314626455307007;0.93215411901474;-9.498824119567871;1.0 122 | 0.9314626455307007;0.93215411901474;-9.498824119567871;1.0 123 | 1.1842787265777588;1.6759123802185059;-9.5149564743042;1.0 124 | 1.4127733707427979;2.00240421295166;-9.535408973693848;1.0 125 | 1.609025001525879;2.171180486679077;-9.554875373840332;1.0 126 | 1.7691943645477295;2.2023813724517822;-9.572571754455566;1.0 127 | 1.8297145366668701;2.020961046218872;-9.582541465759277;1.0 128 | 1.7647697925567627;1.8986501693725586;-9.577229499816895;1.0 129 | 1.5185906887054443;1.6104891300201416;-9.554110527038574;1.0 130 | 1.3787741661071777;1.4997029304504395;-9.540082931518555;1.0 131 | 1.3916633129119873;1.4865474700927734;-9.541773796081543;1.0 132 | 1.4837167263031006;1.2486069202423096;-9.556291580200195;1.0 133 | 1.6066365242004395;1.1211166381835938;-9.5724458694458;1.0 134 | 1.7032382488250732;1.0772719383239746;-9.584182739257812;1.0 135 | 1.8228232860565186;1.1580073833465576;-9.596420288085938;1.0 136 | 2.0222456455230713;1.47361421585083;-9.613750457763672;1.0 137 | 2.0773041248321533;1.4843401908874512;-9.619833946228027;1.0 138 | 2.189255475997925;1.3599352836608887;-9.634688377380371;1.0 139 | 2.350801944732666;1.438401460647583;-9.651739120483398;1.0 140 | 2.6131649017333984;1.7506022453308105;-9.676289558410645;1.0 141 | 2.7996997833251953;2.079364538192749;-9.691929817199707;1.0 142 | 2.8237266540527344;2.334696054458618;-9.690325736999512;1.0 143 | 2.788565158843994;2.4375061988830566;-9.684577941894531;1.0 144 | 2.7406396865844727;2.443836212158203;-9.67901611328125;1.0 145 | 2.6755714416503906;2.4311606884002686;-9.67182731628418;1.0 146 | 2.536923885345459;2.341489553451538;-9.657572746276855;1.0 147 | 2.29437255859375;2.007037401199341;-9.63565444946289;1.0 148 | 2.171407461166382;1.7533199787139893;-9.625971794128418;1.0 149 | 2.1400363445281982;1.4547853469848633;-9.627476692199707;1.0 150 | 2.1939661502838135;1.1989738941192627;-9.637959480285645;1.0 151 | 2.353717803955078;1.1778738498687744;-9.65649700164795;1.0 152 | 2.6263413429260254;1.2727558612823486;-9.685907363891602;1.0 153 | 2.9553589820861816;1.6710479259490967;-9.716582298278809;1.0 154 | 3.000405788421631;1.679823875427246;-9.721559524536133;1.0 155 | 2.9933981895446777;1.5531325340270996;-9.72291374206543;1.0 156 | 3.02059268951416;1.3286681175231934;-9.729823112487793;1.0 157 | 3.1324172019958496;1.3138971328735352;-9.742798805236816;1.0 158 | 3.3282508850097656;1.4303734302520752;-9.763105392456055;1.0 159 | 3.501059055328369;1.6676909923553467;-9.778738975524902;1.0 160 | 3.5897412300109863;1.8833961486816406;-9.785164833068848;1.0 161 | 3.694146156311035;2.3162624835968018;-9.789690017700195;1.0 162 | 3.6840972900390625;2.5597355365753174;-9.784409523010254;1.0 163 | 3.577275276184082;2.575479507446289;-9.77198600769043;1.0 164 | 3.3922033309936523;2.4297685623168945;-9.753402709960938;1.0 165 | 3.193948268890381;2.1352765560150146;-9.735844612121582;1.0 166 | 3.0453295707702637;1.7982337474822998;-9.724658966064453;1.0 167 | 3.0030760765075684;1.6385674476623535;-9.722563743591309;1.0 168 | 3.007911205291748;1.367973804473877;-9.72771167755127;1.0 169 | 3.100468158721924;1.3181183338165283;-9.739092826843262;1.0 170 | 3.1865158081054688;1.3296592235565186;-9.748687744140625;1.0 171 | 3.3563642501831055;1.4462940692901611;-9.766033172607422;1.0 172 | 3.5131988525390625;1.685720682144165;-9.779813766479492;1.0 173 | 4.116020202636719;3.453263759613037;-9.818379402160645;1.0 174 | 3.652557849884033;1.9896275997161865;-9.790508270263672;1.0 175 | 3.6366610527038574;1.5008947849273682;-9.797003746032715;1.0 176 | 3.6822500228881836;1.4523355960845947;-9.803016662597656;1.0 177 | 3.757538318634033;1.493109941482544;-9.810890197753906;1.0 178 | 3.854224681854248;1.5850520133972168;-9.820331573486328;1.0 179 | 4.037461757659912;1.8766188621520996;-9.83622932434082;1.0 180 | 4.1816182136535645;2.1553494930267334;-9.847896575927734;1.0 181 | 4.156808376312256;1.4315543174743652;-9.857372283935547;1.0 182 | 3.0348057746887207;0.9790293574333191;-9.737380981445312;1.0 183 | -1.1645309925079346;0.2741355299949646;-9.27148723602295;1.0 184 | -3.966914653778076;-0.554682731628418;-8.966667175292969;1.0 185 | -5.333769798278809;-2.132967233657837;-8.837940216064453;1.0 186 | -3.6712446212768555;-2.838393211364746;-9.039117813110352;1.0 187 | -2.976569652557373;-2.576744318008423;-9.113723754882812;1.0 188 | -2.170823097229004;-1.815215826034546;-9.192476272583008;1.0 189 | -1.8277311325073242;-1.0265085697174072;-9.218117713928223;1.0 190 | -1.781813144683838;-0.4671350121498108;-9.213837623596191;1.0 191 | -1.951695442199707;-0.3287825584411621;-9.192154884338379;1.0 192 | -2.1326065063476562;-0.2737894058227539;-9.170633316040039;1.0 193 | -2.383432388305664;-0.32264968752861023;-9.14292049407959;1.0 194 | -3.0035791397094727;-0.551734209060669;-9.076240539550781;1.0 195 | -3.3513498306274414;-0.8450651168823242;-9.04164981842041;1.0 196 | -3.7364578247070312;-1.2719969749450684;-9.005081176757812;1.0 197 | -3.8871021270751953;-1.7525136470794678;-8.996102333068848;1.0 198 | -3.1969618797302246;-0.7608497142791748;-9.057788848876953;1.0 199 | -2.5893545150756836;-0.37178659439086914;-9.120321273803711;1.0 200 | -1.9719481468200684;-0.269563764333725;-9.188843727111816;1.0 201 | -1.7769865989685059;-0.7278742790222168;-9.218816757202148;1.0 202 | -1.9574003219604492;-1.4758691787719727;-9.210996627807617;1.0 203 | -2.7033262252807617;-2.315976619720459;-9.140387535095215;1.0 204 | -3.2054858207702637;-2.6935245990753174;-9.089658737182617;1.0 205 | -3.5897250175476074;-2.7954421043395996;-9.047664642333984;1.0 206 | -2.880189895629883;-1.1051981449127197;-9.099687576293945;1.0 207 | -3.6013293266296387;-2.7345387935638428;-9.045309066772461;1.0 208 | -3.725451946258545;-3.3542640209198;-9.041714668273926;1.0 209 | -3.719327449798584;-3.6688919067382812;-9.047758102416992;1.0 210 | -3.622664451599121;-2.810882806777954;-9.04417896270752;1.0 211 | -3.3262133598327637;-2.6719236373901367;-9.075553894042969;1.0 212 | -3.0164999961853027;-2.602569103240967;-9.109619140625;1.0 213 | -2.9075231552124023;-2.7979037761688232;-9.125337600708008;1.0 214 | -2.773679733276367;-3.123744010925293;-9.146106719970703;1.0 215 | -2.537705421447754;-3.420666456222534;-9.17800521850586;1.0 216 | -2.2643957138061523;-3.583988904953003;-9.211881637573242;1.0 217 | -1.9039382934570312;-3.2160000801086426;-9.246648788452148;1.0 218 | -1.9124400615692139;-2.9830470085144043;-9.24172306060791;1.0 219 | -1.8530457019805908;-2.6827266216278076;-9.243378639221191;1.0 220 | -1.7726783752441406;-2.3512516021728516;-9.246891975402832;1.0 221 | -1.645749568939209;-2.028752565383911;-9.255855560302734;1.0 222 | -1.9071063995361328;-2.963960647583008;-9.242005348205566;1.0 223 | -1.8656647205352783;-3.18147349357605;-9.25041675567627;1.0 224 | -1.7651901245117188;-3.1438541412353516;-9.261210441589355;1.0 225 | -1.6590218544006348;-3.0419628620147705;-9.271562576293945;1.0 226 | -1.454249382019043;-2.7042999267578125;-9.2891263961792;1.0 227 | -1.3160767555236816;-2.487891912460327;-9.301172256469727;1.0 228 | -1.0872290134429932;-1.9470248222351074;-9.318024635314941;1.0 229 | -1.211350440979004;-2.56674861907959;-9.314431190490723;1.0 230 | -1.2824950218200684;-3.0408036708831787;-9.314390182495117;1.0 231 | -1.3785035610198975;-3.384348154067993;-9.309301376342773;1.0 232 | -1.4605293273925781;-3.707122325897217;-9.305452346801758;1.0 233 | -1.5788099765777588;-4.027937889099121;-9.297443389892578;1.0 234 | -1.7423546314239502;-4.3936614990234375;-9.28504753112793;1.0 235 | -1.9662961959838867;-4.5365400314331055;-9.261991500854492;1.0 236 | -2.133584976196289;-4.505965709686279;-9.242433547973633;1.0 237 | -2.220651149749756;-4.378552436828613;-9.23036003112793;1.0 238 | -2.226200580596924;-4.208187580108643;-9.226835250854492;1.0 239 | -2.2354254722595215;-4.065610408782959;-9.22336196899414;1.0 240 | -2.194772243499756;-3.9494102001190186;-9.226014137268066;1.0 241 | -2.1145501136779785;-3.8525712490081787;-9.233498573303223;1.0 242 | -1.9837307929992676;-3.6917381286621094;-9.245652198791504;1.0 243 | -1.9055280685424805;-3.6313867568969727;-9.253525733947754;1.0 244 | -1.7544536590576172;-3.529770612716675;-9.268990516662598;1.0 245 | -1.5873806476593018;-3.370896816253662;-9.285304069519043;1.0 246 | -1.3930609226226807;-3.2608556747436523;-9.305546760559082;1.0 247 | -1.2066700458526611;-3.062126636505127;-9.323381423950195;1.0 248 | -1.0425496101379395;-2.8406641483306885;-9.338294982910156;1.0 249 | -0.8627893924713135;-2.6071317195892334;-9.354782104492188;1.0 250 | -0.7189228534698486;-2.326450824737549;-9.366385459899902;1.0 251 | -0.17422866821289062;-0.948042094707489;-9.404947280883789;1.0 252 | -0.45698994398117065;-1.5355055332183838;-9.382752418518066;1.0 253 | -0.7181216478347778;-1.5773496627807617;-9.353748321533203;1.0 254 | 0.36136531829833984;-1.3580451011657715;-9.472862243652344;1.0 255 | -0.43104231357574463;-1.5304510593414307;-9.385618209838867;1.0 256 | -0.5728224515914917;-2.198732614517212;-9.380840301513672;1.0 257 | -0.62645423412323;-2.858865976333618;-9.385953903198242;1.0 258 | -0.5513516664505005;-2.970564365386963;-9.396397590637207;1.0 259 | -0.4155588150024414;-2.8358314037323;-9.409561157226562;1.0 260 | -0.33000385761260986;-2.719906806945801;-9.417326927185059;1.0 261 | -0.2703949511051178;-2.6090385913848877;-9.422226905822754;1.0 262 | -0.20912954211235046;-2.506868600845337;-9.427464485168457;1.0 263 | -0.043351560831069946;-2.2941083908081055;-9.442712783813477;1.0 264 | 0.40987735986709595;-0.9064469933509827;-9.470710754394531;1.0 265 | -0.18938341736793518;-2.8459131717681885;-9.435471534729004;1.0 266 | 0.024905383586883545;-2.1815545558929443;-9.448569297790527;1.0 267 | 0.17468202114105225;-2.026050329208374;-9.462968826293945;1.0 268 | 0.31451159715652466;-1.818342924118042;-9.47535228729248;1.0 269 | 0.4882160425186157;-1.6942715644836426;-9.493011474609375;1.0 270 | 0.6216304898262024;-1.6412124633789062;-9.507291793823242;1.0 271 | 0.677054226398468;-1.8379542827606201;-9.516942024230957;1.0 272 | 0.5784513354301453;-2.0737242698669434;-9.509726524353027;1.0 273 | 0.488498330116272;-2.307809352874756;-9.503467559814453;1.0 274 | 0.40387946367263794;-2.522808313369751;-9.497492790222168;1.0 275 | 0.40575110912323;-2.7209596633911133;-9.50107192993164;1.0 276 | 0.5215057730674744;-2.7164576053619385;-9.514167785644531;1.0 277 | 0.614052414894104;-2.590148687362671;-9.522553443908691;1.0 278 | 0.7378815412521362;-2.439699172973633;-9.534089088439941;1.0 279 | 0.8756937980651855;-2.2684788703918457;-9.546862602233887;1.0 280 | 0.9998824596405029;-2.0728416442871094;-9.557670593261719;1.0 281 | 1.0837806463241577;-1.9482178688049316;-9.565098762512207;1.0 282 | 1.1411552429199219;-1.684385061264038;-9.567145347595215;1.0 283 | 1.2467503547668457;-1.4382297992706299;-9.574979782104492;1.0 284 | 1.0550932884216309;-2.080134153366089;-9.564077377319336;1.0 285 | 1.0060062408447266;-2.387468099594116;-9.563713073730469;1.0 286 | 0.9938951730728149;-2.6063897609710693;-9.566055297851562;1.0 287 | 1.101000189781189;-2.603573799133301;-9.578195571899414;1.0 288 | 1.236793041229248;-2.468839645385742;-9.591358184814453;1.0 289 | 1.3795783519744873;-2.323720693588257;-9.605141639709473;1.0 290 | 1.4864695072174072;-2.131453514099121;-9.614038467407227;1.0 291 | 1.5950191020965576;-1.947887659072876;-9.623270988464355;1.0 292 | 1.696214199066162;-1.819892406463623;-9.632612228393555;1.0 293 | 1.7368667125701904;-1.7036924362182617;-9.63526439666748;1.0 294 | 1.8555073738098145;-1.3376917839050293;-9.642546653747559;1.0 295 | 1.6737968921661377;-2.0317983627319336;-9.633662223815918;1.0 296 | 1.5828287601470947;-2.8255324363708496;-9.636796951293945;1.0 297 | 1.459789514541626;-3.309694528579712;-9.631022453308105;1.0 298 | 1.3135437965393066;-3.6720521450042725;-9.620536804199219;1.0 299 | 1.062932014465332;-3.9103617668151855;-9.596068382263184;1.0 300 | 0.9138780832290649;-3.9754912853240967;-9.580212593078613;1.0 301 | 0.8516762852668762;-3.9785852432250977;-9.573185920715332;1.0 302 | 0.7605712413787842;-3.924142360687256;-9.56189250946045;1.0 303 | 0.6878494024276733;-3.730771064758301;-9.550333023071289;1.0 304 | 0.6913102269172668;-3.513535737991333;-9.547036170959473;1.0 305 | 0.8038968443870544;-3.2569942474365234;-9.555487632751465;1.0 306 | 0.977962851524353;-3.087735414505005;-9.572420120239258;1.0 307 | 1.1557036638259888;-2.890690565109253;-9.589298248291016;1.0 308 | 1.7410385608673096;-2.4788947105407715;-9.648910522460938;1.0 309 | 1.9437923431396484;-2.1777195930480957;-9.66686725616455;1.0 310 | 2.183522939682007;-1.7881312370300293;-9.68752670288086;1.0 311 | 2.4156839847564697;-1.2646641731262207;-9.705050468444824;1.0 312 | 2.149569272994995;-2.3632209300994873;-9.693435668945312;1.0 313 | 2.3601796627044678;-1.726646900177002;-9.706585884094238;1.0 314 | 2.5555830001831055;-1.4810454845428467;-9.724648475646973;1.0 315 | 2.712709903717041;-1.2699685096740723;-9.738943099975586;1.0 316 | 2.901695728302002;-1.1790134906768799;-9.758903503417969;1.0 317 | 2.9723992347717285;-1.4088730812072754;-9.770853996276855;1.0 318 | 2.8927536010742188;-1.6499738693237305;-9.765888214111328;1.0 319 | 2.7834835052490234;-1.9239158630371094;-9.75810718536377;1.0 320 | 2.7018179893493652;-2.201502561569214;-9.753530502319336;1.0 321 | 3.004255771636963;-1.5289955139160156;-9.776521682739258;1.0 322 | 3.1856751441955566;-1.304163932800293;-9.79334545135498;1.0 323 | 3.3597402572631836;-1.1349048614501953;-9.810276985168457;1.0 324 | 3.4445743560791016;-1.1093559265136719;-9.819497108459473;1.0 325 | 3.4313793182373047;-1.4638381004333496;-9.824019432067871;1.0 326 | 3.3151187896728516;-1.748166561126709;-9.815620422363281;1.0 327 | 3.2314348220825195;-2.062241554260254;-9.811432838439941;1.0 328 | 3.2805886268615723;-2.1789934635162354;-9.819011688232422;1.0 329 | 3.427626609802246;-2.1503520011901855;-9.835257530212402;1.0 330 | 3.495882987976074;-2.037797451019287;-9.841111183166504;1.0 331 | 3.656686782836914;-1.7989351749420166;-9.855351448059082;1.0 332 | 3.8338537216186523;-1.4576256275177002;-9.869714736938477;1.0 333 | 3.9913411140441895;-1.2013614177703857;-9.883280754089355;1.0 334 | 4.093261241912842;-0.9829919934272766;-9.891167640686035;1.0 335 | 4.2323689460754395;-0.8656607866287231;-9.905004501342773;1.0 336 | 4.303580284118652;-0.8156949281692505;-9.912260055541992;1.0 337 | 4.237342357635498;-0.891761839389801;-9.906013488769531;1.0 338 | 4.207425594329834;-1.3938777446746826;-9.911141395568848;1.0 339 | 4.133327960968018;-1.8053436279296875;-9.909701347351074;1.0 340 | 4.086979866027832;-1.9858171939849854;-9.907492637634277;1.0 341 | 3.888986587524414;-2.123642683029175;-9.887303352355957;1.0 342 | 3.759608745574951;-2.103728771209717;-9.87224292755127;1.0 343 | 3.7084364891052246;-2.0234625339508057;-9.865056037902832;1.0 344 | 3.784982204437256;-1.954411268234253;-9.872593879699707;1.0 345 | 3.9031152725219727;-1.8682351112365723;-9.88457202911377;1.0 346 | 4.10442590713501;-1.7478091716766357;-9.905433654785156;1.0 347 | 4.3250532150268555;-1.5875272750854492;-9.927816390991211;1.0 348 | 4.448519229888916;-1.482264757156372;-9.940078735351562;1.0 349 | 4.5916666984558105;-1.2919600009918213;-9.95313549041748;1.0 350 | 4.703890323638916;-1.080605387687683;-9.96231460571289;1.0 351 | -------------------------------------------------------------------------------- /documentation/ModchartVariables.txt: -------------------------------------------------------------------------------- 1 | DrunkXModifier, DrunkYModifier, DrunkZModifier 2 | 3 | TipsyXModifier, TipsyYModifier, TipsyZModifier 4 | 5 | ReverseModifier, IncomingAngleModifier, RotateModifier, StrumLineRotateModifier, (the last 3 ones works with [X Y Z, for StrumLine IncomingAngle and Rotate] [rotatePointX and rotatePointY, for Rotate and StrumLine]) 6 | 7 | BumpyModifier, 8 | 9 | XModifier, YModifier, ZModifier, ConfusionModifier, 10 | 11 | ScaleModifier, ScaleXModifier, ScaleYModifier, 12 | 13 | SkewModifier, SkewYModifier, SkewXModifier, SpeedModifier, 14 | 15 | StealthModifier, NoteStealthModifier, InvertModifier, FlipModifier, 16 | 17 | MiniModifier, ShrinkModifier, BeatXModifier, BeatYModifier, BeatZModifier, 18 | 19 | BounceXModifier, BounceYModifier, BounceZModifier, 20 | 21 | EaseCurveModifier, EaseCurveXModifier, EaseCurveYModifier, EaseCurveZModifier, EaseCurveAngleModifier, 22 | 23 | InvertSineModifier, BoostModifier, BrakeModifier, JumpModifier 24 | 25 | --some shits added by me (ed) lmao 26 | 27 | WaveXModifier, WaveYModifier, WaveZModifier, 28 | 29 | TimeStopModifier, StrumAngleModifier, JumpTargetModifier, JumpNotesModifier, 30 | 31 | LaneStealthModifier, EaseXModifier, HiddenModifier, SuddenModifier, NotesModifier, TargetsModifier 32 | 33 | --To move betwen center right and left i show you this shits 34 | MIDSCROLL: 35 | 36 | 340 for right 37 | -340 for left 38 | 0 to center again 39 | 40 | RIGHTSCROLL: 41 | 42 | -370 to center 43 | -670 to left 44 | 0 to right 45 | 46 | --FOR OPONNENT 47 | 48 | MIDSCROLL: 49 | 50 | 340 for center (0,1 strumLines) 51 | -340 for center (2,3 strumLines) 52 | 665 for right (0,1 strumLines) 53 | -665 for left (2,3 strumLines) 54 | 0 to original again 55 | 56 | RIGHTSCROLL: 57 | 58 | 370 to center 59 | 670 to left 60 | 0 to right 61 | 62 | --------------MODCHART VARS---------------- 63 | startMod(name,modClass,type,pf) --To start a modifier 64 | 65 | setMod(name, value) --set a variable for the modifier 66 | 67 | setSubMod(name, subValName,value) --A submodifier variable 68 | 69 | setModTargetLane(name, value) --Strum Specific modifier value 70 | 71 | setModPlayfield(name,value) --Extra line value 72 | 73 | addPlayfield(x,y,z) --Add a extra line 74 | 75 | removePlayfield(idx) --Remove a extra line 76 | 77 | tweenModifier(modifier,val,time,ease) --do a modifier with a tween in seconds 78 | 79 | tweenModifierSubValue(modifier,subValue,val,time,ease) --do a modifier with a subValue 80 | 81 | setModEaseFunc(name,ease) --A mod ease with a value 82 | 83 | set(beat, argsAsString) --Add a working variable in a beat 84 | 85 | ease(beat, time, easeStr, argsAsString) --Add a working variable with movement in a beat 86 | --------------APPLY A MODCHART-------------- 87 | startMod('Whatever','BoostModifier','',0) --'modName','modifiername','lines(strumsToApply, player, opponent, custom, leave [""] for all, playfield 0 = default playfield 88 | 89 | --start time, ease time, ease, modifier data (value, name) 90 | ease(beat, 2, 'expoOut', [[ 91 | 0.5, DrunkY, 92 | ]]) 93 | --Notes moves funky and cool, sustains also do curve effect 94 | 95 | --Check example for more info about this lmao -Ed 96 | --------------SOME CHANGES SHITS LMAO---------------- 97 | ModName:speed 98 | ModName:x 99 | ModName:y 100 | ModName:z 101 | ModName:rotatePointX 102 | ModName:rotatePointY 103 | ---------------LANES YOU CAN USE------------- 104 | case 'player': 105 | PLAYERONLY; 106 | 107 | case 'opponent': 108 | OPPONENTONLY; 109 | 110 | case 'lane' | 'lanespecific': 111 | LANESPECIFIC; 112 | --------------DIFERENCE BETWEN HX AND LUA CUSTOM MODIFIERS----------------- 113 | --LUA 114 | game.playfieldRenderer.modifiers.get("customModTest").math 115 | 116 | --HX 117 | mod.math -------------------------------------------------------------------------------- /examples/customPath.txt: -------------------------------------------------------------------------------- 1 | -5.32266902923584;1.5246357917785645;-8.777054786682129;1.0 2 | -5.234609603881836;1.7484805583953857;-8.783271789550781;1.0 3 | -4.900301456451416;2.3798604011535645;-8.810586929321289;1.0 4 | -4.539057731628418;2.6687521934509277;-8.846787452697754;1.0 5 | -3.8826723098754883;2.9988062381744385;-8.915874481201172;1.0 6 | -3.499480724334717;3.0214765071868896;-8.959095001220703;1.0 7 | -3.3510608673095703;2.920449733734131;-8.977700233459473;1.0 8 | -3.23814058303833;2.734546661376953;-8.9937105178833;1.0 9 | -3.2129225730895996;2.4665908813476562;-9.00113296508789;1.0 10 | -3.3027024269104004;2.1242594718933105;-8.996732711791992;1.0 11 | -3.628297805786133;1.5280909538269043;-8.969809532165527;1.0 12 | -3.9624013900756836;1.1121773719787598;-8.938857078552246;1.0 13 | -4.432987213134766;0.7346479296684265;-8.89172077178955;1.0 14 | -4.989719390869141;0.47027212381362915;-8.832858085632324;1.0 15 | -5.33845329284668;0.40233945846557617;-8.794328689575195;1.0 16 | -5.050148010253906;0.45850127935409546;-8.82618236541748;1.0 17 | -5.029303073883057;0.5452755093574524;-8.827080726623535;1.0 18 | -4.391894817352295;2.143267869949341;-8.872462272644043;1.0 19 | -4.3830060958862305;2.175076484680176;-8.872934341430664;1.0 20 | -5.2553277015686035;0.3583762049674988;-8.804534912109375;1.0 21 | -5.1723856925964355;-0.4300546944141388;-8.82736873626709;1.0 22 | -5.1723856925964355;-0.4300546944141388;-8.82736873626709;1.0 23 | -5.05217981338501;0.43756574392318726;-8.826306343078613;1.0 24 | -4.981097221374512;0.47317057847976685;-8.83379077911377;1.0 25 | -4.445980548858643;0.7297149300575256;-8.890326499938965;1.0 26 | -4.422902584075928;0.6993982195854187;-8.893467903137207;1.0 27 | -4.289186954498291;0.33815646171569824;-8.914822578430176;1.0 28 | -3.974761962890625;-0.13148707151412964;-8.95858383178711;1.0 29 | -3.7403483390808105;-0.294700026512146;-8.988033294677734;1.0 30 | -3.6869254112243652;-0.2799406349658966;-8.993861198425293;1.0 31 | -3.5333566665649414;0.07199054956436157;-9.005355834960938;1.0 32 | -3.3668928146362305;0.2654244303703308;-9.021012306213379;1.0 33 | -3.148952007293701;0.4384259581565857;-9.042874336242676;1.0 34 | -2.9370603561401367;0.688578188419342;-9.062736511230469;1.0 35 | -2.8379602432250977;0.8949999213218689;-9.070507049560547;1.0 36 | -2.75022554397583;1.138371467590332;-9.07635498046875;1.0 37 | -2.7764339447021484;1.2986266613006592;-9.070649147033691;1.0 38 | -2.8319082260131836;1.3400392532348633;-9.06363296508789;1.0 39 | -2.9218978881835938;1.3355627059936523;-9.053467750549316;1.0 40 | -3.004868507385254;1.2715349197387695;-9.045114517211914;1.0 41 | -3.1828699111938477;1.093257188796997;-9.027887344360352;1.0 42 | -3.3691816329956055;0.7088391184806824;-9.013216972351074;1.0 43 | -3.422018527984619;0.3504212498664856;-9.01329517364502;1.0 44 | -3.3937621116638184;0.13399535417556763;-9.020188331604004;1.0 45 | -3.328347682952881;0.08581626415252686;-9.028450965881348;1.0 46 | -3.1835060119628906;0.07486605644226074;-9.045119285583496;1.0 47 | -2.993687152862549;0.16841357946395874;-9.065130233764648;1.0 48 | -2.8458547592163086;0.32340675592422485;-9.079319953918457;1.0 49 | -2.653045654296875;0.5828946232795715;-9.09685230255127;1.0 50 | -2.5239481925964355;0.7908092141151428;-9.108009338378906;1.0 51 | -2.2325916290283203;1.3958618640899658;-9.130884170532227;1.0 52 | -2.1974499225616455;1.4157617092132568;-9.13454532623291;1.0 53 | -2.442473888397217;0.7718679308891296;-9.11760425567627;1.0 54 | -2.5173850059509277;0.256844162940979;-9.117829322814941;1.0 55 | -2.412655830383301;0.2293778657913208;-9.13021469116211;1.0 56 | -2.3232898712158203;0.25984084606170654;-9.139866828918457;1.0 57 | -2.179804801940918;0.39222943782806396;-9.153944969177246;1.0 58 | -2.002357244491577;0.709648072719574;-9.168745040893555;1.0 59 | -1.702239751815796;1.4730639457702637;-9.189926147460938;1.0 60 | -1.635328769683838;1.507857322692871;-9.196949005126953;1.0 61 | -1.62910795211792;1.452498435974121;-9.198596954345703;1.0 62 | -1.8891115188598633;0.7055982947349548;-9.181700706481934;1.0 63 | -1.865096092224121;0.3752055764198303;-9.190047264099121;1.0 64 | -1.7820234298706055;0.3478724956512451;-9.199965476989746;1.0 65 | -1.7135133743286133;0.37427324056625366;-9.207313537597656;1.0 66 | -1.570199966430664;0.48486971855163574;-9.221742630004883;1.0 67 | -1.4240710735321045;0.7396168112754822;-9.23404312133789;1.0 68 | -1.1689012050628662;1.1940202713012695;-9.255358695983887;1.0 69 | -1.050473690032959;1.5260505676269531;-9.26319408416748;1.0 70 | -1.0765066146850586;1.7080979347229004;-9.2571382522583;1.0 71 | -1.1446678638458252;1.7252795696258545;-9.249089241027832;1.0 72 | -1.2324354648590088;1.6864259243011475;-9.239762306213379;1.0 73 | -1.2838106155395508;1.615495204925537;-9.235121726989746;1.0 74 | -1.3679986000061035;1.398923397064209;-9.229220390319824;1.0 75 | -1.3923673629760742;1.163543939590454;-9.230446815490723;1.0 76 | -1.3569157123565674;0.9093559384346008;-9.238801002502441;1.0 77 | -1.279334306716919;0.8200300335884094;-9.249147415161133;1.0 78 | -1.154201865196228;0.8444053530693054;-9.262971878051758;1.0 79 | -1.0420336723327637;0.9141233563423157;-9.274552345275879;1.0 80 | -0.8950022459030151;1.0733113288879395;-9.288578987121582;1.0 81 | -0.7072662115097046;1.4275479316711426;-9.303923606872559;1.0 82 | -0.5383337736129761;1.7215492725372314;-9.31815242767334;1.0 83 | -0.39519548416137695;1.8103539943695068;-9.332931518554688;1.0 84 | -0.33005672693252563;1.8317453861236572;-9.339981079101562;1.0 85 | -0.25195416808128357;1.8077962398529053;-9.349276542663574;1.0 86 | -0.21208593249320984;1.6893668174743652;-9.35582447052002;1.0 87 | -0.2257145494222641;1.443023920059204;-9.35845947265625;1.0 88 | -0.3607226014137268;1.0163805484771729;-9.350346565246582;1.0 89 | -0.4754299521446228;0.7329409718513489;-9.342108726501465;1.0 90 | -0.6449167132377625;0.578081488609314;-9.32545280456543;1.0 91 | -0.7376539707183838;0.5426102876663208;-9.315503120422363;1.0 92 | -0.8489514589309692;0.5818514823913574;-9.302170753479004;1.0 93 | -0.878355860710144;0.758889377117157;-9.295815467834473;1.0 94 | -0.8644500970840454;0.9356613755226135;-9.294394493103027;1.0 95 | -0.8468254804611206;1.161024570465088;-9.292571067810059;1.0 96 | -0.8468254804611206;1.161024570465088;-9.292571067810059;1.0 97 | -0.7261083126068115;1.0496416091918945;-9.308199882507324;1.0 98 | -0.7112677097320557;0.9263364672660828;-9.31198501586914;1.0 99 | -0.633686363697052;0.8370113968849182;-9.322330474853516;1.0 100 | -0.5215896964073181;0.7935743927955627;-9.33582592010498;1.0 101 | -0.31783077120780945;0.8593752980232239;-9.357893943786621;1.0 102 | -0.10308815538883209;1.0491602420806885;-9.379106521606445;1.0 103 | 0.11527067422866821;1.3789005279541016;-9.398353576660156;1.0 104 | 0.3083258867263794;1.7733361721038818;-9.413619995117188;1.0 105 | 0.3854227662086487;1.936307430267334;-9.419624328613281;1.0 106 | 0.3845199942588806;2.0318660736083984;-9.41789722442627;1.0 107 | 0.40919923782348633;1.9931573867797852;-9.42136287689209;1.0 108 | 0.45660877227783203;1.8805487155914307;-9.428672790527344;1.0 109 | 0.5648127794265747;1.7667279243469238;-9.44291877746582;1.0 110 | 0.56011962890625;1.700540542602539;-9.443509101867676;1.0 111 | 0.3671293258666992;0.8970697522163391;-9.435200691223145;1.0 112 | 0.4065456986427307;0.8264201283454895;-9.440886497497559;1.0 113 | 0.5124216079711914;0.8383412957191467;-9.45273208618164;1.0 114 | 0.5950434803962708;0.858787477016449;-9.461787223815918;1.0 115 | 0.9431252479553223;1.3704533576965332;-9.492703437805176;1.0 116 | 1.0598821640014648;1.5977203845977783;-9.502127647399902;1.0 117 | 1.4972403049468994;2.9213738441467285;-9.529407501220703;1.0 118 | 1.5103371143341064;2.9343698024749756;-9.530677795410156;1.0 119 | 0.9662704467773438;0.9311016201972961;-9.502802848815918;1.0 120 | 0.9534022808074951;0.9259839653968811;-9.501425743103027;1.0 121 | 0.9314626455307007;0.93215411901474;-9.498824119567871;1.0 122 | 0.9314626455307007;0.93215411901474;-9.498824119567871;1.0 123 | 1.1842787265777588;1.6759123802185059;-9.5149564743042;1.0 124 | 1.4127733707427979;2.00240421295166;-9.535408973693848;1.0 125 | 1.609025001525879;2.171180486679077;-9.554875373840332;1.0 126 | 1.7691943645477295;2.2023813724517822;-9.572571754455566;1.0 127 | 1.8297145366668701;2.020961046218872;-9.582541465759277;1.0 128 | 1.7647697925567627;1.8986501693725586;-9.577229499816895;1.0 129 | 1.5185906887054443;1.6104891300201416;-9.554110527038574;1.0 130 | 1.3787741661071777;1.4997029304504395;-9.540082931518555;1.0 131 | 1.3916633129119873;1.4865474700927734;-9.541773796081543;1.0 132 | 1.4837167263031006;1.2486069202423096;-9.556291580200195;1.0 133 | 1.6066365242004395;1.1211166381835938;-9.5724458694458;1.0 134 | 1.7032382488250732;1.0772719383239746;-9.584182739257812;1.0 135 | 1.8228232860565186;1.1580073833465576;-9.596420288085938;1.0 136 | 2.0222456455230713;1.47361421585083;-9.613750457763672;1.0 137 | 2.0773041248321533;1.4843401908874512;-9.619833946228027;1.0 138 | 2.189255475997925;1.3599352836608887;-9.634688377380371;1.0 139 | 2.350801944732666;1.438401460647583;-9.651739120483398;1.0 140 | 2.6131649017333984;1.7506022453308105;-9.676289558410645;1.0 141 | 2.7996997833251953;2.079364538192749;-9.691929817199707;1.0 142 | 2.8237266540527344;2.334696054458618;-9.690325736999512;1.0 143 | 2.788565158843994;2.4375061988830566;-9.684577941894531;1.0 144 | 2.7406396865844727;2.443836212158203;-9.67901611328125;1.0 145 | 2.6755714416503906;2.4311606884002686;-9.67182731628418;1.0 146 | 2.536923885345459;2.341489553451538;-9.657572746276855;1.0 147 | 2.29437255859375;2.007037401199341;-9.63565444946289;1.0 148 | 2.171407461166382;1.7533199787139893;-9.625971794128418;1.0 149 | 2.1400363445281982;1.4547853469848633;-9.627476692199707;1.0 150 | 2.1939661502838135;1.1989738941192627;-9.637959480285645;1.0 151 | 2.353717803955078;1.1778738498687744;-9.65649700164795;1.0 152 | 2.6263413429260254;1.2727558612823486;-9.685907363891602;1.0 153 | 2.9553589820861816;1.6710479259490967;-9.716582298278809;1.0 154 | 3.000405788421631;1.679823875427246;-9.721559524536133;1.0 155 | 2.9933981895446777;1.5531325340270996;-9.72291374206543;1.0 156 | 3.02059268951416;1.3286681175231934;-9.729823112487793;1.0 157 | 3.1324172019958496;1.3138971328735352;-9.742798805236816;1.0 158 | 3.3282508850097656;1.4303734302520752;-9.763105392456055;1.0 159 | 3.501059055328369;1.6676909923553467;-9.778738975524902;1.0 160 | 3.5897412300109863;1.8833961486816406;-9.785164833068848;1.0 161 | 3.694146156311035;2.3162624835968018;-9.789690017700195;1.0 162 | 3.6840972900390625;2.5597355365753174;-9.784409523010254;1.0 163 | 3.577275276184082;2.575479507446289;-9.77198600769043;1.0 164 | 3.3922033309936523;2.4297685623168945;-9.753402709960938;1.0 165 | 3.193948268890381;2.1352765560150146;-9.735844612121582;1.0 166 | 3.0453295707702637;1.7982337474822998;-9.724658966064453;1.0 167 | 3.0030760765075684;1.6385674476623535;-9.722563743591309;1.0 168 | 3.007911205291748;1.367973804473877;-9.72771167755127;1.0 169 | 3.100468158721924;1.3181183338165283;-9.739092826843262;1.0 170 | 3.1865158081054688;1.3296592235565186;-9.748687744140625;1.0 171 | 3.3563642501831055;1.4462940692901611;-9.766033172607422;1.0 172 | 3.5131988525390625;1.685720682144165;-9.779813766479492;1.0 173 | 4.116020202636719;3.453263759613037;-9.818379402160645;1.0 174 | 3.652557849884033;1.9896275997161865;-9.790508270263672;1.0 175 | 3.6366610527038574;1.5008947849273682;-9.797003746032715;1.0 176 | 3.6822500228881836;1.4523355960845947;-9.803016662597656;1.0 177 | 3.757538318634033;1.493109941482544;-9.810890197753906;1.0 178 | 3.854224681854248;1.5850520133972168;-9.820331573486328;1.0 179 | 4.037461757659912;1.8766188621520996;-9.83622932434082;1.0 180 | 4.1816182136535645;2.1553494930267334;-9.847896575927734;1.0 181 | 4.156808376312256;1.4315543174743652;-9.857372283935547;1.0 182 | 3.0348057746887207;0.9790293574333191;-9.737380981445312;1.0 183 | -1.1645309925079346;0.2741355299949646;-9.27148723602295;1.0 184 | -3.966914653778076;-0.554682731628418;-8.966667175292969;1.0 185 | -5.333769798278809;-2.132967233657837;-8.837940216064453;1.0 186 | -3.6712446212768555;-2.838393211364746;-9.039117813110352;1.0 187 | -2.976569652557373;-2.576744318008423;-9.113723754882812;1.0 188 | -2.170823097229004;-1.815215826034546;-9.192476272583008;1.0 189 | -1.8277311325073242;-1.0265085697174072;-9.218117713928223;1.0 190 | -1.781813144683838;-0.4671350121498108;-9.213837623596191;1.0 191 | -1.951695442199707;-0.3287825584411621;-9.192154884338379;1.0 192 | -2.1326065063476562;-0.2737894058227539;-9.170633316040039;1.0 193 | -2.383432388305664;-0.32264968752861023;-9.14292049407959;1.0 194 | -3.0035791397094727;-0.551734209060669;-9.076240539550781;1.0 195 | -3.3513498306274414;-0.8450651168823242;-9.04164981842041;1.0 196 | -3.7364578247070312;-1.2719969749450684;-9.005081176757812;1.0 197 | -3.8871021270751953;-1.7525136470794678;-8.996102333068848;1.0 198 | -3.1969618797302246;-0.7608497142791748;-9.057788848876953;1.0 199 | -2.5893545150756836;-0.37178659439086914;-9.120321273803711;1.0 200 | -1.9719481468200684;-0.269563764333725;-9.188843727111816;1.0 201 | -1.7769865989685059;-0.7278742790222168;-9.218816757202148;1.0 202 | -1.9574003219604492;-1.4758691787719727;-9.210996627807617;1.0 203 | -2.7033262252807617;-2.315976619720459;-9.140387535095215;1.0 204 | -3.2054858207702637;-2.6935245990753174;-9.089658737182617;1.0 205 | -3.5897250175476074;-2.7954421043395996;-9.047664642333984;1.0 206 | -2.880189895629883;-1.1051981449127197;-9.099687576293945;1.0 207 | -3.6013293266296387;-2.7345387935638428;-9.045309066772461;1.0 208 | -3.725451946258545;-3.3542640209198;-9.041714668273926;1.0 209 | -3.719327449798584;-3.6688919067382812;-9.047758102416992;1.0 210 | -3.622664451599121;-2.810882806777954;-9.04417896270752;1.0 211 | -3.3262133598327637;-2.6719236373901367;-9.075553894042969;1.0 212 | -3.0164999961853027;-2.602569103240967;-9.109619140625;1.0 213 | -2.9075231552124023;-2.7979037761688232;-9.125337600708008;1.0 214 | -2.773679733276367;-3.123744010925293;-9.146106719970703;1.0 215 | -2.537705421447754;-3.420666456222534;-9.17800521850586;1.0 216 | -2.2643957138061523;-3.583988904953003;-9.211881637573242;1.0 217 | -1.9039382934570312;-3.2160000801086426;-9.246648788452148;1.0 218 | -1.9124400615692139;-2.9830470085144043;-9.24172306060791;1.0 219 | -1.8530457019805908;-2.6827266216278076;-9.243378639221191;1.0 220 | -1.7726783752441406;-2.3512516021728516;-9.246891975402832;1.0 221 | -1.645749568939209;-2.028752565383911;-9.255855560302734;1.0 222 | -1.9071063995361328;-2.963960647583008;-9.242005348205566;1.0 223 | -1.8656647205352783;-3.18147349357605;-9.25041675567627;1.0 224 | -1.7651901245117188;-3.1438541412353516;-9.261210441589355;1.0 225 | -1.6590218544006348;-3.0419628620147705;-9.271562576293945;1.0 226 | -1.454249382019043;-2.7042999267578125;-9.2891263961792;1.0 227 | -1.3160767555236816;-2.487891912460327;-9.301172256469727;1.0 228 | -1.0872290134429932;-1.9470248222351074;-9.318024635314941;1.0 229 | -1.211350440979004;-2.56674861907959;-9.314431190490723;1.0 230 | -1.2824950218200684;-3.0408036708831787;-9.314390182495117;1.0 231 | -1.3785035610198975;-3.384348154067993;-9.309301376342773;1.0 232 | -1.4605293273925781;-3.707122325897217;-9.305452346801758;1.0 233 | -1.5788099765777588;-4.027937889099121;-9.297443389892578;1.0 234 | -1.7423546314239502;-4.3936614990234375;-9.28504753112793;1.0 235 | -1.9662961959838867;-4.5365400314331055;-9.261991500854492;1.0 236 | -2.133584976196289;-4.505965709686279;-9.242433547973633;1.0 237 | -2.220651149749756;-4.378552436828613;-9.23036003112793;1.0 238 | -2.226200580596924;-4.208187580108643;-9.226835250854492;1.0 239 | -2.2354254722595215;-4.065610408782959;-9.22336196899414;1.0 240 | -2.194772243499756;-3.9494102001190186;-9.226014137268066;1.0 241 | -2.1145501136779785;-3.8525712490081787;-9.233498573303223;1.0 242 | -1.9837307929992676;-3.6917381286621094;-9.245652198791504;1.0 243 | -1.9055280685424805;-3.6313867568969727;-9.253525733947754;1.0 244 | -1.7544536590576172;-3.529770612716675;-9.268990516662598;1.0 245 | -1.5873806476593018;-3.370896816253662;-9.285304069519043;1.0 246 | -1.3930609226226807;-3.2608556747436523;-9.305546760559082;1.0 247 | -1.2066700458526611;-3.062126636505127;-9.323381423950195;1.0 248 | -1.0425496101379395;-2.8406641483306885;-9.338294982910156;1.0 249 | -0.8627893924713135;-2.6071317195892334;-9.354782104492188;1.0 250 | -0.7189228534698486;-2.326450824737549;-9.366385459899902;1.0 251 | -0.17422866821289062;-0.948042094707489;-9.404947280883789;1.0 252 | -0.45698994398117065;-1.5355055332183838;-9.382752418518066;1.0 253 | -0.7181216478347778;-1.5773496627807617;-9.353748321533203;1.0 254 | 0.36136531829833984;-1.3580451011657715;-9.472862243652344;1.0 255 | -0.43104231357574463;-1.5304510593414307;-9.385618209838867;1.0 256 | -0.5728224515914917;-2.198732614517212;-9.380840301513672;1.0 257 | -0.62645423412323;-2.858865976333618;-9.385953903198242;1.0 258 | -0.5513516664505005;-2.970564365386963;-9.396397590637207;1.0 259 | -0.4155588150024414;-2.8358314037323;-9.409561157226562;1.0 260 | -0.33000385761260986;-2.719906806945801;-9.417326927185059;1.0 261 | -0.2703949511051178;-2.6090385913848877;-9.422226905822754;1.0 262 | -0.20912954211235046;-2.506868600845337;-9.427464485168457;1.0 263 | -0.043351560831069946;-2.2941083908081055;-9.442712783813477;1.0 264 | 0.40987735986709595;-0.9064469933509827;-9.470710754394531;1.0 265 | -0.18938341736793518;-2.8459131717681885;-9.435471534729004;1.0 266 | 0.024905383586883545;-2.1815545558929443;-9.448569297790527;1.0 267 | 0.17468202114105225;-2.026050329208374;-9.462968826293945;1.0 268 | 0.31451159715652466;-1.818342924118042;-9.47535228729248;1.0 269 | 0.4882160425186157;-1.6942715644836426;-9.493011474609375;1.0 270 | 0.6216304898262024;-1.6412124633789062;-9.507291793823242;1.0 271 | 0.677054226398468;-1.8379542827606201;-9.516942024230957;1.0 272 | 0.5784513354301453;-2.0737242698669434;-9.509726524353027;1.0 273 | 0.488498330116272;-2.307809352874756;-9.503467559814453;1.0 274 | 0.40387946367263794;-2.522808313369751;-9.497492790222168;1.0 275 | 0.40575110912323;-2.7209596633911133;-9.50107192993164;1.0 276 | 0.5215057730674744;-2.7164576053619385;-9.514167785644531;1.0 277 | 0.614052414894104;-2.590148687362671;-9.522553443908691;1.0 278 | 0.7378815412521362;-2.439699172973633;-9.534089088439941;1.0 279 | 0.8756937980651855;-2.2684788703918457;-9.546862602233887;1.0 280 | 0.9998824596405029;-2.0728416442871094;-9.557670593261719;1.0 281 | 1.0837806463241577;-1.9482178688049316;-9.565098762512207;1.0 282 | 1.1411552429199219;-1.684385061264038;-9.567145347595215;1.0 283 | 1.2467503547668457;-1.4382297992706299;-9.574979782104492;1.0 284 | 1.0550932884216309;-2.080134153366089;-9.564077377319336;1.0 285 | 1.0060062408447266;-2.387468099594116;-9.563713073730469;1.0 286 | 0.9938951730728149;-2.6063897609710693;-9.566055297851562;1.0 287 | 1.101000189781189;-2.603573799133301;-9.578195571899414;1.0 288 | 1.236793041229248;-2.468839645385742;-9.591358184814453;1.0 289 | 1.3795783519744873;-2.323720693588257;-9.605141639709473;1.0 290 | 1.4864695072174072;-2.131453514099121;-9.614038467407227;1.0 291 | 1.5950191020965576;-1.947887659072876;-9.623270988464355;1.0 292 | 1.696214199066162;-1.819892406463623;-9.632612228393555;1.0 293 | 1.7368667125701904;-1.7036924362182617;-9.63526439666748;1.0 294 | 1.8555073738098145;-1.3376917839050293;-9.642546653747559;1.0 295 | 1.6737968921661377;-2.0317983627319336;-9.633662223815918;1.0 296 | 1.5828287601470947;-2.8255324363708496;-9.636796951293945;1.0 297 | 1.459789514541626;-3.309694528579712;-9.631022453308105;1.0 298 | 1.3135437965393066;-3.6720521450042725;-9.620536804199219;1.0 299 | 1.062932014465332;-3.9103617668151855;-9.596068382263184;1.0 300 | 0.9138780832290649;-3.9754912853240967;-9.580212593078613;1.0 301 | 0.8516762852668762;-3.9785852432250977;-9.573185920715332;1.0 302 | 0.7605712413787842;-3.924142360687256;-9.56189250946045;1.0 303 | 0.6878494024276733;-3.730771064758301;-9.550333023071289;1.0 304 | 0.6913102269172668;-3.513535737991333;-9.547036170959473;1.0 305 | 0.8038968443870544;-3.2569942474365234;-9.555487632751465;1.0 306 | 0.977962851524353;-3.087735414505005;-9.572420120239258;1.0 307 | 1.1557036638259888;-2.890690565109253;-9.589298248291016;1.0 308 | 1.7410385608673096;-2.4788947105407715;-9.648910522460938;1.0 309 | 1.9437923431396484;-2.1777195930480957;-9.66686725616455;1.0 310 | 2.183522939682007;-1.7881312370300293;-9.68752670288086;1.0 311 | 2.4156839847564697;-1.2646641731262207;-9.705050468444824;1.0 312 | 2.149569272994995;-2.3632209300994873;-9.693435668945312;1.0 313 | 2.3601796627044678;-1.726646900177002;-9.706585884094238;1.0 314 | 2.5555830001831055;-1.4810454845428467;-9.724648475646973;1.0 315 | 2.712709903717041;-1.2699685096740723;-9.738943099975586;1.0 316 | 2.901695728302002;-1.1790134906768799;-9.758903503417969;1.0 317 | 2.9723992347717285;-1.4088730812072754;-9.770853996276855;1.0 318 | 2.8927536010742188;-1.6499738693237305;-9.765888214111328;1.0 319 | 2.7834835052490234;-1.9239158630371094;-9.75810718536377;1.0 320 | 2.7018179893493652;-2.201502561569214;-9.753530502319336;1.0 321 | 3.004255771636963;-1.5289955139160156;-9.776521682739258;1.0 322 | 3.1856751441955566;-1.304163932800293;-9.79334545135498;1.0 323 | 3.3597402572631836;-1.1349048614501953;-9.810276985168457;1.0 324 | 3.4445743560791016;-1.1093559265136719;-9.819497108459473;1.0 325 | 3.4313793182373047;-1.4638381004333496;-9.824019432067871;1.0 326 | 3.3151187896728516;-1.748166561126709;-9.815620422363281;1.0 327 | 3.2314348220825195;-2.062241554260254;-9.811432838439941;1.0 328 | 3.2805886268615723;-2.1789934635162354;-9.819011688232422;1.0 329 | 3.427626609802246;-2.1503520011901855;-9.835257530212402;1.0 330 | 3.495882987976074;-2.037797451019287;-9.841111183166504;1.0 331 | 3.656686782836914;-1.7989351749420166;-9.855351448059082;1.0 332 | 3.8338537216186523;-1.4576256275177002;-9.869714736938477;1.0 333 | 3.9913411140441895;-1.2013614177703857;-9.883280754089355;1.0 334 | 4.093261241912842;-0.9829919934272766;-9.891167640686035;1.0 335 | 4.2323689460754395;-0.8656607866287231;-9.905004501342773;1.0 336 | 4.303580284118652;-0.8156949281692505;-9.912260055541992;1.0 337 | 4.237342357635498;-0.891761839389801;-9.906013488769531;1.0 338 | 4.207425594329834;-1.3938777446746826;-9.911141395568848;1.0 339 | 4.133327960968018;-1.8053436279296875;-9.909701347351074;1.0 340 | 4.086979866027832;-1.9858171939849854;-9.907492637634277;1.0 341 | 3.888986587524414;-2.123642683029175;-9.887303352355957;1.0 342 | 3.759608745574951;-2.103728771209717;-9.87224292755127;1.0 343 | 3.7084364891052246;-2.0234625339508057;-9.865056037902832;1.0 344 | 3.784982204437256;-1.954411268234253;-9.872593879699707;1.0 345 | 3.9031152725219727;-1.8682351112365723;-9.88457202911377;1.0 346 | 4.10442590713501;-1.7478091716766357;-9.905433654785156;1.0 347 | 4.3250532150268555;-1.5875272750854492;-9.927816390991211;1.0 348 | 4.448519229888916;-1.482264757156372;-9.940078735351562;1.0 349 | 4.5916666984558105;-1.2919600009918213;-9.95313549041748;1.0 350 | 4.703890323638916;-1.080605387687683;-9.96231460571289;1.0 351 | -------------------------------------------------------------------------------- /examples/leather/modchart.lua: -------------------------------------------------------------------------------- 1 | function createPost() 2 | 3 | --name, modifier class, type (defaults to all), playfield number (-1 = all) 4 | --other types: 5 | -- player 6 | -- opponent 7 | -- lane (needs to have its target lane set) 8 | startMod('reverse', 'ReverseModifier', '', -1) 9 | 10 | for i = 0,3 do 11 | local beat = i*8 --2 sections, loop 4x to last for 8 sections 12 | 13 | --start time, ease time, ease, modifier data (value, name) 14 | ease(beat, 2, 'expoOut', [[ 15 | 1, reverse, 16 | 360, confusion 17 | ]]) 18 | --reverse flips the scroll 19 | --confusion spins the notes 20 | 21 | --one section after 22 | ease((beat)+4, 2, 'expoOut', [[ 23 | 0, reverse, 24 | 0, confusion 25 | ]]) 26 | end 27 | 28 | 29 | startMod('drunkPF0', 'DrunkXModifier', '', 0) --playfield 0 = default playfield 30 | addPlayfield(0,0,0) 31 | startMod('zPF1', 'ZModifier', '', 1) 32 | startMod('tipsyPF1', 'TipsyYModifier', '', 1) 33 | 34 | ease(32, 4, 'cubeInOut', [[ 35 | -300, zPF1, 36 | 1, tipsyPF1, 37 | 2, tipsyPF1:speed 38 | ]]) --puting ":" makes it ease a submod, in this case its changing the speed 39 | 40 | 41 | for i = 4,7 do 42 | local beat = i*8 43 | 44 | --start time, ease time, ease, modifier data (value, name) 45 | ease(beat, 1, 'expoOut', [[ 46 | 1.5, drunkPF0, 47 | 4, drunkPF0:speed 48 | ]]) 49 | 50 | --one section after 51 | ease((beat)+4, 1, 'expoOut', [[ 52 | -1.5, drunkPF0 53 | ]]) 54 | end 55 | 56 | 57 | startMod('customModTest', 'Modifier', '', -1) 58 | 59 | ease(64, 1, 'cubeInOut', [[ 60 | 0, zPF1, 61 | 0, tipsyPF1, 62 | 0, drunkPF0, 63 | 1, customModTest 64 | ]]) 65 | end 66 | -------------------------------------------------------------------------------- /examples/leather/modifiers.hx: -------------------------------------------------------------------------------- 1 | 2 | //move notes and strums back a little 3 | PlayState.instance.playfieldRenderer.modifiers.get("customModTest").noteMath = function(noteData, lane, curPos, pf){ 4 | noteData.z += PlayState.instance.playfieldRenderer.modifiers.get("customModTest").currentValue * -500; 5 | } 6 | PlayState.instance.playfieldRenderer.modifiers.get("customModTest").strumMath = function(noteData, lane, pf){ 7 | noteData.z += PlayState.instance.playfieldRenderer.modifiers.get("customModTest").currentValue * -500; 8 | } 9 | //do crazy incoming angles 10 | PlayState.instance.playfieldRenderer.modifiers.get("customModTest").incomingAngleMath = function(lane, curPos, pf){ 11 | var xAngle = 45*lane + curPos/30; 12 | var yAngle = 90*lane + curPos/7; 13 | var value = PlayState.instance.playfieldRenderer.modifiers.get("customModTest").currentValue; 14 | return [xAngle*value, yAngle*value]; 15 | } -------------------------------------------------------------------------------- /examples/modchart editor testing/fusion-reactor/customMods/IncomingAngleCurve.hx: -------------------------------------------------------------------------------- 1 | function initMod(mod) 2 | { 3 | mod.incomingAngleMath = function(lane, curPos, pf) 4 | { 5 | return [0, mod.currentValue*(curPos*0.015)]; 6 | }; 7 | } -------------------------------------------------------------------------------- /examples/modchart editor testing/fusion-reactor/customMods/IncomingAngleSmooth.hx: -------------------------------------------------------------------------------- 1 | function initMod(mod) 2 | { 3 | mod.incomingAngleMath = function(lane, curPos, pf) 4 | { 5 | return [0, mod.currentValue+(curPos*0.015)]; 6 | }; 7 | } -------------------------------------------------------------------------------- /examples/modchart editor testing/fusion-reactor/customMods/InvertIncomingAngle.hx: -------------------------------------------------------------------------------- 1 | function initMod(mod) 2 | { 3 | mod.incomingAngleMath = function(lane, curPos, pf) 4 | { 5 | if (lane % 2 == 0) 6 | { 7 | return [0, mod.currentValue+(curPos*0.015)]; 8 | } 9 | return [0, -mod.currentValue-(curPos*0.015)]; 10 | }; 11 | } -------------------------------------------------------------------------------- /examples/modchart editor testing/fusion-reactor/customMods/MoveYWaveShit.hx: -------------------------------------------------------------------------------- 1 | function initMod(mod) 2 | { 3 | mod.noteMath = function(noteData, lane, curPos, pf) 4 | { 5 | noteData.y += 260*Math.sin(((Conductor.songPosition+curPos)*0.0008)+(lane/4)); 6 | }; 7 | mod.strumMath = function(noteData, lane, pf) 8 | { 9 | noteData.y += 260*Math.sin((Conductor.songPosition*0.0008)+(lane/4)); 10 | }; 11 | } -------------------------------------------------------------------------------- /examples/psych/script.lua: -------------------------------------------------------------------------------- 1 | function onCreatePost() 2 | 3 | --name, modifier class, type (defaults to all), playfield number (-1 = all) 4 | --other types: 5 | -- player 6 | -- opponent 7 | -- lane (needs to have its target lane set) 8 | startMod('reverse', 'ReverseModifier', '', -1) 9 | 10 | for i = 0,3 do 11 | local beat = i*8 --2 sections, loop 4x to last for 8 sections 12 | 13 | --start time, ease time, ease, modifier data (value, name) 14 | ease(beat, 2, 'expoOut', [[ 15 | 1, reverse, 16 | 360, confusion 17 | ]]) 18 | --reverse flips the scroll 19 | --confusion spins the notes 20 | 21 | --one section after 22 | ease((beat)+4, 2, 'expoOut', [[ 23 | 0, reverse, 24 | 0, confusion 25 | ]]) 26 | end 27 | 28 | 29 | startMod('drunkPF0', 'DrunkXModifier', '', 0) --playfield 0 = default playfield 30 | addPlayfield(0,0,0) 31 | startMod('zPF1', 'ZModifier', '', 1) 32 | startMod('tipsyPF1', 'TipsyYModifier', '', 1) 33 | 34 | ease(32, 4, 'cubeInOut', [[ 35 | -300, zPF1, 36 | 1, tipsyPF1, 37 | 2, tipsyPF1:speed 38 | ]]) --puting ":" makes it ease a submod, in this case its changing the speed 39 | 40 | 41 | for i = 4,7 do 42 | local beat = i*8 43 | 44 | --start time, ease time, ease, modifier data (value, name) 45 | ease(beat, 1, 'expoOut', [[ 46 | 1.5, drunkPF0, 47 | 4, drunkPF0:speed 48 | ]]) 49 | 50 | --one section after 51 | ease((beat)+4, 1, 'expoOut', [[ 52 | -1.5, drunkPF0 53 | ]]) 54 | end 55 | 56 | 57 | startMod('customModTest', 'Modifier', '', -1) 58 | 59 | --you might get an error if you have luaDebugMode enabled, just ignore them lol it should still work 60 | runHaxeCode([[ 61 | 62 | //move notes and strums back a little 63 | game.playfieldRenderer.modifiers.get("customModTest").noteMath = function(noteData, lane, curPos, pf) 64 | { 65 | noteData.z += game.playfieldRenderer.modifiers.get("customModTest").currentValue * -500; 66 | } 67 | game.playfieldRenderer.modifiers.get("customModTest").strumMath = function(noteData, lane, pf) 68 | { 69 | noteData.z += game.playfieldRenderer.modifiers.get("customModTest").currentValue * -500; 70 | } 71 | 72 | //do crazy incoming angles 73 | game.playfieldRenderer.modifiers.get("customModTest").incomingAngleMath = function(lane, curPos, pf) 74 | { 75 | var xAngle = 45*lane + curPos/30; 76 | var yAngle = 90*lane + curPos/7; 77 | var value = game.playfieldRenderer.modifiers.get("customModTest").currentValue; 78 | return [xAngle*value, yAngle*value]; 79 | } 80 | ]]) 81 | 82 | ease(64, 1, 'cubeInOut', [[ 83 | 0, zPF1, 84 | 0, tipsyPF1, 85 | 0, drunkPF0, 86 | 1, customModTest 87 | ]]) 88 | end 89 | -------------------------------------------------------------------------------- /examples/readme.txt: -------------------------------------------------------------------------------- 1 | if you want a customPath name it "path" and put it inside customMods folder (inside a song) so it will load the path 2 | 3 | don't worry it won't crash if the path is not found but it will if path its wrong, check customPath for a better example 4 | 5 | -Edwhak -------------------------------------------------------------------------------- /haxelib.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "fnf-modcharting-tools", 3 | "url" : "https://github.com/EdwhakKB/FNF-Modcharting-Tools", 4 | "license": "Apache", 5 | "tags": ["fnf"], 6 | "description": "A modchart framework for Friday Night Funkin.", 7 | "version": "1.0.1", 8 | "classPath": "source/", 9 | "releasenote": "", 10 | "contributors": ["TheZoroForce240","UncertainProd","EdwhakKB","Vortex","Glowsoony"], 11 | "dependencies": { 12 | } 13 | } -------------------------------------------------------------------------------- /include.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /readme/custommods.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EdwhakKB/FNF-Modcharting-Tools/47a411c67e7deaa39c4e29d8640c8b2f4e36ea7d/readme/custommods.gif -------------------------------------------------------------------------------- /readme/modifiers.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EdwhakKB/FNF-Modcharting-Tools/47a411c67e7deaa39c4e29d8640c8b2f4e36ea7d/readme/modifiers.gif -------------------------------------------------------------------------------- /readme/sustains.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EdwhakKB/FNF-Modcharting-Tools/47a411c67e7deaa39c4e29d8640c8b2f4e36ea7d/readme/sustains.gif -------------------------------------------------------------------------------- /source/flixel/addons/effects/FlxSkewedSprite.hx: -------------------------------------------------------------------------------- 1 | package flixel.addons.effects; 2 | 3 | import openfl.geom.Matrix; 4 | import flixel.FlxCamera; 5 | import flixel.FlxG; 6 | import flixel.FlxSprite; 7 | import flixel.graphics.frames.FlxFrame.FlxFrameAngle; 8 | import flixel.math.FlxAngle; 9 | import flixel.math.FlxPoint; 10 | import flixel.util.FlxDestroyUtil; 11 | 12 | /** 13 | * @author Zaphod 14 | */ 15 | class FlxSkewedSprite extends FlxSprite 16 | { 17 | 18 | public var skew(default, null):FlxPoint = FlxPoint.get(); 19 | 20 | public var skewOffset:Bool = false; 21 | public var flipSkew:Bool = false; 22 | 23 | /** 24 | * Tranformation matrix for this sprite. 25 | * Used only when matrixExposed is set to true 26 | */ 27 | public var transformMatrix(default, null):Matrix = new Matrix(); 28 | 29 | /** 30 | * Bool flag showing whether transformMatrix is used for rendering or not. 31 | * False by default, which means that transformMatrix isn't used for rendering 32 | */ 33 | public var matrixExposed:Bool = false; 34 | 35 | /** 36 | * Internal helper matrix object. Used for rendering calculations when matrixExposed is set to false 37 | */ 38 | var _skewMatrix:Matrix = new Matrix(); 39 | 40 | /** 41 | * WARNING: This will remove this sprite entirely. Use kill() if you 42 | * want to disable it temporarily only and reset() it later to revive it. 43 | * Used to clean up memory. 44 | */ 45 | override public function destroy():Void 46 | { 47 | skew = FlxDestroyUtil.put(skew); 48 | _skewMatrix = null; 49 | transformMatrix = null; 50 | 51 | super.destroy(); 52 | } 53 | 54 | override function drawComplex(camera:FlxCamera):Void 55 | { 56 | _frame.prepareMatrix(_matrix, FlxFrameAngle.ANGLE_0, checkFlipX(), checkFlipY()); 57 | _matrix.translate(-origin.x, -origin.y); 58 | _matrix.scale(scale.x, scale.y); 59 | 60 | if (matrixExposed) 61 | { 62 | _matrix.concat(transformMatrix); 63 | } 64 | else 65 | { 66 | if (bakedRotationAngle <= 0) 67 | { 68 | updateTrig(); 69 | 70 | if (angle != 0) 71 | _matrix.rotateWithTrig(_cosAngle, _sinAngle); 72 | } 73 | 74 | updateSkewMatrix(); 75 | _matrix.concat(_skewMatrix); 76 | } 77 | 78 | getScreenPosition(_point, camera).subtractPoint(offset); 79 | _point.addPoint(origin); 80 | if (isPixelPerfectRender(camera)) 81 | _point.floor(); 82 | 83 | _matrix.translate(_point.x, _point.y); 84 | camera.drawPixels(_frame, framePixels, _matrix, colorTransform, blend, antialiasing, shader); 85 | } 86 | 87 | function updateSkewMatrix():Void 88 | { 89 | _skewMatrix.identity(); 90 | 91 | if (skew.x != 0 || skew.y != 0) 92 | { 93 | _skewMatrix.b = skew.y * FlxAngle.TO_RAD; 94 | _skewMatrix.c = skew.x * FlxAngle.TO_RAD; 95 | } 96 | 97 | } 98 | 99 | override public function isSimpleRender(?camera:FlxCamera):Bool 100 | { 101 | if (FlxG.renderBlit) 102 | { 103 | return super.isSimpleRender(camera) && (skew.x == 0) && (skew.y == 0) && !matrixExposed; 104 | } 105 | else 106 | { 107 | return false; 108 | } 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /source/flixel/tweens/misc/BezierPathNumTween.hx: -------------------------------------------------------------------------------- 1 | package flixel.tweens.misc; 2 | 3 | import flixel.tweens.FlxTween; 4 | 5 | /** 6 | * Tweens a numeric value. See FlxTween.num() 7 | */ 8 | class BezierPathNumTween extends FlxTween 9 | { 10 | /** 11 | * The current value. 12 | */ 13 | public var value(default, null):Float; 14 | 15 | // Tween information. 16 | var _tweenFunction:Float->Void; 17 | var _points:Array; 18 | 19 | /** 20 | * Clean up references 21 | */ 22 | override public function destroy():Void 23 | { 24 | super.destroy(); 25 | _tweenFunction = null; 26 | } 27 | 28 | /** 29 | * Tweens the value from one value to another. 30 | * 31 | * @param fromValue Start value. 32 | * @param toValue End value. 33 | * @param duration Duration of the tween. 34 | * @param tweenFunction Optional tween function. See FlxTween.num() 35 | */ 36 | public function tween(points:Array, duration:Float, ?tweenFunction:Float->Void):BezierPathNumTween 37 | { 38 | _tweenFunction = tweenFunction; 39 | _points = points; 40 | value = points[0]; 41 | this.duration = duration; 42 | start(); 43 | return this; 44 | } 45 | 46 | override function update(elapsed:Float):Void 47 | { 48 | super.update(elapsed); 49 | value = bezierPath(scale,_points); 50 | 51 | if (_tweenFunction != null) 52 | _tweenFunction(value); 53 | } 54 | 55 | function bezierPath(t:Float, points:Array):Float { 56 | var n:Int = points.length - 1; 57 | var curve:Float = 0; 58 | 59 | for (i in 0...points.length) { 60 | var coeff:Float = 1; 61 | for (j in 0...i) { 62 | coeff = coeff * (n - j) / (j + 1); 63 | } 64 | 65 | curve += coeff * Math.pow(1 - t, n - i) * Math.pow(t, i) * points[i]; 66 | } 67 | 68 | return curve; 69 | } 70 | } -------------------------------------------------------------------------------- /source/flixel/tweens/misc/BezierPathTween.hx: -------------------------------------------------------------------------------- 1 | package flixel.tweens.misc; 2 | 3 | import flixel.math.FlxPoint; 4 | import flixel.tweens.FlxTween.FlxTweenManager; 5 | import flixel.tweens.FlxTween.TweenOptions; 6 | import flixel.util.FlxDestroyUtil; 7 | 8 | /** 9 | * A series of points which will determine a path from the 10 | * beginning point to the end point using quadratic curves. 11 | */ 12 | class BezierPathTween extends FlxTween 13 | { 14 | // Path information. 15 | var _object:Dynamic; 16 | var _properties:Dynamic>; 17 | var _propertyInfos:Array; 18 | var _distance:Float = 0; 19 | 20 | // Curve information. 21 | var _updateCurve:Bool = true; 22 | 23 | function new(Options:TweenOptions, ?manager:FlxTweenManager) 24 | { 25 | super(Options, manager); 26 | } 27 | 28 | function tween(object:Dynamic, properties:Dynamic>, duration:Float){ 29 | #if FLX_DEBUG 30 | if (object == null) 31 | throw "Cannot tween variables of an object that is null."; 32 | else if (properties == null) 33 | throw "Cannot tween null properties."; 34 | #end 35 | _object = object; 36 | _properties = properties; 37 | this.duration = duration; 38 | _propertyInfos = []; 39 | start(); 40 | initializeVars(); 41 | } 42 | 43 | override public function destroy():Void 44 | { 45 | super.destroy(); 46 | } 47 | 48 | /** 49 | * Gets the point on the path. 50 | */ 51 | 52 | override public function start():BezierPathTween 53 | { 54 | super.start(); 55 | return this; 56 | } 57 | 58 | override function update(elapsed:Float):Void 59 | { 60 | var delay:Float = (executions > 0) ? loopDelay : startDelay; 61 | 62 | // Leave properties alone until delay is over 63 | if (_secondsSinceStart < delay) 64 | super.update(elapsed); 65 | else 66 | { 67 | if (Math.isNaN(_propertyInfos[0].startValue)) 68 | setStartValues(); 69 | 70 | super.update(elapsed); 71 | 72 | if (active) 73 | for (info in _propertyInfos) 74 | if (info.points.length < 3){ 75 | Reflect.setProperty(info.object, info.field, info.startValue + info.range * scale); 76 | } 77 | else 78 | Reflect.setProperty(info.object, info.field, bezierPath(scale,info.points)); 79 | } 80 | } 81 | 82 | function initializeVars():Void 83 | { 84 | var fieldPaths:Array; 85 | if (Reflect.isObject(_properties)) 86 | fieldPaths = Reflect.fields(_properties); 87 | else 88 | throw "Unsupported properties container - use an object containing key/value pairs."; 89 | 90 | for (fieldPath in fieldPaths) 91 | { 92 | var target = _object; 93 | var path = fieldPath.split("."); 94 | var field = path.pop(); 95 | for (component in path) 96 | { 97 | target = Reflect.getProperty(target, component); 98 | if (!Reflect.isObject(target)) 99 | throw 'The object does not have the property "$component" in "$fieldPath"'; 100 | } 101 | var propFieldValues = Reflect.field(_properties, fieldPath); 102 | 103 | var arr:BezierTweenProperty = { 104 | object: target, 105 | field: field, 106 | startValue: Math.NaN, 107 | points: propFieldValues, 108 | range: propFieldValues[propFieldValues.length-1] 109 | }; 110 | 111 | _propertyInfos.push(arr); 112 | } 113 | } 114 | 115 | function setStartValues() 116 | { 117 | for (info in _propertyInfos) 118 | { 119 | if (Reflect.getProperty(info.object, info.field) == null) 120 | throw 'The object does not have the property "${info.field}"'; 121 | if (Math.isNaN(info.points[0])){ 122 | var value:Dynamic = Reflect.getProperty(info.object, info.field); 123 | if (Math.isNaN(value)) 124 | throw 'The property "${info.field}" is not numeric.'; 125 | 126 | info.startValue = value; 127 | info.points[0] = value; 128 | info.range = info.points[info.points.length-1] - value; 129 | } 130 | else{ 131 | info.startValue = info.points[0]; 132 | info.range = info.points[info.points.length-1] - info.points[0]; 133 | } 134 | } 135 | } 136 | 137 | function bezierPath(t:Float, points:Array):Float { 138 | var n:Int = points.length - 1; 139 | var curve:Float = 0; 140 | 141 | for (i in 0...points.length) { 142 | var coeff:Float = 1; 143 | for (j in 0...i) { 144 | coeff = coeff * (n - j) / (j + 1); 145 | } 146 | 147 | curve += coeff * Math.pow(1 - t, n - i) * Math.pow(t, i) * points[i]; 148 | } 149 | 150 | return curve; 151 | } 152 | } 153 | 154 | private typedef BezierTweenProperty = 155 | { 156 | object:Dynamic, 157 | field:String, 158 | startValue:Float, 159 | points:Array, 160 | range:Float 161 | } -------------------------------------------------------------------------------- /source/import.hx: -------------------------------------------------------------------------------- 1 | #if LEATHER 2 | import states.PlayState; 3 | import game.Song; 4 | import game.Section.SwagSection; 5 | import game.Note; 6 | import ui.FlxScrollableDropDownMenu; 7 | import game.Conductor; 8 | import utilities.CoolUtil; 9 | import game.StrumNote; 10 | import utilities.NoteVariables; 11 | import states.LoadingState; 12 | import states.MusicBeatState; 13 | import substates.MusicBeatSubstate; 14 | #elseif (PSYCH && PSYCHVERSION >= "0.7") 15 | import flixel.addons.ui.FlxUIDropDownMenu; 16 | import backend.Section.SwagSection; 17 | import states.PlayState; 18 | import backend.CoolUtil; 19 | import backend.Conductor; 20 | import backend.ClientPrefs; 21 | import backend.Paths; 22 | import states.LoadingState; 23 | import backend.Difficulty; 24 | #if SCEModchartingTools 25 | import substates.MusicBeatSubstate; 26 | #else 27 | import backend.MusicBeatSubstate; 28 | #end 29 | import objects.Note; 30 | #if SCEModchartingTools 31 | import objects.StrumArrow; 32 | #else 33 | import objects.StrumNote; 34 | #end 35 | import backend.Song; 36 | #else 37 | import Section.SwagSection; 38 | import Song; 39 | import MusicBeatSubstate; 40 | #end 41 | 42 | #if (PSYCH && PSYCHVERSION >= "0.7") 43 | #if LUA_ALLOWED 44 | import psychlua.FunkinLua; 45 | import psychlua.HScript as FunkinHScript; 46 | #end 47 | #end 48 | 49 | #if sys 50 | import sys.FileSystem; 51 | import sys.io.File; 52 | #end 53 | -------------------------------------------------------------------------------- /source/managers/TweenManager.hx: -------------------------------------------------------------------------------- 1 | package managers; 2 | 3 | import flixel.util.FlxColor; 4 | import flixel.FlxSprite; 5 | import flixel.math.FlxPoint; 6 | import flixel.FlxObject; 7 | import flixel.tweens.FlxTween; 8 | import flixel.tweens.misc.*; 9 | 10 | class TweenManager extends FlxTweenManager 11 | { 12 | public function bezierPathTween(Object:Dynamic, Values:Dynamic>, Duration:Float = 1, ?Options:TweenOptions):BezierPathTween{ 13 | @:privateAccess{ 14 | var tween = new BezierPathTween(Options, this); 15 | tween.tween(Object, Values, Duration); 16 | return add(tween); 17 | } 18 | } 19 | public function bezierPathNumTween(Points:Array, Duration:Float = 1, ?Options:TweenOptions,?TweenFunction:Float->Void):BezierPathNumTween{ 20 | @:privateAccess{ 21 | var tween = new BezierPathNumTween(Options, this); 22 | tween.tween(Points, Duration, TweenFunction); 23 | return add(tween); 24 | } 25 | } 26 | /** 27 | * Tweens numeric public properties of an Object. Shorthand for creating a VarTween, starting it and adding it to the TweenManager. 28 | * 29 | * ```haxe 30 | * this.createTween(Object, { x: 500, y: 350, "scale.x": 2 }, 2.0, { ease: easeFunction, onStart: onStart, onUpdate: onUpdate, onComplete: onComplete, type: ONESHOT }); 31 | * ``` 32 | * 33 | * @param Object The object containing the properties to tween. 34 | * @param Values An object containing key/value pairs of properties and target values. 35 | * @param Duration Duration of the tween in seconds. 36 | * @param Options A structure with tween options. 37 | * @return The added VarTween object. 38 | * @since 4.2.0 39 | */ 40 | public function createTween(Object:Dynamic, Values:Dynamic, Duration:Float = 1, ?Options:TweenOptions):FlxTween 41 | { 42 | var daTween = this.tween(Object, Values, Duration, Options); 43 | daTween.manager = this; 44 | return daTween; 45 | } 46 | 47 | /** 48 | * Tweens some numeric value. Shorthand for creating a NumTween, starting it and adding it to the TweenManager. Using it in 49 | * conjunction with a TweenFunction requires more setup, but is faster than VarTween because it doesn't use Reflection. 50 | * 51 | * ```haxe 52 | * function tweenFunction(s:FlxSprite, v:Float) { s.alpha = v; } 53 | * this.createNum(1, 0, 2.0, { ease: easeFunction, onStart: onStart, onUpdate: onUpdate, onComplete: onComplete, type: ONESHOT }, tweenFunction.bind(mySprite)); 54 | * ``` 55 | * 56 | * Trivia: For historical reasons, you can use either onUpdate or TweenFunction to accomplish the same thing, but TweenFunction 57 | * gives you the updated Float as a direct argument. 58 | * 59 | * @param FromValue Start value. 60 | * @param ToValue End value. 61 | * @param Duration Duration of the tween. 62 | * @param Options A structure with tween options. 63 | * @param TweenFunction A function to be called when the tweened value updates. It is recommended not to use an anonymous 64 | * function if you are maximizing performance, as those will be compiled to Dynamics on cpp. 65 | * @return The added NumTween object. 66 | * @since 4.2.0 67 | */ 68 | public function createNum(FromValue:Float, ToValue:Float, Duration:Float = 1, ?Options:TweenOptions, ?TweenFunction:Float->Void):FlxTween 69 | { 70 | var daTween = this.num(FromValue, ToValue, Duration, Options, TweenFunction); 71 | daTween.manager = this; 72 | return daTween; 73 | } 74 | 75 | /** 76 | * Tweens numeric value which represents angle. Shorthand for creating a AngleTween object, starting it and adding it to the TweenManager. 77 | * 78 | * ```haxe 79 | * this.createAngle(Sprite, -90, 90, 2.0, { ease: easeFunction, onStart: onStart, onUpdate: onUpdate, onComplete: onComplete, type: ONESHOT }); 80 | * ``` 81 | * 82 | * @param Sprite Optional Sprite whose angle should be tweened. 83 | * @param FromAngle Start angle. 84 | * @param ToAngle End angle. 85 | * @param Duration Duration of the tween. 86 | * @param Options A structure with tween options. 87 | * @return The added AngleTween object. 88 | * @since 4.2.0 89 | */ 90 | public function createAngle(?Sprite:FlxSprite, FromAngle:Float, ToAngle:Float, Duration:Float = 1, ?Options:TweenOptions):FlxTween 91 | { 92 | var daTween = this.angle(Sprite, FromAngle, ToAngle, Duration, Options); 93 | daTween.manager = this; 94 | return daTween; 95 | } 96 | 97 | /** 98 | * Tweens numeric value which represents color. Shorthand for creating a ColorTween object, starting it and adding it to a TweenPlugin. 99 | * 100 | * ```haxe 101 | * this.createColor(Sprite, 2.0, 0x000000, 0xffffff, 0.0, 1.0, { ease: easeFunction, onStart: onStart, onUpdate: onUpdate, onComplete: onComplete, type: ONESHOT }); 102 | * ``` 103 | * 104 | * @param Sprite Optional Sprite whose color should be tweened. 105 | * @param Duration Duration of the tween in seconds. 106 | * @param FromColor Start color. 107 | * @param ToColor End color. 108 | * @param Options A structure with tween options. 109 | * @return The added ColorTween object. 110 | * @since 4.2.0 111 | */ 112 | public function createColor(?Sprite:FlxSprite, Duration:Float = 1, FromColor:FlxColor, ToColor:FlxColor, ?Options:TweenOptions):FlxTween 113 | { 114 | var daTween = this.color(Sprite, Duration, FromColor, ToColor, Options); 115 | daTween.manager = this; 116 | return daTween; 117 | } 118 | 119 | /** 120 | * Create a new LinearMotion tween. 121 | * 122 | * ```haxe 123 | * this.createLinearMotion(Object, 0, 0, 500, 20, 5, false, { ease: easeFunction, onStart: onStart, onUpdate: onUpdate, onComplete: onComplete, type: ONESHOT }); 124 | * ``` 125 | * 126 | * @param Object The object to move (FlxObject or FlxSpriteGroup) 127 | * @param FromX X start. 128 | * @param FromY Y start. 129 | * @param ToX X finish. 130 | * @param ToY Y finish. 131 | * @param DurationOrSpeed Duration (in seconds) or speed of the movement. 132 | * @param UseDuration Whether to use the previous param as duration or speed. 133 | * @param Options A structure with tween options. 134 | * @return The LinearMotion object. 135 | * @since 4.2.0 136 | */ 137 | public function createLinearMotion(Object:FlxObject, FromX:Float, FromY:Float, ToX:Float, ToY:Float, DurationOrSpeed:Float = 1, UseDuration:Bool = true, 138 | ?Options:TweenOptions):FlxTween 139 | { 140 | var daTween = this.linearMotion(Object, FromX, FromY, ToX, ToY, Options); 141 | daTween.manager = this; 142 | return daTween; 143 | } 144 | 145 | /** 146 | * Create a new QuadMotion tween. 147 | * 148 | * ```haxe 149 | * this.createQuadMotion(Object, 0, 100, 300, 500, 100, 2, 5, false, { ease: easeFunction, onStart: onStart, onUpdate: onUpdate, onComplete: onComplete, type: ONESHOT }); 150 | * ``` 151 | * 152 | * @param Object The object to move (FlxObject or FlxSpriteGroup) 153 | * @param FromX X start. 154 | * @param FromY Y start. 155 | * @param ControlX X control, used to determine the curve. 156 | * @param ControlY Y control, used to determine the curve. 157 | * @param ToX X finish. 158 | * @param ToY Y finish. 159 | * @param DurationOrSpeed Duration (in seconds) or speed of the movement. 160 | * @param UseDuration Whether to use the previous param as duration or speed. 161 | * @param Options A structure with tween options. 162 | * @return The QuadMotion object. 163 | * @since 4.2.0 164 | */ 165 | public function createQuadMotion(Object:FlxObject, FromX:Float, FromY:Float, ControlX:Float, ControlY:Float, ToX:Float, ToY:Float, 166 | DurationOrSpeed:Float = 1, UseDuration:Bool = true, ?Options:TweenOptions):FlxTween 167 | { 168 | var daTween = this.quadMotion(Object, FromX, FromY, ControlX, ControlY, ToX, ToY, DurationOrSpeed, UseDuration, Options); 169 | daTween.manager = this; 170 | return daTween; 171 | } 172 | 173 | /** 174 | * Create a new CubicMotion tween. 175 | * 176 | * ```haxe 177 | * this.createCubicMotion(_sprite, 0, 0, 500, 100, 400, 200, 100, 100, 2, { ease: easeFunction, onStart: onStart, onUpdate: onUpdate, onComplete: onComplete, type: ONESHOT }); 178 | * ``` 179 | * 180 | * @param Object The object to move (FlxObject or FlxSpriteGroup) 181 | * @param FromX X start. 182 | * @param FromY Y start. 183 | * @param aX First control x. 184 | * @param aY First control y. 185 | * @param bX Second control x. 186 | * @param bY Second control y. 187 | * @param ToX X finish. 188 | * @param ToY Y finish. 189 | * @param Duration Duration of the movement in seconds. 190 | * @param Options A structure with tween options. 191 | * @return The CubicMotion object. 192 | * @since 4.2.0 193 | */ 194 | public function createCubicMotion(Object:FlxObject, FromX:Float, FromY:Float, aX:Float, aY:Float, bX:Float, bY:Float, ToX:Float, ToY:Float, 195 | Duration:Float = 1, ?Options:TweenOptions):FlxTween 196 | { 197 | var daTween = this.cubicMotion(Object, FromX, FromY, aX, aY, bX, bY, ToX, ToY, Duration, Options); 198 | daTween.manager = this; 199 | return daTween; 200 | } 201 | 202 | /** 203 | * Create a new CircularMotion tween. 204 | * 205 | * ```haxe 206 | * this.createCircularMotion(Object, 250, 250, 50, 0, true, 2, true, { ease: easeFunction, onStart: onStart, onUpdate: onUpdate, onComplete: onComplete, type: ONESHOT }); 207 | * ``` 208 | * 209 | * @param Object The object to move (FlxObject or FlxSpriteGroup) 210 | * @param CenterX X position of the circle's center. 211 | * @param CenterY Y position of the circle's center. 212 | * @param Radius Radius of the circle. 213 | * @param Angle Starting position on the circle. 214 | * @param Clockwise If the motion is clockwise. 215 | * @param DurationOrSpeed Duration of the movement in seconds. 216 | * @param UseDuration Duration of the movement. 217 | * @param Ease Optional easer function. 218 | * @param Options A structure with tween options. 219 | * @return The CircularMotion object. 220 | * @since 4.2.0 221 | */ 222 | public function createCircularMotion(Object:FlxObject, CenterX:Float, CenterY:Float, Radius:Float, Angle:Float, Clockwise:Bool, DurationOrSpeed:Float = 1, 223 | UseDuration:Bool = true, ?Options:TweenOptions):FlxTween 224 | { 225 | var daTween = this.circularMotion(Object, CenterX, CenterY, Radius, Angle, Clockwise, DurationOrSpeed, UseDuration, Options); 226 | daTween.manager = this; 227 | return daTween; 228 | } 229 | 230 | /** 231 | * Create a new LinearPath tween. 232 | * 233 | * ```haxe 234 | * this.createLinearPath(Object, [FlxPoint.get(0, 0), FlxPoint.get(100, 100)], 2, true, { ease: easeFunction, onStart: onStart, onUpdate: onUpdate, onComplete: onComplete, type: ONESHOT }); 235 | * ``` 236 | * 237 | * @param Object The object to move (FlxObject or FlxSpriteGroup) 238 | * @param Points An array of at least 2 FlxPoints defining the path 239 | * @param DurationOrSpeed Duration (in seconds) or speed of the movement. 240 | * @param UseDuration Whether to use the previous param as duration or speed. 241 | * @param Options A structure with tween options. 242 | * @return The LinearPath object. 243 | * @since 4.2.0 244 | */ 245 | public function createLinearPath(Object:FlxObject, Points:Array, DurationOrSpeed:Float = 1, UseDuration:Bool = true, 246 | ?Options:TweenOptions):FlxTween 247 | { 248 | var daTween = this.linearPath(Object, Points, DurationOrSpeed, UseDuration, Options); 249 | daTween.manager = this; 250 | return daTween; 251 | } 252 | 253 | /** 254 | * Create a new QuadPath tween. 255 | * 256 | * ```haxe 257 | * this.createQuadPath(Object, [FlxPoint.get(0, 0), FlxPoint.get(200, 200), FlxPoint.get(400, 0)], 2, true, { ease: easeFunction, onStart: onStart, onUpdate: onUpdate, onComplete: onComplete, type: ONESHOT }); 258 | * ``` 259 | * 260 | * @param Object The object to move (FlxObject or FlxSpriteGroup) 261 | * @param Points An array of at least 3 FlxPoints defining the path 262 | * @param DurationOrSpeed Duration (in seconds) or speed of the movement. 263 | * @param UseDuration Whether to use the previous param as duration or speed. 264 | * @param Options A structure with tween options. 265 | * @return The QuadPath object. 266 | * @since 4.2.0 267 | */ 268 | public function createQuadPath(Object:FlxObject, Points:Array, DurationOrSpeed:Float = 1, UseDuration:Bool = true, 269 | ?Options:TweenOptions):FlxTween 270 | { 271 | var daTween = this.quadPath(Object, Points, DurationOrSpeed, UseDuration, Options); 272 | daTween.manager = this; 273 | return daTween; 274 | } 275 | 276 | /** 277 | * Tweens value by using bezier path. Minimum 2 points. 278 | * 279 | * ```haxe 280 | * this.createBezierPathTween(Object, { x: [500,1000,500], y: [350,400,400,350]}, 2.0, { ease: easeFunction, onStart: onStart, onUpdate: onUpdate, onComplete: onComplete, type: ONESHOT }); 281 | * ``` 282 | * 283 | * @param Object The object containing the properties to tween. 284 | * @param Values An object containing key/value pairs of properties and the value as in array containing points. Tip: Use Math.Nan at the first point to use the object's original value! 285 | * @param Duration Duration of the tween in seconds. 286 | * @param Options A structure with tween options. 287 | * @return The added BezierPathTween object. 288 | */ 289 | public function createBezierPathTween(Object:Dynamic, Values:Dynamic>, Duration:Float = 1, ?Options:TweenOptions):BezierPathTween 290 | { 291 | var daTween = this.bezierPathTween(Object, Values, Duration, Options); 292 | daTween.manager = this; 293 | return daTween; 294 | } 295 | 296 | 297 | /** 298 | * Cancels all related tweens on the specified object. 299 | * 300 | * Note: Any tweens with the specified fields are cancelled, if the tween has other properties they 301 | * will also be cancelled. 302 | * 303 | * @param Object The object with tweens to cancel. 304 | * @param FieldPaths Optional list of the tween field paths to search for. If null or empty, all tweens on the specified 305 | * object are canceled. Allows dot paths to check child properties. 306 | * 307 | * @since 4.9.0 308 | */ 309 | public function cancelTweensByObject(Object:Dynamic, ?FieldPaths:Array):Void 310 | { 311 | this.cancelTweensOf(Object, FieldPaths); 312 | } 313 | 314 | /** 315 | * Immediately updates all tweens on the specified object with the specified fields that 316 | * are not looping (type `FlxTween.LOOPING` or `FlxTween.PINGPONG`) and `active` through 317 | * their endings, triggering their `onComplete` callbacks. 318 | * 319 | * Note: if they haven't yet begun, this will first trigger their `onStart` callback. 320 | * 321 | * Note: their `onComplete` callbacks are triggered in the next frame. 322 | * To trigger them immediately, call `FlxTween.globalManager.update(0);` after this function. 323 | * 324 | * In no case should it trigger an `onUpdate` callback. 325 | * 326 | * Note: Any tweens with the specified fields are completed, if the tween has other properties they 327 | * will also be completed. 328 | * 329 | * @param Object The object with tweens to complete. 330 | * @param FieldPaths Optional list of the tween field paths to search for. If null or empty, all tweens on 331 | * the specified object are completed. Allows dot paths to check child properties. 332 | * 333 | * @since 4.9.0 334 | */ 335 | public function completeTweensByObject(Object:Dynamic, ?FieldPaths:Array):Void 336 | { 337 | this.completeTweensOf(Object, FieldPaths); 338 | } 339 | 340 | public function pauseTweens():Void 341 | { 342 | if (this == null) 343 | return; 344 | this.active = false; 345 | } 346 | 347 | public function resumeTweens():Void 348 | { 349 | if (this == null) 350 | return; 351 | this.active = true; 352 | } 353 | 354 | public function destroyTweens():Void 355 | { 356 | if (this == null) 357 | return; 358 | this.clear(); 359 | } 360 | } 361 | -------------------------------------------------------------------------------- /source/modcharting/ModTable.hx: -------------------------------------------------------------------------------- 1 | package modcharting; 2 | 3 | import flixel.math.FlxMath; 4 | import flixel.tweens.FlxTween; 5 | import modcharting.Modifier; 6 | #if LEATHER 7 | import game.Conductor; 8 | #end 9 | 10 | class ModTable 11 | { 12 | public var modifiers:Map = new Map(); 13 | private var instance:ModchartMusicBeatState = null; 14 | private var renderer:PlayfieldRenderer = null; 15 | 16 | //The table is used to precalculate all the playfield and lane checks on each modifier, 17 | //so it should end up with a lot less loops and if checks each frame 18 | //index table by playfield, then lane, and then loop through each modifier 19 | private var table:Array>> = []; 20 | 21 | public function new(instance:ModchartMusicBeatState, renderer:PlayfieldRenderer) 22 | { 23 | this.instance = instance; 24 | this.renderer = renderer; 25 | loadDefaultModifiers(); 26 | reconstructTable(); 27 | } 28 | 29 | public function add(mod:Modifier) : Void 30 | { 31 | mod.instance = instance; 32 | mod.renderer = renderer; 33 | remove(mod.tag); //in case you replace one??? 34 | modifiers.set(mod.tag, mod); 35 | } 36 | public function remove(tag:String) : Void 37 | { 38 | if (modifiers.exists(tag)) 39 | modifiers.remove(tag); 40 | } 41 | public function clear() : Void 42 | { 43 | modifiers.clear(); 44 | 45 | loadDefaultModifiers(); 46 | } 47 | public function resetMods() : Void 48 | { 49 | for (mod in modifiers) 50 | mod.reset(); 51 | } 52 | public function setModTargetLane(tag:String, lane:Int) : Void 53 | { 54 | if (modifiers.exists(tag)) 55 | { 56 | modifiers.get(tag).targetLane = lane; 57 | } 58 | } 59 | 60 | public function loadDefaultModifiers() : Void 61 | { 62 | //default modifiers 63 | add(new XModifier('x')); 64 | add(new YModifier('y')); 65 | add(new ZModifier('z')); 66 | add(new ConfusionModifier('confusion')); 67 | 68 | for (i in 0...(NoteMovement.keyCount+NoteMovement.playerKeyCount)) 69 | { 70 | add(new XModifier('x'+i, ModifierType.LANESPECIFIC)); 71 | add(new YModifier('y'+i, ModifierType.LANESPECIFIC)); 72 | add(new ZModifier('z'+i, ModifierType.LANESPECIFIC)); 73 | add(new ConfusionModifier('confusion'+i, ModifierType.LANESPECIFIC)); 74 | setModTargetLane('x'+i, i); 75 | setModTargetLane('y'+i, i); 76 | setModTargetLane('z'+i, i); 77 | setModTargetLane('confusion'+i, i); 78 | } 79 | } 80 | 81 | public function reconstructTable() : Void 82 | { 83 | table = []; 84 | 85 | for (pf in 0...renderer.playfields.length) 86 | { 87 | if (table[pf] == null) 88 | table[pf] = []; 89 | 90 | for (lane in 0...NoteMovement.totalKeyCount) 91 | { 92 | table[pf].push([]); 93 | 94 | for (mod in modifiers) 95 | { 96 | if (mod.checkLane(lane) && mod.checkPlayField(pf)) 97 | { 98 | table[pf][lane].push(mod); //add mod to table 99 | } 100 | } 101 | } 102 | } 103 | } 104 | 105 | public function applyStrumMods(noteData:NotePositionData, lane:Int, pf:Int) : Void 106 | { 107 | if (table[pf] != null && table[pf][lane] != null) 108 | { 109 | var modList:Array = table[pf][lane]; 110 | for (mod in modList) 111 | mod.getStrumPath(noteData, lane, pf); 112 | } 113 | } 114 | public function applyNoteMods(noteData:NotePositionData, lane:Int, curPos:Float, pf:Int) : Void 115 | { 116 | if (table[pf] != null && table[pf][lane] != null) 117 | { 118 | var modList:Array = table[pf][lane]; 119 | for (mod in modList) 120 | mod.getNotePath(noteData, lane, curPos, pf); 121 | } 122 | } 123 | public function applyNoteDistMods(noteDist:Float, lane:Int, pf:Int) : Float 124 | { 125 | if (table[pf] != null && table[pf][lane] != null) 126 | { 127 | var modList:Array = table[pf][lane]; 128 | for (mod in modList) 129 | noteDist = mod.getNoteDist(noteDist, lane, 0, pf); 130 | } 131 | return noteDist; 132 | } 133 | public function applyCurPosMods(lane:Int, curPos:Float, pf:Int) : Float 134 | { 135 | if (table[pf] != null && table[pf][lane] != null) 136 | { 137 | var modList:Array = table[pf][lane]; 138 | for (mod in modList) 139 | curPos = mod.getNoteCurPos(lane, curPos, pf); 140 | } 141 | return curPos; 142 | } 143 | public function applyIncomingAngleMods(lane:Int, curPos:Float, pf:Int) : Array 144 | { 145 | var incomingAngle:Array = [0,0]; 146 | if (table[pf] != null && table[pf][lane] != null) 147 | { 148 | var modList:Array = table[pf][lane]; 149 | for (mod in modList) 150 | { 151 | var ang = mod.getIncomingAngle(lane, curPos, pf); //need to get incoming angle before 152 | incomingAngle[0] += ang[0]; 153 | incomingAngle[1] += ang[1]; 154 | } 155 | } 156 | return incomingAngle; 157 | } 158 | 159 | 160 | 161 | public function tweenModifier(modifier:String, val:Float, time:Float, ease:String, beat:Float, ?tag:String = null) 162 | { 163 | var modifiers:Map = renderer.modifierTable.modifiers; 164 | if (modifiers.exists(modifier)) 165 | { 166 | var easefunc = ModchartUtil.getFlxEaseByString(ease); 167 | if (Conductor.songPosition >= ModchartUtil.getTimeFromBeat(beat)+(time*1000)) //cancel if should have ended 168 | { 169 | modifiers.get(modifier).currentValue = val; 170 | return; 171 | } 172 | time /= renderer.speed; 173 | var tween = renderer.createTween(modifiers.get(modifier), {currentValue: val}, time, {ease: easefunc, 174 | onComplete: function(twn:FlxTween) { 175 | var modifierTag:String = (tag != null ? tag : modifier); 176 | #if PSYCH 177 | #if (PSYCHVERSION >= "0.7") 178 | PlayState.instance.callOnScripts("onModifierComplete", [modifierTag]); 179 | #else 180 | PlayState.instance.callOnLuas("onModifierComplete", [modifierTag]); 181 | #end 182 | #end 183 | } 184 | }); 185 | if (Conductor.songPosition > ModchartUtil.getTimeFromBeat(beat)) //skip to where it should be i guess?? 186 | { 187 | @:privateAccess 188 | tween._secondsSinceStart += ((Conductor.songPosition-ModchartUtil.getTimeFromBeat(beat))*0.001); 189 | @:privateAccess 190 | tween.update(0); 191 | } 192 | if (renderer.editorPaused) 193 | tween.active = false; 194 | } 195 | } 196 | 197 | public function tweenModifierSubValue(modifier:String, subValue:String, val:Float, time:Float, ease:String, beat:Float, ?tag:String = null) 198 | { 199 | var modifiers:Map = renderer.modifierTable.modifiers; 200 | if (modifiers.exists(modifier)) 201 | { 202 | if (modifiers.get(modifier).subValues.exists(subValue)) 203 | { 204 | var easefunc = ModchartUtil.getFlxEaseByString(ease); 205 | var tag = modifier+' '+subValue; 206 | 207 | var startValue = modifiers.get(modifier).subValues.get(subValue).value; 208 | 209 | if (Conductor.songPosition >= ModchartUtil.getTimeFromBeat(beat)+(time*1000)) //cancel if should have ended 210 | { 211 | modifiers.get(modifier).subValues.get(subValue).value = val; 212 | return; 213 | } 214 | time /= renderer.speed; 215 | var tween = renderer.createTweenNum(startValue, val, time, {ease: easefunc, 216 | onComplete: function(twn:FlxTween) { 217 | if (modifiers.exists(modifier)) 218 | modifiers.get(modifier).subValues.get(subValue).value = val; 219 | var modifierTag:String = (tag != null ? tag : '$modifier-$subValue'); 220 | #if PSYCH 221 | #if (PSYCHVERSION >= "0.7") 222 | PlayState.instance.callOnScripts("onModifierComplete", [modifier, subValue]); 223 | #else 224 | PlayState.instance.callOnLuas("onModifierComplete", [modifier, subValue]); 225 | #end 226 | #end 227 | }, 228 | onUpdate: function(twn:FlxTween) { 229 | //need to update like this because its inside a map 230 | if (modifiers.exists(modifier)) 231 | modifiers.get(modifier).subValues.get(subValue).value = FlxMath.lerp(startValue, val, easefunc(twn.percent)); 232 | } 233 | }); 234 | if (Conductor.songPosition > ModchartUtil.getTimeFromBeat(beat)) //skip to where it should be i guess?? 235 | { 236 | @:privateAccess 237 | tween._secondsSinceStart += ((Conductor.songPosition-ModchartUtil.getTimeFromBeat(beat))*0.001); 238 | @:privateAccess 239 | tween.update(0); 240 | } 241 | if (renderer.editorPaused) 242 | tween.active = false; 243 | } 244 | 245 | } 246 | } 247 | } 248 | -------------------------------------------------------------------------------- /source/modcharting/ModchartEvent.hx: -------------------------------------------------------------------------------- 1 | package modcharting; 2 | 3 | class ModchartEvent 4 | { 5 | public var time:Float = 0; 6 | public var func:Array->Void; 7 | public var args:Array; 8 | public function new(time:Float, func:Array->Void, args:Array) 9 | { 10 | this.time = time; 11 | this.func = func; 12 | this.args = args; 13 | } 14 | /*public function call() 15 | { 16 | Reflect.callMethod(null, func, args); 17 | }*/ 18 | } -------------------------------------------------------------------------------- /source/modcharting/ModchartEventManager.hx: -------------------------------------------------------------------------------- 1 | package modcharting; 2 | 3 | #if LEATHER 4 | import game.Conductor; 5 | #end 6 | 7 | class ModchartEventManager 8 | { 9 | private var renderer:PlayfieldRenderer; 10 | public function new(renderer:PlayfieldRenderer) 11 | { 12 | this.renderer = renderer; 13 | } 14 | private var events:Array = []; 15 | public function update(elapsed:Float) 16 | { 17 | if (events.length > 1) 18 | { 19 | events.sort(function(a, b){ 20 | if (a.time < b.time) 21 | return -1; 22 | else if (a.time > b.time) 23 | return 1; 24 | else 25 | return 0; 26 | }); 27 | } 28 | while(events.length > 0) { 29 | var event:ModchartEvent = events[0]; 30 | if(Conductor.songPosition < event.time) { 31 | break; 32 | } 33 | //Reflect.callMethod(this, event.func, event.args); 34 | event.func(event.args); 35 | events.shift(); 36 | } 37 | Modifier.beat = ((Conductor.songPosition *0.001)*(Conductor.bpm/60)); 38 | } 39 | public function addEvent(beat:Float, func:Array->Void, args:Array) 40 | { 41 | var time = ModchartUtil.getTimeFromBeat(beat); 42 | events.push(new ModchartEvent(time, func, args)); 43 | } 44 | public function clearEvents() 45 | { 46 | events = []; 47 | } 48 | } -------------------------------------------------------------------------------- /source/modcharting/ModchartFile.hx: -------------------------------------------------------------------------------- 1 | package modcharting; 2 | 3 | import flixel.math.FlxMath; 4 | import haxe.Exception; 5 | import haxe.Json; 6 | import haxe.format.JsonParser; 7 | import lime.utils.Assets; 8 | #if LEATHER 9 | import states.PlayState; 10 | import game.Note; 11 | import game.Conductor; 12 | #if polymod 13 | import polymod.backends.PolymodAssets; 14 | #end 15 | #end 16 | #if sys 17 | import sys.FileSystem; 18 | import sys.io.File; 19 | #end 20 | #if hscript 21 | import hscript.*; 22 | #end 23 | #if (HSCRIPT_ALLOWED && PSYCH && PSYCHVERSION >= "0.7") 24 | import psychlua.HScript as FunkinHScript; 25 | #end 26 | using StringTools; 27 | 28 | typedef ModchartJson = 29 | { 30 | var modifiers:Array>; 31 | var events:Array>; 32 | var playfields:Int; 33 | } 34 | 35 | class ModchartFile 36 | { 37 | //used for indexing 38 | public static final MOD_NAME = 0; //the modifier name 39 | public static final MOD_CLASS = 1; //the class/custom mod it uses 40 | public static final MOD_TYPE = 2; //the type, which changes if its for the player, opponent, a specific lane or all 41 | public static final MOD_PF = 3; //the playfield that mod uses 42 | public static final MOD_LANE = 4; //the lane the mod uses 43 | 44 | public static final EVENT_TYPE = 0; //event type (set or ease) 45 | public static final EVENT_DATA = 1; //event data 46 | public static final EVENT_REPEAT = 2; //event repeat data 47 | 48 | public static final EVENT_TIME = 0; //event time (in beats) 49 | public static final EVENT_SETDATA = 1; //event data (for sets) 50 | public static final EVENT_EASETIME = 1; //event ease time 51 | public static final EVENT_EASE = 2; //event ease 52 | public static final EVENT_EASEDATA = 3; //event data (for eases) 53 | 54 | public static final EVENT_REPEATBOOL = 0; //if event should repeat 55 | public static final EVENT_REPEATCOUNT = 1; //how many times it repeats 56 | public static final EVENT_REPEATBEATGAP = 2; //how many beats in between each repeat 57 | 58 | 59 | public var data:ModchartJson = null; 60 | private var renderer:PlayfieldRenderer; 61 | public var scriptListen:Bool = false; 62 | #if hscript 63 | public var customModifiers:Map = new Map(); 64 | #end 65 | public var hasDifficultyModchart:Bool = false; //so it loads false as default! 66 | 67 | public function new(renderer:PlayfieldRenderer) 68 | { 69 | #if PSYCH 70 | #if (PSYCHVERSION >= "0.7") 71 | data = loadFromJson(PlayState.SONG.song.toLowerCase(), Difficulty.getString().toLowerCase() == null ? Difficulty.defaultList[PlayState.storyDifficulty] : Difficulty.getString().toLowerCase()); 72 | #elseif (PSYCHVERSION < "0.7") 73 | data = loadFromJson(PlayState.SONG.song.toLowerCase(), CoolUtil.difficultyString().toLowerCase() == null ? CoolUtil.difficulties[PlayState.storyDifficulty] : CoolUtil.difficultyString().toLowerCase()); 74 | #end 75 | #else 76 | data = loadFromJson(PlayState.SONG.song.toLowerCase(), PlayState.storyDifficultyStr); 77 | #end 78 | this.renderer = renderer; 79 | renderer.modchart = this; 80 | loadPlayfields(); 81 | loadModifiers(); 82 | loadEvents(); 83 | } 84 | 85 | public function loadFromJson(folder:String, difficulty:String):ModchartJson //load da shit 86 | { 87 | var rawJson = null; 88 | var filePath = null; 89 | 90 | var folderShit:String = ""; 91 | 92 | var moddyFile:String = Paths.json(#if PSYCH Paths.formatToSongPath(folder) #else PlayState.SONG.song #end + '/modchart-' + difficulty.toLowerCase()); 93 | var moddyFile2:String = Paths.json(#if PSYCH Paths.formatToSongPath(folder) #else PlayState.SONG.song #end + '/modchart'); 94 | 95 | #if MODS_ALLOWED 96 | var moddyFileMods:String = Paths.modsJson(#if PSYCH Paths.formatToSongPath(folder) #else PlayState.SONG.song #end + '/modchart-' + difficulty.toLowerCase()); 97 | var moddyFileMods2:String = Paths.modsJson(#if PSYCH Paths.formatToSongPath(folder) #else PlayState.SONG.song #end + '/modchart'); 98 | #end 99 | 100 | #if PSYCH 101 | try 102 | { 103 | 104 | #if sys 105 | #if MODS_ALLOWED 106 | if(FileSystem.exists(moddyFileMods) && difficulty.toLowerCase() != null) 107 | hasDifficultyModchart = true; 108 | if (FileSystem.exists(moddyFileMods2) && !FileSystem.exists(moddyFileMods)) 109 | hasDifficultyModchart = false; 110 | else if(FileSystem.exists(moddyFileMods2) && difficulty.toLowerCase() == null && !FileSystem.exists(moddyFileMods)) hasDifficultyModchart = false; 111 | #end 112 | 113 | if(FileSystem.exists(moddyFile) && difficulty.toLowerCase() != null) 114 | hasDifficultyModchart = true; 115 | if (FileSystem.exists(moddyFile) && !FileSystem.exists(moddyFile)) 116 | hasDifficultyModchart = false; 117 | else if(FileSystem.exists(moddyFile2) && difficulty.toLowerCase() == null && !FileSystem.exists(moddyFile)) hasDifficultyModchart = false; 118 | 119 | #if MODS_ALLOWED 120 | if (hasDifficultyModchart) 121 | { 122 | rawJson = File.getContent(moddyFileMods).trim(); 123 | folderShit = moddyFileMods.replace('modchart-' + difficulty.toLowerCase() + '.json', "customMods/"); 124 | 125 | trace('${difficulty} Modchart Found In Mods! loading modchart-${difficulty.toLowerCase()}.json'); 126 | } 127 | else 128 | { 129 | rawJson = File.getContent(moddyFileMods2).trim(); 130 | folderShit = moddyFileMods2.replace('modchart.json', "customMods/"); 131 | 132 | trace('${difficulty} Modchart Has Not Been Found In Mods! loading modchart.json'); 133 | } 134 | #end 135 | 136 | if (hasDifficultyModchart) 137 | { 138 | rawJson = File.getContent(moddyFile).trim(); 139 | folderShit = moddyFile.replace('modchart-' + difficulty.toLowerCase() + '.json', "customMods/"); 140 | 141 | trace('${difficulty} Modchart Found! loading modchart-${difficulty.toLowerCase()}.json'); 142 | } 143 | else 144 | { 145 | rawJson = File.getContent(moddyFile2).trim(); 146 | folderShit = moddyFile2.replace('modchart.json', "customMods/"); 147 | 148 | trace('${difficulty} Modchart Has Not Been Found! loading modchart.json'); 149 | } 150 | #else 151 | #if MODS_ALLOWED 152 | if(Assets.exists(moddyFileMods) && difficulty.toLowerCase() != null) 153 | hasDifficultyModchart = true; 154 | if (Assets.exists(moddyFileMods2) && !Assets.exists(moddyFileMods)) 155 | hasDifficultyModchart = false; 156 | else if(Assets.exists(moddyFileMods2) && difficulty.toLowerCase() == null && !Assets.exists(moddyFileMods)) hasDifficultyModchart = false; 157 | #end 158 | 159 | if(Assets.exists(moddyFile) && difficulty.toLowerCase() != null) 160 | hasDifficultyModchart = true; 161 | if (Assets.exists(moddyFile) && !Assets.exists(moddyFile)) 162 | hasDifficultyModchart = false; 163 | else if(Assets.exists(moddyFile2) && difficulty.toLowerCase() == null && !Assets.exists(moddyFile)) hasDifficultyModchart = false; 164 | 165 | #if MODS_ALLOWED 166 | if (hasDifficultyModchart) 167 | { 168 | rawJson = File.getContent(moddyFileMods).trim(); 169 | folderShit = moddyFileMods.replace('modchart-' + difficulty.toLowerCase() + '.json', "customMods/"); 170 | 171 | trace('${difficulty} Modchart Found In Mods! loading modchart-${difficulty.toLowerCase()}.json'); 172 | } 173 | else 174 | { 175 | rawJson = File.getContent(moddyFileMods2).trim(); 176 | folderShit = moddyFileMods2.replace('modchart.json', "customMods/"); 177 | 178 | trace('${difficulty} Modchart Has Not Been Found In Mods! loading modchart.json'); 179 | } 180 | #end 181 | 182 | if (hasDifficultyModchart) 183 | { 184 | rawJson = File.getContent(moddyFile).trim(); 185 | folderShit = moddyFile.replace('modchart-' + difficulty.toLowerCase() + '.json', "customMods/"); 186 | 187 | trace('${difficulty} Modchart Found! loading modchart-${difficulty.toLowerCase()}.json'); 188 | } 189 | else 190 | { 191 | rawJson = File.getContent(moddyFile2).trim(); 192 | folderShit = moddyFile2.replace('modchart.json', "customMods/"); 193 | 194 | trace('${difficulty} Modchart Has Not Been Found! loading modchart.json'); 195 | } 196 | #end 197 | } 198 | catch(e:Dynamic) 199 | { 200 | trace(e); 201 | } 202 | #end 203 | 204 | if (rawJson == null) 205 | { 206 | try 207 | { 208 | #if MODS_ALLOWED 209 | if (hasDifficultyModchart) 210 | { 211 | 212 | #if LEATHER 213 | filePath = Paths.json("song data/" + folder + '/modchart-' + difficulty.toLowerCase()); 214 | folderShit = PolymodAssets.getPath(filePath.replace('modchart-' + difficulty.toLowerCase() + '.json', "customMods/")); 215 | #else 216 | filePath = Paths.modsJson(folder + '/modchart-' + difficulty.toLowerCase()); 217 | folderShit = filePath.replace('modchart-' + difficulty.toLowerCase() + '.json', "customMods/"); 218 | #end 219 | 220 | trace('${difficulty} Modchart FolderShit Found In Mods! loading modchart-${difficulty.toLowerCase()}.json'); 221 | } 222 | else 223 | { 224 | #if LEATHER 225 | filePath = Paths.json("song data/" + folder + '/modchart'); 226 | folderShit = PolymodAssets.getPath(filePath.replace('modchart.json', "customMods/")); 227 | #else 228 | filePath = Paths.modsJson(folder + '/modchart'); 229 | folderShit = filePath.replace('modchart.json', "customMods/"); 230 | #end 231 | 232 | trace('${difficulty} Modchart Has No FolderShit Found In Mods! loading modchart.json'); 233 | } 234 | #end 235 | 236 | 237 | if (hasDifficultyModchart) 238 | { 239 | #if LEATHER 240 | filePath = Paths.json("song data/" + folder + '/modchart-' + difficulty.toLowerCase()); 241 | folderShit = PolymodAssets.getPath(filePath.replace('modchart-' + difficulty.toLowerCase() + '.json', "customMods/")); 242 | #else 243 | filePath = Paths.json(folder + '/modchart-' + difficulty.toLowerCase()); 244 | folderShit = filePath.replace('modchart-' + difficulty.toLowerCase() + '.json', "customMods/"); 245 | #end 246 | 247 | trace('${difficulty} Modchart FolderShit Found! loading modchart-${difficulty.toLowerCase()}.json'); 248 | } 249 | else 250 | { 251 | #if LEATHER 252 | filePath = Paths.json("song data/" + folder + '/modchart'); 253 | folderShit = PolymodAssets.getPath(filePath.replace('modchart.json', "customMods/")); 254 | #else 255 | filePath = Paths.json(folder + '/modchart'); 256 | folderShit = filePath.replace('modchart.json', "customMods/"); 257 | #end 258 | 259 | trace('${difficulty} Modchart Has No FolderShit Found! loading modchart.json'); 260 | } 261 | } 262 | catch(e:Dynamic) 263 | { 264 | trace(e); 265 | } 266 | 267 | trace(filePath); 268 | #if sys 269 | if(FileSystem.exists(filePath)) 270 | rawJson = File.getContent(filePath).trim(); 271 | else #end //should become else if i think??? 272 | if (Assets.exists(filePath)) 273 | rawJson = Assets.getText(filePath).trim(); 274 | 275 | } 276 | var json:ModchartJson = null; 277 | if (rawJson != null) 278 | { 279 | for (i in 0...difficulty.length) 280 | json = cast Json.parse(rawJson); 281 | trace('loaded json'); 282 | trace(folderShit); 283 | 284 | #if (hscript && sys) 285 | if (FileSystem.isDirectory(folderShit)) 286 | { 287 | trace("folder le exists"); 288 | for (file in FileSystem.readDirectory(folderShit)) 289 | { 290 | trace(file); 291 | if(file.endsWith('.hx')) //custom mods!!!! 292 | { 293 | var scriptStr = File.getContent(folderShit + file); 294 | var scriptInit:Dynamic = null; 295 | scriptInit = #if (HSCRIPT_ALLOWED && PSYCH && PSYCHVERSION >= "0.7") new FunkinHScript(null, scriptStr) #else new CustomModifierScript(scriptStr) #end; 296 | customModifiers.set(file.replace(".hx", ""), scriptInit); 297 | trace('loaded custom mod: ' + file); 298 | } 299 | } 300 | } 301 | #end 302 | } 303 | else 304 | { 305 | json = {modifiers: [], events: [], playfields: 1}; 306 | } 307 | return json; 308 | } 309 | public function loadEmpty() 310 | { 311 | data.modifiers = []; 312 | data.events = []; 313 | data.playfields = 1; 314 | } 315 | 316 | public function loadModifiers() 317 | { 318 | if (data == null || renderer == null) 319 | return; 320 | renderer.modifierTable.clear(); 321 | for (i in data.modifiers) 322 | { 323 | ModchartFuncs.startMod(i[MOD_NAME], i[MOD_CLASS], i[MOD_TYPE], Std.parseInt(i[MOD_PF]), renderer.instance); 324 | if (i[MOD_LANE] != null) 325 | ModchartFuncs.setModTargetLane(i[MOD_NAME], i[MOD_LANE], renderer.instance); 326 | } 327 | renderer.modifierTable.reconstructTable(); 328 | } 329 | public function loadPlayfields() 330 | { 331 | if (data == null || renderer == null) 332 | return; 333 | 334 | renderer.playfields = []; 335 | for (i in 0...data.playfields) 336 | renderer.addNewPlayfield(0,0,0,1); 337 | } 338 | public function loadEvents() 339 | { 340 | if (data == null || renderer == null) 341 | return; 342 | renderer.eventManager.clearEvents(); 343 | for (i in data.events) 344 | { 345 | if (i[EVENT_REPEAT] == null) //add repeat data if it doesnt exist 346 | i[EVENT_REPEAT] = [false, 1, 0]; 347 | 348 | if (i[EVENT_REPEAT][EVENT_REPEATBOOL]) 349 | { 350 | for (j in 0...(Std.int(i[EVENT_REPEAT][EVENT_REPEATCOUNT])+1)) 351 | { 352 | addEvent(i, (j*i[EVENT_REPEAT][EVENT_REPEATBEATGAP])); 353 | } 354 | } 355 | else 356 | { 357 | addEvent(i); 358 | } 359 | 360 | } 361 | } 362 | private function addEvent(i:Array, ?beatOffset:Float = 0) 363 | { 364 | switch(i[EVENT_TYPE]) 365 | { 366 | case "ease": 367 | ModchartFuncs.ease(Std.parseFloat(i[EVENT_DATA][EVENT_TIME])+beatOffset, Std.parseFloat(i[EVENT_DATA][EVENT_EASETIME]), i[EVENT_DATA][EVENT_EASE], i[EVENT_DATA][EVENT_EASEDATA], renderer.instance); 368 | case "set": 369 | ModchartFuncs.set(Std.parseFloat(i[EVENT_DATA][EVENT_TIME])+beatOffset, i[EVENT_DATA][EVENT_SETDATA], renderer.instance); 370 | case "hscript": 371 | //maybe just run some code??? 372 | } 373 | } 374 | 375 | public function createDataFromRenderer() //a way to convert script modcharts into json modcharts 376 | { 377 | if (renderer == null) 378 | return; 379 | 380 | data.playfields = renderer.playfields.length; 381 | scriptListen = true; 382 | } 383 | } 384 | 385 | #if hscript 386 | class CustomModifierScript 387 | { 388 | public var interp:Interp = null; 389 | var script:Expr; 390 | var parser:Parser; 391 | public function new(scriptStr:String) 392 | { 393 | parser = new Parser(); 394 | parser.allowTypes = true; 395 | parser.allowMetadata = true; 396 | parser.allowJSON = true; 397 | 398 | try 399 | { 400 | interp = new Interp(); 401 | script = parser.parseString(scriptStr); //load da shit 402 | interp.execute(script); 403 | } 404 | catch(e) 405 | { 406 | lime.app.Application.current.window.alert(e.message, 'Error on custom mod .hx!'); 407 | return; 408 | } 409 | init(); 410 | } 411 | private function init() 412 | { 413 | if (interp == null) 414 | return; 415 | 416 | #if LEATHER 417 | interp.variables.set('mod', Modifier); //the game crashes without this???????? what??????????? -- fue glow 418 | #end 419 | 420 | interp.variables.set('Math', Math); 421 | interp.variables.set('PlayfieldRenderer', PlayfieldRenderer); 422 | interp.variables.set('ModchartUtil', ModchartUtil); 423 | interp.variables.set('Modifier', Modifier); 424 | interp.variables.set('ModifierSubValue', Modifier.ModifierSubValue); 425 | interp.variables.set('BeatXModifier', Modifier.BeatXModifier); 426 | interp.variables.set('NoteMovement', NoteMovement); 427 | interp.variables.set('NotePositionData', NotePositionData); 428 | interp.variables.set('ModchartFile', ModchartFile); 429 | interp.variables.set('FlxG', flixel.FlxG); 430 | interp.variables.set('FlxSprite', flixel.FlxSprite); 431 | interp.variables.set('FlxMath', FlxMath); 432 | interp.variables.set('FlxCamera', flixel.FlxCamera); 433 | interp.variables.set('FlxTimer', flixel.util.FlxTimer); 434 | interp.variables.set('FlxTween', flixel.tweens.FlxTween); 435 | interp.variables.set('FlxEase', flixel.tweens.FlxEase); 436 | interp.variables.set('PlayState', #if (PSYCH && PSYCHVERSION >= "0.7") states.PlayState #else PlayState #end); 437 | interp.variables.set('game', #if (PSYCH && PSYCHVERSION >= "0.7") states.PlayState.instance #else PlayState.instance #end); 438 | interp.variables.set('Paths', #if (PSYCH && PSYCHVERSION >= "0.7") backend.Paths #else Paths #end); 439 | interp.variables.set('Conductor', #if (PSYCH && PSYCHVERSION >= "0.7") backend.Conductor #else Conductor #end); 440 | interp.variables.set('StringTools', StringTools); 441 | interp.variables.set('Note', #if (PSYCH && PSYCHVERSION >= "0.7") objects.Note #else Note #end); 442 | 443 | #if PSYCH 444 | interp.variables.set('ClientPrefs', #if (PSYCHVERSION >= "0.7") backend.ClientPrefs #else ClientPrefs #end); 445 | interp.variables.set('ColorSwap', #if (PSYCHVERSION >= "0.7") shaders.ColorSwap #else ColorSwap #end); 446 | #end 447 | 448 | 449 | } 450 | public function call(event:String, args:Array) 451 | { 452 | if (interp == null) 453 | return; 454 | if (interp.variables.exists(event)) //make sure it exists 455 | { 456 | try 457 | { 458 | if (args.length > 0) 459 | Reflect.callMethod(null, interp.variables.get(event), args); 460 | else 461 | interp.variables.get(event)(); //if function doesnt need an arg 462 | } 463 | catch(e) 464 | { 465 | lime.app.Application.current.window.alert(e.message, 'Error on custom mod .hx!'); 466 | } 467 | } 468 | } 469 | public function initMod(mod:Modifier) 470 | { 471 | call("initMod", [mod]); 472 | } 473 | 474 | public function destroy() 475 | { 476 | interp = null; 477 | } 478 | } 479 | #end 480 | -------------------------------------------------------------------------------- /source/modcharting/ModchartFuncs.hx: -------------------------------------------------------------------------------- 1 | package modcharting; 2 | 3 | import haxe.Json; 4 | import openfl.net.FileReference; 5 | import flixel.FlxG; 6 | #if LUA_ALLOWED 7 | import llua.Lua; 8 | import llua.LuaL; 9 | import llua.State; 10 | import llua.Convert; 11 | #end 12 | 13 | #if LEATHER 14 | import states.PlayState; 15 | import game.Conductor; 16 | #if linc_luajit 17 | import modding.ModchartUtilities; 18 | #end 19 | import modding.scripts.languages.HScript; 20 | #end 21 | 22 | #if (PSYCH && PSYCHVERSION >= "0.7") 23 | #if LUA_ALLOWED 24 | import psychlua.FunkinLua; 25 | import psychlua.HScript as FunkinHScript; 26 | #end 27 | #end 28 | 29 | import modcharting.Modifier; 30 | import modcharting.PlayfieldRenderer; 31 | import modcharting.NoteMovement; 32 | import modcharting.ModchartUtil; 33 | 34 | import openfl.events.Event; 35 | import openfl.events.IOErrorEvent; 36 | 37 | using StringTools; 38 | 39 | //for lua and hscript 40 | class ModchartFuncs 41 | { 42 | public static function loadLuaFunctions(#if (PSYCH && PSYCHVERSION >= "0.7") funkin:FunkinLua #end) 43 | { 44 | #if PSYCH 45 | #if LUA_ALLOWED 46 | #if !(PSYCHVERSION >= "0.7") 47 | for (funkin in PlayState.instance.luaArray) 48 | { 49 | #if hscript 50 | funkin.initHaxeModule(); 51 | #end 52 | #end 53 | Lua_helper.add_callback(funkin.lua, 'startMod', function(name:String, modClass:String, type:String = '', pf:Int = -1){ 54 | startMod(name,modClass,type,pf); 55 | 56 | PlayState.instance.playfieldRenderer.modifierTable.reconstructTable(); //needs to be reconstructed for lua modcharts 57 | }); 58 | Lua_helper.add_callback(funkin.lua, 'setMod', function(name:String, value:Float){ 59 | setMod(name, value); 60 | }); 61 | Lua_helper.add_callback(funkin.lua, 'setSubMod', function(name:String, subValName:String, value:Float){ 62 | setSubMod(name, subValName,value); 63 | }); 64 | Lua_helper.add_callback(funkin.lua, 'setModTargetLane', function(name:String, value:Int){ 65 | setModTargetLane(name, value); 66 | }); 67 | Lua_helper.add_callback(funkin.lua, 'setModPlayfield', function(name:String, value:Int){ 68 | setModPlayfield(name,value); 69 | }); 70 | Lua_helper.add_callback(funkin.lua, 'addPlayfield', function(?x:Float = 0, ?y:Float = 0, ?z:Float = 0){ 71 | addPlayfield(x,y,z); 72 | }); 73 | Lua_helper.add_callback(funkin.lua, 'removePlayfield', function(idx:Int){ 74 | removePlayfield(idx); 75 | }); 76 | Lua_helper.add_callback(funkin.lua, 'tweenModifier', function(modifier:String, val:Float, time:Float, ease:String, ?tag:String = null){ 77 | tweenModifier(modifier,val,time,ease,null,tag); 78 | }); 79 | Lua_helper.add_callback(funkin.lua, 'tweenModifierSubValue', function(modifier:String, subValue:String, val:Float, time:Float, ease:String, ?tag:String = null){ 80 | tweenModifierSubValue(modifier,subValue,val,time,ease,null,tag); 81 | }); 82 | Lua_helper.add_callback(funkin.lua, 'setModEaseFunc', function(name:String, ease:String){ 83 | setModEaseFunc(name,ease); 84 | }); 85 | Lua_helper.add_callback(funkin.lua, 'set', function(beat:Float, argsAsString:String){ 86 | set(beat, argsAsString); 87 | }); 88 | Lua_helper.add_callback(funkin.lua, 'ease', function(beat:Float, time:Float, easeStr:String, argsAsString:String, ?tag:String = null){ 89 | ease(beat, time, easeStr, argsAsString, null, tag); 90 | }); 91 | #if !(PSYCHVERSION >= "0.7") } #end 92 | 93 | #if (PSYCHVERSION >= "0.7") 94 | loadHaxeFunctions(funkin); 95 | #end 96 | #end 97 | #if !(PSYCHVERSION >= "0.7") 98 | #if hscript 99 | if (FunkinLua.hscript != null) 100 | { 101 | FunkinLua.hscript.variables.set('Math', Math); 102 | FunkinLua.hscript.variables.set('PlayfieldRenderer', PlayfieldRenderer); 103 | FunkinLua.hscript.variables.set('ModchartUtil', ModchartUtil); 104 | FunkinLua.hscript.variables.set('Modifier', Modifier); 105 | FunkinLua.hscript.variables.set('NoteMovement', NoteMovement); 106 | FunkinLua.hscript.variables.set('NotePositionData', NotePositionData); 107 | FunkinLua.hscript.variables.set('ModchartFile', ModchartFile); 108 | } 109 | #end 110 | #end 111 | 112 | #elseif (LEATHER && linc_luajit) 113 | @:privateAccess 114 | { 115 | ModchartUtilities.instance.setLuaFunction('startMod', function(name:String, modClass:String, type:String = '', pf:Int = -1){ 116 | startMod(name,modClass,type,pf); 117 | 118 | PlayState.instance.playfieldRenderer.modifierTable.reconstructTable(); //needs to be reconstructed for lua modcharts 119 | }); 120 | ModchartUtilities.instance.setLuaFunction('setMod', function(name:String, value:Float){ 121 | setMod(name, value); 122 | }); 123 | ModchartUtilities.instance.setLuaFunction('setSubMod', function(name:String, subValName:String, value:Float){ 124 | setSubMod(name, subValName,value); 125 | }); 126 | ModchartUtilities.instance.setLuaFunction('setModTargetLane', function(name:String, value:Int){ 127 | setModTargetLane(name, value); 128 | }); 129 | ModchartUtilities.instance.setLuaFunction('setModPlayfield', function(name:String, value:Int){ 130 | setModPlayfield(name,value); 131 | }); 132 | ModchartUtilities.instance.setLuaFunction('addPlayfield', function(?x:Float = 0, ?y:Float = 0, ?z:Float = 0){ 133 | addPlayfield(x,y,z); 134 | }); 135 | ModchartUtilities.instance.setLuaFunction('removePlayfield', function(idx:Int){ 136 | removePlayfield(idx); 137 | }); 138 | ModchartUtilities.instance.setLuaFunction('tweenModifier', function(modifier:String, val:Float, time:Float, ease:String, ?tag:String = null){ 139 | tweenModifier(modifier,val,time,ease,null,tag); 140 | }); 141 | ModchartUtilities.instance.setLuaFunction('tweenModifierSubValue', function(modifier:String, subValue:String, val:Float, time:Float, ease:String, ?tag:String = null){ 142 | tweenModifierSubValue(modifier,subValue,val,time,ease,null,tag); 143 | }); 144 | ModchartUtilities.instance.setLuaFunction('setModEaseFunc', function(name:String, ease:String){ 145 | setModEaseFunc(name,ease); 146 | }); 147 | ModchartUtilities.instance.setLuaFunction('setModifier', function(beat:Float, argsAsString:String){ 148 | set(beat, argsAsString); 149 | }); 150 | ModchartUtilities.instance.setLuaFunction('easeModifier', function(beat:Float, time:Float, easeStr:String, argsAsString:String, ?tag:String = null){ 151 | ease(beat, time, easeStr, argsAsString, null, tag); 152 | }); 153 | ModchartUtilities.instance.setLuaFunction('ease', function(beat:Float, time:Float, easeStr:String, argsAsString:String, ?tag:String = null){ 154 | ease(beat, time, easeStr, argsAsString, null, tag); 155 | }); 156 | } 157 | #end 158 | } 159 | 160 | 161 | public static function loadHaxeFunctions(#if PSYCH funkin:FunkinLua#end) 162 | { 163 | #if (PSYCH && PSYCHVERSION >= "0.7") 164 | #if HSCRIPT_ALLOWED 165 | FunkinHScript.initHaxeModule(funkin); 166 | 167 | if (funkin.hscript != null) 168 | { 169 | #if (SScript >= "6.1.80") 170 | funkin.hscript.setClass(Math); 171 | funkin.hscript.setClass(PlayfieldRenderer); 172 | funkin.hscript.setClass(ModchartUtil); 173 | funkin.hscript.setClass(Modifier); 174 | funkin.hscript.setClass(NoteMovement); 175 | funkin.hscript.setClass(NotePositionData); 176 | funkin.hscript.setClass(ModchartFile); 177 | #else 178 | funkin.hscript.set('Math', Math); 179 | funkin.hscript.set('PlayfieldRenderer', PlayfieldRenderer); 180 | funkin.hscript.set('ModchartUtil', ModchartUtil); 181 | funkin.hscript.set('Modifier', Modifier); 182 | funkin.hscript.set('NoteMovement', NoteMovement); 183 | funkin.hscript.set('NotePositionData', NotePositionData); 184 | funkin.hscript.set('ModchartFile', ModchartFile); 185 | #end 186 | } 187 | #end 188 | #elseif LEATHER 189 | /*if(flixel.FlxG.state == states.PlayState.instance){ 190 | HScript.instance.interp.variables.set('PlayfieldRenderer', PlayfieldRenderer); 191 | HScript.instance.interp.variables.set('ModchartUtil', ModchartUtil); 192 | HScript.instance.interp.variables.set('Modifier', Modifier); 193 | HScript.instance.interp.variables.set('NoteMovement', NoteMovement); 194 | HScript.instance.interp.variables.set('NotePositionData', NotePositionData); 195 | HScript.instance.interp.variables.set('ModchartFile', ModchartFile); 196 | }*/ 197 | #end 198 | } 199 | #if (HSCRIPT_ALLOWED && PSYCH && PSYCHVERSION >= "0.7") 200 | public static function loadHScriptFunctions(parent:Dynamic) 201 | { 202 | #if HSCRIPT_ALLOWED 203 | parent.set('startMod', function(name:String, modClass:String, type:String = '', pf:Int = -1){ 204 | startMod(name, modClass, type, pf); 205 | 206 | if (PlayState.instance == FlxG.state && PlayState.instance.playfieldRenderer != null) 207 | { 208 | PlayState.instance.playfieldRenderer.modifierTable.reconstructTable(); //needs to be reconstructed for lua modcharts 209 | } 210 | }); 211 | parent.set('setMod', function(name:String, value:Float){ 212 | setMod(name, value); 213 | }); 214 | parent.set('setSubMod', function(name:String, subValName:String, value:Float){ 215 | setSubMod(name, subValName,value); 216 | }); 217 | parent.set('setModTargetLane', function(name:String, value:Int){ 218 | setModTargetLane(name, value); 219 | }); 220 | parent.set('setModPlayfield', function(name:String, value:Int){ 221 | setModPlayfield(name,value); 222 | }); 223 | parent.set('addPlayfield', function(?x:Float = 0, ?y:Float = 0, ?z:Float = 0){ 224 | addPlayfield(x,y,z); 225 | }); 226 | parent.set('removePlayfield', function(idx:Int){ 227 | removePlayfield(idx); 228 | }); 229 | parent.set('tweenModifier', function(modifier:String, val:Float, time:Float, ease:String, ?tag:String = null){ 230 | tweenModifier(modifier,val,time,ease,null,tag); 231 | }); 232 | parent.set('tweenModifierSubValue', function(modifier:String, subValue:String, val:Float, time:Float, ease:String, ?tag:String = null){ 233 | tweenModifierSubValue(modifier,subValue,val,time,ease,null,tag); 234 | }); 235 | parent.set('setModEaseFunc', function(name:String, ease:String, ?tag:String = null){ 236 | setModEaseFunc(name,ease); 237 | }); 238 | parent.set('setModValue', function(beat:Float, argsAsString:String){ 239 | set(beat, argsAsString); 240 | }); 241 | parent.set('easeModValue', function(beat:Float, time:Float, easeStr:String, argsAsString:String, ?tag:String = null){ 242 | ease(beat, time, easeStr, argsAsString, null, tag); 243 | }); 244 | #end 245 | } 246 | #end 247 | 248 | public static function startMod(name:String, modClass:String, type:String = '', pf:Int = -1, ?instance:ModchartMusicBeatState = null) 249 | { 250 | if (instance == null) 251 | { 252 | instance = PlayState.instance; 253 | if (instance.playfieldRenderer.modchart != null) 254 | if (instance.playfieldRenderer.modchart.scriptListen) 255 | { 256 | instance.playfieldRenderer.modchart.data.modifiers.push([name, modClass, type, pf]); 257 | trace(name,modClass,type,pf); 258 | } 259 | } 260 | 261 | if (instance.playfieldRenderer.modchart != null) 262 | if (instance.playfieldRenderer.modchart.customModifiers.exists(modClass)) 263 | { 264 | var modifier = new Modifier(name, getModTypeFromString(type), pf); 265 | if (instance.playfieldRenderer.modchart.customModifiers.get(modClass).interp != null) 266 | instance.playfieldRenderer.modchart.customModifiers.get(modClass).interp.variables.set('instance', instance); 267 | instance.playfieldRenderer.modchart.customModifiers.get(modClass).initMod(modifier); //need to do it this way instead because using current value in the modifier script didnt work 268 | //var modifier = instance.playfieldRenderer.modchart.customModifiers.get(modClass).copy(); 269 | //modifier.tag = name; //set correct stuff because its copying shit 270 | //modifier.playfield = pf; 271 | //modifier.type = getModTypeFromString(type); 272 | instance.playfieldRenderer.modifierTable.add(modifier); 273 | return; 274 | } 275 | 276 | var mod = Type.resolveClass('modcharting.'+modClass); 277 | if (mod == null) {mod = Type.resolveClass('modcharting.'+modClass+"Modifier");} //dont need to add "Modifier" to the end of every mod 278 | 279 | if (mod != null) 280 | { 281 | var modType = getModTypeFromString(type); 282 | var modifier = Type.createInstance(mod, [name, modType, pf]); 283 | instance.playfieldRenderer.modifierTable.add(modifier); 284 | } 285 | } 286 | public static function getModTypeFromString(type:String) 287 | { 288 | var modType = ModifierType.ALL; 289 | switch (type.toLowerCase()) 290 | { 291 | case 'player': 292 | modType = ModifierType.PLAYERONLY; 293 | case 'opponent': 294 | modType = ModifierType.OPPONENTONLY; 295 | case 'lane' | 'lanespecific': 296 | modType = ModifierType.LANESPECIFIC; 297 | } 298 | return modType; 299 | } 300 | 301 | public static function setMod(name:String, value:Float, ?instance:ModchartMusicBeatState = null) 302 | { 303 | if (instance == null) 304 | instance = PlayState.instance; 305 | if (instance.playfieldRenderer.modchart != null) 306 | if (instance.playfieldRenderer.modchart.scriptListen) 307 | { 308 | instance.playfieldRenderer.modchart.data.events.push(["set", [0, value+","+name]]); 309 | } 310 | if (instance.playfieldRenderer.modifierTable.modifiers.exists(name)) 311 | instance.playfieldRenderer.modifierTable.modifiers.get(name).currentValue = value; 312 | } 313 | public static function setSubMod(name:String, subValName:String, value:Float, ?instance:ModchartMusicBeatState = null) 314 | { 315 | if (instance == null) 316 | instance = PlayState.instance; 317 | if (instance.playfieldRenderer.modchart != null) 318 | if (instance.playfieldRenderer.modchart.scriptListen) 319 | { 320 | instance.playfieldRenderer.modchart.data.events.push(["set", [0, value+","+name+":"+subValName]]); 321 | } 322 | if (instance.playfieldRenderer.modifiers.exists(name)) 323 | if (instance.playfieldRenderer.modifiers.get(name).subValues.exists(subValName)) 324 | instance.playfieldRenderer.modifiers.get(name).subValues.get(subValName).value = value; 325 | else 326 | instance.playfieldRenderer.modifiers.get(name).subValues.set(subValName,new Modifier.ModifierSubValue(value)); 327 | } 328 | public static function setModTargetLane(name:String, value:Int, ?instance:ModchartMusicBeatState = null) 329 | { 330 | if (instance == null) 331 | instance = PlayState.instance; 332 | if (instance.playfieldRenderer.modifierTable.modifiers.exists(name)) 333 | instance.playfieldRenderer.modifierTable.modifiers.get(name).targetLane = value; 334 | } 335 | public static function setModPlayfield(name:String, value:Int, ?instance:ModchartMusicBeatState = null) 336 | { 337 | if (instance == null) 338 | instance = PlayState.instance; 339 | if (instance.playfieldRenderer.modifierTable.modifiers.exists(name)) 340 | instance.playfieldRenderer.modifierTable.modifiers.get(name).playfield = value; 341 | } 342 | public static function addPlayfield(?x:Float = 0, ?y:Float = 0, ?z:Float = 0, ?instance:ModchartMusicBeatState = null) 343 | { 344 | if (instance == null) 345 | instance = PlayState.instance; 346 | instance.playfieldRenderer.addNewPlayfield(x,y,z); 347 | } 348 | public static function removePlayfield(idx:Int, ?instance:ModchartMusicBeatState = null) 349 | { 350 | if (instance == null) 351 | instance = PlayState.instance; 352 | instance.playfieldRenderer.playfields.remove(instance.playfieldRenderer.playfields[idx]); 353 | } 354 | 355 | public static function tweenModifier(modifier:String, val:Float, time:Float, ease:String, ?instance:ModchartMusicBeatState = null, ?tag:String = null) 356 | { 357 | if (instance == null) 358 | instance = PlayState.instance; 359 | instance.playfieldRenderer.modifierTable.tweenModifier(modifier, val, time, ease, Modifier.beat, tag); 360 | } 361 | 362 | public static function tweenModifierSubValue(modifier:String, subValue:String, val:Float, time:Float, ease:String, ?instance:ModchartMusicBeatState = null, ?tag:String = null) 363 | { 364 | if (instance == null) 365 | instance = PlayState.instance; 366 | instance.playfieldRenderer.modifierTable.tweenModifierSubValue(modifier, subValue, val, time, ease, Modifier.beat, tag); 367 | } 368 | 369 | public static function setModEaseFunc(name:String, ease:String, ?instance:ModchartMusicBeatState = null) 370 | { 371 | if (instance == null) 372 | instance = PlayState.instance; 373 | if (instance.playfieldRenderer.modifierTable.modifiers.exists(name)) 374 | { 375 | var mod = instance.playfieldRenderer.modifierTable.modifiers.get(name); 376 | if (Std.isOfType(mod, EaseCurveModifier)) 377 | { 378 | var temp:Dynamic = mod; 379 | var castedMod:EaseCurveModifier = temp; 380 | castedMod.setEase(ease); 381 | } 382 | } 383 | } 384 | public static function set(beat:Float, argsAsString:String, ?instance:ModchartMusicBeatState = null) 385 | { 386 | if (instance == null) 387 | { 388 | instance = PlayState.instance; 389 | if (instance.playfieldRenderer.modchart != null) 390 | if (instance.playfieldRenderer.modchart.scriptListen) 391 | { 392 | instance.playfieldRenderer.modchart.data.events.push(["set", [beat, argsAsString]]); 393 | } 394 | } 395 | var args = argsAsString.trim().replace(' ', '').split(','); 396 | 397 | instance.playfieldRenderer.eventManager.addEvent(beat, function(arguments:Array) { 398 | for (i in 0...Math.floor(arguments.length/2)) 399 | { 400 | var name:String = Std.string(arguments[1 + (i*2)]); 401 | var value:Float = Std.parseFloat(arguments[0 + (i*2)]); 402 | if(Math.isNaN(value)) 403 | value = 0; 404 | if (instance.playfieldRenderer.modifierTable.modifiers.exists(name)) 405 | { 406 | instance.playfieldRenderer.modifierTable.modifiers.get(name).currentValue = value; 407 | } 408 | else 409 | { 410 | var subModCheck = name.split(':'); 411 | if (subModCheck.length > 1) 412 | { 413 | var modName = subModCheck[0]; 414 | var subModName = subModCheck[1]; 415 | if (instance.playfieldRenderer.modifierTable.modifiers.exists(modName)) 416 | instance.playfieldRenderer.modifierTable.modifiers.get(modName).subValues.get(subModName).value = value; 417 | } 418 | } 419 | 420 | } 421 | }, args); 422 | } 423 | public static function ease(beat:Float, time:Float, ease:String, argsAsString:String, ?instance:ModchartMusicBeatState = null, ?tag:String = null):Void 424 | { 425 | if (instance == null) 426 | { 427 | instance = PlayState.instance; 428 | if (instance.playfieldRenderer.modchart != null) 429 | if (instance.playfieldRenderer.modchart.scriptListen) 430 | { 431 | instance.playfieldRenderer.modchart.data.events.push(["ease", [beat, time, ease, argsAsString, tag]]); 432 | } 433 | } 434 | 435 | if(Math.isNaN(time)) 436 | time = 1; 437 | 438 | var args = argsAsString.trim().replace(' ', '').split(','); 439 | 440 | var func = function(arguments:Array) { 441 | 442 | for (i in 0...Math.floor(arguments.length/2)) 443 | { 444 | var name:String = Std.string(arguments[1 + (i*2)]); 445 | var value:Float = Std.parseFloat(arguments[0 + (i*2)]); 446 | if(Math.isNaN(value)) 447 | value = 0; 448 | var subModCheck = name.split(':'); 449 | if (subModCheck.length > 1) 450 | { 451 | var modName = subModCheck[0]; 452 | var subModName = subModCheck[1]; 453 | //trace(subModCheck); 454 | instance.playfieldRenderer.modifierTable.tweenModifierSubValue(modName, subModName, value, time*Conductor.crochet*0.001, ease, beat, tag); 455 | } 456 | else 457 | instance.playfieldRenderer.modifierTable.tweenModifier(name, value, time*Conductor.crochet*0.001, ease, beat, tag); 458 | 459 | } 460 | }; 461 | instance.playfieldRenderer.eventManager.addEvent(beat, func, args); 462 | } 463 | 464 | } 465 | -------------------------------------------------------------------------------- /source/modcharting/ModchartMusicBeatState.hx: -------------------------------------------------------------------------------- 1 | package modcharting; 2 | 3 | import flixel.addons.ui.FlxUIState; 4 | import modcharting.*; 5 | class ModchartMusicBeatState extends FlxUIState 6 | { 7 | //just stores the renderer so instancing shit can work properly i guess 8 | public var playfieldRenderer:PlayfieldRenderer; 9 | } -------------------------------------------------------------------------------- /source/modcharting/ModchartUtil.hx: -------------------------------------------------------------------------------- 1 | package modcharting; 2 | 3 | import flixel.tweens.FlxEase; 4 | import flixel.math.FlxMath; 5 | import flixel.math.FlxAngle; 6 | import openfl.geom.Vector3D; 7 | import flixel.FlxG; 8 | 9 | #if LEATHER 10 | import states.PlayState; 11 | import game.Note; 12 | import game.Conductor; 13 | #elseif (PSYCH && PSYCHVERSION >= "0.7") 14 | import states.PlayState; 15 | import objects.Note; 16 | #else 17 | import PlayState; 18 | import Note; 19 | #end 20 | 21 | using StringTools; 22 | 23 | class ModchartUtil 24 | { 25 | public static function getDownscroll(instance:ModchartMusicBeatState) 26 | { 27 | //need to test each engine 28 | //not expecting all to work 29 | #if PSYCH 30 | #if (PSYCHVERSION >= "0.7") 31 | return ClientPrefs.downScroll; 32 | #else 33 | return ClientPrefs.data.downScroll; 34 | #end 35 | #elseif LEATHER 36 | return utilities.Options.getData("downscroll"); 37 | #elseif ANDROMEDA //dunno why youd use this on andromeda but whatever, already got its own cool modchart system 38 | return instance.currentOptions.downScroll; 39 | #elseif KADE 40 | return PlayStateChangeables.useDownscroll; 41 | #elseif FOREVER_LEGACY //forever might not work just yet because of the multiple strumgroups 42 | return Init.trueSettings.get('Downscroll'); 43 | #elseif FPSPLUS 44 | return Config.downscroll; 45 | #elseif MIC_D_UP //basically no one uses this anymore 46 | return MainVariables._variables.scroll == "down" 47 | #else 48 | return false; 49 | #end 50 | } 51 | public static function getMiddlescroll(instance:ModchartMusicBeatState) 52 | { 53 | #if PSYCH 54 | #if (PSYCHVERSION >= "0.7") 55 | return ClientPrefs.middleScroll; 56 | #else 57 | return ClientPrefs.data.middleScroll; 58 | #end 59 | #elseif LEATHER 60 | return utilities.Options.getData("middlescroll"); 61 | #else 62 | return false; 63 | #end 64 | } 65 | public static function getScrollSpeed(instance:PlayState) 66 | { 67 | if (instance == null) 68 | return PlayState.SONG.speed; 69 | 70 | #if (PSYCH || ANDROMEDA) 71 | return instance.songSpeed; 72 | #elseif LEATHER 73 | @:privateAccess 74 | return instance.speed; 75 | #elseif KADE 76 | return PlayStateChangeables.scrollSpeed == 1 ? PlayState.SONG.speed : PlayStateChangeables.scrollSpeed; 77 | #else 78 | return PlayState.SONG.speed; //most engines just use this 79 | #end 80 | } 81 | 82 | public static function getIsPixelStage(instance:ModchartMusicBeatState) 83 | { 84 | if (instance == null) 85 | return false; 86 | #if LEATHER 87 | return PlayState.SONG.ui_Skin == 'pixel'; 88 | #else 89 | return PlayState.isPixelStage; 90 | #end 91 | } 92 | 93 | public static function getNoteOffsetX(daNote:Note, instance:ModchartMusicBeatState) 94 | { 95 | #if PSYCH 96 | return daNote.offsetX; 97 | #elseif LEATHER 98 | //fuck 99 | var offset:Float = 0; 100 | 101 | var lane = daNote.noteData; 102 | if (daNote.mustPress) 103 | lane += NoteMovement.keyCount; 104 | var strum = instance.playfieldRenderer.strumGroup.members[lane]; 105 | 106 | var arrayVal = Std.string([lane, daNote.arrow_Type, daNote.isSustainNote]); 107 | 108 | if (!NoteMovement.leatherEngineOffsetStuff.exists(arrayVal)) 109 | { 110 | var tempShit:Float = 0.0; 111 | 112 | 113 | var targetX = NoteMovement.defaultStrumX[lane]; 114 | var xPos = targetX; 115 | while (Std.int(xPos + (daNote.width / 2)) != Std.int(targetX + (strum.width / 2))) 116 | { 117 | xPos += (xPos + daNote.width > targetX + strum.width ? -0.1 : 0.1); 118 | tempShit += (xPos + daNote.width > targetX + strum.width ? -0.1 : 0.1); 119 | } 120 | //trace(arrayVal); 121 | //trace(tempShit); 122 | 123 | NoteMovement.leatherEngineOffsetStuff.set(arrayVal, tempShit); 124 | } 125 | offset = NoteMovement.leatherEngineOffsetStuff.get(arrayVal); 126 | 127 | return offset; 128 | #else 129 | return (daNote.isSustainNote ? 37 : 0); //the magic number 130 | #end 131 | } 132 | 133 | static var currentFakeCrochet:Float = -1; 134 | static var lastBpm:Float = -1; 135 | 136 | public static function getFakeCrochet() 137 | { 138 | if (PlayState.SONG.bpm != lastBpm) 139 | { 140 | currentFakeCrochet = (60 / PlayState.SONG.bpm) * 1000; //only need to calculate once 141 | lastBpm = PlayState.SONG.bpm; 142 | } 143 | return currentFakeCrochet; 144 | 145 | } 146 | 147 | public static var zNear:Float = 0; 148 | public static var zFar:Float = 100; 149 | public static var defaultFOV:Float = 90; 150 | 151 | /** 152 | Converts a Vector3D to its in world coordinates using perspective math 153 | **/ 154 | public static function calculatePerspective(pos:Vector3D, FOV:Float, offsetX:Float = 0, offsetY:Float = 0) 155 | { 156 | 157 | /* math from opengl lol 158 | found from this website https://ogldev.org/www/tutorial12/tutorial12.html 159 | */ 160 | 161 | //TODO: maybe try using actual matrix??? 162 | 163 | var newz = pos.z - 1; 164 | var zRange = zNear - zFar; 165 | var tanHalfFOV = FlxMath.fastSin(FOV*0.5)/FlxMath.fastCos(FOV*0.5); //faster tan 166 | if (pos.z > 1) //if above 1000 z basically 167 | newz = 0; //should stop weird mirroring with high z values 168 | 169 | //var m00 = 1/(tanHalfFOV); 170 | //var m11 = 1/tanHalfFOV; 171 | //var m22 = (-zNear - zFar) / zRange; //isnt this just 1 lol 172 | //var m23 = 2 * zFar * zNear / zRange; 173 | //var m32 = 1; 174 | 175 | var xOffsetToCenter = pos.x - (FlxG.width*0.5); //so the perspective focuses on the center of the screen 176 | var yOffsetToCenter = pos.y - (FlxG.height*0.5); 177 | 178 | var zPerspectiveOffset = (newz+(2 * zFar * zNear / zRange)); 179 | 180 | 181 | //xOffsetToCenter += (offsetX / (1/-zPerspectiveOffset)); 182 | //yOffsetToCenter += (offsetY / (1/-zPerspectiveOffset)); 183 | xOffsetToCenter += (offsetX * -zPerspectiveOffset); 184 | yOffsetToCenter += (offsetY * -zPerspectiveOffset); 185 | 186 | var xPerspective = xOffsetToCenter*(1/tanHalfFOV); 187 | var yPerspective = yOffsetToCenter*tanHalfFOV; 188 | xPerspective /= -zPerspectiveOffset; 189 | yPerspective /= -zPerspectiveOffset; 190 | 191 | pos.x = xPerspective+(FlxG.width*0.5); //offset it back to normal 192 | pos.y = yPerspective+(FlxG.height*0.5); 193 | pos.z = zPerspectiveOffset; 194 | 195 | 196 | 197 | //pos.z -= 1; 198 | //pos = perspectiveMatrix.transformVector(pos); 199 | 200 | return pos; 201 | } 202 | /** 203 | Returns in-world 3D coordinates using polar angle, azimuthal angle and a radius. 204 | (Spherical to Cartesian) 205 | 206 | @param theta Angle used along the polar axis. 207 | @param phi Angle used along the azimuthal axis. 208 | @param radius Distance to center. 209 | **/ 210 | public static function getCartesianCoords3D(theta:Float, phi:Float, radius:Float):Vector3D 211 | { 212 | var pos:Vector3D = new Vector3D(); 213 | var rad = FlxAngle.TO_RAD; 214 | pos.x = FlxMath.fastCos(theta*rad)*FlxMath.fastSin(phi*rad); 215 | pos.y = FlxMath.fastCos(phi*rad); 216 | pos.z = FlxMath.fastSin(theta*rad)*FlxMath.fastSin(phi*rad); 217 | pos.x *= radius; 218 | pos.y *= radius; 219 | pos.z *= radius; 220 | 221 | return pos; 222 | } 223 | 224 | public static function getFlxEaseByString(?ease:String = '') { 225 | switch(ease.toLowerCase().trim()) { 226 | case 'backin': return FlxEase.backIn; 227 | case 'backinout': return FlxEase.backInOut; 228 | case 'backout': return FlxEase.backOut; 229 | case 'bouncein': return FlxEase.bounceIn; 230 | case 'bounceinout': return FlxEase.bounceInOut; 231 | case 'bounceout': return FlxEase.bounceOut; 232 | case 'circin': return FlxEase.circIn; 233 | case 'circinout': return FlxEase.circInOut; 234 | case 'circout': return FlxEase.circOut; 235 | case 'cubein': return FlxEase.cubeIn; 236 | case 'cubeinout': return FlxEase.cubeInOut; 237 | case 'cubeout': return FlxEase.cubeOut; 238 | case 'elasticin': return FlxEase.elasticIn; 239 | case 'elasticinout': return FlxEase.elasticInOut; 240 | case 'elasticout': return FlxEase.elasticOut; 241 | case 'expoin': return FlxEase.expoIn; 242 | case 'expoinout': return FlxEase.expoInOut; 243 | case 'expoout': return FlxEase.expoOut; 244 | case 'quadin': return FlxEase.quadIn; 245 | case 'quadinout': return FlxEase.quadInOut; 246 | case 'quadout': return FlxEase.quadOut; 247 | case 'quartin': return FlxEase.quartIn; 248 | case 'quartinout': return FlxEase.quartInOut; 249 | case 'quartout': return FlxEase.quartOut; 250 | case 'quintin': return FlxEase.quintIn; 251 | case 'quintinout': return FlxEase.quintInOut; 252 | case 'quintout': return FlxEase.quintOut; 253 | case 'sinein': return FlxEase.sineIn; 254 | case 'sineinout': return FlxEase.sineInOut; 255 | case 'sineout': return FlxEase.sineOut; 256 | case 'smoothstepin': return FlxEase.smoothStepIn; 257 | case 'smoothstepinout': return FlxEase.smoothStepInOut; 258 | case 'smoothstepout': return FlxEase.smoothStepInOut; 259 | case 'smootherstepin': return FlxEase.smootherStepIn; 260 | case 'smootherstepinout': return FlxEase.smootherStepInOut; 261 | case 'smootherstepout': return FlxEase.smootherStepOut; 262 | } 263 | return FlxEase.linear; 264 | } 265 | 266 | 267 | public static function getTimeFromBeat(beat:Float) 268 | { 269 | var totalTime:Float = 0; 270 | var curBpm = Conductor.bpm; 271 | if (PlayState.SONG != null) 272 | curBpm = PlayState.SONG.bpm; 273 | for (i in 0...Math.floor(beat)) 274 | { 275 | if (Conductor.bpmChangeMap.length > 0) 276 | { 277 | for (j in 0...Conductor.bpmChangeMap.length) 278 | { 279 | if (totalTime >= Conductor.bpmChangeMap[j].songTime) 280 | curBpm = Conductor.bpmChangeMap[j].bpm; 281 | } 282 | } 283 | totalTime += (60/curBpm)*1000; 284 | } 285 | 286 | var leftOverBeat = beat - Math.floor(beat); 287 | totalTime += (60/curBpm)*1000*leftOverBeat; 288 | 289 | return totalTime; 290 | } 291 | } -------------------------------------------------------------------------------- /source/modcharting/NoteMovement.hx: -------------------------------------------------------------------------------- 1 | package modcharting; 2 | 3 | #if LEATHER 4 | import states.PlayState; 5 | import game.Note; 6 | #elseif (PSYCH && PSYCHVERSION >= "0.7") 7 | import states.PlayState; 8 | import objects.Note; 9 | #else 10 | import PlayState; 11 | import Note; 12 | #end 13 | 14 | using StringTools; 15 | 16 | class NoteMovement 17 | { 18 | public static var keyCount = 4; 19 | public static var playerKeyCount = 4; 20 | public static var totalKeyCount = 8; 21 | public static var arrowScale:Float = 0.7; 22 | public static var arrowSize:Float = 112; 23 | public static var defaultStrumX:Array = []; 24 | public static var defaultStrumY:Array = []; 25 | public static var defaultSkewX:Array = []; 26 | public static var defaultSkewY:Array = []; 27 | public static var defaultScale:Array = []; 28 | public static var arrowSizes:Array = []; 29 | #if LEATHER 30 | public static var leatherEngineOffsetStuff:Map = []; 31 | #end 32 | 33 | public static function getDefaultStrumPos(game:PlayState) 34 | { 35 | defaultStrumX = []; //reset 36 | defaultStrumY = []; 37 | defaultSkewX = []; 38 | defaultSkewY = []; 39 | defaultScale = []; 40 | arrowSizes = []; 41 | keyCount = #if (LEATHER || KADE) PlayState.strumLineNotes.length-PlayState.playerStrums.length #else game.strumLineNotes.length-game.playerStrums.length #end; //base game doesnt have opponent strums as group 42 | playerKeyCount = #if (LEATHER || KADE) PlayState.playerStrums.length #else game.playerStrums.length #end; 43 | 44 | for (i in #if (LEATHER || KADE) 0...PlayState.strumLineNotes.members.length #else 0...game.strumLineNotes.members.length #end) 45 | { 46 | #if (LEATHER || KADE) 47 | var strum = PlayState.strumLineNotes.members[i]; 48 | #else 49 | var strum = game.strumLineNotes.members[i]; 50 | #end 51 | defaultSkewX.push(strum.skew.x); 52 | defaultSkewY.push(strum.skew.y); 53 | defaultStrumX.push(strum.x); 54 | defaultStrumY.push(strum.y); 55 | #if LEATHER 56 | var localKeyCount = (i < keyCount ? keyCount : playerKeyCount); 57 | var s = Std.parseFloat(game.ui_settings[0]) * (Std.parseFloat(game.ui_settings[2]) - (Std.parseFloat(game.mania_size[localKeyCount-1]))); 58 | #else 59 | var s = 0.7; 60 | #end 61 | 62 | defaultScale.push(s); 63 | arrowSizes.push(160*s); 64 | } 65 | #if LEATHER 66 | leatherEngineOffsetStuff.clear(); 67 | #end 68 | totalKeyCount = keyCount + playerKeyCount; 69 | } 70 | public static function getDefaultStrumPosEditor(game:modcharting.ModchartEditorState) 71 | { 72 | #if ((PSYCH || LEATHER) && !DISABLE_MODCHART_EDITOR) 73 | defaultStrumX = []; //reset 74 | defaultStrumY = []; 75 | defaultSkewX = []; 76 | defaultSkewY = []; 77 | defaultScale = []; 78 | arrowSizes = []; 79 | keyCount = game.strumLineNotes.length-game.playerStrums.length; //base game doesnt have opponent strums as group 80 | playerKeyCount = game.playerStrums.length; 81 | 82 | 83 | for (i in 0...game.strumLineNotes.members.length) 84 | { 85 | var strum = game.strumLineNotes.members[i]; 86 | defaultSkewX.push(strum.skew.x); 87 | defaultSkewY.push(strum.skew.y); 88 | defaultStrumX.push(strum.x); 89 | defaultStrumY.push(strum.y); 90 | #if LEATHER 91 | var localKeyCount = (i < keyCount ? keyCount : playerKeyCount); 92 | var s = Std.parseFloat(game.ui_settings[0]) * (Std.parseFloat(game.ui_settings[2]) - (Std.parseFloat(game.mania_size[localKeyCount-1]))); 93 | #else 94 | var s = 0.7; 95 | #end 96 | 97 | defaultScale.push(s); 98 | arrowSizes.push(160*s); 99 | } 100 | #end 101 | #if LEATHER 102 | leatherEngineOffsetStuff.clear(); 103 | #end 104 | } 105 | public static function setNotePath(daNote:Note, lane:Int, scrollSpeed:Float, curPos:Float, noteDist:Float, incomingAngleX:Float, incomingAngleY:Float) 106 | { 107 | daNote.x = defaultStrumX[lane]; 108 | daNote.y = defaultStrumY[lane]; 109 | daNote.z = 0; 110 | 111 | var pos = ModchartUtil.getCartesianCoords3D(incomingAngleX,incomingAngleY, curPos*noteDist); 112 | daNote.y += pos.y; 113 | daNote.x += pos.x; 114 | daNote.z += pos.z; 115 | 116 | daNote.skew.x = defaultSkewX[lane]; 117 | daNote.skew.y = defaultSkewY[lane]; 118 | } 119 | 120 | public static function getLaneDiffFromCenter(lane:Int) 121 | { 122 | var col:Float = lane%4; 123 | if ((col+1) > (keyCount*0.5)) 124 | { 125 | col -= (keyCount*0.5)+1; 126 | } 127 | else 128 | { 129 | col -= (keyCount*0.5); 130 | } 131 | 132 | //col = (col-col-col); //flip pos/negative 133 | 134 | //trace(col); 135 | 136 | return col; 137 | } 138 | 139 | 140 | } 141 | 142 | -------------------------------------------------------------------------------- /source/modcharting/NotePositionData.hx: -------------------------------------------------------------------------------- 1 | package modcharting; 2 | 3 | import flixel.util.FlxDestroyUtil.IFlxDestroyable; 4 | import flixel.util.FlxPool; 5 | 6 | class NotePositionData implements IFlxDestroyable 7 | { 8 | static var pool:FlxPool = new FlxPool(NotePositionData); 9 | 10 | public var x:Float; 11 | public var y:Float; 12 | public var z:Float; 13 | public var angle:Float; 14 | public var alpha:Float; 15 | public var scaleX:Float; 16 | public var scaleY:Float; 17 | public var skewX:Float; 18 | public var skewY:Float; 19 | public var curPos:Float; 20 | public var noteDist:Float; 21 | public var lane:Int; 22 | public var index:Int; 23 | public var playfieldIndex:Int; 24 | public var isStrum:Bool; 25 | public var incomingAngleX:Float; 26 | public var incomingAngleY:Float; 27 | public var strumTime:Float; 28 | public function new() {} 29 | public function destroy() {} 30 | public static function get() : NotePositionData 31 | { 32 | return pool.get(); 33 | } 34 | 35 | public function setupStrum(x:Float, y:Float, z:Float, lane:Int, scaleX:Float, scaleY:Float, skewX:Float, skewY:Float, pf:Int) 36 | { 37 | this.x = x; 38 | this.y = y; 39 | this.z = z; 40 | this.angle = 0; 41 | this.alpha = 1; 42 | this.scaleX = scaleX; 43 | this.scaleY = scaleY; 44 | this.skewX = skewX; 45 | this.skewY = skewY; 46 | this.index = lane; 47 | this.playfieldIndex = pf; 48 | this.lane = lane; 49 | this.curPos = 0; 50 | this.noteDist = 0; 51 | this.isStrum = true; 52 | this.incomingAngleX = 0; 53 | this.incomingAngleY = 0; 54 | this.strumTime = 0; 55 | } 56 | 57 | public function setupNote(x:Float, y:Float, z:Float, lane:Int, scaleX:Float, scaleY:Float, skewX:Float, skewY:Float, pf:Int, alpha:Float, curPos:Float, noteDist:Float, iaX:Float, iaY:Float, strumTime:Float, index:Int) 58 | { 59 | this.x = x; 60 | this.y = y; 61 | this.z = z; 62 | this.angle = 0; 63 | this.alpha = alpha; 64 | this.scaleX = scaleX; 65 | this.scaleY = scaleY; 66 | this.skewX = skewX; 67 | this.skewY = skewY; 68 | this.index = index; 69 | this.playfieldIndex = pf; 70 | this.lane = lane; 71 | this.curPos = curPos; 72 | this.noteDist = noteDist; 73 | this.isStrum = false; 74 | this.incomingAngleX = iaX; 75 | this.incomingAngleY = iaY; 76 | this.strumTime = strumTime; 77 | } 78 | } -------------------------------------------------------------------------------- /source/modcharting/Playfield.hx: -------------------------------------------------------------------------------- 1 | package modcharting; 2 | 3 | class Playfield 4 | { 5 | public var x:Float = 0; 6 | public var y:Float = 0; 7 | public var z:Float = 0; 8 | public var alpha:Float = 1; 9 | 10 | public function new(x:Float = 0, y:Float = 0, z:Float = 0, alpha:Float = 1) 11 | { 12 | this.x = x; 13 | this.y = y; 14 | this.z = z; 15 | this.alpha = alpha; 16 | } 17 | 18 | public function applyOffsets(noteData:NotePositionData) 19 | { 20 | noteData.x += x; 21 | noteData.y += y; 22 | noteData.z += z; 23 | noteData.alpha *= alpha; 24 | } 25 | } -------------------------------------------------------------------------------- /source/modcharting/PlayfieldRenderer.hx: -------------------------------------------------------------------------------- 1 | package modcharting; 2 | 3 | import flixel.tweens.misc.BezierPathTween; 4 | import flixel.tweens.misc.BezierPathNumTween; 5 | import flixel.util.FlxTimer.FlxTimerManager; 6 | import flixel.math.FlxMath; 7 | import flixel.tweens.FlxTween; 8 | import flixel.tweens.FlxEase; 9 | import flixel.graphics.FlxGraphic; 10 | import flixel.util.FlxColor; 11 | import flixel.FlxStrip; 12 | import flixel.graphics.tile.FlxDrawTrianglesItem.DrawData; 13 | import openfl.geom.Vector3D; 14 | import flixel.util.FlxSpriteUtil; 15 | import flixel.graphics.frames.FlxFrame; 16 | import flixel.group.FlxGroup.FlxTypedGroup; 17 | import flixel.FlxSprite; 18 | 19 | import flixel.FlxG; 20 | import modcharting.Modifier; 21 | import managers.*; 22 | import flixel.system.FlxAssets.FlxShader; 23 | import managers.TweenManager; 24 | 25 | #if LEATHER 26 | import states.PlayState; 27 | import game.Note; 28 | import game.StrumNote; 29 | import game.Conductor; 30 | #elseif (PSYCH && PSYCHVERSION >= "0.7") 31 | import states.PlayState; 32 | import objects.Note; 33 | import objects.StrumNote; 34 | #else 35 | import PlayState; 36 | import Note; 37 | import StrumNote; 38 | #end 39 | 40 | using StringTools; 41 | 42 | //a few todos im gonna leave here: 43 | 44 | //setup quaternions for everything else (incoming angles and the rotate mod) 45 | //do add and remove buttons on stacked events in editor 46 | //fix switching event type in editor so you can actually do set events 47 | //finish setting up tooltips in editor 48 | //start documenting more stuff idk 49 | 50 | typedef StrumNoteType = 51 | #if (PSYCH || LEATHER) StrumNote 52 | #elseif KADE StaticArrow 53 | #elseif FOREVER_LEGACY UIStaticArrow 54 | #elseif ANDROMEDA Receptor 55 | #else FlxSprite #end; 56 | 57 | class PlayfieldRenderer extends FlxSprite //extending flxsprite just so i can edit draw 58 | { 59 | public var strumGroup:FlxTypedGroup; 60 | public var notes:FlxTypedGroup; 61 | public var instance:ModchartMusicBeatState; 62 | public var playStateInstance:PlayState; 63 | public var playfields:Array = []; //adding an extra playfield will add 1 for each player 64 | 65 | public var eventManager:ModchartEventManager; 66 | public var modifierTable:ModTable; 67 | public var tweenManager:TweenManager = null; 68 | public var timerManager:FlxTimerManager = null; 69 | 70 | public var modchart:ModchartFile; 71 | public var inEditor:Bool = false; 72 | public var editorPaused:Bool = false; 73 | 74 | public var speed:Float = 1.0; 75 | 76 | public var modifiers(get, default):Map; 77 | 78 | private function get_modifiers() : Map 79 | { 80 | return modifierTable.modifiers; //back compat with lua modcharts 81 | } 82 | 83 | 84 | public function new(strumGroup:FlxTypedGroup, notes:FlxTypedGroup,instance:ModchartMusicBeatState) 85 | { 86 | super(0,0); 87 | this.strumGroup = strumGroup; 88 | this.notes = notes; 89 | this.instance = instance; 90 | if (Std.isOfType(instance, PlayState)) 91 | playStateInstance = cast instance; //so it just casts once 92 | 93 | strumGroup.visible = false; //drawing with renderer instead 94 | notes.visible = false; 95 | 96 | //fix stupid crash because the renderer in playstate is still technically null at this point and its needed for json loading 97 | instance.playfieldRenderer = this; 98 | 99 | tweenManager = new TweenManager(); 100 | timerManager = new FlxTimerManager(); 101 | eventManager = new ModchartEventManager(this); 102 | modifierTable = new ModTable(instance, this); 103 | addNewPlayfield(0,0,0); 104 | modchart = new ModchartFile(this); 105 | } 106 | 107 | 108 | public function addNewPlayfield(?x:Float = 0, ?y:Float = 0, ?z:Float = 0, ?alpha:Float = 1) 109 | { 110 | playfields.push(new Playfield(x,y,z,alpha)); 111 | } 112 | 113 | override function update(elapsed:Float) 114 | { 115 | try { 116 | eventManager.update(elapsed); 117 | tweenManager.update(elapsed); //should be automatically paused when you pause in game 118 | timerManager.update(elapsed); 119 | } catch(e) { 120 | trace(e); 121 | } 122 | super.update(elapsed); 123 | } 124 | 125 | 126 | override public function draw() 127 | { 128 | if (alpha == 0 || !visible) 129 | return; 130 | 131 | strumGroup.cameras = this.cameras; 132 | notes.cameras = this.cameras; 133 | 134 | try { 135 | drawStuff(getNotePositions()); 136 | } catch(e) { 137 | trace(e); 138 | } 139 | //draw notes to screen 140 | } 141 | 142 | 143 | private function addDataToStrum(strumData:NotePositionData, strum:StrumNoteType) 144 | { 145 | strum.x = strumData.x; 146 | strum.y = strumData.y; 147 | //Add Z to your strumNoteType if you want it youself! 148 | //strum.z = strumData.z; 149 | strum.angle = strumData.angle; 150 | strum.alpha = strumData.alpha; 151 | strum.scale.x = strumData.scaleX; 152 | strum.scale.y = strumData.scaleY; 153 | strum.skew.x = strumData.skewX; 154 | strum.skew.y = strumData.skewY; 155 | } 156 | 157 | private function getDataForStrum(i:Int, pf:Int) 158 | { 159 | var strumX = NoteMovement.defaultStrumX[i]; 160 | var strumY = NoteMovement.defaultStrumY[i]; 161 | var strumZ = 0; 162 | var strumScaleX = NoteMovement.defaultScale[i]; 163 | var strumScaleY = NoteMovement.defaultScale[i]; 164 | var strumSkewX = NoteMovement.defaultSkewX[i]; 165 | var strumSkewY = NoteMovement.defaultSkewY[i]; 166 | if (ModchartUtil.getIsPixelStage(instance)) 167 | { 168 | //work on pixel stages 169 | strumScaleX = 1*PlayState.daPixelZoom; 170 | strumScaleY = 1*PlayState.daPixelZoom; 171 | } 172 | var strumData:NotePositionData = NotePositionData.get(); 173 | strumData.setupStrum(strumX, strumY, strumZ, i, strumScaleX, strumScaleY, strumSkewX, strumSkewY, pf); 174 | playfields[pf].applyOffsets(strumData); 175 | modifierTable.applyStrumMods(strumData, i, pf); 176 | return strumData; 177 | } 178 | 179 | 180 | 181 | private function addDataToNote(noteData:NotePositionData, daNote:Note) 182 | { 183 | daNote.x = noteData.x; 184 | daNote.y = noteData.y; 185 | daNote.z = noteData.z; 186 | daNote.angle = noteData.angle; 187 | daNote.alpha = noteData.alpha; 188 | daNote.scale.x = noteData.scaleX; 189 | daNote.scale.y = noteData.scaleY; 190 | daNote.skew.x = noteData.skewX; 191 | daNote.skew.y = noteData.skewY; 192 | } 193 | private function createDataFromNote(noteIndex:Int, playfieldIndex:Int, curPos:Float, noteDist:Float, incomingAngle:Array) 194 | { 195 | var noteX = notes.members[noteIndex].x; 196 | var noteY = notes.members[noteIndex].y; 197 | var noteZ = notes.members[noteIndex].z; 198 | var lane = getLane(noteIndex); 199 | var noteScaleX = NoteMovement.defaultScale[lane]; 200 | var noteScaleY = NoteMovement.defaultScale[lane]; 201 | var noteSkewX = notes.members[noteIndex].skew.x; 202 | var noteSkewY = notes.members[noteIndex].skew.y; 203 | 204 | var noteAlpha:Float = #if PSYCH notes.members[noteIndex].multAlpha; #else notes.members[noteIndex].isSustainNote ? 0.6 : 1; #end 205 | 206 | if (ModchartUtil.getIsPixelStage(instance)) 207 | { 208 | //work on pixel stages 209 | noteScaleX = 1*PlayState.daPixelZoom; 210 | noteScaleY = 1*PlayState.daPixelZoom; 211 | } 212 | 213 | var noteData:NotePositionData = NotePositionData.get(); 214 | noteData.setupNote(noteX, noteY, noteZ, lane, noteScaleX, noteScaleY, noteSkewX, noteSkewY, playfieldIndex, noteAlpha, 215 | curPos, noteDist, incomingAngle[0], incomingAngle[1], notes.members[noteIndex].strumTime, noteIndex); 216 | playfields[playfieldIndex].applyOffsets(noteData); 217 | return noteData; 218 | } 219 | 220 | private function getNoteCurPos(noteIndex:Int, strumTimeOffset:Float = 0) 221 | { 222 | #if PSYCH 223 | if (notes.members[noteIndex].isSustainNote && ModchartUtil.getDownscroll(instance)) 224 | strumTimeOffset -= Std.int(Conductor.stepCrochet/getCorrectScrollSpeed()); //psych does this to fix its sustains but that breaks the visuals so basically reverse it back to normal 225 | #else 226 | if (notes.members[noteIndex].isSustainNote && !ModchartUtil.getDownscroll(instance)) 227 | strumTimeOffset += Conductor.stepCrochet; //fix upscroll lol 228 | #end 229 | var distance = (Conductor.songPosition - notes.members[noteIndex].strumTime) + strumTimeOffset; 230 | return distance*getCorrectScrollSpeed(); 231 | } 232 | private function getLane(noteIndex:Int) 233 | { 234 | return (notes.members[noteIndex].mustPress ? notes.members[noteIndex].noteData+NoteMovement.keyCount : notes.members[noteIndex].noteData); 235 | } 236 | private function getNoteDist(noteIndex:Int) 237 | { 238 | var noteDist = -0.45; 239 | if (ModchartUtil.getDownscroll(instance)) 240 | noteDist *= -1; 241 | return noteDist; 242 | } 243 | 244 | 245 | private function getNotePositions() 246 | { 247 | var notePositions:Array = []; 248 | for (pf in 0...playfields.length) 249 | { 250 | for (i in 0...strumGroup.members.length) 251 | { 252 | var strumData = getDataForStrum(i, pf); 253 | notePositions.push(strumData); 254 | } 255 | for (i in 0...notes.members.length) 256 | { 257 | var songSpeed = getCorrectScrollSpeed(); 258 | 259 | var lane = getLane(i); 260 | 261 | var noteDist = getNoteDist(i); 262 | noteDist = modifierTable.applyNoteDistMods(noteDist, lane, pf); 263 | 264 | var sustainTimeThingy:Float = 0; 265 | 266 | //just causes too many issues lol, might fix it at some point 267 | /*if (notes.members[i].animation.curAnim.name.endsWith('end') && ClientPrefs.downScroll) 268 | { 269 | if (noteDist > 0) 270 | sustainTimeThingy = (NoteMovement.getFakeCrochet()/4)/2; //fix stretched sustain ends (downscroll) 271 | //else 272 | //sustainTimeThingy = (-NoteMovement.getFakeCrochet()/4)/songSpeed; 273 | }*/ 274 | 275 | var curPos = getNoteCurPos(i, sustainTimeThingy); 276 | curPos = modifierTable.applyCurPosMods(lane, curPos, pf); 277 | 278 | if ((notes.members[i].wasGoodHit || (notes.members[i].prevNote.wasGoodHit)) && curPos >= 0 && notes.members[i].isSustainNote) 279 | curPos = 0; //sustain clip 280 | 281 | var incomingAngle:Array = modifierTable.applyIncomingAngleMods(lane, curPos, pf); 282 | if (noteDist < 0) 283 | incomingAngle[0] += 180; //make it match for both scrolls 284 | 285 | //get the general note path 286 | NoteMovement.setNotePath(notes.members[i], lane, songSpeed, curPos, noteDist, incomingAngle[0], incomingAngle[1]); 287 | 288 | //save the position data 289 | var noteData = createDataFromNote(i, pf, curPos, noteDist, incomingAngle); 290 | 291 | //add offsets to data with modifiers 292 | modifierTable.applyNoteMods(noteData, lane, curPos, pf); 293 | 294 | //add position data to list 295 | notePositions.push(noteData); 296 | } 297 | } 298 | //sort by z before drawing 299 | notePositions.sort(function(a, b){ 300 | if (a.z < b.z) 301 | return -1; 302 | else if (a.z > b.z) 303 | return 1; 304 | else 305 | return 0; 306 | }); 307 | return notePositions; 308 | } 309 | 310 | private function drawStrum(noteData:NotePositionData) 311 | { 312 | if (noteData.alpha <= 0) 313 | return; 314 | var changeX:Bool = ((noteData.z > 0 || noteData.z < 0) && noteData.z != 0); 315 | var strumNote = strumGroup.members[noteData.index]; 316 | var thisNotePos = changeX ? 317 | ModchartUtil.calculatePerspective(new Vector3D(noteData.x+(strumNote.width/2), noteData.y+(strumNote.height/2), noteData.z*0.001), 318 | ModchartUtil.defaultFOV*(Math.PI/180), -(strumNote.width/2), -(strumNote.height/2)) 319 | : new Vector3D(noteData.x, noteData.y, 0); 320 | 321 | noteData.x = thisNotePos.x; 322 | noteData.y = thisNotePos.y; 323 | if (changeX) { 324 | noteData.scaleX *= (1/-thisNotePos.z); 325 | noteData.scaleY *= (1/-thisNotePos.z); 326 | } 327 | // noteData.skewX = skewX + noteData.skewX; 328 | // noteData.skewY = skewY + noteData.skewY; 329 | 330 | addDataToStrum(noteData, strumGroup.members[noteData.index]); //set position and stuff before drawing 331 | strumGroup.members[noteData.index].cameras = this.cameras; 332 | 333 | strumGroup.members[noteData.index].draw(); 334 | } 335 | private function drawNote(noteData:NotePositionData) 336 | { 337 | if (noteData.alpha <= 0) 338 | return; 339 | var changeX:Bool = ((noteData.z > 0 || noteData.z < 0) && noteData.z != 0); 340 | var daNote = notes.members[noteData.index]; 341 | var thisNotePos = changeX ? 342 | ModchartUtil.calculatePerspective(new Vector3D(noteData.x+(daNote.width/2)+ModchartUtil.getNoteOffsetX(daNote, instance), noteData.y+(daNote.height/2), noteData.z*0.001), 343 | ModchartUtil.defaultFOV*(Math.PI/180), -(daNote.width/2), -(daNote.height/2)) 344 | : new Vector3D(noteData.x, noteData.y, 0); 345 | 346 | noteData.x = thisNotePos.x; 347 | noteData.y = thisNotePos.y; 348 | if (changeX) { 349 | noteData.scaleX *= (1/-thisNotePos.z); 350 | noteData.scaleY *= (1/-thisNotePos.z); 351 | } 352 | // noteData.skewX = skewX + noteData.skewX; 353 | // noteData.skewY = skewY + noteData.skewY; 354 | //set note position using the position data 355 | addDataToNote(noteData, notes.members[noteData.index]); 356 | //make sure it draws on the correct camera 357 | notes.members[noteData.index].cameras = this.cameras; 358 | //draw it 359 | notes.members[noteData.index].draw(); 360 | } 361 | private function drawSustainNote(noteData:NotePositionData) 362 | { 363 | if (noteData.alpha <= 0) 364 | return; 365 | var daNote = notes.members[noteData.index]; 366 | if (daNote.mesh == null) 367 | daNote.mesh = new SustainStrip(daNote); 368 | 369 | daNote.mesh.scrollFactor.x = daNote.scrollFactor.x; 370 | daNote.mesh.scrollFactor.y = daNote.scrollFactor.y; 371 | daNote.alpha = noteData.alpha; 372 | daNote.mesh.alpha = daNote.alpha; 373 | 374 | var songSpeed = getCorrectScrollSpeed(); 375 | var lane = noteData.lane; 376 | 377 | //makes the sustain match the center of the parent note when at weird angles 378 | var yOffsetThingy = (NoteMovement.arrowSizes[lane]/2); 379 | 380 | var thisNotePos = ModchartUtil.calculatePerspective(new Vector3D(noteData.x+(daNote.width/2)+ModchartUtil.getNoteOffsetX(daNote, instance), noteData.y+(NoteMovement.arrowSizes[noteData.lane]/2), noteData.z*0.001), 381 | ModchartUtil.defaultFOV*(Math.PI/180), -(daNote.width/2), yOffsetThingy-(NoteMovement.arrowSizes[noteData.lane]/2)); 382 | 383 | var timeToNextSustain = ModchartUtil.getFakeCrochet()/4; 384 | if (noteData.noteDist < 0) 385 | timeToNextSustain *= -1; //weird shit that fixes upscroll lol 386 | // timeToNextSustain = -ModchartUtil.getFakeCrochet()/4; //weird shit that fixes upscroll lol 387 | 388 | #if (PSYCH && !(PSYCHVERSION >= "0.7")) 389 | var nextHalfNotePos = getSustainPoint(noteData, timeToNextSustain*0.5); 390 | var nextNotePos = getSustainPoint(noteData, timeToNextSustain); 391 | #else 392 | var nextHalfNotePos = ModchartUtil.getDownscroll(instance) ? getSustainPoint(noteData, timeToNextSustain*0.458) : getSustainPoint(noteData, timeToNextSustain*0.548); 393 | var nextNotePos = ModchartUtil.getDownscroll(instance) ? getSustainPoint(noteData, timeToNextSustain+2.2) : getSustainPoint(noteData, timeToNextSustain-2.2); 394 | #end 395 | 396 | var flipGraphic = false; 397 | 398 | // mod/bound to 360, add 360 for negative angles, mod again just in case 399 | var fixedAngY = ((noteData.incomingAngleY%360)+360)%360; 400 | 401 | var reverseClip = (fixedAngY > 90 && fixedAngY < 270); 402 | 403 | if (noteData.noteDist > 0) //downscroll 404 | { 405 | if (!ModchartUtil.getDownscroll(instance)) //fix reverse 406 | flipGraphic = true; 407 | } 408 | else 409 | { 410 | if (ModchartUtil.getDownscroll(instance)) 411 | flipGraphic = true; 412 | } 413 | //render that shit 414 | daNote.mesh.constructVertices(noteData, thisNotePos, nextHalfNotePos, nextNotePos, flipGraphic, reverseClip); 415 | 416 | daNote.mesh.cameras = this.cameras; 417 | daNote.mesh.draw(); 418 | } 419 | 420 | private function drawStuff(notePositions:Array) 421 | { 422 | for (noteData in notePositions) 423 | { 424 | if (noteData.isStrum) //draw strum 425 | drawStrum(noteData); 426 | else if (!notes.members[noteData.index].isSustainNote) //draw regular note 427 | drawNote(noteData); 428 | else{ //draw sustain 429 | #if LEATHER /*disable the funny sustains options for low-end pc lol*/if(utilities.Options.getData("optimizedModcharts")) drawNote(noteData) else #end drawSustainNote(noteData); 430 | } 431 | 432 | } 433 | } 434 | 435 | function getSustainPoint(noteData:NotePositionData, timeOffset:Float):NotePositionData 436 | { 437 | var daNote:Note = notes.members[noteData.index]; 438 | var songSpeed:Float = getCorrectScrollSpeed(); 439 | var lane:Int = noteData.lane; 440 | var pf:Int = noteData.playfieldIndex; 441 | 442 | var noteDist:Float = getNoteDist(noteData.index); 443 | var curPos:Float = getNoteCurPos(noteData.index, timeOffset); 444 | 445 | curPos = modifierTable.applyCurPosMods(lane, curPos, pf); 446 | 447 | if ((daNote.wasGoodHit || (daNote.prevNote.wasGoodHit)) && curPos >= 0) 448 | curPos = 0; 449 | noteDist = modifierTable.applyNoteDistMods(noteDist, lane, pf); 450 | var incomingAngle:Array = modifierTable.applyIncomingAngleMods(lane, curPos, pf); 451 | if (noteDist < 0) 452 | incomingAngle[0] += 180; //make it match for both scrolls 453 | //get the general note path for the next note 454 | NoteMovement.setNotePath(daNote, lane, songSpeed, curPos, noteDist, incomingAngle[0], incomingAngle[1]); 455 | //save the position data 456 | var noteData = createDataFromNote(noteData.index, pf, curPos, noteDist, incomingAngle); 457 | //add offsets to data with modifiers 458 | modifierTable.applyNoteMods(noteData, lane, curPos, pf); 459 | var yOffsetThingy = (NoteMovement.arrowSizes[lane]/2); 460 | var finalNotePos = ModchartUtil.calculatePerspective(new Vector3D(noteData.x+(daNote.width/2)+ModchartUtil.getNoteOffsetX(daNote, instance), noteData.y+(NoteMovement.arrowSizes[noteData.lane]/2), noteData.z*0.001), 461 | ModchartUtil.defaultFOV*(Math.PI/180), -(daNote.width/2), yOffsetThingy-(NoteMovement.arrowSizes[noteData.lane]/2)); 462 | 463 | noteData.x = finalNotePos.x; 464 | noteData.y = finalNotePos.y; 465 | noteData.z = finalNotePos.z; 466 | 467 | return noteData; 468 | } 469 | 470 | public function getCorrectScrollSpeed() 471 | { 472 | if (inEditor) 473 | return PlayState.SONG.speed; //just use this while in editor so the instance shit works 474 | else 475 | return ModchartUtil.getScrollSpeed(playStateInstance); 476 | return 1.0; 477 | } 478 | 479 | public function createTween(Object:Dynamic, Values:Dynamic, Duration:Float, ?Options:TweenOptions):FlxTween 480 | { 481 | var tween:FlxTween = tweenManager.tween(Object, Values, Duration, Options); 482 | tween.manager = tweenManager; 483 | return tween; 484 | } 485 | 486 | public function createTweenNum(FromValue:Float, ToValue:Float, Duration:Float = 1, ?Options:TweenOptions, ?TweenFunction:Float->Void):FlxTween 487 | { 488 | var tween:FlxTween = tweenManager.num(FromValue, ToValue, Duration, Options, TweenFunction); 489 | tween.manager = tweenManager; 490 | return tween; 491 | } 492 | 493 | public function createBezierPathTween(Object:Dynamic, Values:Dynamic, Duration:Float, ?Options:TweenOptions):FlxTween 494 | { 495 | var tween:FlxTween = tweenManager.bezierPathTween(Object, Values, Duration, Options); 496 | tween.manager = tweenManager; 497 | return tween; 498 | } 499 | 500 | public function createBezierPathNumTween(Points:Array, Duration:Float, ?Options:TweenOptions, ?TweenFunction:Float->Void):FlxTween 501 | { 502 | var tween:FlxTween = tweenManager.bezierPathNumTween(Points, Duration, Options,TweenFunction); 503 | tween.manager = tweenManager; 504 | return tween; 505 | } 506 | 507 | override public function destroy() 508 | { 509 | if (modchart != null) 510 | { 511 | #if hscript 512 | for (customMod in modchart.customModifiers) 513 | { 514 | customMod.destroy(); //make sure the interps are dead 515 | } 516 | #end 517 | } 518 | super.destroy(); 519 | } 520 | 521 | } 522 | -------------------------------------------------------------------------------- /source/modcharting/SimpleQuaternion.hx: -------------------------------------------------------------------------------- 1 | package modcharting; 2 | 3 | import flixel.math.FlxAngle; 4 | import openfl.geom.Vector3D; 5 | import flixel.math.FlxMath; 6 | 7 | typedef Quaternion = 8 | { 9 | var x:Float; 10 | var y:Float; 11 | var z:Float; 12 | var w:Float; 13 | }; 14 | //me whenthe 15 | class SimpleQuaternion 16 | { 17 | //no more gimbal lock fuck you 18 | public static function fromEuler(roll:Float, pitch:Float, yaw:Float) : Quaternion 19 | { 20 | //https://en.wikipedia.org/wiki/Conversion_between_quaternions_and_Euler_angles 21 | var cr = FlxMath.fastCos(roll * FlxAngle.TO_RAD); 22 | var sr = FlxMath.fastSin(roll * FlxAngle.TO_RAD); 23 | var cp = FlxMath.fastCos(pitch * FlxAngle.TO_RAD); 24 | var sp = FlxMath.fastSin(pitch * FlxAngle.TO_RAD); 25 | var cy = FlxMath.fastCos(yaw * FlxAngle.TO_RAD); 26 | var sy = FlxMath.fastSin(yaw * FlxAngle.TO_RAD); 27 | 28 | var q:Quaternion = {x: 0, y: 0, z: 0, w:0 }; 29 | q.w = cr * cp * cy + sr * sp * sy; 30 | q.x = sr * cp * cy - cr * sp * sy; 31 | q.y = cr * sp * cy + sr * cp * sy; 32 | q.z = cr * cp * sy - sr * sp * cy; 33 | return q; 34 | } 35 | public static function transformVector(v:Vector3D, q:Quaternion) : Vector3D 36 | { 37 | 38 | 39 | return v; 40 | } 41 | public static function normalize(q:Quaternion) : Quaternion 42 | { 43 | var length = Math.sqrt(q.w*q.w + q.x*q.x + q.y*q.y + q.z*q.z); 44 | q.w = q.w / length; 45 | q.x = q.x / length; 46 | q.y = q.y / length; 47 | q.z = q.z / length; 48 | 49 | return q; 50 | } 51 | public static function conjugate(q:Quaternion) : Quaternion 52 | { 53 | q.y = -q.y; 54 | q.z = -q.z; 55 | q.w = -q.w; 56 | return q; 57 | } 58 | public static function multiply(q1:Quaternion, q2:Quaternion) : Quaternion 59 | { 60 | var x = q1.x * q2.x - q1.y * q2.y - q1.z * q2.z - q1.w * q2.w; 61 | var y = q1.x * q2.y + q1.y * q2.x + q1.z * q2.w - q1.w * q2.z; 62 | var z = q1.x * q2.z - q1.y * q2.w + q1.z * q2.x + q1.w * q2.y; 63 | var w = q1.x * q2.w + q1.y * q2.z - q1.z * q2.y + q1.w * q2.x; 64 | 65 | q1.x = x; 66 | q1.y = y; 67 | q1.z = z; 68 | q1.w = w; 69 | 70 | return q1; 71 | } 72 | } -------------------------------------------------------------------------------- /source/modcharting/SustainStrip.hx: -------------------------------------------------------------------------------- 1 | package modcharting; 2 | 3 | import flixel.graphics.tile.FlxDrawTrianglesItem.DrawData; 4 | import openfl.geom.Vector3D; 5 | #if LEATHER 6 | import game.Note; 7 | #elseif (PSYCH && PSYCHVERSION >= "0.7") 8 | import objects.Note; 9 | #else 10 | import Note; 11 | #end 12 | import flixel.FlxStrip; 13 | 14 | class SustainStrip extends FlxStrip 15 | { 16 | private static final noteUV:Array = [ 17 | 0,0, //top left 18 | 1,0, //top right 19 | 0,0.5, //half left 20 | 1,0.5, //half right 21 | 0,1, //bottom left 22 | 1,1, //bottom right 23 | ]; 24 | private static final noteIndices:Array = [ 25 | 0,1,2,1,3,2, 2,3,4,3,4,5 26 | //makes 4 triangles 27 | ]; 28 | 29 | private var daNote:Note; 30 | 31 | override public function new(daNote:Note) 32 | { 33 | this.daNote = daNote; 34 | daNote.alpha = 1; 35 | super(0,0); 36 | loadGraphic(daNote.updateFramePixels()); 37 | shader = daNote.shader; 38 | for (uv in noteUV) 39 | { 40 | uvtData.push(uv); 41 | vertices.push(0); 42 | } 43 | for (ind in noteIndices) 44 | indices.push(ind); 45 | } 46 | 47 | public function constructVertices(noteData:NotePositionData, thisNotePos:Vector3D, nextHalfNotePos:NotePositionData, nextNotePos:NotePositionData, flipGraphic:Bool, reverseClip:Bool) 48 | { 49 | var yOffset = -1; //fix small gaps 50 | if (reverseClip) 51 | yOffset *= -1; 52 | 53 | var verts:Array = []; 54 | if (flipGraphic) 55 | { 56 | verts.push(nextNotePos.x); 57 | verts.push(nextNotePos.y); //slight offset to fix small gaps 58 | verts.push(nextNotePos.x+(daNote.frameWidth*(1/-nextNotePos.z)*noteData.scaleX)); 59 | verts.push(nextNotePos.y); 60 | 61 | verts.push(nextHalfNotePos.x); 62 | verts.push(nextHalfNotePos.y); 63 | verts.push(nextHalfNotePos.x+(daNote.frameWidth*(1/-nextHalfNotePos.z)*noteData.scaleX)); 64 | verts.push(nextHalfNotePos.y); 65 | 66 | verts.push(thisNotePos.x); 67 | verts.push(thisNotePos.y); 68 | verts.push(thisNotePos.x+(daNote.frameWidth*(1/-thisNotePos.z)*nextNotePos.scaleX)); 69 | verts.push(thisNotePos.y); 70 | } 71 | else 72 | { 73 | verts.push(thisNotePos.x); 74 | verts.push(thisNotePos.y); //fliped this with the down ones (last) to test if it bugs of it fixes itself 75 | verts.push(thisNotePos.x+(daNote.frameWidth*(1/-thisNotePos.z)*noteData.scaleX)); 76 | verts.push(thisNotePos.y); 77 | 78 | verts.push(nextHalfNotePos.x); 79 | verts.push(nextHalfNotePos.y); 80 | verts.push(nextHalfNotePos.x+(daNote.frameWidth*(1/-nextHalfNotePos.z)*noteData.scaleX)); 81 | verts.push(nextHalfNotePos.y); 82 | 83 | verts.push(nextNotePos.x); 84 | verts.push(nextNotePos.y); //slight offset to fix small gaps 85 | verts.push(nextNotePos.x+(daNote.frameWidth*(1/-nextNotePos.z)*nextNotePos.scaleX)); 86 | verts.push(nextNotePos.y); 87 | } 88 | vertices = new DrawData(12, true, verts); 89 | } 90 | } --------------------------------------------------------------------------------