diff --git a/.github/workflows/Android Buildyml b/.github/workflows/Android Buildyml new file mode 100644 index 00000000000..8d40311097a --- /dev/null +++ b/.github/workflows/Android Buildyml @@ -0,0 +1,80 @@ +# This is a basic workflow to help you get started with Actions + +name: Android Build CI + +# Controls when the workflow will run +on: [push, pull_request, workflow_dispatch] + +# A workflow run is made up of one or more jobs that can run sequentially or in parallel +jobs: + # This workflow contains a single job called "build" + build: + # The type of runner that the job will run on + runs-on: ubuntu-latest + + # Steps represent a sequence of tasks that will be executed as part of the job + steps: + # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it + - uses: actions/checkout@v2 + - uses: krdlab/setup-haxe@v1 + with: + haxe-version: 4.2.3 + + - name: Cache haxelib path + uses: actions/cache@v2 + with: + path: | + %HAXELIB_ROOT% + key: ${{ runner.os }}-android + + - name: Setup Android SDK Tools + uses: android-actions/setup-android@v2.0.2 + + - name: Setup Java JDK + uses: actions/setup-java@v2.3.1 + with: + distribution: 'zulu' + java-version: '11' + + - uses: nttld/setup-ndk@v1 + with: + ndk-version: r20b + + # Runs a set of commands using the runners shell + - name: script run line haha + run: | + mkdir -p "%HAXELIB_ROOT%" + haxelib setup "%HAXELIB_ROOT%" + haxelib install lime 7.9.0 --quiet + haxelib install openfl --quiet + haxelib install flixel 4.9.0 --quiet + haxelib install hxcpp --quiet + haxelib run lime setup + haxelib run lime config ANDROID_SDK $ANDROID_SDK_ROOT + haxelib run lime config ANDROID_NDK_ROOT $ANDROID_NDK_ROOT + haxelib run lime config JAVA_HOME $JAVA_HOME + haxelib run lime config ANDROID_SETUP true + haxelib install flixel-tools --quiet + haxelib install flixel-ui --quiet + haxelib install flixel-addons 2.10.0 --quiet + haxelib install hscript --quiet + haxelib git faxe https://github.com/uhrobots/faxe --quiet + haxelib git polymod https://github.com/MasterEric/polymod.git --quiet + haxelib git discord_rpc https://github.com/Aidan63/linc_discord-rpc --quiet + haxelib git extension-webm https://github.com/KlavierGayming/extension-webm --quiet + haxelib git linc_luajit https://github.com/Sirox228/linc_luajit + haxelib run lime config HXCPP_ARM64 true + haxelib run lime config HXCPP_x86 true + haxelib install actuate + haxelib run lime rebuild extension-webm android + haxelib list + + - name: Build Log + run: | + haxelib run lime setup android + haxelib run lime build android -final + + - uses: actions/upload-artifact@v2 + with: + name: Android Build + path: export/release/android/bin/app/build/outputs/apk/debug diff --git a/.github/workflows/html5.yml b/.github/workflows/html5.yml deleted file mode 100644 index bf1844688bc..00000000000 --- a/.github/workflows/html5.yml +++ /dev/null @@ -1,54 +0,0 @@ -# This is a basic workflow to help you get started with Actions - -name: HTML5 Build CI - -# Controls when the workflow will run -on: [push, pull_request] - -# A workflow run is made up of one or more jobs that can run sequentially or in parallel -jobs: - # This workflow contains a single job called "build" - build: - # The type of runner that the job will run on - runs-on: ubuntu-latest - - # Steps represent a sequence of tasks that will be executed as part of the job - steps: - # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it - - uses: actions/checkout@v2 - - uses: krdlab/setup-haxe@v1 - with: - haxe-version: 4.1.5 - # Runs a set of commands using the runners shell - - name: script run line haha - run: | - sudo add-apt-repository ppa:haxe/releases -y - sudo apt-get update - sudo apt-get install gcc-multilib g++-multilib haxe -y - mkdir "%HAXELIB_ROOT%" - haxelib setup "%HAXELIB_ROOT%" - haxelib install lime 7.9.0 - haxelib install openfl - haxelib install flixel - haxelib run lime setup flixel - haxelib run lime setup - haxelib install flixel-tools - haxelib install flixel-addons - haxelib install flixel-ui - haxelib install hscript - haxelib install flixel-addons - haxelib git faxe https://github.com/uhrobots/faxe - haxelib git polymod https://github.com/MasterEric/polymod.git - haxelib git discord_rpc https://github.com/Aidan63/linc_discord-rpc - haxelib git extension-webm https://github.com/KadeDev/extension-webm - haxelib run lime rebuild extension-webm linux - haxelib git linc_luajit https://github.com/MasterEric/linc_luajit.git - haxelib git hxvm-luajit https://github.com/nebulazorua/hxvm-luajit.git - haxelib install actuate - haxelib list - haxelib run lime build html5 - - - uses: actions/upload-artifact@v2 - with: - name: HTML5 Build - path: export/release/html5/bin diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml deleted file mode 100644 index 924795d799a..00000000000 --- a/.github/workflows/linux.yml +++ /dev/null @@ -1,54 +0,0 @@ -# This is a basic workflow to help you get started with Actions - -name: Linux Build CI - -# Controls when the workflow will run -on: [push, pull_request] - -# A workflow run is made up of one or more jobs that can run sequentially or in parallel -jobs: - # This workflow contains a single job called "build" - build: - # The type of runner that the job will run on - runs-on: ubuntu-latest - - # Steps represent a sequence of tasks that will be executed as part of the job - steps: - # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it - - uses: actions/checkout@v2 - - uses: krdlab/setup-haxe@v1 - with: - haxe-version: 4.1.5 - # Runs a set of commands using the runners shell - - name: script run line haha - run: | - sudo add-apt-repository ppa:haxe/releases -y - sudo apt-get update - sudo apt-get install gcc-multilib g++-multilib haxe -y - mkdir "%HAXELIB_ROOT%" - haxelib setup "%HAXELIB_ROOT%" - haxelib install lime 7.9.0 - haxelib install openfl - haxelib install flixel - haxelib run lime setup flixel - haxelib run lime setup - haxelib install flixel-tools - haxelib install flixel-addons - haxelib install flixel-ui - haxelib install hscript - haxelib install flixel-addons - haxelib git faxe https://github.com/uhrobots/faxe - haxelib git polymod https://github.com/MasterEric/polymod.git - haxelib git discord_rpc https://github.com/Aidan63/linc_discord-rpc - haxelib git extension-webm https://github.com/KadeDev/extension-webm - haxelib run lime rebuild extension-webm linux - haxelib git linc_luajit https://github.com/MasterEric/linc_luajit.git - haxelib git hxvm-luajit https://github.com/nebulazorua/hxvm-luajit.git - haxelib install actuate - haxelib list - haxelib run lime build linux - - - uses: actions/upload-artifact@v2 - with: - name: Linux Build - path: export/release/linux/bin diff --git a/.github/workflows/staleIssue.yml b/.github/workflows/staleIssue.yml deleted file mode 100644 index af2fcd50681..00000000000 --- a/.github/workflows/staleIssue.yml +++ /dev/null @@ -1,18 +0,0 @@ -name: Close inactive issues -on: [workflow_dispatch] - -jobs: - close-issues: - runs-on: ubuntu-latest - steps: - - uses: actions/stale@v3 - with: - days-before-issue-stale: 7 - days-before-issue-close: 0 - stale-issue-label: "stale" - stale-issue-message: "This issue is stale because it has been open for 7 days with no activity." - close-issue-message: "This issue was closed because it has become stale" - days-before-pr-stale: -1 - days-before-pr-close: -1 - repo-token: ${{ secrets.GITHUB_TOKEN }} - exempt-issue-labels: false diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml deleted file mode 100644 index 93a69869998..00000000000 --- a/.github/workflows/windows.yml +++ /dev/null @@ -1,54 +0,0 @@ -# This is a basic workflow to help you get started with Actions - -name: Windows Build CI - -# Controls when the workflow will run -on: [push, pull_request] - -# A workflow run is made up of one or more jobs that can run sequentially or in parallel -jobs: - # This workflow contains a single job called "build" - build: - # The type of runner that the job will run on - runs-on: windows-latest - - # Steps represent a sequence of tasks that will be executed as part of the job - steps: - # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it - - uses: actions/checkout@v2 - - uses: krdlab/setup-haxe@v1 - with: - haxe-version: 4.1.5 - # Runs a set of commands using the runners shell - - name: script run line haha - run: | - cinst haxe --version 4.1.5 -y - RefreshEnv - mkdir "%HAXELIB_ROOT%" - haxelib setup "%HAXELIB_ROOT%" - haxelib install lime 7.9.0 - RefreshEnv - haxelib install openfl - haxelib install flixel - haxelib run lime setup flixel - haxelib run lime setup - haxelib install flixel-tools - haxelib install flixel-addons - haxelib install flixel-ui - haxelib install hscript - haxelib install flixel-addons - haxelib git faxe https://github.com/uhrobots/faxe - haxelib git polymod https://github.com/MasterEric/polymod.git - haxelib git discord_rpc https://github.com/Aidan63/linc_discord-rpc - haxelib git extension-webm https://github.com/KadeDev/extension-webm - haxelib run lime rebuild extension-webm windows - haxelib git linc_luajit https://github.com/nebulazorua/linc_luajit.git - haxelib git hxvm-luajit https://github.com/nebulazorua/hxvm-luajit - haxelib install actuate - haxelib list - haxelib run lime build windows - - - uses: actions/upload-artifact@v2 - with: - name: Windows Build - path: export/release/windows/bin diff --git a/Project.xml b/Project.xml index 7b87057ddaa..20c7b213b3b 100644 --- a/Project.xml +++ b/Project.xml @@ -30,6 +30,9 @@ + + + @@ -126,7 +129,7 @@ - + @@ -194,11 +197,11 @@ - + - + - + diff --git a/assets/preload/data/songs/tutorial/modchart.lua b/assets/preload/data/songs/tutorial/modchart.lua index 71a33b8a3c3..badd1f73136 100644 --- a/assets/preload/data/songs/tutorial/modchart.lua +++ b/assets/preload/data/songs/tutorial/modchart.lua @@ -1,37 +1,23 @@ -function start(song) -- do nothing - spinLength = 0 +function start (song) + print("Song: " .. song .. " @ " .. bpm .. " donwscroll: " .. downscroll) end -function update(elapsed) - if difficulty == 2 and curStep > 400 then - if spinLength < 32 then - spinLength = spinLength + 0.2 +function update (elapsed) + local currentBeat = (songPos / 1000)*(bpm/60) + for i=0,7 do + setActorY(defaultStrum0Y + 10 * math.cos((currentBeat + i*0.25) * math.pi), i) end - - - local currentBeat = (songPos / 1000)*(bpm/60) - for i=0,7,1 do - local receptor = _G['receptor_'..i] - receptor.angle = (spinLength / 7) * -math.sin((currentBeat + i*0.25) * math.pi) - receptor.x = receptor.defaultX + spinLength * math.sin((currentBeat + i*0.25) * math.pi) - receptor.y = receptor.defaultY + spinLength * math.cos((currentBeat + i*0.25) * math.pi) - end - end -end - -function beatHit(beat) -- do nothing - end -function stepHit(step) -- do nothing - -end +function beatHit (beat) -function playerTwoTurn() - camGame.tweenZoom(camGame,1.3,(crochet * 4) / 1000) end -function playerOneTurn() - camGame.tweenZoom(camGame,1,(crochet * 4) / 1000) +function stepHit (step) + if curStep == 20 or curStep == 248 or curStep == 375 or curStep == 632 or curStep == 696 or curStep == 824 or curStep == 952 or curStep == 1208 then + for i = 0, 7 do + tweenPosXAngle(i, _G['defaultStrum'..i..'X'],getActorAngle(i) + 360, 0.6, 'setDefault') + end + end end \ No newline at end of file diff --git a/assets/preload/images/key_shift.png b/assets/preload/images/key_shift.png new file mode 100644 index 00000000000..bea725fbf2f Binary files /dev/null and b/assets/preload/images/key_shift.png differ diff --git a/assets/preload/images/key_space.png b/assets/preload/images/key_space.png new file mode 100644 index 00000000000..3aa0a5ed0db Binary files /dev/null and b/assets/preload/images/key_space.png differ diff --git a/assets/preload/images/virtual-input.png b/assets/preload/images/virtual-input.png new file mode 100644 index 00000000000..6199fbbf823 Binary files /dev/null and b/assets/preload/images/virtual-input.png differ diff --git a/assets/preload/images/virtual-input.txt b/assets/preload/images/virtual-input.txt new file mode 100644 index 00000000000..f2d38e28db8 --- /dev/null +++ b/assets/preload/images/virtual-input.txt @@ -0,0 +1,21 @@ +base = 798 138 252 252 +thumb = 798 393 156 156 +a = 0 0 396 135 +b = 0 138 396 135 +c = 0 276 396 135 +down = 0 414 396 135 +left = 399 0 396 135 +right = 399 138 396 135 +up = 399 276 396 135 +x = 798 0 396 135 +y = 399 414 396 135 +6 = 0 548 396 135 +1 = 0 685 396 135 +7 = 0 821 396 135 +in = 397 547 396 135 +out = 395 682 396 135 +save = 401 820 396 135 +l = 800 682 396 135 +r = 800 820 396 135 +r2 = 0 956 396 135 +stage = 1194 0 396 135 \ No newline at end of file diff --git a/assets/shared/images/hitbox/hitbox.png b/assets/shared/images/hitbox/hitbox.png new file mode 100644 index 00000000000..79d0b2278c3 Binary files /dev/null and b/assets/shared/images/hitbox/hitbox.png differ diff --git a/assets/shared/images/hitbox/hitbox.xml b/assets/shared/images/hitbox/hitbox.xml new file mode 100644 index 00000000000..183916bfb59 --- /dev/null +++ b/assets/shared/images/hitbox/hitbox.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/assets/shared/images/hitbox/hitbox_hint.png b/assets/shared/images/hitbox/hitbox_hint.png new file mode 100644 index 00000000000..196c5c86c97 Binary files /dev/null and b/assets/shared/images/hitbox/hitbox_hint.png differ diff --git a/assets/shared/images/hitbox/hitbox_hint_old.png b/assets/shared/images/hitbox/hitbox_hint_old.png new file mode 100644 index 00000000000..98b2cd8a439 Binary files /dev/null and b/assets/shared/images/hitbox/hitbox_hint_old.png differ diff --git a/dependencies/android/build.gradle b/dependencies/android/build.gradle new file mode 100644 index 00000000000..a132abee26b --- /dev/null +++ b/dependencies/android/build.gradle @@ -0,0 +1,21 @@ +buildscript { + repositories { + jcenter() + google() + } + + dependencies { + classpath 'com.android.tools.build:gradle:::ANDROID_GRADLE_PLUGIN::' + } +} + +apply plugin: 'com.android.library' + +android { + compileSdkVersion Integer.parseInt(project.ANDROID_BUILD_SDK_VERSION) + buildToolsVersion project.ANDROID_BUILD_TOOLS_VERSION +} + +dependencies { + api project(':deps:extension-api') +} diff --git a/dependencies/android/src/main/AndroidManifest.xml b/dependencies/android/src/main/AndroidManifest.xml new file mode 100644 index 00000000000..785bf6187eb --- /dev/null +++ b/dependencies/android/src/main/AndroidManifest.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/dependencies/android/src/main/java/org/haxe/extension/Tools.java b/dependencies/android/src/main/java/org/haxe/extension/Tools.java new file mode 100644 index 00000000000..bde9e4d61dc --- /dev/null +++ b/dependencies/android/src/main/java/org/haxe/extension/Tools.java @@ -0,0 +1,155 @@ +package org.haxe.extension; + + +import android.Manifest; +import android.app.Activity; +import android.content.res.AssetManager; +import android.content.Context; +import android.content.Intent; +import android.os.Bundle; +import android.os.Handler; +import android.view.View; +import org.haxe.lime.HaxeObject; + + +/* + You can use the Android Extension class in order to hook + into the Android activity lifecycle. This is not required + for standard Java code, this is designed for when you need + deeper integration. + + You can access additional references from the Extension class, + depending on your needs: + + - Extension.assetManager (android.content.res.AssetManager) + - Extension.callbackHandler (android.os.Handler) + - Extension.mainActivity (android.app.Activity) + - Extension.mainContext (android.content.Context) + - Extension.mainView (android.view.View) + + You can also make references to static or instance methods + and properties on Java classes. These classes can be included + as single files using within your + project, or use the full Android Library Project format (such + as this example) in order to include your own AndroidManifest + data, additional dependencies, etc. + + These are also optional, though this example shows a static + function for performing a single task, like returning a value + back to Haxe from Java. +*/ +public class Tools extends Extension { + + public static int sampleMethod (int inputValue) { + + // Extension.mainActivity.requestPermissions(new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, + // 1); + + // Extension.mainActivity.finish(); + + return inputValue * 102; + } + + public static void requestPermissions (String p) { + Extension.mainActivity.requestPermissions(new String[]{p}, 1); + } + + + /** + * Called when an activity you launched exits, giving you the requestCode + * you started it with, the resultCode it returned, and any additional data + * from it. + */ + public boolean onActivityResult (int requestCode, int resultCode, Intent data) { + + return true; + + } + + /** + * Called when the activity receives th results for permission requests. + */ + public boolean onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) { + + return true; + + } + + + /** + * Called when the activity is starting. + */ + public void onCreate (Bundle savedInstanceState) { + + + + } + + + /** + * Perform any final cleanup before an activity is destroyed. + */ + public void onDestroy () { + + + + } + + + /** + * Called as part of the activity lifecycle when an activity is going into + * the background, but has not (yet) been killed. + */ + public void onPause () { + + + + } + + + /** + * Called after {@link #onStop} when the current activity is being + * re-displayed to the user (the user has navigated back to it). + */ + public void onRestart () { + + + + } + + + /** + * Called after {@link #onRestart}, or {@link #onPause}, for your activity + * to start interacting with the user. + */ + public void onResume () { + + + + } + + + /** + * Called after {@link #onCreate} — or after {@link #onRestart} when + * the activity had been stopped, but is now again being displayed to the + * user. + */ + public void onStart () { + + + + } + + + /** + * Called when the activity is no longer visible to the user, because + * another activity has been resumed and is covering this one. + */ + public void onStop () { + + + + } + + +} \ No newline at end of file diff --git a/source/AnimationDebug.hx b/source/AnimationDebug.hx index 4d1bedfd8b4..10c4bc064b1 100644 --- a/source/AnimationDebug.hx +++ b/source/AnimationDebug.hx @@ -21,7 +21,7 @@ import flixel.addons.ui.FlxUIInputText; import flixel.addons.ui.FlxUINumericStepper; import flixel.addons.ui.FlxUITabMenu; import flixel.addons.ui.FlxUITooltip.FlxUITooltipStyle; - +import ui.FlxVirtualPad; /** *DEBUG MODE */ @@ -52,6 +52,8 @@ class AnimationDebug extends MusicBeatState var characters:Array; + var _pad:FlxVirtualPad; + public function new(daAnim:String = 'bf') { super(); @@ -143,6 +145,10 @@ class AnimationDebug extends MusicBeatState FlxG.camera.follow(camFollow); + _pad = new FlxVirtualPad(ANIMATION, ANIMATION); + _pad.alpha = 0.75; + add(_pad); + super.create(); } @@ -227,6 +233,8 @@ class AnimationDebug extends MusicBeatState result += text + "\n"; } + openfl.system.System.setClipboard(result.trim()); + if ((result != null) && (result.length > 0)) { _file = new FileReference(); @@ -288,7 +296,7 @@ class AnimationDebug extends MusicBeatState function addHelpText():Void { - var helpTextValue = "Help:\nQ/E : Zoom in and out\nF : Flip\nI/J/K/L : Pan Camera\nW/S : Cycle Animation\nArrows : Offset Animation\nShift-Arrows : Offset Animation x10\nSpace : Replay Animation\nCTRL-S : Save Offsets to File\nEnter/ESC : Exit\nPress F1 to hide/show this!\n"; + var helpTextValue = "Help:\nIN/OUT : Zoom in and out\nUP/DOWN : Cycle Animation\nDrag : Offset Animation\nA : Replay Animation\nSAVE : Save Offsets to ClipBoard\nB : Exit"; helpText = new FlxText(940, 20, 0, helpTextValue, 15); helpText.scrollFactor.set(); helpText.y = FlxG.height - helpText.height - 20; @@ -336,32 +344,32 @@ class AnimationDebug extends MusicBeatState // TO MOUSE MOVEMENT????????? } - if (FlxG.keys.justPressed.ESCAPE) + if (_pad.buttonB.justPressed) { FlxG.mouse.visible = false; FlxG.switchState(new PlayState()); } - if (FlxG.keys.justPressed.E) + if (_pad.buttonIn.justPressed) FlxG.camera.zoom += 0.25; - if (FlxG.keys.justPressed.Q) + if (_pad.buttonOut.justPressed) FlxG.camera.zoom -= 0.25; if (FlxG.keys.justPressed.F) char.flipX = !char.flipX; - if (FlxG.keys.pressed.I || FlxG.keys.pressed.J || FlxG.keys.pressed.K || FlxG.keys.pressed.L) + if (_pad.buttonUp.pressed || _pad.buttonDown.pressed || _pad.buttonLeft.pressed || _pad.buttonRight.pressed) { - if (FlxG.keys.pressed.I) + if (_pad.buttonUp.pressed) camFollow.velocity.y = -90; - else if (FlxG.keys.pressed.K) + else if (_pad.buttonDown.pressed) camFollow.velocity.y = 90; else camFollow.velocity.y = 0; - if (FlxG.keys.pressed.J) + if (_pad.buttonLeft.pressed) camFollow.velocity.x = -90; - else if (FlxG.keys.pressed.L) + else if (_pad.buttonRight.pressed) camFollow.velocity.x = 90; else camFollow.velocity.x = 0; @@ -369,14 +377,14 @@ class AnimationDebug extends MusicBeatState else { camFollow.velocity.set(); - } + } - if (FlxG.keys.justPressed.W) + if (_pad.buttonUp2.justPressed) { curAnim -= 1; } - if (FlxG.keys.justPressed.S) + if (_pad.buttonDown2.justPressed) { curAnim += 1; } @@ -387,7 +395,7 @@ class AnimationDebug extends MusicBeatState if (curAnim >= animList.length) curAnim = 0; - if (FlxG.keys.justPressed.S || FlxG.keys.justPressed.W || FlxG.keys.justPressed.SPACE) + if (_pad.buttonDown2.justPressed || _pad.buttonUp2.justPressed || _pad.buttonA.justPressed) { char.playAnim(animList[curAnim]); @@ -422,7 +430,7 @@ class AnimationDebug extends MusicBeatState char.playAnim(animList[curAnim]); } - if (FlxG.keys.pressed.CONTROL && FlxG.keys.justPressed.S) + if (_pad.buttonSave.justPressed) saveBoyOffsets(); if (FlxG.keys.justPressed.F1) diff --git a/source/Asset2File.hx b/source/Asset2File.hx new file mode 100644 index 00000000000..b0bfcabedd1 --- /dev/null +++ b/source/Asset2File.hx @@ -0,0 +1,32 @@ +package; + +import haxe.crypto.Md5; +import openfl.utils.Assets; +#if sys +import sys.FileSystem; +import sys.io.File; +#end + +class Asset2File +{ + static var path:String = lime.system.System.applicationStorageDirectory; + + public static function getPath(id:String, ?ext:String = "") + { + #if android + var file = Assets.getBytes(id); + + var md5 = Md5.encode(Md5.make(file).toString()); + + if (FileSystem.exists(path + md5 + ext)) + return path + md5 + ext; + + + File.saveBytes(path + md5 + ext, file); + + return path + md5 + ext; + #else + return #if sys Sys.getCwd() + #end id; + #end + } +} diff --git a/source/ChartingState.hx b/source/ChartingState.hx index e02c9bc3138..50823e321ce 100644 --- a/source/ChartingState.hx +++ b/source/ChartingState.hx @@ -3,7 +3,7 @@ package; import Song.SongMeta; import openfl.system.System; import lime.app.Application; -#if FEATURE_FILESYSTEM +#if sys import sys.io.File; import sys.FileSystem; #end @@ -48,6 +48,7 @@ import openfl.utils.ByteArray; #if FEATURE_DISCORD import Discord.DiscordClient; #end +import ui.FlxVirtualPad; using StringTools; @@ -59,6 +60,12 @@ class ChartingState extends MusicBeatState public var playClaps:Bool = false; + var _pad:FlxVirtualPad; + //add buttons + var key_space:FlxButton; + var key_shift:FlxButton; + + public var snap:Int = 16; public var deezNuts:Map = new Map(); // snap conversion map @@ -446,6 +453,21 @@ class ChartingState extends MusicBeatState Debug.logTrace("create"); + _pad = new FlxVirtualPad(FULL, NONE); + _pad.alpha = 0.75; + add(_pad); + + // add buttons + key_space = new FlxButton(60, 60, ""); + key_space.loadGraphic(Paths.image("key_space")); //"assets/images/key_space.png" + key_space.alpha = 0.75; + add(key_space); + + key_shift = new FlxButton(60, 200, ""); + key_shift.loadGraphic(Paths.image("key_shift")); //"assets/images/key_shift.png" + key_shift.alpha = 0.75; + add(key_shift); + super.create(); } @@ -2086,11 +2108,11 @@ class ChartingState extends MusicBeatState } } - if (FlxG.keys.pressed.SHIFT) + if (FlxG.keys.pressed.SHIFT || key_shift.pressed) { - if (FlxG.keys.justPressed.RIGHT) + if (FlxG.keys.justPressed.RIGHT || FlxG.keys.justPressed.D || _pad.buttonRight.justPressed) speed += 0.1; - else if (FlxG.keys.justPressed.LEFT) + else if (FlxG.keys.justPressed.LEFT || FlxG.keys.justPressed.A || _pad.buttonLeft.justPressed) speed -= 0.1; if (speed > 3) @@ -2613,8 +2635,14 @@ class ChartingState extends MusicBeatState if (doInput) { - if (FlxG.keys.justPressed.ENTER) + #if android + var androidback = FlxG.android.justReleased.BACK; + #else + var androidback = false; + #end + if (FlxG.keys.justPressed.ENTER || androidback) { + FlxG.mouse.visible = false; lastSection = curSection; PlayState.SONG = _song; @@ -2717,7 +2745,7 @@ class ChartingState extends MusicBeatState var shiftThing:Int = 1; if (FlxG.keys.pressed.SHIFT) shiftThing = 4; - if (FlxG.keys.justPressed.SPACE) + if (FlxG.keys.justPressed.SPACE || key_space.justPressed) { if (FlxG.sound.music.playing) { @@ -2737,9 +2765,9 @@ class ChartingState extends MusicBeatState if (FlxG.sound.music.time < 0 || curDecimalBeat < 0) FlxG.sound.music.time = 0; - if (!FlxG.keys.pressed.SHIFT) + if (!FlxG.keys.pressed.SHIFT || !key_shift.pressed) { - if (FlxG.keys.pressed.W || FlxG.keys.pressed.S) + if (FlxG.keys.pressed.W || FlxG.keys.pressed.S || _pad.buttonUp.pressed || _pad.buttonDown.pressed) { FlxG.sound.music.pause(); if (!PlayState.isSM) @@ -2748,7 +2776,7 @@ class ChartingState extends MusicBeatState var daTime:Float = 700 * FlxG.elapsed; - if (FlxG.keys.pressed.W) + if (FlxG.keys.pressed.W || _pad.buttonUp.pressed) { FlxG.sound.music.time -= daTime; } @@ -2761,7 +2789,7 @@ class ChartingState extends MusicBeatState } else { - if (FlxG.keys.justPressed.W || FlxG.keys.justPressed.S) + if (FlxG.keys.justPressed.W || FlxG.keys.justPressed.S || _pad.buttonUp.pressed || _pad.buttonDown.pressed) { FlxG.sound.music.pause(); if (!PlayState.isSM) @@ -2769,7 +2797,7 @@ class ChartingState extends MusicBeatState var daTime:Float = Conductor.stepCrochet * 2; - if (FlxG.keys.justPressed.W) + if (FlxG.keys.justPressed.W || _pad.buttonUp.justPressed) { FlxG.sound.music.time -= daTime; } @@ -3600,6 +3628,8 @@ class ChartingState extends MusicBeatState var data:String = Json.stringify(json, null, " "); + openfl.system.System.setClipboard(data.trim()); + if ((data != null) && (data.length > 0)) { _file = new FileReference(); diff --git a/source/Config.hx b/source/Config.hx new file mode 100644 index 00000000000..e15be60f3af --- /dev/null +++ b/source/Config.hx @@ -0,0 +1,94 @@ +package; + +import ui.FlxVirtualPad; +import flixel.FlxG; +import flixel.util.FlxSave; +import flixel.math.FlxPoint; + +class Config { + var save:FlxSave; + + public function new() + { + save = new FlxSave(); + save.bind("saveconrtol"); + } + + public function setdownscroll(?value:Bool):Bool { + if (save.data.isdownscroll == null) save.data.isdownscroll = false; + + save.data.isdownscroll = !save.data.isdownscroll; + save.flush(); + return save.data.isdownscroll; + } + + public function getdownscroll():Bool { + if (save.data.isdownscroll != null) return save.data.isdownscroll; + return false; + } + + public function getcontrolmode():Int { + // load control mode num from FlxSave + if (save.data.buttonsmode != null) return save.data.buttonsmode[0]; + return 0; + } + + public function setcontrolmode(mode:Int = 0):Int { + // save control mode num from FlxSave + if (save.data.buttonsmode == null) save.data.buttonsmode = new Array(); + save.data.buttonsmode[0] = mode; + save.flush(); + + return save.data.buttonsmode[0]; + } + + public function savecustom(_pad:FlxVirtualPad) { + trace("saved"); + + if (save.data.buttons == null) + { + save.data.buttons = new Array(); + + for (buttons in _pad) + { + save.data.buttons.push(FlxPoint.get(buttons.x, buttons.y)); + } + }else + { + var tempCount:Int = 0; + for (buttons in _pad) + { + save.data.buttons[tempCount] = FlxPoint.get(buttons.x, buttons.y); + tempCount++; + } + } + save.flush(); + } + + public function loadcustom(_pad:FlxVirtualPad):FlxVirtualPad { + //load pad + if (save.data.buttons == null) return _pad; + var tempCount:Int = 0; + + for(buttons in _pad) + { + buttons.x = save.data.buttons[tempCount].x; + buttons.y = save.data.buttons[tempCount].y; + tempCount++; + } + return _pad; + } + + public function setFrameRate(fps:Int = 60) { + if (fps < 10) return; + + FlxG.stage.frameRate = fps; + save.data.framerate = fps; + save.flush(); + } + + public function getFrameRate():Int { + if (save.data.framerate != null) return save.data.framerate; + return 60; + } +} \ No newline at end of file diff --git a/source/Controls.hx b/source/Controls.hx index 28182212e57..5b8cd1350be 100644 --- a/source/Controls.hx +++ b/source/Controls.hx @@ -11,6 +11,9 @@ import flixel.input.actions.FlxActionSet; import flixel.input.gamepad.FlxGamepadButton; import flixel.input.gamepad.FlxGamepadInputID; import flixel.input.keyboard.FlxKey; +import ui.Hitbox; +import ui.FlxVirtualPad; +import flixel.ui.FlxButton; #if (haxe >= "4.0.0") enum abstract Action(String) to String from String @@ -32,6 +35,9 @@ enum abstract Action(String) to String from String var PAUSE = "pause"; var RESET = "reset"; var CHEAT = "cheat"; + var SIX = "six"; + var ONE = "one"; + var SEVEN = "seven"; } #else @:enum @@ -54,6 +60,9 @@ abstract Action(String) to String from String var PAUSE = "pause"; var RESET = "reset"; var CHEAT = "cheat"; + var SIX = "six"; + var ONE = "one"; + var SEVEN = "seven"; } #end @@ -79,6 +88,9 @@ enum Control BACK; PAUSE; CHEAT; + SIX; + ONE; + SEVEN; } enum KeyboardScheme @@ -112,6 +124,9 @@ class Controls extends FlxActionSet var _pause = new FlxActionDigital(Action.PAUSE); var _reset = new FlxActionDigital(Action.RESET); var _cheat = new FlxActionDigital(Action.CHEAT); + var _six = new FlxActionDigital(Action.SIX); + var _one = new FlxActionDigital(Action.ONE); + var _seven = new FlxActionDigital(Action.SEVEN); #if (haxe >= "4.0.0") var byName:Map = []; @@ -207,6 +222,23 @@ class Controls extends FlxActionSet inline function get_CHEAT() return _cheat.check(); + public var SIX(get, never):Bool; + + inline function get_SIX() + return _six.check(); + + public var ONE(get, never):Bool; + + inline function get_ONE() + return _one.check(); + + public var SEVEN(get, never):Bool; + + inline function get_SEVEN() + return _seven.check(); + + + #if (haxe >= "4.0.0") public function new(name, scheme = None) { @@ -229,6 +261,9 @@ class Controls extends FlxActionSet add(_pause); add(_reset); add(_cheat); + add(_six); + add(_one); + add(_seven); for (action in digitalActions) byName[action.name] = action; @@ -257,6 +292,9 @@ class Controls extends FlxActionSet add(_pause); add(_reset); add(_cheat); + add(_six); + add(_one); + add(_seven); for (action in digitalActions) byName[action.name] = action; @@ -267,6 +305,122 @@ class Controls extends FlxActionSet } #end + public var trackedinputs:Array = []; + + public function addbutton(action:FlxActionDigital, button:FlxButton, state:FlxInputState) { + var input = new FlxActionInputDigitalIFlxInput(button, state); + trackedinputs.push(input); + + action.add(input); + //action.addInput(button, state); + } + + public function setHitBox(hitbox:Hitbox) + { + inline forEachBound(Control.UP, (action, state) -> addbutton(action, hitbox.buttonUp, state)); + inline forEachBound(Control.DOWN, (action, state) -> addbutton(action, hitbox.buttonDown, state)); + inline forEachBound(Control.LEFT, (action, state) -> addbutton(action, hitbox.buttonLeft, state)); + inline forEachBound(Control.RIGHT, (action, state) -> addbutton(action, hitbox.buttonRight, state)); + } + + + public function setVirtualPad(virtualPad:FlxVirtualPad, ?DPad:FlxDPadMode, ?Action:FlxActionMode) { + if (DPad == null) + DPad = NONE; + if (Action == null) + Action = NONE; + + switch (DPad) + { + case UP_DOWN: + inline forEachBound(Control.UP, (action, state) -> addbutton(action, virtualPad.buttonUp, state)); + inline forEachBound(Control.DOWN, (action, state) -> addbutton(action, virtualPad.buttonDown, state)); + case LEFT_RIGHT: + inline forEachBound(Control.LEFT, (action, state) -> addbutton(action, virtualPad.buttonLeft, state)); + inline forEachBound(Control.RIGHT, (action, state) -> addbutton(action, virtualPad.buttonRight, state)); + case UP_LEFT_RIGHT: + inline forEachBound(Control.UP, (action, state) -> addbutton(action, virtualPad.buttonUp, state)); + inline forEachBound(Control.LEFT, (action, state) -> addbutton(action, virtualPad.buttonLeft, state)); + inline forEachBound(Control.RIGHT, (action, state) -> addbutton(action, virtualPad.buttonRight, state)); + case FULL | RIGHT_FULL: + inline forEachBound(Control.UP, (action, state) -> addbutton(action, virtualPad.buttonUp, state)); + inline forEachBound(Control.DOWN, (action, state) -> addbutton(action, virtualPad.buttonDown, state)); + inline forEachBound(Control.LEFT, (action, state) -> addbutton(action, virtualPad.buttonLeft, state)); + inline forEachBound(Control.RIGHT, (action, state) -> addbutton(action, virtualPad.buttonRight, state)); + case ANIMATION: + case NONE: + } + + switch (Action) + { + case A: + inline forEachBound(Control.ACCEPT, (action, state) -> addbutton(action, virtualPad.buttonA, state)); + case A_B: + inline forEachBound(Control.ACCEPT, (action, state) -> addbutton(action, virtualPad.buttonA, state)); + inline forEachBound(Control.BACK, (action, state) -> addbutton(action, virtualPad.buttonB, state)); + case STAGE: + case SONGD: + case ANIMATION: + case A_B_6: + inline forEachBound(Control.ACCEPT, (action, state) -> addbutton(action, virtualPad.buttonA, state)); + inline forEachBound(Control.BACK, (action, state) -> addbutton(action, virtualPad.buttonB, state)); + inline forEachBound(Control.SIX, (action, state) -> addbutton(action, virtualPad.button6, state)); + case A_B_6_1: + inline forEachBound(Control.ACCEPT, (action, state) -> addbutton(action, virtualPad.buttonA, state)); + inline forEachBound(Control.BACK, (action, state) -> addbutton(action, virtualPad.buttonB, state)); + inline forEachBound(Control.SIX, (action, state) -> addbutton(action, virtualPad.button6, state)); + inline forEachBound(Control.ONE, (action, state) -> addbutton(action, virtualPad.button1, state)); + case A_B_6_1_7: + inline forEachBound(Control.ACCEPT, (action, state) -> addbutton(action, virtualPad.buttonA, state)); + inline forEachBound(Control.BACK, (action, state) -> addbutton(action, virtualPad.buttonB, state)); + inline forEachBound(Control.SIX, (action, state) -> addbutton(action, virtualPad.button6, state)); + inline forEachBound(Control.ONE, (action, state) -> addbutton(action, virtualPad.button1, state)); + inline forEachBound(Control.SEVEN, (action, state) -> addbutton(action, virtualPad.button7, state)); + case A_B_C: + inline forEachBound(Control.ACCEPT, (action, state) -> addbutton(action, virtualPad.buttonA, state)); + inline forEachBound(Control.BACK, (action, state) -> addbutton(action, virtualPad.buttonB, state)); + case A_B_X_Y: + inline forEachBound(Control.ACCEPT, (action, state) -> addbutton(action, virtualPad.buttonA, state)); + inline forEachBound(Control.BACK, (action, state) -> addbutton(action, virtualPad.buttonB, state)); + case NONE: + } + } + + + public function removeFlxInput(Tinputs) { + for (action in this.digitalActions) + { + var i = action.inputs.length; + + while (i-- > 0) + { + var input = action.inputs[i]; + /*if (input.device == IFLXINPUT_OBJECT) + action.remove(input);*/ + + var x = Tinputs.length; + while (x-- > 0) + if (Tinputs[x] == input) + action.remove(input); + } + } + } + + + + #if android + public function addAndroidBack() { + // fix this later + + /* + var BACK = #if (openfl >= "8.0.0") 0x4000010E #else 27 #end; + _back.addKey(BACK, JUST_RELEASED); + _back.addKey(BACK, JUST_PRESSED); + _back.addKey(BACK, PRESSED); + */ + } + #end + override function update() { super.update(); @@ -311,6 +465,9 @@ class Controls extends FlxActionSet case PAUSE: _pause; case RESET: _reset; case CHEAT: _cheat; + case SIX: _six; + case ONE: _one; + case SEVEN: _seven; } } @@ -356,6 +513,12 @@ class Controls extends FlxActionSet func(_reset, JUST_PRESSED); case CHEAT: func(_cheat, JUST_PRESSED); + case SIX: + func(_six, JUST_PRESSED); + case ONE: + func(_one, JUST_PRESSED); + case SEVEN: + func(_seven, JUST_PRESSED); } } diff --git a/source/FreeplayState.hx b/source/FreeplayState.hx index 6163487f431..e7a5146bcef 100644 --- a/source/FreeplayState.hx +++ b/source/FreeplayState.hx @@ -6,7 +6,7 @@ import flixel.system.FlxSound; #if FEATURE_STEPMANIA import smTools.SMFile; #end -#if FEATURE_FILESYSTEM +#if sys import sys.FileSystem; import sys.io.File; #end @@ -85,7 +85,7 @@ class FreeplayState extends MusicBeatState #if !FEATURE_STEPMANIA trace("FEATURE_STEPMANIA was not specified during build, sm file loading is disabled."); - #elseif FEATURE_STEPMANIA + #elseif windows // TODO: Refactor this to use OpenFlAssets. trace("tryin to load sm files"); for (i in FileSystem.readDirectory("assets/sm/")) @@ -133,9 +133,9 @@ class FreeplayState extends MusicBeatState var isDebug:Bool = false; - #if debug + // #if debug isDebug = true; - #end + //#end persistentUpdate = true; @@ -209,6 +209,10 @@ class FreeplayState extends MusicBeatState var swag:Alphabet = new Alphabet(1, 0, "swag"); + #if mobileC + addVirtualPad(FULL, A_B_6_1_7); + #end + super.create(); } @@ -318,12 +322,12 @@ class FreeplayState extends MusicBeatState FlxG.sound.music.volume -= 0.5 * FlxG.elapsed; } - var upP = FlxG.keys.justPressed.UP; - var downP = FlxG.keys.justPressed.DOWN; - var accepted = FlxG.keys.justPressed.ENTER; - var dadDebug = FlxG.keys.justPressed.SIX; - var charting = FlxG.keys.justPressed.SEVEN; - var bfDebug = FlxG.keys.justPressed.ZERO; + var upP = controls.UP_P; + var downP = controls.DOWN_P; + var accepted = controls.ACCEPT; + var dadDebug = controls.SIX; + var charting = controls.SEVEN; + var bfDebug = controls.ONE; var gamepad:FlxGamepad = FlxG.gamepads.lastActive; @@ -396,9 +400,9 @@ class FreeplayState extends MusicBeatState } else { - if (FlxG.keys.justPressed.LEFT) + if (controls.LEFT_P) changeDiff(-1); - if (FlxG.keys.justPressed.RIGHT) + if (controls.RIGHT_P) changeDiff(1); } @@ -421,7 +425,7 @@ class FreeplayState extends MusicBeatState loadSong(true); // AnimationDebug and StageDebug are only enabled in debug builds. - #if debug + // #if debug if (dadDebug) { loadAnimDebug(true); @@ -430,7 +434,7 @@ class FreeplayState extends MusicBeatState { loadAnimDebug(false); } - #end + // #end } function loadAnimDebug(dad:Bool = true) @@ -594,7 +598,7 @@ class FreeplayState extends MusicBeatState diffCalcText.text = 'RATING: ${DiffCalc.CalculateDiff(songData.get(songs[curSelected].songName)[curDifficulty])}'; diffText.text = CoolUtil.difficultyFromInt(curDifficulty).toUpperCase(); - #if PRELOAD_ALL + #if windows if (songs[curSelected].songCharacter == "sm") { var data = songs[curSelected]; diff --git a/source/GameOverSubstate.hx b/source/GameOverSubstate.hx index 6f1c2cfb806..a91b01bc546 100644 --- a/source/GameOverSubstate.hx +++ b/source/GameOverSubstate.hx @@ -6,6 +6,7 @@ import flixel.FlxSubState; import flixel.math.FlxPoint; import flixel.util.FlxColor; import flixel.util.FlxTimer; +import flixel.FlxCamera; class GameOverSubstate extends MusicBeatSubstate { @@ -46,6 +47,15 @@ class GameOverSubstate extends MusicBeatSubstate FlxG.camera.target = null; bf.playAnim('firstDeath'); + + #if mobileC + addVirtualPad(NONE, A_B); + var camcontrol = new FlxCamera(); + FlxG.cameras.add(camcontrol); + camcontrol.bgColor.alpha = 0; + _virtualpad.cameras = [camcontrol]; + #end + } var startVibin:Bool = false; diff --git a/source/GitarooPause.hx b/source/GitarooPause.hx index cce3c49ad1e..e65732392b1 100644 --- a/source/GitarooPause.hx +++ b/source/GitarooPause.hx @@ -51,6 +51,11 @@ class GitarooPause extends MusicBeatState changeThing(); + #if mobileC + addVirtualPad(LEFT_RIGHT, A_B); + #end + + super.create(); } diff --git a/source/LoadReplayState.hx b/source/LoadReplayState.hx index 627f8e06d04..e710b4023bd 100644 --- a/source/LoadReplayState.hx +++ b/source/LoadReplayState.hx @@ -16,7 +16,7 @@ import flixel.input.keyboard.FlxKey; import flixel.math.FlxMath; import flixel.text.FlxText; import flixel.util.FlxColor; -#if FEATURE_FILESYSTEM +#if sys import sys.FileSystem; import sys.io.File; #end diff --git a/source/Main.hx b/source/Main.hx index 4666b0806ee..28d2c5e1bdc 100644 --- a/source/Main.hx +++ b/source/Main.hx @@ -16,6 +16,7 @@ import openfl.Lib; import openfl.display.FPS; import openfl.display.Sprite; import openfl.events.Event; +import lime.system.System; class Main extends Sprite { @@ -23,7 +24,7 @@ class Main extends Sprite var gameHeight:Int = 720; // Height of the game in pixels (might be less / more in actual pixels depending on your zoom). var initialState:Class = TitleState; // The FlxState the game starts with. var zoom:Float = -1; // If -1, zoom is automatically calculated to fit the window dimensions. - var framerate:Int = 120; // How many frames per second the game should run at. + var framerate:Int = 60; // How many frames per second the game should run at. var skipSplash:Bool = true; // Whether to skip the flixel splash screen that appears in release mode. var startFullscreen:Bool = false; // Whether to start the game in fullscreen on desktop targets @@ -31,6 +32,8 @@ class Main extends Sprite public static var instance:Main; + public static var path:String = System.applicationStorageDirectory; + public static var watermarks = true; // Whether to put Kade Engine literally anywhere // You can pretty much ignore everything from here on - your code should go in your states. @@ -84,6 +87,13 @@ class Main extends Sprite gameHeight = Math.ceil(stageHeight / zoom); } + #if mobile + gameWidth = 1280; + gameHeight = 720; + zoom = 1; + #end + + #if !cpp framerate = 60; #end @@ -94,19 +104,16 @@ class Main extends Sprite // Gotta run this before any assets get loaded. ModCore.initialize(); - #if !mobile fpsCounter = new KadeEngineFPS(10, 3, 0xFFFFFF); bitmapFPS = ImageOutline.renderImage(fpsCounter, 1, 0x000000, true); bitmapFPS.smoothing = true; - #end game = new FlxGame(gameWidth, gameHeight, initialState, zoom, framerate, framerate, skipSplash, startFullscreen); addChild(game); - #if !mobile + addChild(fpsCounter); toggleFPS(FlxG.save.data.fps); - #end // Finish up loading debug tools. Debug.onGameStart(); diff --git a/source/MainMenuState.hx b/source/MainMenuState.hx index 4bd5188e3d5..d06076483e2 100644 --- a/source/MainMenuState.hx +++ b/source/MainMenuState.hx @@ -136,6 +136,10 @@ class MainMenuState extends MusicBeatState changeItem(); + #if mobileC + addVirtualPad(UP_DOWN, A_B); + #end + super.create(); } @@ -166,13 +170,13 @@ class MainMenuState extends MusicBeatState } } - if (FlxG.keys.justPressed.UP) + if (controls.UP_P) { FlxG.sound.play(Paths.sound('scrollMenu')); changeItem(-1); } - if (FlxG.keys.justPressed.DOWN) + if (controls.DOWN_P) { FlxG.sound.play(Paths.sound('scrollMenu')); changeItem(1); diff --git a/source/ModchartState.hx b/source/ModchartState.hx index a54ca8b747c..99630d2fb9d 100644 --- a/source/ModchartState.hx +++ b/source/ModchartState.hx @@ -383,7 +383,7 @@ class ModchartState } #end - new LuaSprite(sprite, toBeCalled).Register(lua); + // new LuaSprite(sprite, toBeCalled).Register(lua); return toBeCalled; } diff --git a/source/MusicBeatState.hx b/source/MusicBeatState.hx index 77e952149ef..c358d2f8ea6 100644 --- a/source/MusicBeatState.hx +++ b/source/MusicBeatState.hx @@ -13,6 +13,10 @@ import openfl.Lib; import Conductor.BPMChangeEvent; import flixel.FlxG; import flixel.addons.ui.FlxUIState; +#if mobileC +import ui.FlxVirtualPad; +import flixel.input.actions.FlxActionInput; +#end class MusicBeatState extends FlxUIState { @@ -27,12 +31,36 @@ class MusicBeatState extends FlxUIState inline function get_controls():Controls return PlayerSettings.player1.controls; + #if mobileC + var _virtualpad:FlxVirtualPad; + + var trackedinputs:Array = []; + + // adding virtualpad to state + public function addVirtualPad(?DPad:FlxDPadMode, ?Action:FlxActionMode) { + _virtualpad = new FlxVirtualPad(DPad, Action); + _virtualpad.alpha = 0.75; + add(_virtualpad); + controls.setVirtualPad(_virtualpad, DPad, Action); + trackedinputs = controls.trackedinputs; + controls.trackedinputs = []; + + #if android + controls.addAndroidBack(); + #end + } + + #else + public function addVirtualPad(?DPad, ?Action){}; + #end + public static var initSave:Bool = false; private var assets:Array = []; override function destroy() { + controls.removeFlxInput(trackedinputs); Application.current.window.onFocusIn.remove(onWindowFocusOut); Application.current.window.onFocusIn.remove(onWindowFocusIn); super.destroy(); diff --git a/source/MusicBeatSubstate.hx b/source/MusicBeatSubstate.hx index 66c06af9fa4..14e09e587f6 100644 --- a/source/MusicBeatSubstate.hx +++ b/source/MusicBeatSubstate.hx @@ -7,6 +7,10 @@ import flixel.input.gamepad.FlxGamepad; import Conductor.BPMChangeEvent; import flixel.FlxG; import flixel.FlxSubState; +#if mobileC +import ui.FlxVirtualPad; +import flixel.input.actions.FlxActionInput; +#end class MusicBeatSubstate extends FlxSubState { @@ -17,6 +21,7 @@ class MusicBeatSubstate extends FlxSubState override function destroy() { + controls.removeFlxInput(trackedinputs); Application.current.window.onFocusIn.remove(onWindowFocusOut); Application.current.window.onFocusIn.remove(onWindowFocusIn); super.destroy(); @@ -39,6 +44,29 @@ class MusicBeatSubstate extends FlxSubState inline function get_controls():Controls return PlayerSettings.player1.controls; + #if mobileC + var _virtualpad:FlxVirtualPad; + + var trackedinputs:Array = []; + + // adding virtualpad to state + public function addVirtualPad(?DPad:FlxDPadMode, ?Action:FlxActionMode) { + _virtualpad = new FlxVirtualPad(DPad, Action); + _virtualpad.alpha = 0.75; + add(_virtualpad); + controls.setVirtualPad(_virtualpad, DPad, Action); + trackedinputs = controls.trackedinputs; + controls.trackedinputs = []; + + #if android + controls.addAndroidBack(); + #end + } + + #else + public function addVirtualPad(?DPad, ?Action){}; + #end + override function update(elapsed:Float) { // everyStep(); diff --git a/source/Options.hx b/source/Options.hx index 6f16fda1842..e7921f0a27a 100644 --- a/source/Options.hx +++ b/source/Options.hx @@ -1767,6 +1767,24 @@ class ResetScoreOption extends Option } } +class MobileControls extends Option +{ + public function new(desc:String) + { + super(); + description = desc; + } + public override function press():Bool + { + FlxG.switchState(new options.CustomControlsState()); + return true; + } + private override function updateDisplay():String + { + return "Mobile Controls"; + } + +} class ResetSettings extends Option { var confirm:Bool = false; diff --git a/source/OptionsMenu.hx b/source/OptionsMenu.hx index cbb7108f155..8157dd7aeac 100644 --- a/source/OptionsMenu.hx +++ b/source/OptionsMenu.hx @@ -17,6 +17,7 @@ import flixel.input.keyboard.FlxKey; import flixel.math.FlxMath; import flixel.text.FlxText; import flixel.util.FlxColor; +import ui.FlxVirtualPad; class OptionCata extends FlxSprite { @@ -114,10 +115,13 @@ class OptionsMenu extends FlxSubState public var descText:FlxText; public var descBack:FlxSprite; + var _pad:FlxVirtualPad; + override function create() { options = [ new OptionCata(50, 40, "Gameplay", [ + new MobileControls("edit a control"), new ScrollSpeedOption("Change your scroll speed. (1 = Chart dependent)"), new OffsetThing("Change the note audio offset (how many milliseconds a note is offset in a chart)"), new AccuracyDOption("Change how accuracy is calculated. (Accurate = Simple, Complex = Milisecond Based)"), @@ -237,6 +241,10 @@ class OptionsMenu extends FlxSubState selectedOption = selectedCat.options[0]; + _pad = new FlxVirtualPad(FULL, A_B); + _pad.alpha = 0.75; + add(_pad); + super.create(); } @@ -350,14 +358,14 @@ class OptionsMenu extends FlxSubState var any = false; var escape = false; - accept = FlxG.keys.justPressed.ENTER || (gamepad != null ? gamepad.justPressed.A : false); - right = FlxG.keys.justPressed.RIGHT || (gamepad != null ? gamepad.justPressed.DPAD_RIGHT : false); - left = FlxG.keys.justPressed.LEFT || (gamepad != null ? gamepad.justPressed.DPAD_LEFT : false); - up = FlxG.keys.justPressed.UP || (gamepad != null ? gamepad.justPressed.DPAD_UP : false); - down = FlxG.keys.justPressed.DOWN || (gamepad != null ? gamepad.justPressed.DPAD_DOWN : false); + accept = FlxG.keys.justPressed.ENTER || _pad.buttonA.justPressed|| (gamepad != null ? gamepad.justPressed.A : false); + right = FlxG.keys.justPressed.RIGHT || _pad.buttonRight.justPressed || (gamepad != null ? gamepad.justPressed.DPAD_RIGHT : false); + left = FlxG.keys.justPressed.LEFT || _pad.buttonLeft.justPressed || (gamepad != null ? gamepad.justPressed.DPAD_LEFT : false); + up = FlxG.keys.justPressed.UP || _pad.buttonUp.justPressed || (gamepad != null ? gamepad.justPressed.DPAD_UP : false); + down = FlxG.keys.justPressed.DOWN || _pad.buttonDown.justPressed || (gamepad != null ? gamepad.justPressed.DPAD_DOWN : false); any = FlxG.keys.justPressed.ANY || (gamepad != null ? gamepad.justPressed.ANY : false); - escape = FlxG.keys.justPressed.ESCAPE || (gamepad != null ? gamepad.justPressed.B : false); + escape = FlxG.keys.justPressed.ESCAPE || _pad.buttonB.justPressed || (gamepad != null ? gamepad.justPressed.B : false); if (selectedCat != null && !isInCat) { diff --git a/source/OutdatedSubState.hx b/source/OutdatedSubState.hx index 45d2ba5f2e9..b6b83ff1363 100644 --- a/source/OutdatedSubState.hx +++ b/source/OutdatedSubState.hx @@ -91,6 +91,9 @@ class OutdatedSubState extends MusicBeatState else FlxTween.tween(kadeLogo, {alpha: 0.8}, 0.8, {ease: FlxEase.quartInOut}); }, 0); + #if mobileC + addVirtualPad(NONE, A_B); + #end } override function update(elapsed:Float) diff --git a/source/Paths.hx b/source/Paths.hx index 10c2f12e6d5..f40b4875cba 100644 --- a/source/Paths.hx +++ b/source/Paths.hx @@ -121,12 +121,17 @@ class Paths inline static public function lua(key:String, ?library:String) { - return getPath('data/$key.lua', TEXT, library); + return Main.path + getPath('data/$key.lua', TEXT, library); } + inline static public function luaAsset(key:String,?library:String) + { + return getPath('data/$key.lua', TEXT, library); + } + inline static public function luaImage(key:String, ?library:String) { - return getPath('data/$key.png', IMAGE, library); + return Main.path + getPath('data/$key.png', IMAGE, library); } inline static public function txt(key:String, ?library:String) diff --git a/source/PauseSubState.hx b/source/PauseSubState.hx index 3ee3f5f7e96..39fe7e30591 100644 --- a/source/PauseSubState.hx +++ b/source/PauseSubState.hx @@ -17,6 +17,7 @@ import flixel.text.FlxText; import flixel.tweens.FlxEase; import flixel.tweens.FlxTween; import flixel.util.FlxColor; +import flixel.FlxCamera; class PauseSubState extends MusicBeatSubstate { @@ -128,6 +129,16 @@ class PauseSubState extends MusicBeatSubstate changeSelection(); cameras = [FlxG.cameras.list[FlxG.cameras.list.length - 1]]; + + #if mobileC + addVirtualPad(UP_DOWN, A_B); + + var camcontrol = new FlxCamera(); + FlxG.cameras.add(camcontrol); + camcontrol.bgColor.alpha = 0; + _virtualpad.cameras = [camcontrol]; + #end + } override function update(elapsed:Float) @@ -191,12 +202,6 @@ class PauseSubState extends MusicBeatSubstate close(); case "Restart Song": PlayState.startTime = 0; - if (PlayState.instance.useVideo) - { - GlobalVideo.get().stop(); - PlayState.instance.remove(PlayState.instance.videoSprite); - PlayState.instance.removedVideo = true; - } PlayState.instance.clean(); FlxG.resetState(); PlayState.stageTesting = false; @@ -205,18 +210,6 @@ class PauseSubState extends MusicBeatSubstate close(); case "Exit to menu": PlayState.startTime = 0; - if (PlayState.instance.useVideo) - { - GlobalVideo.get().stop(); - PlayState.instance.remove(PlayState.instance.videoSprite); - PlayState.instance.removedVideo = true; - } - if (PlayState.loadRep) - { - FlxG.save.data.botplay = false; - FlxG.save.data.scrollSpeed = 1; - FlxG.save.data.downscroll = false; - } PlayState.loadRep = false; PlayState.stageTesting = false; #if FEATURE_LUAMODCHART diff --git a/source/PlayState.hx b/source/PlayState.hx index 8dd1f29986a..1827ac1fa80 100644 --- a/source/PlayState.hx +++ b/source/PlayState.hx @@ -12,7 +12,7 @@ import openfl.media.Sound; #if FEATURE_STEPMANIA import smTools.SMFile; #end -#if FEATURE_FILESYSTEM +#if sys import sys.io.File; import Sys; import sys.FileSystem; @@ -80,6 +80,10 @@ import openfl.filters.ShaderFilter; #if FEATURE_DISCORD import Discord.DiscordClient; #end +import openfl.Assets; +import ui.Mobilecontrols; +import ui.FlxVirtualPad; +import ModchartState; using StringTools; @@ -291,6 +295,12 @@ class PlayState extends MusicBeatState // API stuff + #if mobileC + var mcontrols:Mobilecontrols; + var _pad:FlxVirtualPad; + #end + + public function addObject(object:FlxBasic) { add(object); @@ -355,17 +365,23 @@ class PlayState extends MusicBeatState removedVideo = false; - #if FEATURE_LUAMODCHART - // TODO: Refactor this to use OpenFlAssets. - executeModchart = FileSystem.exists(Paths.lua('songs/${PlayState.SONG.songId}/modchart')); - if (isSM) - executeModchart = FileSystem.exists(pathToSm + "/modchart.lua"); - if (executeModchart) - PlayStateChangeables.Optimize = false; - #end - #if !cpp - executeModchart = false; // FORCE disable for non cpp targets - #end + executeModchart = FileSystem.exists(Paths.lua(PlayState.SONG.song.toLowerCase() + "/modchart")); + + if (!executeModchart && openfl.utils.Assets.exists("assets/data/" + SONG.song.toLowerCase() + "/modchart.lua")) + { + var path = Paths.luaAsset(SONG.song.toLowerCase() + "/modchart"); + var luaFile = openfl.Assets.getBytes(path); + + FileSystem.createDirectory(Main.path + "assets"); + FileSystem.createDirectory(Main.path + "assets/data"); + FileSystem.createDirectory(Main.path + "assets/data/" + SONG.song.toLowerCase()); + + + File.saveBytes(Paths.lua(SONG.song.toLowerCase() + "/modchart"), luaFile); + + executeModchart = FileSystem.exists(Paths.lua(SONG.song.toLowerCase() + "/modchart")); + } + Debug.logInfo('Searching for mod chart? ($executeModchart) at ${Paths.lua('songs/${PlayState.SONG.songId}/modchart')}'); @@ -964,6 +980,34 @@ class PlayState extends MusicBeatState laneunderlay.cameras = [camHUD]; laneunderlayOpponent.cameras = [camHUD]; + #if mobileC + mcontrols = new Mobilecontrols(); + switch (mcontrols.mode) + { + case VIRTUALPAD_RIGHT | VIRTUALPAD_LEFT | VIRTUALPAD_CUSTOM: + controls.setVirtualPad(mcontrols._virtualPad, FULL, NONE); + case HITBOX: + controls.setHitBox(mcontrols._hitbox); + default: + } + trackedinputs = controls.trackedinputs; + controls.trackedinputs = []; + + _pad = new FlxVirtualPad(NONE, SONGD); + _pad.alpha = 0.75; + add(_pad); + + var camcontrol = new FlxCamera(); + FlxG.cameras.add(camcontrol); + camcontrol.bgColor.alpha = 0; + mcontrols.cameras = [camcontrol]; + _pad.cameras = [camcontrol]; + + mcontrols.visible = false; + + add(mcontrols); + #end + if (isStoryMode) doof.cameras = [camHUD]; kadeEngineWatermark.cameras = [camHUD]; @@ -1134,6 +1178,10 @@ class PlayState extends MusicBeatState function startCountdown():Void { + #if mobileC + mcontrols.visible = true; + #end + inCutscene = false; appearStaticArrows(); @@ -2273,7 +2321,7 @@ class PlayState extends MusicBeatState var pauseBind = FlxKey.fromString(FlxG.save.data.pauseBind); var gppauseBind = FlxKey.fromString(FlxG.save.data.gppauseBind); - if ((FlxG.keys.anyJustPressed([pauseBind]) || KeyBinds.gamepad && FlxG.keys.anyJustPressed([gppauseBind])) + if ((FlxG.keys.anyJustPressed([pauseBind]) #if android || FlxG.android.justReleased.BACK #end || KeyBinds.gamepad && FlxG.keys.anyJustPressed([gppauseBind])) && startedCountdown && canPause && !cannotDie) @@ -2372,7 +2420,7 @@ class PlayState extends MusicBeatState /* if (FlxG.keys.justPressed.NINE) FlxG.switchState(new Charting()); */ - #if debug + #if cpp if (FlxG.keys.justPressed.SIX) { if (useVideo) @@ -2397,7 +2445,7 @@ class PlayState extends MusicBeatState } if (!PlayStateChangeables.Optimize) - if (FlxG.keys.justPressed.EIGHT && songStarted) + if (FlxG.keys.justPressed.EIGHT || _pad.buttonStage.justPressed && songStarted) { paused = true; if (useVideo) @@ -3295,6 +3343,10 @@ class PlayState extends MusicBeatState function endSong():Void { + #if mobileC + mcontrols.visible = false; + #end + endingSong = true; FlxG.stage.removeEventListener(KeyboardEvent.KEY_DOWN, handleInput); FlxG.stage.removeEventListener(KeyboardEvent.KEY_UP, releaseInput); @@ -3305,7 +3357,7 @@ class PlayState extends MusicBeatState } if (!loadRep) - rep.SaveReplay(saveNotes, saveJudge, replayAna); + trace('amogus'); else { PlayStateChangeables.botPlay = false; @@ -3887,8 +3939,6 @@ class PlayState extends MusicBeatState }); } - if ((KeyBinds.gamepad && !FlxG.keys.justPressed.ANY)) - { // PRESSES, check for note hits if (pressArray.contains(true) && generatedMusic) { @@ -3900,36 +3950,38 @@ class PlayState extends MusicBeatState var directionsAccounted:Array = [false, false, false, false]; // we don't want to do judgments for more than one presses notes.forEachAlive(function(daNote:Note) - { - if (daNote.canBeHit && daNote.mustPress && !daNote.wasGoodHit && !directionsAccounted[daNote.noteData]) { - if (directionList.contains(daNote.noteData)) + if (daNote.canBeHit && daNote.mustPress && !daNote.tooLate && !daNote.wasGoodHit) { - directionsAccounted[daNote.noteData] = true; - for (coolNote in possibleNotes) + if (!directionsAccounted[daNote.noteData]) { - if (coolNote.noteData == daNote.noteData && Math.abs(daNote.strumTime - coolNote.strumTime) < 10) - { // if it's the same note twice at < 10ms distance, just delete it - // EXCEPT u cant delete it in this loop cuz it fucks with the collection lol - dumbNotes.push(daNote); - break; + if (directionList.contains(daNote.noteData)) + { + directionsAccounted[daNote.noteData] = true; + for (coolNote in possibleNotes) + { + if (coolNote.noteData == daNote.noteData && Math.abs(daNote.strumTime - coolNote.strumTime) < 10) + { // if it's the same note twice at < 10ms distance, just delete it + // EXCEPT u cant delete it in this loop cuz it fucks with the collection lol + dumbNotes.push(daNote); + break; + } + else if (coolNote.noteData == daNote.noteData && daNote.strumTime < coolNote.strumTime) + { // if daNote is earlier than existing note (coolNote), replace + possibleNotes.remove(coolNote); + possibleNotes.push(daNote); + break; + } + } } - else if (coolNote.noteData == daNote.noteData && daNote.strumTime < coolNote.strumTime) - { // if daNote is earlier than existing note (coolNote), replace - possibleNotes.remove(coolNote); + else + { possibleNotes.push(daNote); - break; + directionList.push(daNote.noteData); } } } - else - { - directionsAccounted[daNote.noteData] = true; - possibleNotes.push(daNote); - directionList.push(daNote.noteData); - } - } - }); + }); for (note in dumbNotes) { @@ -3989,7 +4041,7 @@ class PlayState extends MusicBeatState for (i in anas) if (i != null) replayAna.anaArray.push(i); // put em all there - } + if (PlayStateChangeables.botPlay) notes.forEachAlive(function(daNote:Note) { @@ -4027,13 +4079,10 @@ class PlayState extends MusicBeatState { if (!PlayStateChangeables.botPlay) { - if (keys[spr.ID] - && spr.animation.curAnim.name != 'confirm' - && spr.animation.curAnim.name != 'pressed' - && !spr.animation.curAnim.name.startsWith('dirCon')) - spr.playAnim('pressed', false); - if (!keys[spr.ID]) - spr.playAnim('static', false); + if (pressArray[spr.ID] && spr.animation.curAnim.name != 'confirm') + spr.animation.play('pressed'); + if (!holdArray[spr.ID]) + spr.animation.play('static'); } else if (FlxG.save.data.cpuStrums) { @@ -4359,13 +4408,13 @@ class PlayState extends MusicBeatState saveJudge.push(note.rating); } - if (!PlayStateChangeables.botPlay || FlxG.save.data.cpuStrums) + /* if (!PlayStateChangeables.botPlay || FlxG.save.data.cpuStrums) { playerStrums.forEach(function(spr:StaticArrow) { pressArrow(spr, spr.ID, note); }); - } + } */ if (!note.isSustainNote) { diff --git a/source/ResultsScreen.hx b/source/ResultsScreen.hx index d431b542652..16d8d09c066 100644 --- a/source/ResultsScreen.hx +++ b/source/ResultsScreen.hx @@ -30,10 +30,11 @@ import lime.app.Application; import flixel.math.FlxMath; import flixel.text.FlxText; import flixel.input.FlxKeyManager; +import flixel.FlxCamera; using StringTools; -class ResultsScreen extends FlxSubState +class ResultsScreen extends MusicBeatSubstate { public var background:FlxSprite; public var text:FlxText; @@ -181,6 +182,11 @@ class ResultsScreen extends FlxSubState cameras = [FlxG.cameras.list[FlxG.cameras.list.length - 1]]; + #if mobileC + addVirtualPad(NONE, A); + #end + + super.create(); } @@ -194,7 +200,13 @@ class ResultsScreen extends FlxSubState // keybinds - if (PlayerSettings.player1.controls.ACCEPT) + #if android + var androidback = FlxG.android.justReleased.BACK; + #else + var androidback = false; + #end + + if (controls.ACCEPT || androidback) { if (music != null) music.fadeOut(0.3); diff --git a/source/StageDebugState.hx b/source/StageDebugState.hx index fbec31360cb..92b552ea247 100644 --- a/source/StageDebugState.hx +++ b/source/StageDebugState.hx @@ -12,6 +12,7 @@ import flixel.util.FlxCollision; import openfl.events.Event; import openfl.events.IOErrorEvent; import openfl.net.FileReference; +import ui.FlxVirtualPad; using StringTools; @@ -41,7 +42,8 @@ class StageDebugState extends FlxState var camGame:FlxCamera; var charMode:Bool = true; var usedObjects:Array = []; - + var _pad:FlxVirtualPad; + public function new(daStage:String = 'stage', daGf:String = 'gf', daBf:String = 'bf', opponent:String = 'dad') { super(); @@ -105,18 +107,28 @@ class StageDebugState extends FlxState FlxG.camera = camGame; camGame.follow(camFollow); + _pad = new FlxVirtualPad(FULL, STAGE); + _pad.alpha = 75; + add(_pad); + + var camcontrol = new FlxCamera(); + FlxG.cameras.add(camcontrol); + camcontrol.bgColor.alpha = 0; + _pad.cameras = [camcontrol]; + posText = new FlxText(0, 0); posText.size = 26; posText.scrollFactor.set(); posText.cameras = [camHUD]; add(posText); + addHelpText(); } var helpText:FlxText; function addHelpText():Void { - var helpTextValue = "Help:\nQ/E : Zoom in and out\nI/J/K/L : Pan Camera\nSpace : Cycle Object\nShift : Switch Mode (Char/Stage)\nClick and Drag : Move Active Object\nZ/X : Rotate Object\nR : Reset Rotation\nCTRL-S : Save Offsets to File\nESC : Return to Stage\nPress F1 to hide/show this!\n"; + var helpTextValue = "Help:\nIN/OUT : Zoom in and out\nUP/DOWN/LEFT/RIGHT : Pan Camera\nA : Cycle Object\nC : Switch Mode (Char/Stage)\nClick and Drag : Move Active Object\nL/R : Rotate Object\nR : Reset Rotation\nSAVE : Save Offsets to ClipBoard\nB : Return to Stage\nPress F1 to hide/show this!\n"; helpText = new FlxText(940, 0, 0, helpTextValue, 15); helpText.scrollFactor.set(); helpText.cameras = [camHUD]; @@ -127,16 +139,16 @@ class StageDebugState extends FlxState override public function update(elapsed:Float) { - if (FlxG.keys.justPressed.E) + if (FlxG.keys.justPressed.E || _pad.buttonIn.justPressed) camGame.zoom += 0.1; - if (FlxG.keys.justPressed.Q) + if (FlxG.keys.justPressed.Q || _pad.buttonOut.justPressed) { if (camGame.zoom > 0.11) // me when floating point error camGame.zoom -= 0.1; } FlxG.watch.addQuick('Camera Zoom', camGame.zoom); - if (FlxG.keys.justPressed.SHIFT) + if (_pad.buttonC.justPressed) { charMode = !charMode; dragging = false; @@ -146,18 +158,18 @@ class StageDebugState extends FlxState getNextObject(); } - if (FlxG.keys.pressed.I || FlxG.keys.pressed.J || FlxG.keys.pressed.K || FlxG.keys.pressed.L) + if (_pad.buttonUp.pressed || _pad.buttonDown.pressed || _pad.buttonLeft.pressed ||_pad.buttonRight.pressed) { - if (FlxG.keys.pressed.I) + if (_pad.buttonUp.pressed) camFollow.velocity.y = -90; - else if (FlxG.keys.pressed.K) + else if (_pad.buttonDown.pressed) camFollow.velocity.y = 90; else camFollow.velocity.y = 0; - if (FlxG.keys.pressed.J) + if (_pad.buttonLeft.pressed) camFollow.velocity.x = -90; - else if (FlxG.keys.pressed.L) + else if (_pad.buttonRight.pressed) camFollow.velocity.x = 90; else camFollow.velocity.x = 0; @@ -167,7 +179,7 @@ class StageDebugState extends FlxState camFollow.velocity.set(); } - if (FlxG.keys.justPressed.SPACE) + if (_pad.buttonA.justPressed) { if (charMode) { @@ -196,16 +208,16 @@ class StageDebugState extends FlxState if (dragging && FlxG.mouse.justReleased || FlxG.keys.justPressed.TAB) dragging = false; - if (FlxG.keys.pressed.Z) + if (_pad.buttonL.pressed) curChar.angle -= 1 * Math.ceil(elapsed); - else if (FlxG.keys.pressed.X) + else if (_pad.buttonR.pressed) curChar.angle += 1 * Math.ceil(elapsed); - else if (FlxG.keys.pressed.R) + else if (_pad.buttonR2.justPressed) curChar.angle = 0; posText.text = (curCharString + " X: " + curChar.x + " Y: " + curChar.y + " Rotation: " + curChar.angle); - if (FlxG.keys.justPressed.ESCAPE) + if (_pad.buttonB.justPressed) { FlxG.switchState(new PlayState()); PlayState.stageTesting = true; @@ -239,7 +251,7 @@ class StageDebugState extends FlxState } } - if (FlxG.keys.pressed.CONTROL && FlxG.keys.justPressed.S) + if (_pad.buttonSave.justPressed) saveBoyPos(); if (FlxG.keys.justPressed.F1) @@ -319,6 +331,8 @@ class StageDebugState extends FlxState ++curCharIndex; } + openfl.system.System.setClipboard(result.trim()); + if ((result != null) && (result.length > 0)) { _file = new FileReference(); diff --git a/source/StoryMenuState.hx b/source/StoryMenuState.hx index d6b65bd0385..f4d3d2d4e9f 100644 --- a/source/StoryMenuState.hx +++ b/source/StoryMenuState.hx @@ -233,6 +233,10 @@ class StoryMenuState extends MusicBeatState trace("Line 165"); + #if mobileC + addVirtualPad(FULL, A_B); + #end + super.create(); } @@ -291,12 +295,12 @@ class StoryMenuState extends MusicBeatState } } - if (FlxG.keys.justPressed.UP) + if (controls.UP_P) { changeWeek(-1); } - if (FlxG.keys.justPressed.DOWN) + if (controls.DOWN_P) { changeWeek(1); } diff --git a/source/TitleState.hx b/source/TitleState.hx index d3f05e4e527..e8f533b3576 100644 --- a/source/TitleState.hx +++ b/source/TitleState.hx @@ -45,10 +45,9 @@ class TitleState extends MusicBeatState override public function create():Void { - // TODO: Refactor this to use OpenFlAssets. - #if FEATURE_FILESYSTEM - if (!sys.FileSystem.exists(Sys.getCwd() + "/assets/replays")) - sys.FileSystem.createDirectory(Sys.getCwd() + "/assets/replays"); + + #if android + FlxG.android.preventDefaultKeys = [BACK]; #end @:privateAccess diff --git a/source/VideoPlayer.hx b/source/VideoPlayer.hx new file mode 100644 index 00000000000..834a36c4ed9 --- /dev/null +++ b/source/VideoPlayer.hx @@ -0,0 +1,145 @@ +package; + +import flixel.system.FlxSound; +import flixel.FlxCamera; +import haxe.macro.Expr.Catch; +import openfl.Assets; +import openfl.media.Sound; +import flixel.FlxSprite; +import webm.*; +import Asset2File; +#if sys +import webm.WebmPlayer; +#end +import PlayState; +import flixel.addons.ui.FlxUIState; +import flixel.FlxSprite; +import flixel.FlxG; +import flixel.util.FlxPath; + +/**-200 -200 + usage: + var video = new VideoPlayer(0, 0, 'videos/ughintro.webm'); + video.play(); + add(video); + + - Bitstream not supported by this decoder + maybe use vp8 (idk) +**/ +using StringTools; + +class VideoPlayer extends FlxSprite { + public var finishCallback:Void->Void=null; + + #if sys + public var player:WebmPlayer; + #end + + public var sound:FlxSound; + public var soundMultiplier:Float = 1; + public var prevSoundMultiplier:Float = 1; + var videoFrames:Int = 0; + var doShit:Bool = false; + + public var pathfile:String; + + public function new(x, y, path:String) + { + super(x, y); + + #if sys + //WebmPlayer.SKIP_STEP_LIMIT = 90; + + pathfile = path; + + var path = Asset2File.getPath(path, ".webm"); + + videoFrames = Std.parseInt(Assets.getText(pathfile.replace(".webm", ".txt"))); + + var io:WebmIo = new WebmIoFile(path); + player = new WebmPlayer(); + player.fuck(io); + + player.addEventListener('play', function(e) { + trace('play!'); + }); + + player.addEventListener('end', function(e) { + if (finishCallback != null) + finishCallback(); + }); + + player.addEventListener('stop', function(e) { + if (finishCallback != null) + finishCallback(); + }); + + loadGraphic(player.bitmapData); + sound = FlxG.sound.play(pathfile.replace('.webm', '.ogg')); + sound.time = sound.length * soundMultiplier; + doShit = true; + #end + + #if html5 + trace('video is unsupported'); + #end + } + + public function play() { + #if sys + player.play(); + #end + + #if html5 + #end + } + + public function ownCamera() { + var cam = new FlxCamera(); + FlxG.cameras.add(cam); + cam.bgColor.alpha = 0; + cameras = [cam]; + } + override public function update(elapsed:Float) { + super.update(elapsed); + #if sys + soundMultiplier = player.renderedCount / videoFrames; + if (soundMultiplier > 1) + { + soundMultiplier = 1; + } + if (soundMultiplier < 0) + { + soundMultiplier = 0; + } + if (soundMultiplier == 0) + { + if (prevSoundMultiplier != 0) + { + sound.pause(); + sound.time = 0; + } + } else { + if (prevSoundMultiplier == 0) + { + sound.resume(); + sound.time = sound.length * soundMultiplier; + } + } + prevSoundMultiplier = soundMultiplier; + if (doShit) + { + var compareShit:Float = 50; + if (sound.time >= (sound.length * soundMultiplier) + compareShit || sound.time <= (sound.length * soundMultiplier) - compareShit) + sound.time = sound.length * soundMultiplier; + } + #end + } + + override public function destroy() { + #if sys + player.stop(); + super.destroy(); + #end + } +} \ No newline at end of file diff --git a/source/VideoState.hx b/source/VideoState.hx new file mode 100644 index 00000000000..81161aadf7e --- /dev/null +++ b/source/VideoState.hx @@ -0,0 +1,52 @@ +package; + +import MusicBeatState; +import VideoPlayer; +import flixel.*; +import flixel.text.FlxText; + +class VideoState extends MusicBeatState { + var nextState:FlxState; + var source:String = "videos/"; + var sizething:Bool; + + public function new(fileName:String = "ass",trans:FlxState, ?multiplySize:Bool = false) { + nextState = trans; + source = fileName; + sizething = multiplySize; + super(); + } + override function create() { + FlxG.sound.music.stop(); + var video = new VideoPlayer(0, 0, source); + video.finishCallback = () -> { + remove(video); + LoadingState.loadAndSwitchState(nextState); + } + video.ownCamera(); + video.setGraphicSize(FlxG.width); + video.updateHitbox(); + add(video); + video.play(); + + var text:FlxText = new FlxText(5, FlxG.height - 23, 0, #if android "Tap the screen to skip" #else "Press Space To Skip" #end, 16); + add(text); + + super.create(); + } + override function update(elapsed:Float) { + super.update(elapsed); + + for (touch in FlxG.touches.list) + { + if (touch.justPressed) + { + LoadingState.loadAndSwitchState(nextState); + } + } + if (FlxG.keys.justPressed.SPACE) + { + LoadingState.loadAndSwitchState(nextState); + } + } +} \ No newline at end of file diff --git a/source/options/AboutState.hx b/source/options/AboutState.hx new file mode 100644 index 00000000000..2c997915244 --- /dev/null +++ b/source/options/AboutState.hx @@ -0,0 +1,71 @@ +package options; + +import flash.text.TextField; +import flixel.FlxG; +import flixel.FlxSprite; +import flixel.addons.display.FlxGridOverlay; +import flixel.group.FlxGroup.FlxTypedGroup; +import flixel.math.FlxMath; +import flixel.text.FlxText; +import flixel.util.FlxColor; +import lime.utils.Assets; + +using StringTools; + +class AboutState extends MusicBeatState +{ + var logoBl:FlxSprite; + + var text:FlxText; + + override function create() + { + + // LOAD MUSIC + + // LOAD CHARACTERS + + var bg:FlxSprite = new FlxSprite().loadGraphic(Paths.image('menuBGBlue')); + + logoBl = new FlxSprite(-150, -100); + logoBl.frames = Paths.getSparrowAtlas('logoBumpin'); + logoBl.antialiasing = true; + logoBl.animation.addByPrefix('bump', 'logo bumpin', 24); + logoBl.animation.play('bump'); + logoBl.updateHitbox(); + logoBl.screenCenter(); + logoBl.y = logoBl.y - 100; + + text = new FlxText(0, 0, 0, "version 0.2.7.1" + "\n" + "ported by luckydog7", 64); + text.setFormat(Paths.font("vcr.ttf"), 32, FlxColor.WHITE, RIGHT); + text.screenCenter(); + text.y = text.y + 150; + + add(bg); + add(logoBl); + add(text); + + + super.create(); + } + + + override function update(elapsed:Float) + { + super.update(elapsed); + + if (FlxG.sound.music.volume < 0.7) + { + FlxG.sound.music.volume += 0.5 * FlxG.elapsed; + } + + #if android + if (FlxG.android.justReleased.BACK) + { + FlxG.switchState(new OptionsMenu()); + } + #end + + } + +} \ No newline at end of file diff --git a/source/options/CustomControlsState.hx b/source/options/CustomControlsState.hx new file mode 100644 index 00000000000..7cffbe49d69 --- /dev/null +++ b/source/options/CustomControlsState.hx @@ -0,0 +1,413 @@ +package options; + +import flixel.ui.FlxButton; +import flixel.addons.ui.FlxUIButton; +import flixel.text.FlxText; +import flixel.FlxG; +import flixel.FlxSprite; +import flixel.util.FlxColor; +import ui.FlxVirtualPad; +import flixel.util.FlxSave; +import flixel.math.FlxPoint; +import haxe.Json; +import ui.Hitbox; +import Config; +#if lime +import lime.system.Clipboard; +#end + +using StringTools; + +class CustomControlsState extends MusicBeatSubstate +{ + + var _pad:FlxVirtualPad; + var _hb:Hitbox; + + var exitbutton:FlxUIButton; + var exportbutton:FlxUIButton; + var importbutton:FlxUIButton; + + var up_text:FlxText; + var down_text:FlxText; + var left_text:FlxText; + var right_text:FlxText; + + var inputvari:FlxText; + + var leftArrow:FlxSprite; + var rightArrow:FlxSprite; + //'hitbox', + var controlitems:Array = ['right control', 'left control','keyboard','custom', 'hitbox']; + + var curSelected:Int = 0; + + var buttonistouched:Bool = false; + + var bindbutton:flixel.ui.FlxButton; + + var config:Config; + + public function new() + { + super(); + + //init config + config = new Config(); + + // bg + var bg:FlxSprite = new FlxSprite(-80).loadGraphic('assets/images/menuBG.png'); + bg.scrollFactor.x = 0; + bg.scrollFactor.y = 0.18; + bg.setGraphicSize(Std.int(bg.width * 1.1)); + bg.updateHitbox(); + bg.screenCenter(); + bg.antialiasing = true; + + // load curSelected + curSelected = config.getcontrolmode(); + + + //pad + _pad = new FlxVirtualPad(RIGHT_FULL, NONE); + _pad.alpha = 0; + + + + //text inputvari + inputvari = new FlxText(125, 50, 0,controlitems[0], 48); + + //arrows + var ui_tex = Paths.getSparrowAtlas('campaign_menu_UI_assets'); + + leftArrow = new FlxSprite(inputvari.x - 60,inputvari.y - 10); + leftArrow.frames = ui_tex; + leftArrow.animation.addByPrefix('idle', "arrow left"); + leftArrow.animation.addByPrefix('press', "arrow push left"); + leftArrow.animation.play('idle'); + + rightArrow = new FlxSprite(inputvari.x + inputvari.width + 10, leftArrow.y); + rightArrow.frames = ui_tex; + rightArrow.animation.addByPrefix('idle', 'arrow right'); + rightArrow.animation.addByPrefix('press', "arrow push right", 24, false); + rightArrow.animation.play('idle'); + + + //text + up_text = new FlxText(200, 200, 0,"Button up x:" + _pad.buttonUp.x +" y:" + _pad.buttonUp.y, 24); + down_text = new FlxText(200, 250, 0,"Button down x:" + _pad.buttonDown.x +" y:" + _pad.buttonDown.y, 24); + left_text = new FlxText(200, 300, 0,"Button left x:" + _pad.buttonLeft.x +" y:" + _pad.buttonLeft.y, 24); + right_text = new FlxText(200, 350, 0,"Button right x:" + _pad.buttonRight.x +" y:" + _pad.buttonRight.y, 24); + + //hitboxes + + _hb = new Hitbox(); + _hb.visible = false; + + // buttons + + exitbutton = new FlxUIButton(FlxG.width - 650,25,"exit"); + exitbutton.resize(125,50); + exitbutton.setLabelFormat("VCR OSD Mono",24,FlxColor.BLACK,"center"); + + var savebutton = new FlxUIButton((exitbutton.x + exitbutton.width + 25),25,"exit and save",() -> { + save(); + FlxG.switchState(new OptionsMenu()); + }); + savebutton.resize(250,50); + savebutton.setLabelFormat("VCR OSD Mono",24,FlxColor.BLACK,"center"); + + exportbutton = new FlxUIButton(FlxG.width - 150, 25, "export", () -> { savetoclipboard(_pad); } ); + exportbutton.resize(125,50); + exportbutton.setLabelFormat("VCR OSD Mono", 24, FlxColor.BLACK,"center"); + + importbutton = new FlxUIButton(exportbutton.x, 100, "import", () -> { loadfromclipboard(_pad); }); + importbutton.resize(125,50); + importbutton.setLabelFormat("VCR OSD Mono", 24, FlxColor.BLACK,"center"); + + // add bg + add(bg); + + // add buttons + add(exitbutton); + add(savebutton); + add(exportbutton); + add(importbutton); + + // add virtualpad + this.add(_pad); + + //add hb + add(_hb); + + + // add arrows and text + add(inputvari); + add(leftArrow); + add(rightArrow); + + // add texts + add(up_text); + add(down_text); + add(left_text); + add(right_text); + + // change selection + changeSelection(); + } + + override function update(elapsed:Float) + { + super.update(elapsed); + + #if android + var androidback:Bool = FlxG.android.justReleased.BACK; + #else + var androidback:Bool = false; + #end + if (exitbutton.justReleased || androidback){ + FlxG.switchState(new OptionsMenu()); + } + + for (touch in FlxG.touches.list){ + //left arrow animation + arrowanimate(touch); + + //change Selection + if(touch.overlaps(leftArrow) && touch.justPressed){ + changeSelection(-1); + }else if (touch.overlaps(rightArrow) && touch.justPressed){ + changeSelection(1); + } + + //custom pad + trackbutton(touch); + } + } + + function changeSelection(change:Int = 0,?forceChange:Int) + { + curSelected += change; + + if (curSelected < 0) + curSelected = controlitems.length - 1; + if (curSelected >= controlitems.length) + curSelected = 0; + trace(curSelected); + + if (forceChange != null) + { + curSelected = forceChange; + } + + inputvari.text = controlitems[curSelected]; + + if (forceChange != null) + { + if (curSelected == 2){ + _pad.visible = true; + } + + return; + } + + _hb.visible = false; + + switch curSelected{ + case 0: + remove(_pad); + _pad.alpha = 0; + _hb.visible = true; + /* this.remove(_pad); + _pad = null; + _pad = new FlxVirtualPad(RIGHT_FULL, NONE); + _pad.alpha = 0.75; + this.add(_pad);*/ + case 1: + this.remove(_pad); + _pad = null; + _pad = new FlxVirtualPad(FULL, NONE); + _pad.alpha = 0.75; + this.add(_pad); + case 2: + trace(2); + _pad.alpha = 0; + case 3: + trace(3); + this.add(_pad); + _pad.alpha = 0.75; + loadcustom(); + case 4: + remove(_pad); + _pad.alpha = 0; + _hb.visible = true; + + } + + } + + function arrowanimate(touch:flixel.input.touch.FlxTouch){ + if(touch.overlaps(leftArrow) && touch.pressed){ + leftArrow.animation.play('press'); + } + + if(touch.overlaps(leftArrow) && touch.released){ + leftArrow.animation.play('idle'); + } + //right arrow animation + if(touch.overlaps(rightArrow) && touch.pressed){ + rightArrow.animation.play('press'); + } + + if(touch.overlaps(rightArrow) && touch.released){ + rightArrow.animation.play('idle'); + } + } + + function trackbutton(touch:flixel.input.touch.FlxTouch){ + //custom pad + + if (buttonistouched){ + + if (bindbutton.justReleased && touch.justReleased) + { + bindbutton = null; + buttonistouched = false; + }else + { + movebutton(touch, bindbutton); + setbuttontexts(); + } + + }else { + if (_pad.buttonUp.justPressed) { + if (curSelected != 3) + changeSelection(0,3); + + movebutton(touch, _pad.buttonUp); + } + + if (_pad.buttonDown.justPressed) { + if (curSelected != 3) + changeSelection(0,3); + + movebutton(touch, _pad.buttonDown); + } + + if (_pad.buttonRight.justPressed) { + if (curSelected != 3) + changeSelection(0,3); + + movebutton(touch, _pad.buttonRight); + } + + if (_pad.buttonLeft.justPressed) { + if (curSelected != 3) + changeSelection(0,3); + + movebutton(touch, _pad.buttonLeft); + } + } + } + + function movebutton(touch:flixel.input.touch.FlxTouch, button:flixel.ui.FlxButton) { + button.x = touch.x - _pad.buttonUp.width / 2; + button.y = touch.y - _pad.buttonUp.height / 2; + bindbutton = button; + buttonistouched = true; + } + + function setbuttontexts() { + up_text.text = "Button up x:" + _pad.buttonUp.x +" y:" + _pad.buttonUp.y; + down_text.text = "Button down x:" + _pad.buttonDown.x +" y:" + _pad.buttonDown.y; + left_text.text = "Button left x:" + _pad.buttonLeft.x +" y:" + _pad.buttonLeft.y; + right_text.text = "Button right x:" + _pad.buttonRight.x +" y:" + _pad.buttonRight.y; + } + + + + function save() { + + config.setcontrolmode(curSelected); + + if (curSelected == 3){ + savecustom(); + } + } + + function savecustom() { + trace("saved"); + + //Config.setdata(55); + + config.savecustom(_pad); + } + + function loadcustom():Void{ + //load pad + _pad = config.loadcustom(_pad); + + } + + function resizebuttons(vpad:FlxVirtualPad, ?int:Int = 200) { + for (button in vpad) + { + button.setGraphicSize(260); + button.updateHitbox(); + } + } + + function savetoclipboard(pad:FlxVirtualPad) { + trace("saved"); + + var json = { + buttonsarray : [] + }; + + var tempCount:Int = 0; + var buttonsarray = new Array(); + + for (buttons in pad) + { + buttonsarray[tempCount] = FlxPoint.get(buttons.x, buttons.y); + + tempCount++; + } + + json.buttonsarray = buttonsarray; + + trace(json); + + var data:String = Json.stringify(json); + + openfl.system.System.setClipboard(data.trim()); + } + + function loadfromclipboard(pad:FlxVirtualPad):Void{ + //load pad + + if (curSelected != 3) + changeSelection(0,3); + + var cbtext:String = Clipboard.text; // this not working on android 10 or higher + + if (!cbtext.endsWith("}")) return; + + var json = Json.parse(cbtext); + + var tempCount:Int = 0; + + for(buttons in pad) + { + buttons.x = json.buttonsarray[tempCount].x; + buttons.y = json.buttonsarray[tempCount].y; + tempCount++; + } + setbuttontexts(); + } + + override function destroy() + { + super.destroy(); + } +} diff --git a/source/options/SetFpsSubState.hx b/source/options/SetFpsSubState.hx new file mode 100644 index 00000000000..5156e8d81f3 --- /dev/null +++ b/source/options/SetFpsSubState.hx @@ -0,0 +1,144 @@ +package options; + +import flixel.text.FlxText; +import flixel.tweens.FlxEase; +import flixel.tweens.FlxTween; +import flixel.group.FlxGroup.FlxTypedGroup; +import flixel.FlxG; +import flixel.FlxSprite; +import flixel.util.FlxColor; +import ui.FlxVirtualPad; +import flixel.util.FlxSave; +import flixel.math.FlxPoint; +import Config; + +class SetFpsSubState extends MusicBeatSubstate +{ + var grpMenuShit:FlxTypedGroup; + + var menuItems:Array = ['default fps', 'ninety fps']; + var curSelected:Int = 0; + + var _pad:FlxVirtualPad; + + var _gamesave:FlxSave; + + public function new() + { + super(); + + var bg:FlxSprite = new FlxSprite().makeGraphic(FlxG.width, FlxG.height, FlxColor.BLACK); + bg.alpha = 0.6; + bg.scrollFactor.set(); + add(bg); + + FlxTween.tween(bg, {alpha: 0.6}, 0.4, {ease: FlxEase.quartInOut}); + + grpMenuShit = new FlxTypedGroup(); + add(grpMenuShit); + + for (i in 0...menuItems.length) + { + var songText:Alphabet = new Alphabet(0, (70 * i) + 30, menuItems[i], true, false); + songText.isMenuItem = true; + songText.targetY = i; + grpMenuShit.add(songText); + } + + var notice = new FlxText(0, 0, 0,"the fps will be changed after you restart the game", 24); + add(notice); + notice.x = (FlxG.width / 2) - (notice.width / 2); + notice.y = FlxG.height - 56; + notice.alpha = 0.3; + + changeSelection(); + + cameras = [FlxG.cameras.list[FlxG.cameras.list.length - 1]]; + + _gamesave = new FlxSave(); + _gamesave.bind("gamesetup"); + + _pad = new FlxVirtualPad(UP_DOWN, A_B); + _pad.alpha = 0.75; + this.add(_pad); + } + + override function update(elapsed:Float) + { + super.update(elapsed); + /* + var upP = controls.UP_P; + var downP = controls.DOWN_P; + var accepted = controls.ACCEPT; + */ + var UP_P = _pad.buttonUp.justReleased; + var DOWN_P = _pad.buttonDown.justReleased; + var BACK = _pad.buttonB.justReleased; + var ACCEPT = _pad.buttonA.justReleased; + + #if android + var BACK = _pad.buttonB.justPressed || FlxG.android.justReleased.BACK; + #else + var BACK = _pad.buttonB.justPressed; + #end + + if (UP_P) + { + changeSelection(-1); + } + if (DOWN_P) + { + changeSelection(1); + } + + if (BACK) + { + close(); + } + + if (ACCEPT) + { + switch (curSelected){ + case 1: + new Config().setFrameRate(90); + default: + new Config().setFrameRate(); + } + close(); + } + + + } + + override function destroy() + { + super.destroy(); + } + + function changeSelection(change:Int = 0):Void + { + curSelected += change; + + if (curSelected < 0) + curSelected = menuItems.length - 1; + if (curSelected >= menuItems.length) + curSelected = 0; + + var bullShit:Int = 0; + + for (item in grpMenuShit.members) + { + item.targetY = bullShit - curSelected; + bullShit++; + + item.alpha = 0.6; + // item.setGraphicSize(Std.int(item.width * 0.8)); + + if (item.targetY == 0) + { + item.alpha = 1; + // item.setGraphicSize(Std.int(item.width)); + } + } + } +} diff --git a/source/ui/FlxVirtualPad.hx b/source/ui/FlxVirtualPad.hx new file mode 100644 index 00000000000..f57e79e44ff --- /dev/null +++ b/source/ui/FlxVirtualPad.hx @@ -0,0 +1,281 @@ +package ui; + +import flixel.FlxG; +import flixel.graphics.frames.FlxTileFrames; +import flixel.group.FlxSpriteGroup; +import flixel.math.FlxPoint; +import flixel.system.FlxAssets; +import flixel.util.FlxDestroyUtil; +import flixel.ui.FlxButton; +import flixel.graphics.frames.FlxAtlasFrames; +import flash.display.BitmapData; +import flixel.graphics.FlxGraphic; +import openfl.utils.ByteArray; + +/** + * A gamepad which contains 4 directional buttons and 4 action buttons. + * It's easy to set the callbacks and to customize the layout. + * + * @author Ka Wing Chin + */ +@:keep @:bitmap("assets/preload/images/virtual-input.png") +class GraphicVirtualInput extends BitmapData {} + +@:file("assets/preload/images/virtual-input.txt") +class VirtualInputData extends #if (lime_legacy || nme) ByteArray #else ByteArrayData #end {} + +class FlxVirtualPad extends FlxSpriteGroup +{ + public var buttonA:FlxButton; + public var buttonB:FlxButton; + public var buttonC:FlxButton; + public var buttonY:FlxButton; + public var buttonX:FlxButton; + public var buttonLeft:FlxButton; + public var buttonUp:FlxButton; + public var buttonRight:FlxButton; + public var buttonDown:FlxButton; + + public var button6:FlxButton; + public var button1:FlxButton; + public var button7:FlxButton; + public var buttonIn:FlxButton; + public var buttonOut:FlxButton; + public var buttonSave:FlxButton; + public var buttonL:FlxButton; + public var buttonR:FlxButton; + public var buttonR2:FlxButton; + public var buttonStage:FlxButton; + + public var buttonUp2:FlxButton; + public var buttonDown2:FlxButton; + + + /** + * Group of directions buttons. + */ + public var dPad:FlxSpriteGroup; + + /** + * Group of action buttons. + */ + public var actions:FlxSpriteGroup; + + /** + * Create a gamepad which contains 4 directional buttons and 4 action buttons. + * + * @param DPadMode The D-Pad mode. `FULL` for example. + * @param ActionMode The action buttons mode. `A_B_C` for example. + */ + public function new(?DPad:FlxDPadMode, ?Action:FlxActionMode) + { + super(); + scrollFactor.set(); + + if (DPad == null) + DPad = FULL; + if (Action == null) + Action = A_B_C; + + dPad = new FlxSpriteGroup(); + dPad.scrollFactor.set(); + + actions = new FlxSpriteGroup(); + actions.scrollFactor.set(); + + switch (DPad) + { + case UP_DOWN: + dPad.add(add(buttonUp = createButton(0, FlxG.height - 85 * 3, 44 * 3, 45 * 3, "up"))); + dPad.add(add(buttonDown = createButton(0, FlxG.height - 45 * 3, 44 * 3, 45 * 3, "down"))); + case LEFT_RIGHT: + dPad.add(add(buttonLeft = createButton(0, FlxG.height - 45 * 3, 44 * 3, 45 * 3, "left"))); + dPad.add(add(buttonRight = createButton(42 * 3, FlxG.height - 45 * 3, 44 * 3, 45 * 3, "right"))); + case UP_LEFT_RIGHT: + dPad.add(add(buttonUp = createButton(35 * 3, FlxG.height - 81 * 3, 44 * 3, 45 * 3, "up"))); + dPad.add(add(buttonLeft = createButton(0, FlxG.height - 45 * 3, 44 * 3, 45 * 3, "left"))); + dPad.add(add(buttonRight = createButton(69 * 3, FlxG.height - 45 * 3, 44 * 3, 45 * 3, "right"))); + case FULL: + dPad.add(add(buttonUp = createButton(35 * 3, FlxG.height - 116 * 3, 44 * 3, 45 * 3, "up"))); + dPad.add(add(buttonLeft = createButton(0, FlxG.height - 81 * 3, 44 * 3, 45 * 3, "left"))); + dPad.add(add(buttonRight = createButton(69 * 3, FlxG.height - 81 * 3, 44 * 3, 45 * 3, "right"))); + dPad.add(add(buttonDown = createButton(35 * 3, FlxG.height - 45 * 3, 44 * 3, 45 * 3, "down"))); + case RIGHT_FULL: + dPad.add(add(buttonUp = createButton(FlxG.width - 86 * 3, FlxG.height - 66 - 116 * 3, 44 * 3, 45 * 3, "up"))); + dPad.add(add(buttonLeft = createButton(FlxG.width - 130 * 3, FlxG.height - 66 - 81 * 3, 44 * 3, 45 * 3, "left"))); + dPad.add(add(buttonRight = createButton(FlxG.width - 44 * 3, FlxG.height - 66 - 81 * 3, 44 * 3, 45 * 3, "right"))); + dPad.add(add(buttonDown = createButton(FlxG.width - 86 * 3, FlxG.height - 66 - 45 * 3, 44 * 3, 45 * 3, "down"))); + case ANIMATION: + dPad.add(add(buttonUp2 = createButton(0, FlxG.height - 85 * 3, 44 * 3, 45 * 3, "up"))); + dPad.add(add(buttonDown2 = createButton(0, FlxG.height - 45 * 3, 44 * 3, 45 * 3, "down"))); + + dPad.add(add(buttonUp = createButton(75 * 3, FlxG.height - 116 * 3, 44 * 3, 45 * 3, "up"))); + dPad.add(add(buttonLeft = createButton(40 * 3, FlxG.height - 81 * 3, 44 * 3, 45 * 3, "left"))); + dPad.add(add(buttonRight = createButton(109 * 3, FlxG.height - 81 * 3, 44 * 3, 45 * 3, "right"))); + dPad.add(add(buttonDown = createButton(75 * 3, FlxG.height - 45 * 3, 44 * 3, 45 * 3, "down"))); + case NONE: // do nothing + } + + switch (Action) + { + case A: + actions.add(add(buttonA = createButton(FlxG.width - 44 * 3, FlxG.height - 45 * 3, 44 * 3, 45 * 3, "a"))); + case A_B: + actions.add(add(buttonA = createButton(FlxG.width - 44 * 3, FlxG.height - 45 * 3, 44 * 3, 45 * 3, "a"))); + actions.add(add(buttonB = createButton(FlxG.width - 86 * 3, FlxG.height - 45 * 3, 44 * 3, 45 * 3, "b"))); + case STAGE: + actions.add(add(buttonA = createButton(FlxG.width - 44 * 3, FlxG.height - 45 * 3, 44 * 3, 45 * 3, "a"))); + actions.add(add(buttonB = createButton(FlxG.width - 86 * 3, FlxG.height - 45 * 3, 44 * 3, 45 * 3, "b"))); + actions.add(add(buttonC = createButton(FlxG.width - 128 * 3, FlxG.height - 45 * 3, 44 * 3, 45 * 3, "c"))); + actions.add(add(buttonIn = createButton(FlxG.width - 44 * 3, FlxG.height - 116 * 3, 44 * 3, 45 * 3, "in"))); + actions.add(add(buttonOut = createButton(FlxG.width - 86 * 3, FlxG.height - 116 * 3, 44 * 3, 45 * 3, "out"))); + actions.add(add(buttonSave = createButton(FlxG.width - 86 * 3, FlxG.height - 160 * 3, 44 * 3, 45 * 3, "save"))); + actions.add(add(buttonL = createButton(0, FlxG.height - 160 * 3, 44 * 3, 45 * 3, "l"))); + actions.add(add(buttonR = createButton(42 * 3, FlxG.height - 160 * 3, 44 * 3, 45 * 3, "r"))); + actions.add(add(buttonR2 = createButton(84 * 3, FlxG.height - 160 * 3, 44 * 3, 45 * 3, "r2"))); + case ANIMATION: + actions.add(add(buttonA = createButton(FlxG.width - 44 * 3, FlxG.height - 45 * 3, 44 * 3, 45 * 3, "a"))); + actions.add(add(buttonB = createButton(FlxG.width - 86 * 3, FlxG.height - 45 * 3, 44 * 3, 45 * 3, "b"))); + actions.add(add(buttonIn = createButton(FlxG.width - 44 * 3, FlxG.height - 116 * 3, 44 * 3, 45 * 3, "in"))); + actions.add(add(buttonOut = createButton(FlxG.width - 86 * 3, FlxG.height - 116 * 3, 44 * 3, 45 * 3, "out"))); + actions.add(add(buttonSave = createButton(FlxG.width - 86 * 3, FlxG.height - 160 * 3, 44 * 3, 45 * 3, "save"))); + case SONGD: + actions.add(add(buttonStage = createButton(0, FlxG.height - 240 * 3, 44 * 3, 45 * 3, "stage"))); + case A_B_6: + actions.add(add(buttonA = createButton(FlxG.width - 44 * 3, FlxG.height - 45 * 3, 44 * 3, 45 * 3, "a"))); + actions.add(add(buttonB = createButton(FlxG.width - 86 * 3, FlxG.height - 45 * 3, 44 * 3, 45 * 3, "b"))); + actions.add(add(button6 = createButton(FlxG.width - 44 * 3, FlxG.height - 116 * 3, 44 * 3, 45 * 3, "6"))); + case A_B_6_1: + actions.add(add(buttonA = createButton(FlxG.width - 44 * 3, FlxG.height - 45 * 3, 44 * 3, 45 * 3, "a"))); + actions.add(add(buttonB = createButton(FlxG.width - 86 * 3, FlxG.height - 45 * 3, 44 * 3, 45 * 3, "b"))); + actions.add(add(button6 = createButton(FlxG.width - 44 * 3, FlxG.height - 116 * 3, 44 * 3, 45 * 3, "6"))); + actions.add(add(button1 = createButton(FlxG.width - 86 * 3, FlxG.height - 116 * 3, 44 * 3, 45 * 3, "1"))); + case A_B_6_1_7: + actions.add(add(buttonA = createButton(FlxG.width - 44 * 3, FlxG.height - 45 * 3, 44 * 3, 45 * 3, "a"))); + actions.add(add(buttonB = createButton(FlxG.width - 86 * 3, FlxG.height - 45 * 3, 44 * 3, 45 * 3, "b"))); + actions.add(add(button6 = createButton(FlxG.width - 44 * 3, FlxG.height - 116 * 3, 44 * 3, 45 * 3, "6"))); + actions.add(add(button1 = createButton(FlxG.width - 44 * 3, FlxG.height - 160 * 3, 44 * 3, 45 * 3, "1"))); + actions.add(add(button7 = createButton(FlxG.width - 86 * 3, FlxG.height - 116 * 3, 44 * 3, 45 * 3, "7"))); + case A_B_C: + actions.add(add(buttonA = createButton(FlxG.width - 128, FlxG.height - 45, 44, 45, "a"))); + actions.add(add(buttonB = createButton(FlxG.width - 86, FlxG.height - 45, 44, 45, "b"))); + actions.add(add(buttonC = createButton(FlxG.width - 44, FlxG.height - 45, 44, 45, "c"))); + case A_B_X_Y: + actions.add(add(buttonY = createButton(FlxG.width - 86, FlxG.height - 85, 44, 45, "y"))); + actions.add(add(buttonX = createButton(FlxG.width - 44, FlxG.height - 85, 44, 45, "x"))); + actions.add(add(buttonB = createButton(FlxG.width - 86, FlxG.height - 45, 44, 45, "b"))); + actions.add(add(buttonA = createButton(FlxG.width - 44, FlxG.height - 45, 44, 45, "a"))); + case NONE: // do nothing + } + } + + override public function destroy():Void + { + super.destroy(); + + dPad = FlxDestroyUtil.destroy(dPad); + actions = FlxDestroyUtil.destroy(actions); + + dPad = null; + actions = null; + buttonA = null; + buttonB = null; + buttonC = null; + buttonY = null; + buttonX = null; + buttonLeft = null; + buttonUp = null; + buttonDown = null; + buttonRight = null; + + button1 = null; + button6 = null; + button7 = null; + buttonIn = null; + buttonOut = null; + buttonSave = null; + buttonL = null; + buttonR = null; + buttonR2 = null; + buttonStage = null; + buttonUp2 = null; + buttonDown2 = null; + } + + /** + * @param X The x-position of the button. + * @param Y The y-position of the button. + * @param Width The width of the button. + * @param Height The height of the button. + * @param Graphic The image of the button. It must contains 3 frames (`NORMAL`, `HIGHLIGHT`, `PRESSED`). + * @param Callback The callback for the button. + * @return The button + */ + public function createButton(X:Float, Y:Float, Width:Int, Height:Int, Graphic:String, ?OnClick:Void->Void):FlxButton + { + var button = new FlxButton(X, Y); + var frame = getVirtualInputFrames().getByName(Graphic); + button.frames = FlxTileFrames.fromFrame(frame, FlxPoint.get(Width, Height)); + button.resetSizeFromFrame(); + button.solid = false; + button.immovable = true; + button.scrollFactor.set(); + + #if FLX_DEBUG + button.ignoreDrawDebug = true; + #end + + if (OnClick != null) + button.onDown.callback = OnClick; + + return button; + } + + public static function getVirtualInputFrames():FlxAtlasFrames + { + #if !web + var bitmapData = new GraphicVirtualInput(0, 0); + #end + + /* + #if html5 // dirty hack for openfl/openfl#682 + Reflect.setProperty(bitmapData, "width", 399); + Reflect.setProperty(bitmapData, "height", 183); + #end + */ + + #if !web + var graphic:FlxGraphic = FlxGraphic.fromBitmapData(bitmapData); + return FlxAtlasFrames.fromSpriteSheetPacker(graphic, Std.string(new VirtualInputData())); + #else + var graphic:FlxGraphic = FlxGraphic.fromAssetKey(Paths.image('virtual-input')); + return FlxAtlasFrames.fromSpriteSheetPacker(graphic, Std.string(new VirtualInputData())); + #end + } +} + +enum FlxDPadMode +{ + NONE; + UP_DOWN; + ANIMATION; + LEFT_RIGHT; + UP_LEFT_RIGHT; + RIGHT_FULL; + FULL; +} + +enum FlxActionMode +{ + NONE; + A; + A_B; + ANIMATION; + SONGD; + STAGE; + A_B_6; + A_B_6_1; + A_B_6_1_7; + A_B_C; + A_B_X_Y; +} diff --git a/source/ui/Hitbox.hx b/source/ui/Hitbox.hx new file mode 100644 index 00000000000..77b983b7469 --- /dev/null +++ b/source/ui/Hitbox.hx @@ -0,0 +1,98 @@ +package ui; + +import flixel.graphics.FlxGraphic; +import flixel.addons.ui.FlxButtonPlus; +import flixel.FlxSprite; +import flixel.FlxG; +import flixel.graphics.frames.FlxTileFrames; +import flixel.group.FlxSpriteGroup; +import flixel.math.FlxPoint; +import flixel.system.FlxAssets; +import flixel.util.FlxDestroyUtil; +import flixel.ui.FlxButton; +import flixel.graphics.frames.FlxAtlasFrames; +import flixel.graphics.frames.FlxFrame; +import flixel.ui.FlxVirtualPad; +import flixel.tweens.FlxTween; +import flixel.tweens.FlxEase; + +// copyed from flxvirtualpad +class Hitbox extends FlxSpriteGroup +{ + public var hitbox:FlxSpriteGroup; + + var sizex:Int = 320; + + var screensizey:Int = 720; + + public var buttonLeft:FlxButton; + public var buttonDown:FlxButton; + public var buttonUp:FlxButton; + public var buttonRight:FlxButton; + + public function new(?widghtScreen:Int) + { + super(); + + /*if (widghtScreen == null) + widghtScreen = FlxG.width;*/ + + sizex = widghtScreen != null ? Std.int(widghtScreen / 4) : 320; + + + //add graphic + hitbox = new FlxSpriteGroup(); + hitbox.scrollFactor.set(); + + var hitbox_hint:FlxSprite = new FlxSprite(0, 0).loadGraphic('assets/shared/images/hitbox/hitbox_hint.png'); + + hitbox_hint.alpha = 0.2; + + add(hitbox_hint); + + + hitbox.add(add(buttonLeft = createhitbox(0, "left"))); + + hitbox.add(add(buttonDown = createhitbox(sizex, "down"))); + + hitbox.add(add(buttonUp = createhitbox(sizex * 2, "up"))); + + hitbox.add(add(buttonRight = createhitbox(sizex * 3, "right"))); + } + + public function createhitbox(X:Float, framestring:String) { + var button = new FlxButton(X, 0); + var frames = FlxAtlasFrames.fromSparrow('assets/shared/images/hitbox/hitbox.png', 'assets/shared/images/hitbox/hitbox.xml'); + + var graphic:FlxGraphic = FlxGraphic.fromFrame(frames.getByName(framestring)); + + button.loadGraphic(graphic); + + button.alpha = 0; + + + button.onDown.callback = function (){ + FlxTween.num(0, 0.75, .075, {ease: FlxEase.circInOut}, function (a:Float) { button.alpha = a; }); + }; + + button.onUp.callback = function (){ + FlxTween.num(0.75, 0, .1, {ease: FlxEase.circInOut}, function (a:Float) { button.alpha = a; }); + } + + button.onOut.callback = function (){ + FlxTween.num(button.alpha, 0, .2, {ease: FlxEase.circInOut}, function (a:Float) { button.alpha = a; }); + } + + return button; + } + + override public function destroy():Void + { + super.destroy(); + + buttonLeft = null; + buttonDown = null; + buttonUp = null; + buttonRight = null; + } +} \ No newline at end of file diff --git a/source/ui/Mobilecontrols.hx b/source/ui/Mobilecontrols.hx new file mode 100644 index 00000000000..7ee82621040 --- /dev/null +++ b/source/ui/Mobilecontrols.hx @@ -0,0 +1,84 @@ +package ui; + +import flixel.FlxG; +import flixel.group.FlxSpriteGroup; + +import ui.FlxVirtualPad; +import ui.Hitbox; + +import Config; + +class Mobilecontrols extends FlxSpriteGroup +{ + public var mode:ControlsGroup = HITBOX; + + public var _hitbox:Hitbox; + public var _virtualPad:FlxVirtualPad; + + var config:Config; + + public function new() + { + super(); + + config = new Config(); + + // load control mode num from Config.hx + mode = getModeFromNumber(config.getcontrolmode()); + trace(config.getcontrolmode()); + + switch (mode) + { + case VIRTUALPAD_RIGHT: + initVirtualPad(0); + case VIRTUALPAD_LEFT: + initVirtualPad(1); + case VIRTUALPAD_CUSTOM: + initVirtualPad(2); + case HITBOX: + _hitbox = new Hitbox(); + add(_hitbox); + case KEYBOARD: + } + } + + function initVirtualPad(vpadMode:Int) + { + switch (vpadMode) + { + case 1: + _virtualPad = new FlxVirtualPad(FULL, NONE); + case 2: + _virtualPad = new FlxVirtualPad(FULL, NONE); + _virtualPad = config.loadcustom(_virtualPad); + default: // 0 + _virtualPad = new FlxVirtualPad(RIGHT_FULL, NONE); + } + + _virtualPad.alpha = 0.75; + add(_virtualPad); + } + + + public static function getModeFromNumber(modeNum:Int):ControlsGroup { + return switch (modeNum) + { + case 0: VIRTUALPAD_RIGHT; + case 1: VIRTUALPAD_LEFT; + case 2: KEYBOARD; + case 3: VIRTUALPAD_CUSTOM; + case 4: HITBOX; + + default: VIRTUALPAD_RIGHT; + + } + } +} + +enum ControlsGroup { + VIRTUALPAD_RIGHT; + VIRTUALPAD_LEFT; + KEYBOARD; + VIRTUALPAD_CUSTOM; + HITBOX; +} \ No newline at end of file diff --git a/source/vscode-project.hxml b/source/vscode-project.hxml new file mode 100644 index 00000000000..1524649b69d --- /dev/null +++ b/source/vscode-project.hxml @@ -0,0 +1,3 @@ +#automatically generated do not edit +#@date Tue Dec 14 2021 18:35:32 GMT-0300 (Horário Padrão de Brasília) +-cp c:\temp\b03daa7c25a5885336d573e7becc42cc56c88e43 \ No newline at end of file