first commit

This commit is contained in:
MeowcaTheoRange 2024-11-23 14:36:52 -06:00
commit b4d33cdc7a
52 changed files with 3837 additions and 0 deletions

2
.gitattributes vendored Normal file
View file

@ -0,0 +1,2 @@
# Normalize EOL for all files that Git considers text files.
* text=auto eol=lf

4
.gitignore vendored Normal file
View file

@ -0,0 +1,4 @@
# Godot 4+ specific ignores
.godot/
/android/
/addons/

12
FunkPanion.csproj Normal file
View file

@ -0,0 +1,12 @@
<Project Sdk="Godot.NET.Sdk/4.3.0">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<TargetFramework Condition=" '$(GodotTargetPlatform)' == 'android' ">net7.0</TargetFramework>
<TargetFramework Condition=" '$(GodotTargetPlatform)' == 'ios' ">net8.0</TargetFramework>
<EnableDynamicLoading>true</EnableDynamicLoading>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="SharpHook" Version="5.3.8" />
<PackageReference Include="SharpHook.Reactive" Version="5.3.8" />
</ItemGroup>
</Project>

19
FunkPanion.sln Normal file
View file

@ -0,0 +1,19 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 2012
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FunkPanion", "FunkPanion.csproj", "{3011DD22-D461-4393-B9FC-2AD111BC5DD7}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
ExportDebug|Any CPU = ExportDebug|Any CPU
ExportRelease|Any CPU = ExportRelease|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{3011DD22-D461-4393-B9FC-2AD111BC5DD7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3011DD22-D461-4393-B9FC-2AD111BC5DD7}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3011DD22-D461-4393-B9FC-2AD111BC5DD7}.ExportDebug|Any CPU.ActiveCfg = ExportDebug|Any CPU
{3011DD22-D461-4393-B9FC-2AD111BC5DD7}.ExportDebug|Any CPU.Build.0 = ExportDebug|Any CPU
{3011DD22-D461-4393-B9FC-2AD111BC5DD7}.ExportRelease|Any CPU.ActiveCfg = ExportRelease|Any CPU
{3011DD22-D461-4393-B9FC-2AD111BC5DD7}.ExportRelease|Any CPU.Build.0 = ExportRelease|Any CPU
EndGlobalSection
EndGlobal

BIN
assets/BOYFRIEND.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 MiB

View file

@ -0,0 +1,34 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://b6x537wsl3853"
path="res://.godot/imported/BOYFRIEND.png-39cdb7ee73d5290fc66317ae894c5c49.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://assets/BOYFRIEND.png"
dest_files=["res://.godot/imported/BOYFRIEND.png-39cdb7ee73d5290fc66317ae894c5c49.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1

298
assets/BOYFRIEND.xml Normal file
View file

@ -0,0 +1,298 @@
<?xml version="1.0" encoding="utf-8"?>
<TextureAtlas imagePath="BOYFRIEND.png">
<SubTexture name="BF HEY!!0000" x="5388" y="509" width="395" height="416" frameX="0" frameY="0" frameWidth="415" frameHeight="418" />
<SubTexture name="BF HEY!!0001" x="5388" y="509" width="395" height="416" frameX="0" frameY="0" frameWidth="415" frameHeight="418" />
<SubTexture name="BF HEY!!0002" x="5793" y="509" width="413" height="410" frameX="-1" frameY="-8" frameWidth="415" frameHeight="418" />
<SubTexture name="BF HEY!!0003" x="5793" y="509" width="413" height="410" frameX="-1" frameY="-8" frameWidth="415" frameHeight="418" />
<SubTexture name="BF HEY!!0004" x="6216" y="509" width="414" height="412" frameX="-1" frameY="-6" frameWidth="415" frameHeight="418" />
<SubTexture name="BF HEY!!0005" x="6216" y="509" width="414" height="412" frameX="-1" frameY="-6" frameWidth="415" frameHeight="418" />
<SubTexture name="BF HEY!!0006" x="6216" y="509" width="414" height="412" frameX="-1" frameY="-6" frameWidth="415" frameHeight="418" />
<SubTexture name="BF HEY!!0007" x="6216" y="509" width="414" height="412" frameX="-1" frameY="-6" frameWidth="415" frameHeight="418" />
<SubTexture name="BF HEY!!0008" x="6216" y="509" width="414" height="412" frameX="-1" frameY="-6" frameWidth="415" frameHeight="418" />
<SubTexture name="BF HEY!!0009" x="6216" y="509" width="414" height="412" frameX="-1" frameY="-6" frameWidth="415" frameHeight="418" />
<SubTexture name="BF HEY!!0010" x="6216" y="509" width="414" height="412" frameX="-1" frameY="-6" frameWidth="415" frameHeight="418" />
<SubTexture name="BF HEY!!0011" x="6216" y="509" width="414" height="412" frameX="-1" frameY="-6" frameWidth="415" frameHeight="418" />
<SubTexture name="BF HEY!!0012" x="6216" y="509" width="414" height="412" frameX="-1" frameY="-6" frameWidth="415" frameHeight="418" />
<SubTexture name="BF HEY!!0013" x="6216" y="509" width="414" height="412" frameX="-1" frameY="-6" frameWidth="415" frameHeight="418" />
<SubTexture name="BF HEY!!0014" x="6216" y="509" width="414" height="412" frameX="-1" frameY="-6" frameWidth="415" frameHeight="418" />
<SubTexture name="BF HEY!!0015" x="6216" y="509" width="414" height="412" frameX="-1" frameY="-6" frameWidth="415" frameHeight="418" />
<SubTexture name="BF HEY!!0016" x="6216" y="509" width="414" height="412" frameX="-1" frameY="-6" frameWidth="415" frameHeight="418" />
<SubTexture name="BF HEY!!0017" x="6216" y="509" width="414" height="412" frameX="-1" frameY="-6" frameWidth="415" frameHeight="418" />
<SubTexture name="BF HEY!!0018" x="6216" y="509" width="414" height="412" frameX="-1" frameY="-6" frameWidth="415" frameHeight="418" />
<SubTexture name="BF HEY!!0019" x="6216" y="509" width="414" height="412" frameX="-1" frameY="-6" frameWidth="415" frameHeight="418" />
<SubTexture name="BF HEY!!0020" x="6216" y="509" width="414" height="412" frameX="-1" frameY="-6" frameWidth="415" frameHeight="418" />
<SubTexture name="BF HEY!!0021" x="6216" y="509" width="414" height="412" frameX="-1" frameY="-6" frameWidth="415" frameHeight="418" />
<SubTexture name="BF HEY!!0022" x="6216" y="509" width="414" height="412" frameX="-1" frameY="-6" frameWidth="415" frameHeight="418" />
<SubTexture name="BF HEY!!0023" x="6216" y="509" width="414" height="412" frameX="-1" frameY="-6" frameWidth="415" frameHeight="418" />
<SubTexture name="BF HEY!!0024" x="6216" y="509" width="414" height="412" frameX="-1" frameY="-6" frameWidth="415" frameHeight="418" />
<SubTexture name="BF HEY!!0025" x="6216" y="509" width="414" height="412" frameX="-1" frameY="-6" frameWidth="415" frameHeight="418" />
<SubTexture name="BF idle dance0000" x="0" y="2344" width="406" height="392" frameX="-1" frameY="-20" frameWidth="411" frameHeight="412" />
<SubTexture name="BF idle dance0001" x="0" y="2344" width="406" height="392" frameX="-1" frameY="-20" frameWidth="411" frameHeight="412" />
<SubTexture name="BF idle dance0002" x="416" y="2344" width="408" height="393" frameX="0" frameY="-19" frameWidth="411" frameHeight="412" />
<SubTexture name="BF idle dance0003" x="416" y="2344" width="408" height="393" frameX="0" frameY="-19" frameWidth="411" frameHeight="412" />
<SubTexture name="BF idle dance0004" x="834" y="2344" width="405" height="398" frameX="-3" frameY="-14" frameWidth="411" frameHeight="412" />
<SubTexture name="BF idle dance0005" x="834" y="2344" width="405" height="398" frameX="-3" frameY="-14" frameWidth="411" frameHeight="412" />
<SubTexture name="BF idle dance0006" x="1249" y="2344" width="410" height="411" frameX="-1" frameY="-1" frameWidth="411" frameHeight="412" />
<SubTexture name="BF idle dance0007" x="1249" y="2344" width="410" height="411" frameX="-1" frameY="-1" frameWidth="411" frameHeight="412" />
<SubTexture name="BF idle dance0008" x="1669" y="2344" width="408" height="412" frameX="-2" frameY="0" frameWidth="411" frameHeight="412" />
<SubTexture name="BF idle dance0009" x="1669" y="2344" width="408" height="412" frameX="-2" frameY="0" frameWidth="411" frameHeight="412" />
<SubTexture name="BF idle dance0010" x="1669" y="2344" width="408" height="412" frameX="-2" frameY="0" frameWidth="411" frameHeight="412" />
<SubTexture name="BF idle dance0011" x="1669" y="2344" width="408" height="412" frameX="-2" frameY="0" frameWidth="411" frameHeight="412" />
<SubTexture name="BF idle dance0012" x="1669" y="2344" width="408" height="412" frameX="-2" frameY="0" frameWidth="411" frameHeight="412" />
<SubTexture name="BF idle dance0013" x="1669" y="2344" width="408" height="412" frameX="-2" frameY="0" frameWidth="411" frameHeight="412" />
<SubTexture name="BF NOTE DOWN MISS0000" x="6640" y="509" width="374" height="357" frameX="-1" frameY="-35" frameWidth="375" frameHeight="362" />
<SubTexture name="BF NOTE DOWN MISS0001" x="7407" y="509" width="376" height="392" frameX="-1" frameY="0" frameWidth="378" frameHeight="392" />
<SubTexture name="BF NOTE DOWN MISS0002" x="7407" y="509" width="376" height="392" frameX="-1" frameY="0" frameWidth="378" frameHeight="392" />
<SubTexture name="BF NOTE DOWN MISS0003" x="7793" y="509" width="378" height="388" frameX="0" frameY="-4" frameWidth="378" frameHeight="392" />
<SubTexture name="BF NOTE DOWN MISS0004" x="7793" y="509" width="378" height="388" frameX="0" frameY="-4" frameWidth="378" frameHeight="392" />
<SubTexture name="BF NOTE DOWN MISS0005" x="7793" y="509" width="378" height="388" frameX="0" frameY="-4" frameWidth="378" frameHeight="392" />
<SubTexture name="BF NOTE DOWN MISS0006" x="7793" y="509" width="378" height="388" frameX="0" frameY="-4" frameWidth="378" frameHeight="392" />
<SubTexture name="BF NOTE DOWN MISS0007" x="7793" y="509" width="378" height="388" frameX="0" frameY="-4" frameWidth="378" frameHeight="392" />
<SubTexture name="BF NOTE DOWN MISS0008" x="7793" y="509" width="378" height="388" frameX="0" frameY="-4" frameWidth="378" frameHeight="392" />
<SubTexture name="BF NOTE DOWN MISS0009" x="7793" y="509" width="378" height="388" frameX="0" frameY="-4" frameWidth="378" frameHeight="392" />
<SubTexture name="BF NOTE DOWN MISS0010" x="7793" y="509" width="378" height="388" frameX="0" frameY="-4" frameWidth="378" frameHeight="392" />
<SubTexture name="BF NOTE DOWN MISS0011" x="7793" y="509" width="378" height="388" frameX="0" frameY="-4" frameWidth="378" frameHeight="392" />
<SubTexture name="BF NOTE DOWN MISS0012" x="7793" y="509" width="378" height="388" frameX="0" frameY="-4" frameWidth="378" frameHeight="392" />
<SubTexture name="BF NOTE DOWN MISS0013" x="7793" y="509" width="378" height="388" frameX="0" frameY="-4" frameWidth="378" frameHeight="392" />
<SubTexture name="BF NOTE DOWN MISS0014" x="7793" y="509" width="378" height="388" frameX="0" frameY="-4" frameWidth="378" frameHeight="392" />
<SubTexture name="BF NOTE DOWN MISS0015" x="7793" y="509" width="378" height="388" frameX="0" frameY="-4" frameWidth="378" frameHeight="392" />
<SubTexture name="BF NOTE DOWN MISS0016" x="7793" y="509" width="378" height="388" frameX="0" frameY="-4" frameWidth="378" frameHeight="392" />
<SubTexture name="BF NOTE DOWN MISS0017" x="7793" y="509" width="378" height="388" frameX="0" frameY="-4" frameWidth="378" frameHeight="392" />
<SubTexture name="BF NOTE DOWN MISS0018" x="7793" y="509" width="378" height="388" frameX="0" frameY="-4" frameWidth="378" frameHeight="392" />
<SubTexture name="BF NOTE DOWN MISS0019" x="7793" y="509" width="378" height="388" frameX="0" frameY="-4" frameWidth="378" frameHeight="392" />
<SubTexture name="BF NOTE DOWN MISS0020" x="7793" y="509" width="378" height="388" frameX="0" frameY="-4" frameWidth="378" frameHeight="392" />
<SubTexture name="BF NOTE DOWN MISS0021" x="7793" y="509" width="378" height="388" frameX="0" frameY="-4" frameWidth="378" frameHeight="392" />
<SubTexture name="BF NOTE DOWN MISS0022" x="7793" y="509" width="378" height="388" frameX="0" frameY="-4" frameWidth="378" frameHeight="392" />
<SubTexture name="BF NOTE DOWN MISS0023" x="7793" y="509" width="378" height="388" frameX="0" frameY="-4" frameWidth="378" frameHeight="392" />
<SubTexture name="BF NOTE DOWN MISS0024" x="7793" y="509" width="378" height="388" frameX="0" frameY="-4" frameWidth="378" frameHeight="392" />
<SubTexture name="BF NOTE DOWN MISS0025" x="7793" y="509" width="378" height="388" frameX="0" frameY="-4" frameWidth="378" frameHeight="392" />
<SubTexture name="BF NOTE DOWN MISS0026" x="7793" y="509" width="378" height="388" frameX="0" frameY="-4" frameWidth="378" frameHeight="392" />
<SubTexture name="BF NOTE DOWN MISS0027" x="7793" y="509" width="378" height="388" frameX="0" frameY="-4" frameWidth="378" frameHeight="392" />
<SubTexture name="BF NOTE DOWN MISS0028" x="7793" y="509" width="378" height="388" frameX="0" frameY="-4" frameWidth="378" frameHeight="392" />
<SubTexture name="BF NOTE DOWN0000" x="6640" y="509" width="374" height="357" frameX="-1" frameY="-5" frameWidth="375" frameHeight="362" />
<SubTexture name="BF NOTE DOWN0001" x="6640" y="509" width="374" height="357" frameX="-1" frameY="-5" frameWidth="375" frameHeight="362" />
<SubTexture name="BF NOTE DOWN0002" x="7024" y="509" width="373" height="362" frameX="0" frameY="0" frameWidth="375" frameHeight="362" />
<SubTexture name="BF NOTE DOWN0003" x="7024" y="509" width="373" height="362" frameX="0" frameY="0" frameWidth="375" frameHeight="362" />
<SubTexture name="BF NOTE DOWN0004" x="7024" y="509" width="373" height="362" frameX="0" frameY="0" frameWidth="375" frameHeight="362" />
<SubTexture name="BF NOTE DOWN0005" x="7024" y="509" width="373" height="362" frameX="0" frameY="0" frameWidth="375" frameHeight="362" />
<SubTexture name="BF NOTE DOWN0006" x="7024" y="509" width="373" height="362" frameX="0" frameY="0" frameWidth="375" frameHeight="362" />
<SubTexture name="BF NOTE DOWN0007" x="7024" y="509" width="373" height="362" frameX="0" frameY="0" frameWidth="375" frameHeight="362" />
<SubTexture name="BF NOTE DOWN0008" x="7024" y="509" width="373" height="362" frameX="0" frameY="0" frameWidth="375" frameHeight="362" />
<SubTexture name="BF NOTE DOWN0009" x="7024" y="509" width="373" height="362" frameX="0" frameY="0" frameWidth="375" frameHeight="362" />
<SubTexture name="BF NOTE DOWN0010" x="7024" y="509" width="373" height="362" frameX="0" frameY="0" frameWidth="375" frameHeight="362" />
<SubTexture name="BF NOTE DOWN0011" x="7024" y="509" width="373" height="362" frameX="0" frameY="0" frameWidth="375" frameHeight="362" />
<SubTexture name="BF NOTE DOWN0012" x="7024" y="509" width="373" height="362" frameX="0" frameY="0" frameWidth="375" frameHeight="362" />
<SubTexture name="BF NOTE DOWN0013" x="7024" y="509" width="373" height="362" frameX="0" frameY="0" frameWidth="375" frameHeight="362" />
<SubTexture name="BF NOTE DOWN0014" x="7024" y="509" width="373" height="362" frameX="0" frameY="0" frameWidth="375" frameHeight="362" />
<SubTexture name="BF NOTE DOWN0015" x="7024" y="509" width="373" height="362" frameX="0" frameY="0" frameWidth="375" frameHeight="362" />
<SubTexture name="BF NOTE DOWN0016" x="7024" y="509" width="373" height="362" frameX="0" frameY="0" frameWidth="375" frameHeight="362" />
<SubTexture name="BF NOTE DOWN0017" x="7024" y="509" width="373" height="362" frameX="0" frameY="0" frameWidth="375" frameHeight="362" />
<SubTexture name="BF NOTE DOWN0018" x="7024" y="509" width="373" height="362" frameX="0" frameY="0" frameWidth="375" frameHeight="362" />
<SubTexture name="BF NOTE DOWN0019" x="7024" y="509" width="373" height="362" frameX="0" frameY="0" frameWidth="375" frameHeight="362" />
<SubTexture name="BF NOTE DOWN0020" x="7024" y="509" width="373" height="362" frameX="0" frameY="0" frameWidth="375" frameHeight="362" />
<SubTexture name="BF NOTE DOWN0021" x="7024" y="509" width="373" height="362" frameX="0" frameY="0" frameWidth="375" frameHeight="362" />
<SubTexture name="BF NOTE DOWN0022" x="7024" y="509" width="373" height="362" frameX="0" frameY="0" frameWidth="375" frameHeight="362" />
<SubTexture name="BF NOTE DOWN0023" x="7024" y="509" width="373" height="362" frameX="0" frameY="0" frameWidth="375" frameHeight="362" />
<SubTexture name="BF NOTE DOWN0024" x="7024" y="509" width="373" height="362" frameX="0" frameY="0" frameWidth="375" frameHeight="362" />
<SubTexture name="BF NOTE DOWN0025" x="7024" y="509" width="373" height="362" frameX="0" frameY="0" frameWidth="375" frameHeight="362" />
<SubTexture name="BF NOTE DOWN0026" x="7024" y="509" width="373" height="362" frameX="0" frameY="0" frameWidth="375" frameHeight="362" />
<SubTexture name="BF NOTE DOWN0027" x="7024" y="509" width="373" height="362" frameX="0" frameY="0" frameWidth="375" frameHeight="362" />
<SubTexture name="BF NOTE DOWN0028" x="7024" y="509" width="373" height="362" frameX="0" frameY="0" frameWidth="375" frameHeight="362" />
<SubTexture name="BF NOTE DOWN0029" x="7024" y="509" width="373" height="362" frameX="0" frameY="0" frameWidth="375" frameHeight="362" />
<SubTexture name="BF NOTE LEFT MISS0000" x="777" y="988" width="383" height="406" frameX="0" frameY="-26" frameWidth="384" frameHeight="432" />
<SubTexture name="BF NOTE LEFT MISS0001" x="1170" y="988" width="369" height="430" frameX="-15" frameY="0" frameWidth="384" frameHeight="432" />
<SubTexture name="BF NOTE LEFT MISS0002" x="1170" y="988" width="369" height="430" frameX="-15" frameY="0" frameWidth="384" frameHeight="432" />
<SubTexture name="BF NOTE LEFT MISS0003" x="1549" y="988" width="370" height="430" frameX="-13" frameY="0" frameWidth="384" frameHeight="432" />
<SubTexture name="BF NOTE LEFT MISS0004" x="1549" y="988" width="370" height="430" frameX="-13" frameY="0" frameWidth="384" frameHeight="432" />
<SubTexture name="BF NOTE LEFT MISS0005" x="1549" y="988" width="370" height="430" frameX="-13" frameY="0" frameWidth="384" frameHeight="432" />
<SubTexture name="BF NOTE LEFT MISS0006" x="1549" y="988" width="370" height="430" frameX="-13" frameY="0" frameWidth="384" frameHeight="432" />
<SubTexture name="BF NOTE LEFT MISS0007" x="1549" y="988" width="370" height="430" frameX="-13" frameY="0" frameWidth="384" frameHeight="432" />
<SubTexture name="BF NOTE LEFT MISS0008" x="1549" y="988" width="370" height="430" frameX="-13" frameY="0" frameWidth="384" frameHeight="432" />
<SubTexture name="BF NOTE LEFT MISS0009" x="1549" y="988" width="370" height="430" frameX="-13" frameY="0" frameWidth="384" frameHeight="432" />
<SubTexture name="BF NOTE LEFT MISS0010" x="1549" y="988" width="370" height="430" frameX="-13" frameY="0" frameWidth="384" frameHeight="432" />
<SubTexture name="BF NOTE LEFT MISS0011" x="1549" y="988" width="370" height="430" frameX="-13" frameY="0" frameWidth="384" frameHeight="432" />
<SubTexture name="BF NOTE LEFT MISS0012" x="1549" y="988" width="370" height="430" frameX="-13" frameY="0" frameWidth="384" frameHeight="432" />
<SubTexture name="BF NOTE LEFT MISS0013" x="1549" y="988" width="370" height="430" frameX="-13" frameY="0" frameWidth="384" frameHeight="432" />
<SubTexture name="BF NOTE LEFT MISS0014" x="1549" y="988" width="370" height="430" frameX="-13" frameY="0" frameWidth="384" frameHeight="432" />
<SubTexture name="BF NOTE LEFT MISS0015" x="1549" y="988" width="370" height="430" frameX="-13" frameY="0" frameWidth="384" frameHeight="432" />
<SubTexture name="BF NOTE LEFT MISS0016" x="1549" y="988" width="370" height="430" frameX="-13" frameY="0" frameWidth="384" frameHeight="432" />
<SubTexture name="BF NOTE LEFT MISS0017" x="1549" y="988" width="370" height="430" frameX="-13" frameY="0" frameWidth="384" frameHeight="432" />
<SubTexture name="BF NOTE LEFT MISS0018" x="1549" y="988" width="370" height="430" frameX="-13" frameY="0" frameWidth="384" frameHeight="432" />
<SubTexture name="BF NOTE LEFT MISS0019" x="1549" y="988" width="370" height="430" frameX="-13" frameY="0" frameWidth="384" frameHeight="432" />
<SubTexture name="BF NOTE LEFT MISS0020" x="1549" y="988" width="370" height="430" frameX="-13" frameY="0" frameWidth="384" frameHeight="432" />
<SubTexture name="BF NOTE LEFT MISS0021" x="1549" y="988" width="370" height="430" frameX="-13" frameY="0" frameWidth="384" frameHeight="432" />
<SubTexture name="BF NOTE LEFT MISS0022" x="1549" y="988" width="370" height="430" frameX="-13" frameY="0" frameWidth="384" frameHeight="432" />
<SubTexture name="BF NOTE LEFT MISS0023" x="1549" y="988" width="370" height="430" frameX="-13" frameY="0" frameWidth="384" frameHeight="432" />
<SubTexture name="BF NOTE LEFT MISS0024" x="1549" y="988" width="370" height="430" frameX="-13" frameY="0" frameWidth="384" frameHeight="432" />
<SubTexture name="BF NOTE LEFT MISS0025" x="1549" y="988" width="370" height="430" frameX="-13" frameY="0" frameWidth="384" frameHeight="432" />
<SubTexture name="BF NOTE LEFT MISS0026" x="1549" y="988" width="370" height="430" frameX="-13" frameY="0" frameWidth="384" frameHeight="432" />
<SubTexture name="BF NOTE LEFT MISS0027" x="1549" y="988" width="370" height="430" frameX="-13" frameY="0" frameWidth="384" frameHeight="432" />
<SubTexture name="BF NOTE LEFT MISS0028" x="1549" y="988" width="370" height="430" frameX="-13" frameY="0" frameWidth="384" frameHeight="432" />
<SubTexture name="BF NOTE LEFT MISS0029" x="1549" y="988" width="370" height="430" frameX="-13" frameY="0" frameWidth="384" frameHeight="432" />
<SubTexture name="BF NOTE LEFT MISS0030" x="1549" y="988" width="370" height="430" frameX="-13" frameY="0" frameWidth="384" frameHeight="432" />
<SubTexture name="BF NOTE LEFT MISS0031" x="1549" y="988" width="370" height="430" frameX="-13" frameY="0" frameWidth="384" frameHeight="432" />
<SubTexture name="BF NOTE LEFT MISS0032" x="1549" y="988" width="370" height="430" frameX="-13" frameY="0" frameWidth="384" frameHeight="432" />
<SubTexture name="BF NOTE LEFT MISS0033" x="1549" y="988" width="370" height="430" frameX="-13" frameY="0" frameWidth="384" frameHeight="432" />
<SubTexture name="BF NOTE LEFT0000" x="0" y="988" width="383" height="406" frameX="0" frameY="0" frameWidth="385" frameHeight="406" />
<SubTexture name="BF NOTE LEFT0001" x="0" y="988" width="383" height="406" frameX="0" frameY="0" frameWidth="385" frameHeight="406" />
<SubTexture name="BF NOTE LEFT0002" x="393" y="988" width="374" height="404" frameX="-11" frameY="-2" frameWidth="385" frameHeight="406" />
<SubTexture name="BF NOTE LEFT0003" x="393" y="988" width="374" height="404" frameX="-11" frameY="-2" frameWidth="385" frameHeight="406" />
<SubTexture name="BF NOTE LEFT0004" x="393" y="988" width="374" height="404" frameX="-11" frameY="-2" frameWidth="385" frameHeight="406" />
<SubTexture name="BF NOTE LEFT0005" x="393" y="988" width="374" height="404" frameX="-11" frameY="-2" frameWidth="385" frameHeight="406" />
<SubTexture name="BF NOTE LEFT0006" x="393" y="988" width="374" height="404" frameX="-11" frameY="-2" frameWidth="385" frameHeight="406" />
<SubTexture name="BF NOTE LEFT0007" x="393" y="988" width="374" height="404" frameX="-11" frameY="-2" frameWidth="385" frameHeight="406" />
<SubTexture name="BF NOTE LEFT0008" x="393" y="988" width="374" height="404" frameX="-11" frameY="-2" frameWidth="385" frameHeight="406" />
<SubTexture name="BF NOTE LEFT0009" x="393" y="988" width="374" height="404" frameX="-11" frameY="-2" frameWidth="385" frameHeight="406" />
<SubTexture name="BF NOTE LEFT0010" x="393" y="988" width="374" height="404" frameX="-11" frameY="-2" frameWidth="385" frameHeight="406" />
<SubTexture name="BF NOTE LEFT0011" x="393" y="988" width="374" height="404" frameX="-11" frameY="-2" frameWidth="385" frameHeight="406" />
<SubTexture name="BF NOTE LEFT0012" x="393" y="988" width="374" height="404" frameX="-11" frameY="-2" frameWidth="385" frameHeight="406" />
<SubTexture name="BF NOTE LEFT0013" x="393" y="988" width="374" height="404" frameX="-11" frameY="-2" frameWidth="385" frameHeight="406" />
<SubTexture name="BF NOTE LEFT0014" x="393" y="988" width="374" height="404" frameX="-11" frameY="-2" frameWidth="385" frameHeight="406" />
<SubTexture name="BF NOTE RIGHT MISS0000" x="1929" y="988" width="408" height="405" frameX="-7" frameY="-30" frameWidth="409" frameHeight="407" />
<SubTexture name="BF NOTE RIGHT MISS0001" x="2765" y="988" width="395" height="432" frameX="0" frameY="0" frameWidth="415" frameHeight="435" />
<SubTexture name="BF NOTE RIGHT MISS0002" x="2765" y="988" width="395" height="432" frameX="0" frameY="0" frameWidth="415" frameHeight="435" />
<SubTexture name="BF NOTE RIGHT MISS0003" x="3170" y="988" width="400" height="432" frameX="-1" frameY="0" frameWidth="415" frameHeight="435" />
<SubTexture name="BF NOTE RIGHT MISS0004" x="3170" y="988" width="400" height="432" frameX="-1" frameY="0" frameWidth="415" frameHeight="435" />
<SubTexture name="BF NOTE RIGHT MISS0005" x="3170" y="988" width="400" height="432" frameX="-1" frameY="0" frameWidth="415" frameHeight="435" />
<SubTexture name="BF NOTE RIGHT MISS0006" x="3170" y="988" width="400" height="432" frameX="-1" frameY="0" frameWidth="415" frameHeight="435" />
<SubTexture name="BF NOTE RIGHT MISS0007" x="3170" y="988" width="400" height="432" frameX="-1" frameY="0" frameWidth="415" frameHeight="435" />
<SubTexture name="BF NOTE RIGHT MISS0008" x="3170" y="988" width="400" height="432" frameX="-1" frameY="0" frameWidth="415" frameHeight="435" />
<SubTexture name="BF NOTE RIGHT MISS0009" x="3170" y="988" width="400" height="432" frameX="-1" frameY="0" frameWidth="415" frameHeight="435" />
<SubTexture name="BF NOTE RIGHT MISS0010" x="3170" y="988" width="400" height="432" frameX="-1" frameY="0" frameWidth="415" frameHeight="435" />
<SubTexture name="BF NOTE RIGHT MISS0011" x="3170" y="988" width="400" height="432" frameX="-1" frameY="0" frameWidth="415" frameHeight="435" />
<SubTexture name="BF NOTE RIGHT MISS0012" x="3170" y="988" width="400" height="432" frameX="-1" frameY="0" frameWidth="415" frameHeight="435" />
<SubTexture name="BF NOTE RIGHT MISS0013" x="3170" y="988" width="400" height="432" frameX="-1" frameY="0" frameWidth="415" frameHeight="435" />
<SubTexture name="BF NOTE RIGHT MISS0014" x="3170" y="988" width="400" height="432" frameX="-1" frameY="0" frameWidth="415" frameHeight="435" />
<SubTexture name="BF NOTE RIGHT MISS0015" x="3170" y="988" width="400" height="432" frameX="-1" frameY="0" frameWidth="415" frameHeight="435" />
<SubTexture name="BF NOTE RIGHT MISS0016" x="3170" y="988" width="400" height="432" frameX="-1" frameY="0" frameWidth="415" frameHeight="435" />
<SubTexture name="BF NOTE RIGHT MISS0017" x="3170" y="988" width="400" height="432" frameX="-1" frameY="0" frameWidth="415" frameHeight="435" />
<SubTexture name="BF NOTE RIGHT MISS0018" x="3170" y="988" width="400" height="432" frameX="-1" frameY="0" frameWidth="415" frameHeight="435" />
<SubTexture name="BF NOTE RIGHT MISS0019" x="3170" y="988" width="400" height="432" frameX="-1" frameY="0" frameWidth="415" frameHeight="435" />
<SubTexture name="BF NOTE RIGHT MISS0020" x="3170" y="988" width="400" height="432" frameX="-1" frameY="0" frameWidth="415" frameHeight="435" />
<SubTexture name="BF NOTE RIGHT MISS0021" x="3170" y="988" width="400" height="432" frameX="-1" frameY="0" frameWidth="415" frameHeight="435" />
<SubTexture name="BF NOTE RIGHT MISS0022" x="3170" y="988" width="400" height="432" frameX="-1" frameY="0" frameWidth="415" frameHeight="435" />
<SubTexture name="BF NOTE RIGHT MISS0023" x="3170" y="988" width="400" height="432" frameX="-1" frameY="0" frameWidth="415" frameHeight="435" />
<SubTexture name="BF NOTE RIGHT MISS0024" x="3170" y="988" width="400" height="432" frameX="-1" frameY="0" frameWidth="415" frameHeight="435" />
<SubTexture name="BF NOTE RIGHT MISS0025" x="3170" y="988" width="400" height="432" frameX="-1" frameY="0" frameWidth="415" frameHeight="435" />
<SubTexture name="BF NOTE RIGHT MISS0026" x="3170" y="988" width="400" height="432" frameX="-1" frameY="0" frameWidth="415" frameHeight="435" />
<SubTexture name="BF NOTE RIGHT MISS0027" x="3170" y="988" width="400" height="432" frameX="-1" frameY="0" frameWidth="415" frameHeight="435" />
<SubTexture name="BF NOTE RIGHT MISS0028" x="3170" y="988" width="400" height="432" frameX="-1" frameY="0" frameWidth="415" frameHeight="435" />
<SubTexture name="BF NOTE RIGHT MISS0029" x="3170" y="988" width="400" height="432" frameX="-1" frameY="0" frameWidth="415" frameHeight="435" />
<SubTexture name="BF NOTE RIGHT MISS0030" x="3170" y="988" width="400" height="432" frameX="-1" frameY="0" frameWidth="415" frameHeight="435" />
<SubTexture name="BF NOTE RIGHT MISS0031" x="3170" y="988" width="400" height="432" frameX="-1" frameY="0" frameWidth="415" frameHeight="435" />
<SubTexture name="BF NOTE RIGHT MISS0032" x="3170" y="988" width="400" height="432" frameX="-1" frameY="0" frameWidth="415" frameHeight="435" />
<SubTexture name="BF NOTE RIGHT MISS0033" x="3170" y="988" width="400" height="432" frameX="-1" frameY="0" frameWidth="415" frameHeight="435" />
<SubTexture name="BF NOTE RIGHT MISS0034" x="3170" y="988" width="400" height="432" frameX="-1" frameY="0" frameWidth="415" frameHeight="435" />
<SubTexture name="BF NOTE RIGHT MISS0035" x="3170" y="988" width="400" height="432" frameX="-1" frameY="0" frameWidth="415" frameHeight="435" />
<SubTexture name="BF NOTE RIGHT MISS0036" x="3170" y="988" width="400" height="432" frameX="-1" frameY="0" frameWidth="415" frameHeight="435" />
<SubTexture name="BF NOTE RIGHT MISS0037" x="3170" y="988" width="400" height="432" frameX="-1" frameY="0" frameWidth="415" frameHeight="435" />
<SubTexture name="BF NOTE RIGHT MISS0038" x="3170" y="988" width="400" height="432" frameX="-1" frameY="0" frameWidth="415" frameHeight="435" />
<SubTexture name="BF NOTE RIGHT MISS0039" x="3170" y="988" width="400" height="432" frameX="-1" frameY="0" frameWidth="415" frameHeight="435" />
<SubTexture name="BF NOTE RIGHT MISS0040" x="3170" y="988" width="400" height="432" frameX="-1" frameY="0" frameWidth="415" frameHeight="435" />
<SubTexture name="BF NOTE RIGHT MISS0041" x="3170" y="988" width="400" height="432" frameX="-1" frameY="0" frameWidth="415" frameHeight="435" />
<SubTexture name="BF NOTE RIGHT MISS0042" x="3170" y="988" width="400" height="432" frameX="-1" frameY="0" frameWidth="415" frameHeight="435" />
<SubTexture name="BF NOTE RIGHT MISS0043" x="3170" y="988" width="400" height="432" frameX="-1" frameY="0" frameWidth="415" frameHeight="435" />
<SubTexture name="BF NOTE RIGHT MISS0044" x="3170" y="988" width="400" height="432" frameX="-1" frameY="0" frameWidth="415" frameHeight="435" />
<SubTexture name="BF NOTE RIGHT MISS0045" x="3170" y="988" width="400" height="432" frameX="-1" frameY="0" frameWidth="415" frameHeight="435" />
<SubTexture name="BF NOTE RIGHT0000" x="1929" y="988" width="408" height="405" frameX="-1" frameY="-2" frameWidth="409" frameHeight="407" />
<SubTexture name="BF NOTE RIGHT0001" x="1929" y="988" width="408" height="405" frameX="-1" frameY="-2" frameWidth="409" frameHeight="407" />
<SubTexture name="BF NOTE RIGHT0002" x="2347" y="988" width="408" height="407" frameX="0" frameY="0" frameWidth="409" frameHeight="407" />
<SubTexture name="BF NOTE RIGHT0003" x="2347" y="988" width="408" height="407" frameX="0" frameY="0" frameWidth="409" frameHeight="407" />
<SubTexture name="BF NOTE RIGHT0004" x="2347" y="988" width="408" height="407" frameX="0" frameY="0" frameWidth="409" frameHeight="407" />
<SubTexture name="BF NOTE RIGHT0005" x="2347" y="988" width="408" height="407" frameX="0" frameY="0" frameWidth="409" frameHeight="407" />
<SubTexture name="BF NOTE RIGHT0006" x="2347" y="988" width="408" height="407" frameX="0" frameY="0" frameWidth="409" frameHeight="407" />
<SubTexture name="BF NOTE RIGHT0007" x="2347" y="988" width="408" height="407" frameX="0" frameY="0" frameWidth="409" frameHeight="407" />
<SubTexture name="BF NOTE RIGHT0008" x="2347" y="988" width="408" height="407" frameX="0" frameY="0" frameWidth="409" frameHeight="407" />
<SubTexture name="BF NOTE RIGHT0009" x="2347" y="988" width="408" height="407" frameX="0" frameY="0" frameWidth="409" frameHeight="407" />
<SubTexture name="BF NOTE RIGHT0010" x="2347" y="988" width="408" height="407" frameX="0" frameY="0" frameWidth="409" frameHeight="407" />
<SubTexture name="BF NOTE RIGHT0011" x="2347" y="988" width="408" height="407" frameX="0" frameY="0" frameWidth="409" frameHeight="407" />
<SubTexture name="BF NOTE RIGHT0012" x="2347" y="988" width="408" height="407" frameX="0" frameY="0" frameWidth="409" frameHeight="407" />
<SubTexture name="BF NOTE RIGHT0013" x="2347" y="988" width="408" height="407" frameX="0" frameY="0" frameWidth="409" frameHeight="407" />
<SubTexture name="BF NOTE RIGHT0014" x="2347" y="988" width="408" height="407" frameX="0" frameY="0" frameWidth="409" frameHeight="407" />
<SubTexture name="BF NOTE RIGHT0015" x="2347" y="988" width="408" height="407" frameX="0" frameY="0" frameWidth="409" frameHeight="407" />
<SubTexture name="BF NOTE RIGHT0016" x="2347" y="988" width="408" height="407" frameX="0" frameY="0" frameWidth="409" frameHeight="407" />
<SubTexture name="BF NOTE RIGHT0017" x="2347" y="988" width="408" height="407" frameX="0" frameY="0" frameWidth="409" frameHeight="407" />
<SubTexture name="BF NOTE RIGHT0018" x="2347" y="988" width="408" height="407" frameX="0" frameY="0" frameWidth="409" frameHeight="407" />
<SubTexture name="BF NOTE RIGHT0019" x="2347" y="988" width="408" height="407" frameX="0" frameY="0" frameWidth="409" frameHeight="407" />
<SubTexture name="BF NOTE RIGHT0020" x="2347" y="988" width="408" height="407" frameX="0" frameY="0" frameWidth="409" frameHeight="407" />
<SubTexture name="BF NOTE RIGHT0021" x="2347" y="988" width="408" height="407" frameX="0" frameY="0" frameWidth="409" frameHeight="407" />
<SubTexture name="BF NOTE RIGHT0022" x="2347" y="988" width="408" height="407" frameX="0" frameY="0" frameWidth="409" frameHeight="407" />
<SubTexture name="BF NOTE RIGHT0023" x="2347" y="988" width="408" height="407" frameX="0" frameY="0" frameWidth="409" frameHeight="407" />
<SubTexture name="BF NOTE RIGHT0024" x="2347" y="988" width="408" height="407" frameX="0" frameY="0" frameWidth="409" frameHeight="407" />
<SubTexture name="BF NOTE RIGHT0025" x="2347" y="988" width="408" height="407" frameX="0" frameY="0" frameWidth="409" frameHeight="407" />
<SubTexture name="BF NOTE RIGHT0026" x="2347" y="988" width="408" height="407" frameX="0" frameY="0" frameWidth="409" frameHeight="407" />
<SubTexture name="BF NOTE RIGHT0027" x="2347" y="988" width="408" height="407" frameX="0" frameY="0" frameWidth="409" frameHeight="407" />
<SubTexture name="BF NOTE RIGHT0028" x="2347" y="988" width="408" height="407" frameX="0" frameY="0" frameWidth="409" frameHeight="407" />
<SubTexture name="BF NOTE RIGHT0029" x="2347" y="988" width="408" height="407" frameX="0" frameY="0" frameWidth="409" frameHeight="407" />
<SubTexture name="BF NOTE RIGHT0030" x="2347" y="988" width="408" height="407" frameX="0" frameY="0" frameWidth="409" frameHeight="407" />
<SubTexture name="BF NOTE RIGHT0031" x="2347" y="988" width="408" height="407" frameX="0" frameY="0" frameWidth="409" frameHeight="407" />
<SubTexture name="BF NOTE RIGHT0032" x="2347" y="988" width="408" height="407" frameX="0" frameY="0" frameWidth="409" frameHeight="407" />
<SubTexture name="BF NOTE RIGHT0033" x="2347" y="988" width="408" height="407" frameX="0" frameY="0" frameWidth="409" frameHeight="407" />
<SubTexture name="BF NOTE RIGHT0034" x="2347" y="988" width="408" height="407" frameX="0" frameY="0" frameWidth="409" frameHeight="407" />
<SubTexture name="BF NOTE RIGHT0035" x="2347" y="988" width="408" height="407" frameX="0" frameY="0" frameWidth="409" frameHeight="407" />
<SubTexture name="BF NOTE RIGHT0036" x="2347" y="988" width="408" height="407" frameX="0" frameY="0" frameWidth="409" frameHeight="407" />
<SubTexture name="BF NOTE RIGHT0037" x="2347" y="988" width="408" height="407" frameX="0" frameY="0" frameWidth="409" frameHeight="407" />
<SubTexture name="BF NOTE RIGHT0038" x="2347" y="988" width="408" height="407" frameX="0" frameY="0" frameWidth="409" frameHeight="407" />
<SubTexture name="BF NOTE RIGHT0039" x="2347" y="988" width="408" height="407" frameX="0" frameY="0" frameWidth="409" frameHeight="407" />
<SubTexture name="BF NOTE RIGHT0040" x="2347" y="988" width="408" height="407" frameX="0" frameY="0" frameWidth="409" frameHeight="407" />
<SubTexture name="BF NOTE RIGHT0041" x="2347" y="988" width="408" height="407" frameX="0" frameY="0" frameWidth="409" frameHeight="407" />
<SubTexture name="BF NOTE RIGHT0042" x="2347" y="988" width="408" height="407" frameX="0" frameY="0" frameWidth="409" frameHeight="407" />
<SubTexture name="BF NOTE RIGHT0043" x="2347" y="988" width="408" height="407" frameX="0" frameY="0" frameWidth="409" frameHeight="407" />
<SubTexture name="BF NOTE RIGHT0044" x="2347" y="988" width="408" height="407" frameX="0" frameY="0" frameWidth="409" frameHeight="407" />
<SubTexture name="BF NOTE RIGHT0045" x="2347" y="988" width="408" height="407" frameX="0" frameY="0" frameWidth="409" frameHeight="407" />
<SubTexture name="BF NOTE RIGHT0046" x="2347" y="988" width="408" height="407" frameX="0" frameY="0" frameWidth="409" frameHeight="407" />
<SubTexture name="BF NOTE RIGHT0047" x="2347" y="988" width="408" height="407" frameX="0" frameY="0" frameWidth="409" frameHeight="407" />
<SubTexture name="BF NOTE RIGHT0048" x="2347" y="988" width="408" height="407" frameX="0" frameY="0" frameWidth="409" frameHeight="407" />
<SubTexture name="BF NOTE RIGHT0049" x="2347" y="988" width="408" height="407" frameX="0" frameY="0" frameWidth="409" frameHeight="407" />
<SubTexture name="BF NOTE RIGHT0050" x="2347" y="988" width="408" height="407" frameX="0" frameY="0" frameWidth="409" frameHeight="407" />
<SubTexture name="BF NOTE RIGHT0051" x="2347" y="988" width="408" height="407" frameX="0" frameY="0" frameWidth="409" frameHeight="407" />
<SubTexture name="BF NOTE RIGHT0052" x="2347" y="988" width="408" height="407" frameX="0" frameY="0" frameWidth="409" frameHeight="407" />
<SubTexture name="BF NOTE RIGHT0053" x="2347" y="988" width="408" height="407" frameX="0" frameY="0" frameWidth="409" frameHeight="407" />
<SubTexture name="BF NOTE RIGHT0054" x="2347" y="988" width="408" height="407" frameX="0" frameY="0" frameWidth="409" frameHeight="407" />
<SubTexture name="BF NOTE RIGHT0055" x="2347" y="988" width="408" height="407" frameX="0" frameY="0" frameWidth="409" frameHeight="407" />
<SubTexture name="BF NOTE RIGHT0056" x="2347" y="988" width="408" height="407" frameX="0" frameY="0" frameWidth="409" frameHeight="407" />
<SubTexture name="BF NOTE RIGHT0057" x="2347" y="988" width="408" height="407" frameX="0" frameY="0" frameWidth="409" frameHeight="407" />
<SubTexture name="BF NOTE RIGHT0058" x="2347" y="988" width="408" height="407" frameX="0" frameY="0" frameWidth="409" frameHeight="407" />
<SubTexture name="BF NOTE RIGHT0059" x="2347" y="988" width="408" height="407" frameX="0" frameY="0" frameWidth="409" frameHeight="407" />
<SubTexture name="BF NOTE RIGHT0060" x="2347" y="988" width="408" height="407" frameX="0" frameY="0" frameWidth="409" frameHeight="407" />
<SubTexture name="BF NOTE RIGHT0061" x="2347" y="988" width="408" height="407" frameX="0" frameY="0" frameWidth="409" frameHeight="407" />
<SubTexture name="BF NOTE UP MISS0000" x="3580" y="988" width="369" height="446" frameX="-9" frameY="0" frameWidth="376" frameHeight="446" />
<SubTexture name="BF NOTE UP MISS0001" x="4345" y="988" width="360" height="427" frameX="0" frameY="-13" frameWidth="378" frameHeight="446" />
<SubTexture name="BF NOTE UP MISS0002" x="4345" y="988" width="360" height="427" frameX="0" frameY="-13" frameWidth="378" frameHeight="446" />
<SubTexture name="BF NOTE UP MISS0003" x="4715" y="988" width="357" height="430" frameX="-1" frameY="-10" frameWidth="378" frameHeight="446" />
<SubTexture name="BF NOTE UP MISS0004" x="4715" y="988" width="357" height="430" frameX="-1" frameY="-10" frameWidth="378" frameHeight="446" />
<SubTexture name="BF NOTE UP MISS0005" x="4715" y="988" width="357" height="430" frameX="-1" frameY="-10" frameWidth="378" frameHeight="446" />
<SubTexture name="BF NOTE UP MISS0006" x="4715" y="988" width="357" height="430" frameX="-1" frameY="-10" frameWidth="378" frameHeight="446" />
<SubTexture name="BF NOTE UP MISS0007" x="4715" y="988" width="357" height="430" frameX="-1" frameY="-10" frameWidth="378" frameHeight="446" />
<SubTexture name="BF NOTE UP MISS0008" x="4715" y="988" width="357" height="430" frameX="-1" frameY="-10" frameWidth="378" frameHeight="446" />
<SubTexture name="BF NOTE UP MISS0009" x="4715" y="988" width="357" height="430" frameX="-1" frameY="-10" frameWidth="378" frameHeight="446" />
<SubTexture name="BF NOTE UP MISS0010" x="4715" y="988" width="357" height="430" frameX="-1" frameY="-10" frameWidth="378" frameHeight="446" />
<SubTexture name="BF NOTE UP MISS0011" x="4715" y="988" width="357" height="430" frameX="-1" frameY="-10" frameWidth="378" frameHeight="446" />
<SubTexture name="BF NOTE UP MISS0012" x="4715" y="988" width="357" height="430" frameX="-1" frameY="-10" frameWidth="378" frameHeight="446" />
<SubTexture name="BF NOTE UP MISS0013" x="4715" y="988" width="357" height="430" frameX="-1" frameY="-10" frameWidth="378" frameHeight="446" />
<SubTexture name="BF NOTE UP MISS0014" x="4715" y="988" width="357" height="430" frameX="-1" frameY="-10" frameWidth="378" frameHeight="446" />
<SubTexture name="BF NOTE UP MISS0015" x="4715" y="988" width="357" height="430" frameX="-1" frameY="-10" frameWidth="378" frameHeight="446" />
<SubTexture name="BF NOTE UP MISS0016" x="4715" y="988" width="357" height="430" frameX="-1" frameY="-10" frameWidth="378" frameHeight="446" />
<SubTexture name="BF NOTE UP MISS0017" x="4715" y="988" width="357" height="430" frameX="-1" frameY="-10" frameWidth="378" frameHeight="446" />
<SubTexture name="BF NOTE UP MISS0018" x="4715" y="988" width="357" height="430" frameX="-1" frameY="-10" frameWidth="378" frameHeight="446" />
<SubTexture name="BF NOTE UP MISS0019" x="4715" y="988" width="357" height="430" frameX="-1" frameY="-10" frameWidth="378" frameHeight="446" />
<SubTexture name="BF NOTE UP MISS0020" x="4715" y="988" width="357" height="430" frameX="-1" frameY="-10" frameWidth="378" frameHeight="446" />
<SubTexture name="BF NOTE UP MISS0021" x="4715" y="988" width="357" height="430" frameX="-1" frameY="-10" frameWidth="378" frameHeight="446" />
<SubTexture name="BF NOTE UP MISS0022" x="4715" y="988" width="357" height="430" frameX="-1" frameY="-10" frameWidth="378" frameHeight="446" />
<SubTexture name="BF NOTE UP MISS0023" x="4715" y="988" width="357" height="430" frameX="-1" frameY="-10" frameWidth="378" frameHeight="446" />
<SubTexture name="BF NOTE UP0000" x="3580" y="988" width="369" height="446" frameX="-5" frameY="0" frameWidth="376" frameHeight="446" />
<SubTexture name="BF NOTE UP0001" x="3580" y="988" width="369" height="446" frameX="-5" frameY="0" frameWidth="376" frameHeight="446" />
<SubTexture name="BF NOTE UP0002" x="3959" y="988" width="376" height="441" frameX="0" frameY="-5" frameWidth="376" frameHeight="446" />
<SubTexture name="BF NOTE UP0003" x="3959" y="988" width="376" height="441" frameX="0" frameY="-5" frameWidth="376" frameHeight="446" />
<SubTexture name="BF NOTE UP0004" x="3959" y="988" width="376" height="441" frameX="0" frameY="-5" frameWidth="376" frameHeight="446" />
<SubTexture name="BF NOTE UP0005" x="3959" y="988" width="376" height="441" frameX="0" frameY="-5" frameWidth="376" frameHeight="446" />
<SubTexture name="BF NOTE UP0006" x="3959" y="988" width="376" height="441" frameX="0" frameY="-5" frameWidth="376" frameHeight="446" />
<SubTexture name="BF NOTE UP0007" x="3959" y="988" width="376" height="441" frameX="0" frameY="-5" frameWidth="376" frameHeight="446" />
<SubTexture name="BF NOTE UP0008" x="3959" y="988" width="376" height="441" frameX="0" frameY="-5" frameWidth="376" frameHeight="446" />
<SubTexture name="BF NOTE UP0009" x="3959" y="988" width="376" height="441" frameX="0" frameY="-5" frameWidth="376" frameHeight="446" />
<SubTexture name="BF NOTE UP0010" x="3959" y="988" width="376" height="441" frameX="0" frameY="-5" frameWidth="376" frameHeight="446" />
<SubTexture name="BF NOTE UP0011" x="3959" y="988" width="376" height="441" frameX="0" frameY="-5" frameWidth="376" frameHeight="446" />
<SubTexture name="BF NOTE UP0012" x="3959" y="988" width="376" height="441" frameX="0" frameY="-5" frameWidth="376" frameHeight="446" />
<SubTexture name="BF NOTE UP0013" x="3959" y="988" width="376" height="441" frameX="0" frameY="-5" frameWidth="376" frameHeight="446" />
<SubTexture name="BF NOTE UP0014" x="3959" y="988" width="376" height="441" frameX="0" frameY="-5" frameWidth="376" frameHeight="446" />
</TextureAtlas>

BIN
assets/beep.ogg Normal file

Binary file not shown.

19
assets/beep.ogg.import Normal file
View file

@ -0,0 +1,19 @@
[remap]
importer="oggvorbisstr"
type="AudioStreamOggVorbis"
uid="uid://bj6b8h153h1bn"
path="res://.godot/imported/beep.ogg-5c9be1364add69e4f2108f8168ecb666.oggvorbisstr"
[deps]
source_file="res://assets/beep.ogg"
dest_files=["res://.godot/imported/beep.ogg-5c9be1364add69e4f2108f8168ecb666.oggvorbisstr"]
[params]
loop=false
loop_offset=0
bpm=0
beat_count=0
bar_beats=4

6
assets/config/body.tres Normal file
View file

@ -0,0 +1,6 @@
[gd_resource type="LabelSettings" load_steps=2 format=3 uid="uid://c2s3eclr25ots"]
[ext_resource type="FontFile" uid="uid://ce5fs0ro7kp8r" path="res://assets/fonts/Lexend.ttf" id="1_j6m8r"]
[resource]
font = ExtResource("1_j6m8r")

View file

@ -0,0 +1,12 @@
[gd_resource type="FontVariation" load_steps=2 format=3 uid="uid://d1apfvux6r82v"]
[ext_resource type="FontFile" uid="uid://4e3o2ds5xy7p" path="res://assets/fonts/MatSymOut.ttf" id="1_2fm8g"]
[resource]
base_font = ExtResource("1_2fm8g")
variation_opentype = {
1179208780: 1,
1196572996: 0,
1869640570: 24,
2003265652: 400
}

View file

@ -0,0 +1,7 @@
[gd_resource type="LabelSettings" load_steps=2 format=3 uid="uid://2iu8q0tylumo"]
[ext_resource type="FontFile" uid="uid://c6ck52v6qotm" path="res://assets/fonts/B_Lexend.ttf" id="1_gt0lt"]
[resource]
font = ExtResource("1_gt0lt")
font_size = 24

BIN
assets/fonts/B_Lexend.ttf Normal file

Binary file not shown.

View file

@ -0,0 +1,34 @@
[remap]
importer="font_data_dynamic"
type="FontFile"
uid="uid://c6ck52v6qotm"
path="res://.godot/imported/B_Lexend.ttf-11a8f3d5fbc8db49d05674d6da816c6b.fontdata"
[deps]
source_file="res://assets/fonts/B_Lexend.ttf"
dest_files=["res://.godot/imported/B_Lexend.ttf-11a8f3d5fbc8db49d05674d6da816c6b.fontdata"]
[params]
Rendering=null
antialiasing=1
generate_mipmaps=false
disable_embedded_bitmaps=true
multichannel_signed_distance_field=false
msdf_pixel_range=8
msdf_size=48
allow_system_fallback=true
force_autohinter=false
hinting=1
subpixel_positioning=1
oversampling=0.0
Fallbacks=null
fallbacks=[]
Compress=null
compress=true
preload=[]
language_support={}
script_support={}
opentype_features={}

BIN
assets/fonts/Lexend.ttf Normal file

Binary file not shown.

View file

@ -0,0 +1,34 @@
[remap]
importer="font_data_dynamic"
type="FontFile"
uid="uid://ce5fs0ro7kp8r"
path="res://.godot/imported/Lexend.ttf-97328ab4efa8698b78e5efb478c79f57.fontdata"
[deps]
source_file="res://assets/fonts/Lexend.ttf"
dest_files=["res://.godot/imported/Lexend.ttf-97328ab4efa8698b78e5efb478c79f57.fontdata"]
[params]
Rendering=null
antialiasing=1
generate_mipmaps=false
disable_embedded_bitmaps=true
multichannel_signed_distance_field=false
msdf_pixel_range=8
msdf_size=48
allow_system_fallback=true
force_autohinter=false
hinting=1
subpixel_positioning=1
oversampling=0.0
Fallbacks=null
fallbacks=[]
Compress=null
compress=true
preload=[]
language_support={}
script_support={}
opentype_features={}

BIN
assets/fonts/MatSymOut.ttf Normal file

Binary file not shown.

File diff suppressed because one or more lines are too long

BIN
assets/icons/add.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 389 B

View file

@ -0,0 +1,34 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://c0cm2mtr1hjvx"
path="res://.godot/imported/add.png-e64c7df49d8f0ae02115175505e1c3d4.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://assets/icons/add.png"
dest_files=["res://.godot/imported/add.png-e64c7df49d8f0ae02115175505e1c3d4.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1

BIN
assets/icons/close.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 289 B

View file

@ -0,0 +1,34 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://cl7yh6r8n5nns"
path="res://.godot/imported/close.png-8e81c1f7f49413c3a4d65fae064a1aae.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://assets/icons/close.png"
dest_files=["res://.godot/imported/close.png-8e81c1f7f49413c3a4d65fae064a1aae.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1

View file

@ -0,0 +1,4 @@
[gd_resource type="PlaceholderTexture2D" format=3 uid="uid://gvxrvxva3u1v"]
[resource]
size = Vector2(16, 16)

BIN
assets/tap.wav Normal file

Binary file not shown.

24
assets/tap.wav.import Normal file
View file

@ -0,0 +1,24 @@
[remap]
importer="wav"
type="AudioStreamWAV"
uid="uid://8ij8fr2uqb65"
path="res://.godot/imported/tap.wav-212d47e612c1e3e9050ccbc134a93d4e.sample"
[deps]
source_file="res://assets/tap.wav"
dest_files=["res://.godot/imported/tap.wav-212d47e612c1e3e9050ccbc134a93d4e.sample"]
[params]
force/8_bit=false
force/mono=false
force/max_rate=false
force/max_rate_hz=44100
edit/trim=false
edit/normalize=false
edit/loop_mode=0
edit/loop_begin=0
edit/loop_end=-1
compress/mode=0

9
default_bus_layout.tres Normal file
View file

@ -0,0 +1,9 @@
[gd_resource type="AudioBusLayout" format=3 uid="uid://bfmidrbpoihrj"]
[resource]
bus/1/name = &"OSD"
bus/1/solo = false
bus/1/mute = false
bus/1/bypass_fx = false
bus/1/volume_db = 0.0
bus/1/send = &"Master"

110
export_presets.cfg Normal file
View file

@ -0,0 +1,110 @@
[preset.0]
name="Windows Desktop"
platform="Windows Desktop"
runnable=true
advanced_options=false
dedicated_server=false
custom_features=""
export_filter="all_resources"
include_filter=""
exclude_filter=""
export_path="../export/FunkPanion/FunkPanion-win.zip"
encryption_include_filters=""
encryption_exclude_filters=""
encrypt_pck=false
encrypt_directory=false
script_export_mode=2
[preset.0.options]
custom_template/debug=""
custom_template/release=""
debug/export_console_wrapper=1
binary_format/embed_pck=true
texture_format/s3tc_bptc=true
texture_format/etc2_astc=false
binary_format/architecture="x86_64"
codesign/enable=false
codesign/timestamp=true
codesign/timestamp_server_url=""
codesign/digest_algorithm=1
codesign/description=""
codesign/custom_options=PackedStringArray()
application/modify_resources=true
application/icon=""
application/console_wrapper_icon=""
application/icon_interpolation=0
application/file_version=""
application/product_version=""
application/company_name="MeowcaTheoRange"
application/product_name="FunkPanion"
application/file_description=""
application/copyright="MeowcaTheoRange 2024"
application/trademarks=""
application/export_angle=0
application/export_d3d12=0
application/d3d12_agility_sdk_multiarch=true
ssh_remote_deploy/enabled=false
ssh_remote_deploy/host="user@host_ip"
ssh_remote_deploy/port="22"
ssh_remote_deploy/extra_args_ssh=""
ssh_remote_deploy/extra_args_scp=""
ssh_remote_deploy/run_script="Expand-Archive -LiteralPath '{temp_dir}\\{archive_name}' -DestinationPath '{temp_dir}'
$action = New-ScheduledTaskAction -Execute '{temp_dir}\\{exe_name}' -Argument '{cmd_args}'
$trigger = New-ScheduledTaskTrigger -Once -At 00:00
$settings = New-ScheduledTaskSettingsSet
$task = New-ScheduledTask -Action $action -Trigger $trigger -Settings $settings
Register-ScheduledTask godot_remote_debug -InputObject $task -Force:$true
Start-ScheduledTask -TaskName godot_remote_debug
while (Get-ScheduledTask -TaskName godot_remote_debug | ? State -eq running) { Start-Sleep -Milliseconds 100 }
Unregister-ScheduledTask -TaskName godot_remote_debug -Confirm:$false -ErrorAction:SilentlyContinue"
ssh_remote_deploy/cleanup_script="Stop-ScheduledTask -TaskName godot_remote_debug -ErrorAction:SilentlyContinue
Unregister-ScheduledTask -TaskName godot_remote_debug -Confirm:$false -ErrorAction:SilentlyContinue
Remove-Item -Recurse -Force '{temp_dir}'"
dotnet/include_scripts_content=false
dotnet/include_debug_symbols=false
dotnet/embed_build_outputs=false
[preset.1]
name="Linux"
platform="Linux"
runnable=true
advanced_options=false
dedicated_server=false
custom_features=""
export_filter="all_resources"
include_filter=""
exclude_filter=""
export_path="../export/FunkPanion/FunkPanion-nix.zip"
encryption_include_filters=""
encryption_exclude_filters=""
encrypt_pck=false
encrypt_directory=false
script_export_mode=2
[preset.1.options]
custom_template/debug=""
custom_template/release=""
debug/export_console_wrapper=1
binary_format/embed_pck=true
texture_format/s3tc_bptc=true
texture_format/etc2_astc=false
binary_format/architecture="x86_64"
ssh_remote_deploy/enabled=false
ssh_remote_deploy/host="user@host_ip"
ssh_remote_deploy/port="22"
ssh_remote_deploy/extra_args_ssh=""
ssh_remote_deploy/extra_args_scp=""
ssh_remote_deploy/run_script="#!/usr/bin/env bash
export DISPLAY=:0
unzip -o -q \"{temp_dir}/{archive_name}\" -d \"{temp_dir}\"
\"{temp_dir}/{exe_name}\" {cmd_args}"
ssh_remote_deploy/cleanup_script="#!/usr/bin/env bash
kill $(pgrep -x -f \"{temp_dir}/{exe_name} {cmd_args}\")
rm -rf \"{temp_dir}\""
dotnet/include_scripts_content=false
dotnet/include_debug_symbols=false
dotnet/embed_build_outputs=false

BIN
icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

34
icon.png.import Normal file
View file

@ -0,0 +1,34 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://dm5s1hfa53hpq"
path="res://.godot/imported/icon.png-487276ed1e3a0c39cad0279d744ee560.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://icon.png"
dest_files=["res://.godot/imported/icon.png-487276ed1e3a0c39cad0279d744ee560.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1

108
osd.tres Normal file
View file

@ -0,0 +1,108 @@
[gd_resource type="Theme" load_steps=10 format=3 uid="uid://e62vyqlhf1v1"]
[ext_resource type="FontFile" uid="uid://ce5fs0ro7kp8r" path="res://assets/fonts/Lexend.ttf" id="1_6hrko"]
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_7ci2v"]
content_margin_left = 8.0
content_margin_top = 4.0
content_margin_right = 8.0
content_margin_bottom = 4.0
bg_color = Color(0.12549, 0.12549, 0.12549, 0.25098)
corner_radius_top_left = 6
corner_radius_top_right = 6
corner_radius_bottom_right = 6
corner_radius_bottom_left = 6
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_cpmw2"]
content_margin_left = 8.0
content_margin_top = 4.0
content_margin_right = 8.0
content_margin_bottom = 4.0
bg_color = Color(0.25098, 0.25098, 0.25098, 0.752941)
corner_radius_top_left = 6
corner_radius_top_right = 6
corner_radius_bottom_right = 6
corner_radius_bottom_left = 6
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_gks1w"]
content_margin_left = 8.0
content_margin_top = 4.0
content_margin_right = 8.0
content_margin_bottom = 4.0
bg_color = Color(0.25098, 0.25098, 0.25098, 0.752941)
corner_radius_top_left = 6
corner_radius_top_right = 6
corner_radius_bottom_right = 6
corner_radius_bottom_left = 6
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_mcbjr"]
content_margin_left = 8.0
content_margin_top = 4.0
content_margin_right = 8.0
content_margin_bottom = 4.0
bg_color = Color(0.12549, 0.12549, 0.12549, 0.752941)
corner_radius_top_left = 6
corner_radius_top_right = 6
corner_radius_bottom_right = 6
corner_radius_bottom_left = 6
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_q2tue"]
content_margin_left = 8.0
content_margin_top = 4.0
content_margin_right = 8.0
content_margin_bottom = 4.0
bg_color = Color(0, 0, 0, 0.752941)
corner_radius_top_left = 6
corner_radius_top_right = 6
corner_radius_bottom_right = 6
corner_radius_bottom_left = 6
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_8oovs"]
content_margin_left = 4.0
content_margin_top = 4.0
content_margin_right = 4.0
content_margin_bottom = 4.0
bg_color = Color(0.12549, 0.12549, 0.12549, 0.878431)
border_color = Color(0.12549, 0.12549, 0.12549, 1)
corner_radius_top_left = 8
corner_radius_top_right = 8
corner_radius_bottom_right = 8
corner_radius_bottom_left = 8
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_6r5yo"]
content_margin_left = 8.0
content_margin_top = 4.0
content_margin_right = 8.0
content_margin_bottom = 4.0
bg_color = Color(0.25098, 0.25098, 0.25098, 0.752941)
corner_radius_top_left = 6
corner_radius_top_right = 6
corner_radius_bottom_right = 6
corner_radius_bottom_left = 6
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_n886s"]
content_margin_left = 4.0
content_margin_top = 4.0
content_margin_right = 4.0
content_margin_bottom = 4.0
bg_color = Color(0.12549, 0.12549, 0.12549, 0.878431)
border_color = Color(0.12549, 0.12549, 0.12549, 1)
corner_radius_top_left = 8
corner_radius_top_right = 8
corner_radius_bottom_right = 8
corner_radius_bottom_left = 8
[resource]
Button/fonts/font = ExtResource("1_6hrko")
Button/styles/disabled = SubResource("StyleBoxFlat_7ci2v")
Button/styles/focus = SubResource("StyleBoxFlat_cpmw2")
Button/styles/hover = SubResource("StyleBoxFlat_gks1w")
Button/styles/normal = SubResource("StyleBoxFlat_mcbjr")
Button/styles/pressed = SubResource("StyleBoxFlat_q2tue")
Label/fonts/font = ExtResource("1_6hrko")
PanelContainer/styles/panel = SubResource("StyleBoxFlat_8oovs")
PopupMenu/constants/item_end_padding = 8
PopupMenu/constants/item_start_padding = 8
PopupMenu/constants/v_separation = 8
PopupMenu/styles/hover = SubResource("StyleBoxFlat_6r5yo")
PopupMenu/styles/panel = SubResource("StyleBoxFlat_n886s")

View file

@ -0,0 +1,682 @@
using Godot;
using Godot.Collections;
using System;
using SharpHook;
using System.Linq;
public partial class GlobalInputCSharp : Node
{
#region Setup
TaskPoolGlobalHook Hook = new();
Dictionary<string, string[]> GodotKeyToSharpKey = new()
{
{Key.None.ToString(), new string[] {SharpHook.Native.KeyCode.VcUndefined.ToString()}},
{Key.Escape.ToString(), new string[] {SharpHook.Native.KeyCode.VcEscape.ToString()}},
{Key.F1.ToString(), new string[] {SharpHook.Native.KeyCode.VcF1.ToString()}},
{Key.F2.ToString(), new string[] {SharpHook.Native.KeyCode.VcF2.ToString()}},
{Key.F3.ToString(), new string[] {SharpHook.Native.KeyCode.VcF3.ToString()}},
{Key.F4.ToString(), new string[] {SharpHook.Native.KeyCode.VcF4.ToString()}},
{Key.F5.ToString(), new string[] {SharpHook.Native.KeyCode.VcF5.ToString()}},
{Key.F6.ToString(), new string[] {SharpHook.Native.KeyCode.VcF6.ToString()}},
{Key.F7.ToString(), new string[] {SharpHook.Native.KeyCode.VcF7.ToString()}},
{Key.F8.ToString(), new string[] {SharpHook.Native.KeyCode.VcF8.ToString()}},
{Key.F9.ToString(), new string[] {SharpHook.Native.KeyCode.VcF9.ToString()}},
{Key.F10.ToString(), new string[] {SharpHook.Native.KeyCode.VcF10.ToString()}},
{Key.F11.ToString(), new string[] {SharpHook.Native.KeyCode.VcF11.ToString()}},
{Key.F12.ToString(), new string[] {SharpHook.Native.KeyCode.VcF12.ToString()}},
{Key.F13.ToString(), new string[] {SharpHook.Native.KeyCode.VcF13.ToString()}},
{Key.F14.ToString(), new string[] {SharpHook.Native.KeyCode.VcF14.ToString()}},
{Key.F15.ToString(), new string[] {SharpHook.Native.KeyCode.VcF15.ToString()}},
{Key.F16.ToString(), new string[] {SharpHook.Native.KeyCode.VcF16.ToString()}},
{Key.F17.ToString(), new string[] {SharpHook.Native.KeyCode.VcF17.ToString()}},
{Key.F18.ToString(), new string[] {SharpHook.Native.KeyCode.VcF18.ToString()}},
{Key.F19.ToString(), new string[] {SharpHook.Native.KeyCode.VcF19.ToString()}},
{Key.F20.ToString(), new string[] {SharpHook.Native.KeyCode.VcF20.ToString()}},
{Key.F21.ToString(), new string[] {SharpHook.Native.KeyCode.VcF21.ToString()}},
{Key.F22.ToString(), new string[] {SharpHook.Native.KeyCode.VcF22.ToString()}},
{Key.F23.ToString(), new string[] {SharpHook.Native.KeyCode.VcF23.ToString()}},
{Key.F24.ToString(), new string[] {SharpHook.Native.KeyCode.VcF24.ToString()}},
{Key.Quoteleft.ToString(), new string[] {SharpHook.Native.KeyCode.VcBackQuote.ToString()}},
{Key.Key0.ToString(), new string[] {SharpHook.Native.KeyCode.Vc0.ToString()}},
{Key.Key1.ToString(), new string[] {SharpHook.Native.KeyCode.Vc1.ToString()}},
{Key.Key2.ToString(), new string[] {SharpHook.Native.KeyCode.Vc2.ToString()}},
{Key.Key3.ToString(), new string[] {SharpHook.Native.KeyCode.Vc3.ToString()}},
{Key.Key4.ToString(), new string[] {SharpHook.Native.KeyCode.Vc4.ToString()}},
{Key.Key5.ToString(), new string[] {SharpHook.Native.KeyCode.Vc5.ToString()}},
{Key.Key6.ToString(), new string[] {SharpHook.Native.KeyCode.Vc6.ToString()}},
{Key.Key7.ToString(), new string[] {SharpHook.Native.KeyCode.Vc7.ToString()}},
{Key.Key8.ToString(), new string[] {SharpHook.Native.KeyCode.Vc8.ToString()}},
{Key.Key9.ToString(), new string[] {SharpHook.Native.KeyCode.Vc9.ToString()}},
{Key.Minus.ToString(), new string[] {SharpHook.Native.KeyCode.VcMinus.ToString()}},
{Key.Equal.ToString(), new string[] {SharpHook.Native.KeyCode.VcEquals.ToString()}},
{Key.Backspace.ToString(), new string[] {SharpHook.Native.KeyCode.VcBackspace.ToString()}},
{Key.Tab.ToString(), new string[] {SharpHook.Native.KeyCode.VcTab.ToString()}},
{Key.Capslock.ToString(), new string[] {SharpHook.Native.KeyCode.VcCapsLock.ToString()}},
{Key.A.ToString(), new string[] {SharpHook.Native.KeyCode.VcA.ToString()}},
{Key.B.ToString(), new string[] {SharpHook.Native.KeyCode.VcB.ToString()}},
{Key.C.ToString(), new string[] {SharpHook.Native.KeyCode.VcC.ToString()}},
{Key.D.ToString(), new string[] {SharpHook.Native.KeyCode.VcD.ToString()}},
{Key.E.ToString(), new string[] {SharpHook.Native.KeyCode.VcE.ToString()}},
{Key.F.ToString(), new string[] {SharpHook.Native.KeyCode.VcF.ToString()}},
{Key.G.ToString(), new string[] {SharpHook.Native.KeyCode.VcG.ToString()}},
{Key.H.ToString(), new string[] {SharpHook.Native.KeyCode.VcH.ToString()}},
{Key.I.ToString(), new string[] {SharpHook.Native.KeyCode.VcI.ToString()}},
{Key.J.ToString(), new string[] {SharpHook.Native.KeyCode.VcJ.ToString()}},
{Key.K.ToString(), new string[] {SharpHook.Native.KeyCode.VcK.ToString()}},
{Key.L.ToString(), new string[] {SharpHook.Native.KeyCode.VcL.ToString()}},
{Key.M.ToString(), new string[] {SharpHook.Native.KeyCode.VcM.ToString()}},
{Key.N.ToString(), new string[] {SharpHook.Native.KeyCode.VcN.ToString()}},
{Key.O.ToString(), new string[] {SharpHook.Native.KeyCode.VcO.ToString()}},
{Key.P.ToString(), new string[] {SharpHook.Native.KeyCode.VcP.ToString()}},
{Key.Q.ToString(), new string[] {SharpHook.Native.KeyCode.VcQ.ToString()}},
{Key.R.ToString(), new string[] {SharpHook.Native.KeyCode.VcR.ToString()}},
{Key.S.ToString(), new string[] {SharpHook.Native.KeyCode.VcS.ToString()}},
{Key.T.ToString(), new string[] {SharpHook.Native.KeyCode.VcT.ToString()}},
{Key.U.ToString(), new string[] {SharpHook.Native.KeyCode.VcU.ToString()}},
{Key.V.ToString(), new string[] {SharpHook.Native.KeyCode.VcV.ToString()}},
{Key.W.ToString(), new string[] {SharpHook.Native.KeyCode.VcW.ToString()}},
{Key.X.ToString(), new string[] {SharpHook.Native.KeyCode.VcX.ToString()}},
{Key.Y.ToString(), new string[] {SharpHook.Native.KeyCode.VcY.ToString()}},
{Key.Z.ToString(), new string[] {SharpHook.Native.KeyCode.VcZ.ToString()}},
{Key.Bracketleft.ToString(), new string[] {SharpHook.Native.KeyCode.VcOpenBracket.ToString()}},
{Key.Bracketright.ToString(), new string[] {SharpHook.Native.KeyCode.VcCloseBracket.ToString()}},
{Key.Backslash.ToString(), new string[] {SharpHook.Native.KeyCode.VcBackslash.ToString()}},
{Key.Semicolon.ToString(), new string[] {SharpHook.Native.KeyCode.VcSemicolon.ToString()}},
{Key.Quotedbl.ToString(), new string[] {SharpHook.Native.KeyCode.VcQuote.ToString()}},
{Key.Enter.ToString(), new string[] {SharpHook.Native.KeyCode.VcEnter.ToString()}},
{Key.Comma.ToString(), new string[] {SharpHook.Native.KeyCode.VcComma.ToString()}},
{Key.Period.ToString(), new string[] {SharpHook.Native.KeyCode.VcPeriod.ToString()}},
{Key.Slash.ToString(), new string[] {SharpHook.Native.KeyCode.VcSlash.ToString()}},
{Key.Space.ToString(), new string[] {SharpHook.Native.KeyCode.VcSpace.ToString()}},
{Key.Print.ToString(), new string[] {SharpHook.Native.KeyCode.VcPrintScreen.ToString()}},
{Key.Insert.ToString(), new string[] {SharpHook.Native.KeyCode.VcInsert.ToString()}},
{Key.Home.ToString(), new string[] {SharpHook.Native.KeyCode.VcHome.ToString()}},
{Key.Pageup.ToString(), new string[] {SharpHook.Native.KeyCode.VcPageUp.ToString()}},
{Key.Delete.ToString(), new string[] {SharpHook.Native.KeyCode.VcDelete.ToString()}},
{Key.End.ToString(), new string[] {SharpHook.Native.KeyCode.VcEnd.ToString()}},
{Key.Pagedown.ToString(), new string[] {SharpHook.Native.KeyCode.VcPageDown.ToString()}},
{Key.Down.ToString(), new string[] {SharpHook.Native.KeyCode.VcDown.ToString()}},
{Key.Up.ToString(), new string[] {SharpHook.Native.KeyCode.VcUp.ToString()}},
{Key.Right.ToString(), new string[] {SharpHook.Native.KeyCode.VcRight.ToString()}},
{Key.Left.ToString(), new string[] {SharpHook.Native.KeyCode.VcLeft.ToString()}},
{Key.Numlock.ToString(), new string[] {SharpHook.Native.KeyCode.VcNumLock.ToString()}},
{Key.Kp0.ToString(), new string[] {SharpHook.Native.KeyCode.VcNumPad0.ToString()}},
{Key.Kp1.ToString(), new string[] {SharpHook.Native.KeyCode.VcNumPad1.ToString()}},
{Key.Kp2.ToString(), new string[] {SharpHook.Native.KeyCode.VcNumPad2.ToString()}},
{Key.Kp3.ToString(), new string[] {SharpHook.Native.KeyCode.VcNumPad3.ToString()}},
{Key.Kp4.ToString(), new string[] {SharpHook.Native.KeyCode.VcNumPad4.ToString()}},
{Key.Kp5.ToString(), new string[] {SharpHook.Native.KeyCode.VcNumPad5.ToString()}},
{Key.Kp6.ToString(), new string[] {SharpHook.Native.KeyCode.VcNumPad6.ToString()}},
{Key.Kp7.ToString(), new string[] {SharpHook.Native.KeyCode.VcNumPad7.ToString()}},
{Key.Kp8.ToString(), new string[] {SharpHook.Native.KeyCode.VcNumPad8.ToString()}},
{Key.Kp9.ToString(), new string[] {SharpHook.Native.KeyCode.VcNumPad9.ToString()}},
{Key.KpDivide.ToString(), new string[] {SharpHook.Native.KeyCode.VcNumPadDivide.ToString()}},
{Key.KpMultiply.ToString(), new string[] {SharpHook.Native.KeyCode.VcNumPadMultiply.ToString()}},
{Key.KpSubtract.ToString(), new string[] {SharpHook.Native.KeyCode.VcNumPadSubtract.ToString()}},
{Key.KpAdd.ToString(), new string[] {SharpHook.Native.KeyCode.VcNumPadAdd.ToString()}},
{Key.KpPeriod.ToString(), new string[] {SharpHook.Native.KeyCode.VcNumPadDecimal.ToString()}},
{Key.KpEnter.ToString(), new string[] {SharpHook.Native.KeyCode.VcNumPadEnter.ToString()}},
{Key.Shift.ToString(), new string[] {SharpHook.Native.KeyCode.VcLeftShift.ToString(), SharpHook.Native.KeyCode.VcRightShift.ToString()}},
{Key.Ctrl.ToString(), new string[] {SharpHook.Native.KeyCode.VcLeftControl.ToString(), SharpHook.Native.KeyCode.VcRightControl.ToString()}},
{Key.Alt.ToString(), new string[] {SharpHook.Native.KeyCode.VcLeftAlt.ToString(), SharpHook.Native.KeyCode.VcRightAlt.ToString()}},
{Key.Meta.ToString(), new string[] {SharpHook.Native.KeyCode.VcLeftMeta.ToString(), SharpHook.Native.KeyCode.VcRightMeta.ToString()}},
{"Mouse" + MouseButton.Left.ToString(), new string[] {SharpHook.Native.MouseButton.Button1.ToString()}},
{"Mouse" + MouseButton.Right.ToString(), new string[] {SharpHook.Native.MouseButton.Button2.ToString()}},
{"Mouse" + MouseButton.Middle.ToString(), new string[] {SharpHook.Native.MouseButton.Button3.ToString()}},
{"Mouse" + MouseButton.Xbutton1.ToString(), new string[] {SharpHook.Native.MouseButton.Button4.ToString()}},
{"Mouse" + MouseButton.Xbutton2.ToString(), new string[] {SharpHook.Native.MouseButton.Button5.ToString()}},
{"Mouse" + MouseButton.WheelUp.ToString(), new string[] {"WheelUp"}},
{"Mouse" + MouseButton.WheelDown.ToString(), new string[] {"WheelDown"}},
{"Mouse" + MouseButton.WheelLeft.ToString(), new string[] {"WheelLeft"}},
{"Mouse" + MouseButton.WheelRight.ToString(), new string[] {"WheelRight"}},
};
Dictionary<string, bool> SharpKeyState = new();
Dictionary<string, Dictionary<string, Dictionary<string, bool>>> ActionDictionary = new();
static string OverallInputEventName = "Overall";
#endregion
#region Setup Methods
private void InitializeSharpKeyState()
{
string[] sharpKeyNames = Enum.GetNames(typeof(SharpHook.Native.KeyCode));
foreach (string sharpKeyName in sharpKeyNames) SharpKeyState.Add(sharpKeyName, false);
string[] sharpMouseButtonNames = Enum.GetNames(typeof(SharpHook.Native.MouseButton));
foreach (string sharpMouseButtonName in sharpMouseButtonNames) SharpKeyState.Add(sharpMouseButtonName, false);
SharpKeyState.Add("WheelUp", false);
SharpKeyState.Add("WheelDown", false);
SharpKeyState.Add("WheelLeft", false);
SharpKeyState.Add("WheelRight", false);
}
private void InitializeActionDictionary()
{
foreach (string actionName in InputMap.GetActions())
{
ActionDictionary.Add(actionName, new Dictionary<string, Dictionary<string, bool>>());
foreach (InputEvent inputEvent in InputMap.ActionGetEvents(actionName))
{
string inputEventName = GetEventName(inputEvent);
if (!ActionDictionary[actionName].ContainsKey(inputEventName)) ActionDictionary[actionName].Add(inputEventName, new Dictionary<string, bool>()
{
{"justPressedPrevState", false},
{"justPressedState", false},
{"pressedPrevState", false},
{"pressedState", false},
{"justReleasedPrevState", false},
{"justReleasedState", false}
});
}
if (ActionDictionary[actionName].ContainsKey(OverallInputEventName)) continue;
ActionDictionary[actionName].Add(OverallInputEventName, new Dictionary<string, bool>()
{
{"justPressedPrevState", false},
{"justPressedState", false},
{"pressedPrevState", false},
{"pressedState", false},
{"justReleasedPrevState", false},
{"justReleasedState", false}
});
}
}
private void InitializeSignals()
{
Hook.KeyPressed += OnHookKeyPressed;
Hook.KeyReleased += OnHookKeyReleased;
Hook.MousePressed += OnHookMouseButtonPressed;
Hook.MouseReleased += OnHookMouseButtonReleased;
Hook.MouseWheel += OnHookMouseWheel;
}
#endregion
#region Sharp Hook Signal Handlers
private void OnHookKeyPressed(object sender, KeyboardHookEventArgs e)
{
string[] sharpKeyNames = MapGodotKeyToSharpKey(
MapSharpKeyToGodotKey(e.RawEvent.Keyboard.KeyCode.ToString())
);
UpdateSharpKeyState(sharpKeyNames, true);
}
private void OnHookKeyReleased(object sender, KeyboardHookEventArgs e)
{
string[] sharpKeyNames = MapGodotKeyToSharpKey(
MapSharpKeyToGodotKey(e.RawEvent.Keyboard.KeyCode.ToString())
);
UpdateSharpKeyState(sharpKeyNames, false);
}
private void OnHookMouseButtonPressed(object sender, MouseHookEventArgs e)
{
string[] sharpKeyNames = MapGodotKeyToSharpKey(
MapSharpKeyToGodotKey(e.RawEvent.Mouse.Button.ToString())
);
UpdateSharpKeyState(sharpKeyNames, true);
}
private void OnHookMouseButtonReleased(object sender, MouseHookEventArgs e)
{
string[] sharpKeyNames = MapGodotKeyToSharpKey(
MapSharpKeyToGodotKey(e.RawEvent.Mouse.Button.ToString())
);
UpdateSharpKeyState(sharpKeyNames, false);
}
private void OnHookMouseWheel(object sender, MouseWheelHookEventArgs e)
{
SharpHook.Native.MouseWheelScrollDirection direction = e.RawEvent.Wheel.Direction;
int rotation = e.RawEvent.Wheel.Rotation;
if (direction == SharpHook.Native.MouseWheelScrollDirection.Vertical)
{
if (rotation > 0)
{
UpdateSharpKeyState("WheelUp", true);
}
else if (rotation < 0)
{
UpdateSharpKeyState("WheelDown", true);
}
}
else if (direction == SharpHook.Native.MouseWheelScrollDirection.Horizontal)
{
if (rotation > 0)
{
UpdateSharpKeyState("WheelLeft", true);
}
else if (rotation < 0)
{
UpdateSharpKeyState("WheelRight", true);
}
}
}
#endregion
#region Helper Functions
private static string GetEventName(InputEvent inputEvent)
{
string eventName = "";
switch(inputEvent)
{
case InputEventMouse inputEventMouse:
eventName = inputEventMouse.AsText();
break;
case InputEventKey inputEventKey:
eventName = inputEventKey.AsText().Replace("(Physical)", "").Trim();
break;
}
return eventName;
}
private static string GetEventGodotKey(InputEvent inputEvent)
{
string godotKey = "";
switch (inputEvent)
{
case InputEventMouseButton inputEventMouseButton:
godotKey = "Mouse" + inputEventMouseButton.ButtonIndex.ToString();
break;
case InputEventKey inputEventKey:
godotKey = inputEventKey.PhysicalKeycode.ToString().Replace("(Physical)", "").Trim();
if (godotKey == "") godotKey = inputEventKey.Keycode.ToString().Trim();
break;
}
return godotKey;
}
private bool GetEventState(InputEvent inputEvent)
{
bool state = false;
string godotKeyName = GetEventGodotKey(inputEvent);
string[] sharpKeynames = MapGodotKeyToSharpKey(godotKeyName);
foreach (string sharpKeyName in sharpKeynames)
{
if (SharpKeyState[sharpKeyName]) state = true;
}
return state;
}
private string[] MapGodotKeyToSharpKey(string godotKey)
{
string[] sharpKeyNames = new string[0];
if (GodotKeyToSharpKey.ContainsKey(godotKey))
{
sharpKeyNames = GodotKeyToSharpKey[godotKey];
}
return sharpKeyNames;
}
private string MapSharpKeyToGodotKey(string sharpKey)
{
string godotKey = "";
foreach (string godotKeyName in GodotKeyToSharpKey.Keys){
string[] sharpKeyNames = GodotKeyToSharpKey[godotKeyName];
foreach (string sharpKeyName in sharpKeyNames)
{
if (sharpKeyName == sharpKey) {
godotKey = godotKeyName;
}
}
if (godotKey != "") break;
}
return godotKey;
}
private bool IsEventModifierPressed(KeyModifierMask keyModifierMask)
{
bool keyModifierState = true;
if (keyModifierMask > 0)
{
string keyModifierString = keyModifierMask.ToString().Replace("Mask", "");
string[] keyModifierStringArray = keyModifierString.Split(", ");
foreach (string keyModifier in keyModifierStringArray)
{
string[] sharpKeyNames = MapGodotKeyToSharpKey(keyModifier);
foreach (string sharpKeyName in sharpKeyNames)
{
if (!SharpKeyState[sharpKeyName]) keyModifierState = false;
}
}
}
return keyModifierState;
}
private void UpdateActionDictionary(string action)
{
// Add action if it doesn't exist
if (!ActionDictionary.ContainsKey(action))
{
ActionDictionary.Add(action, new Dictionary<string, Dictionary<string, bool>>());
}
// Add events if they don't exist in the dictionary
Dictionary<string, Dictionary<string, bool>> actionDict = ActionDictionary[action];
InputMap.ActionGetEvents(action).All((inputEvent) => {
if (!actionDict.ContainsKey(GetEventName(inputEvent))) actionDict.Add(GetEventName(inputEvent), new Dictionary<string, bool>()
{
{"justPressedPrevState", false},
{"justPressedState", false},
{"pressedPrevState", false},
{"pressedState", false},
{"justReleasedPrevState", false},
{"justReleasedState", false}
});
return true;
});
// Remove events if they don't exist in the input map
foreach (string eventKey in actionDict.Keys)
{
string[] inputEventNames = InputMap.ActionGetEvents(action).Select((inputEvent) => GetEventName(inputEvent)).ToArray();
if (!inputEventNames.Contains(eventKey) && eventKey != OverallInputEventName)
{
actionDict.Remove(eventKey);
}
}
// Add overall event
if (actionDict.ContainsKey(OverallInputEventName)) return;
actionDict.Add(OverallInputEventName, new Dictionary<string, bool>()
{
{"justPressedPrevState", false},
{"justPressedState", false},
{"pressedPrevState", false},
{"pressedState", false},
{"justReleasedPrevState", false},
{"justReleasedState", false}
});
}
private void UpdateAction(string action, string stateString, string prevStateString)
{
UpdateActionDictionary(action);
bool hasWheel = false;
int eventCount = 0;
int eventLength = InputMap.ActionGetEvents(action).Count;
System.Collections.Generic.List<string> wheelEventNames = new System.Collections.Generic.List<string>();
foreach (InputEvent inputEvent in InputMap.ActionGetEvents(action))
{
string inputEventType = null;
string inputEventName = null;
KeyModifierMask? inputEventModifierMask = null;
switch (inputEvent)
{
case InputEventMouse inputEventMouse:
inputEventType = "MouseButton";
inputEventName = GetEventName(inputEventMouse);
inputEventModifierMask = inputEventMouse.GetModifiersMask();
break;
case InputEventKey inputEventKey:
inputEventType = "Key";
inputEventName = GetEventName(inputEventKey);
inputEventModifierMask = inputEventKey.GetModifiersMask();
break;
}
if (inputEventType == null) continue;
Dictionary<string, bool> eventStateDictionary = ActionDictionary[action][inputEventName];
bool eventModifierState = IsEventModifierPressed((KeyModifierMask) inputEventModifierMask);
eventStateDictionary[prevStateString] = eventStateDictionary[stateString];
eventStateDictionary[stateString] = GetEventState(inputEvent) && eventModifierState;
UpdateOverallEventDictionary(action);
if (GetEventName(inputEvent).Contains("Wheel"))
{
hasWheel = true;
wheelEventNames.Add(GetEventName(inputEvent));
}
if (eventCount == eventLength - 1 && hasWheel)
{
// GD.Print(wheelEventNames);
foreach (string wheelEventName in wheelEventNames)
{
Dictionary<string, bool> wheelEventStateDictionary = ActionDictionary[action][wheelEventName];
if (wheelEventName.Contains("Wheel Up")) {
UpdateSharpKeyState("WheelUp", false);
wheelEventStateDictionary[stateString] = false;
}
if (wheelEventName.Contains("Wheel Down")) {
UpdateSharpKeyState("WheelDown", false);
wheelEventStateDictionary[stateString] = false;
}
if (wheelEventName.Contains("Wheel Left")) {
UpdateSharpKeyState("WheelLeft", false);
wheelEventStateDictionary[stateString] = false;
}
if (wheelEventName.Contains("Wheel Right")) {
UpdateSharpKeyState("WheelRight", false);
wheelEventStateDictionary[stateString] = false;
}
}
}
eventCount++;
}
}
private void UpdateSharpKeyState(string sharpKeyName, bool state)
{
if (SharpKeyState.ContainsKey(sharpKeyName))
{
SharpKeyState[sharpKeyName] = state;
}
}
private void UpdateSharpKeyState(string[] sharpKeyNames, bool state)
{
foreach (string sharpKeyName in sharpKeyNames)
{
UpdateSharpKeyState(sharpKeyName, state);
}
}
private void UpdateOverallEventDictionary(string actionName)
{
Dictionary<string, bool> overallEventStateDictionary = ActionDictionary[actionName]["Overall"];
bool justPressedPrevState = false;
bool justPressedState = false;
bool pressedPrevState = false;
bool pressedState = false;
bool justReleasedPrevState = false;
bool justReleasedState = false;
foreach (InputEvent inputEvent in InputMap.ActionGetEvents(actionName))
{
string eventType = null;
string eventName = null;
switch (inputEvent)
{
case InputEventMouseButton eventMouseButton:
eventType = "MouseButton";
eventName = GetEventName(eventMouseButton);
break;
case InputEventKey eventKey:
eventType = "Key";
eventName = GetEventName(eventKey);
break;
}
if (eventType == null) continue;
Dictionary<string, bool> eventStateDictionary = ActionDictionary[actionName][eventName];
if (eventStateDictionary["justPressedPrevState"]) justPressedPrevState = true;
if (eventStateDictionary["justPressedState"]) justPressedState = true;
if (eventStateDictionary["pressedPrevState"]) pressedPrevState = true;
if (eventStateDictionary["pressedState"]) pressedState = true;
if (eventStateDictionary["justReleasedPrevState"]) justReleasedPrevState = true;
if (eventStateDictionary["justReleasedState"]) justReleasedState = true;
}
overallEventStateDictionary["justPressedPrevState"] = justPressedPrevState;
overallEventStateDictionary["justPressedState"] = justPressedState;
overallEventStateDictionary["pressedPrevState"] = pressedPrevState;
overallEventStateDictionary["pressedState"] = pressedState;
overallEventStateDictionary["justReleasedPrevState"] = justReleasedPrevState;
overallEventStateDictionary["justReleasedState"] = justReleasedState;
}
#endregion
Node2D MousePositionNode2D;
Vector2? screen_min = null;
Vector2? screen_max = null;
public override void _Ready()
{
for (int i = 0; i < DisplayServer.GetScreenCount(); i++)
{
var pos = DisplayServer.ScreenGetPosition(i) - DisplayServer.ScreenGetPosition((int)DisplayServer.ScreenPrimary);
var size = DisplayServer.ScreenGetSize(i);
if (screen_min == null)
{
screen_min = pos;
}
else {
if (pos.X < ((Vector2)screen_min).X) screen_min = new Vector2(pos.X, ((Vector2)screen_min).Y);
if (pos.Y < ((Vector2)screen_min).Y) screen_min = new Vector2(((Vector2)screen_min).X, pos.Y);
}
if (screen_max == null)
{
screen_max = new Vector2(pos.X + size.X, pos.Y + size.Y);
}
else
{
if (pos.X + size.X > ((Vector2)screen_max).X) screen_max = new Vector2(pos.X + size.X, ((Vector2)screen_max).Y);
if (pos.Y + size.Y > ((Vector2)screen_max).Y) screen_max = new Vector2(((Vector2)screen_max).X, pos.Y + size.Y);
}
}
MousePositionNode2D = new();
AddChild(MousePositionNode2D);
InitializeSharpKeyState();
InitializeActionDictionary();
InitializeSignals();
Hook.RunAsync();
}
public override void _Input(InputEvent inputEvent)
{
if (inputEvent is InputEventKey inputEventKey)
{
if (inputEventKey.IsPressed())
{
string[] sharpKeyNames = MapGodotKeyToSharpKey(GetEventGodotKey(inputEventKey));
UpdateSharpKeyState(sharpKeyNames, true);
}
else if (inputEventKey.IsReleased())
{
string[] sharpKeyNames = MapGodotKeyToSharpKey(GetEventGodotKey(inputEventKey));
UpdateSharpKeyState(sharpKeyNames, false);
}
}
GC.Collect();
}
#region Godot Input Methods
public bool IsActionJustPressed(string action)
{
string stateString = "justPressedState";
string prevStateString = "justPressedPrevState";
UpdateAction(action, stateString, prevStateString);
Dictionary<string, bool> overallEventStateDictionary = ActionDictionary[action][OverallInputEventName];
bool prevState = overallEventStateDictionary[prevStateString];
bool state = overallEventStateDictionary[stateString];
if (!prevState && state) return true;
return false;
}
public bool IsActionPressed(string action)
{
string stateString = "pressedState";
string prevStateString = "pressedPrevState";
UpdateAction(action, stateString, prevStateString);
Dictionary<string, bool> overallEventStateDictionary = ActionDictionary[action][OverallInputEventName];
bool prevState = overallEventStateDictionary[prevStateString];
bool state = overallEventStateDictionary[stateString];
if (prevState && state) return true;
return false;
}
public bool IsActionJustReleased(string action)
{
string stateString = "justReleasedState";
string prevStateString = "justReleasedPrevState";
UpdateAction(action, stateString, prevStateString);
Dictionary<string, bool> overallEventStateDictionary = ActionDictionary[action][OverallInputEventName];
bool prevState = overallEventStateDictionary[prevStateString];
bool state = overallEventStateDictionary[stateString];
if (prevState && !state) return true;
return false;
}
public Vector2 GetVector(StringName negativeX, StringName positiveX, StringName negativeY, StringName positiveY){
Vector2 inputVector = new Vector2
{
X = (IsActionPressed(positiveX) ? 1 : 0) - (IsActionPressed(negativeX) ? 1 : 0),
Y = (IsActionPressed(positiveY) ? 1 : 0) - (IsActionPressed(negativeY) ? 1 : 0)
};
return inputVector;
}
public bool IsKeyPressed(Key key)
{
string[] sharpKeyNames = MapGodotKeyToSharpKey(key.ToString());
if (sharpKeyNames.Length == 0) return false;
foreach (string sharpKeyName in sharpKeyNames)
{
if (SharpKeyState[sharpKeyName]) return true;
}
return false;
}
public bool IsAnythingPressed(){
foreach (string actionName in InputMap.GetActions()){
if (IsActionPressed(actionName)) return true;
}
return false;
}
public Vector2 GetMousePosition() {
return (Vector2)(MousePositionNode2D.GetGlobalMousePosition() + DisplayServer.WindowGetPosition() + screen_min);
}
#endregion
}

View file

@ -0,0 +1,6 @@
[gd_scene load_steps=2 format=3 uid="uid://iejpghgiofrp"]
[ext_resource type="Script" path="res://plugins/GlobalInput/global_input_gd_script.gd" id="1_nf3vv"]
[node name="GlobalInputGdScript" type="Node"]
script = ExtResource("1_nf3vv")

View file

@ -0,0 +1,57 @@
#region Header
#01. tool
#02. class_name
#03. extends
extends Node
#endregion
#region Documentation
#-----------------------------------------------------------
#04. # docstring
## hoge
#-----------------------------------------------------------
#endregion
#region Body
#05. signals
#-----------------------------------------------------------
#-----------------------------------------------------------
#06. enums
#-----------------------------------------------------------
#-----------------------------------------------------------
#08. variables
#-----------------------------------------------------------
var global_input_csharp = preload("res://plugins/GlobalInput/GlobalInputCSharp.cs")
var global_input = global_input_csharp.new()
#-----------------------------------------------------------
#09. methods
#-----------------------------------------------------------
func _ready() -> void:
add_child(global_input)
print("GLOBAL KEY INPUT READY")
func is_action_just_pressed(action: StringName) -> bool:
return global_input.IsActionJustPressed(action)
func is_action_pressed(action: StringName) -> bool:
return global_input.IsActionPressed(action)
func is_action_just_released(action: StringName) -> bool:
return global_input.IsActionJustReleased(action)
func is_key_pressed(key: int) -> bool:
return global_input.IsKeyPressed(key)
func get_vector(negative_x, positive_x, negative_y, positive_y) -> Vector2:
return global_input.GetVector(negative_x, positive_x, negative_y, positive_y)
func get_mouse_position() -> Vector2:
return global_input.GetMousePosition()
#-----------------------------------------------------------
#10. signal methods
#-----------------------------------------------------------

106
project.godot Normal file
View file

@ -0,0 +1,106 @@
; Engine configuration file.
; It's best edited using the editor UI and not directly,
; since the parameters that go here are not all obvious.
;
; Format:
; [section] ; section goes between []
; param=value ; assign values to parameters
config_version=5
[application]
config/name="FunkPanion"
config/version="0.1.0"
run/main_scene="res://scenes/main.tscn"
run/disable_stderr=true
config/use_custom_user_dir=true
config/custom_user_dir_name="FunkPanion"
config/quit_on_go_back=false
config/features=PackedStringArray("4.3", "C#", "Forward Plus")
run/max_fps=60
boot_splash/bg_color=Color(0.254902, 0.282353, 0.298039, 1)
boot_splash/image="res://icon.png"
boot_splash/fullsize=false
boot_splash/use_filter=false
config/icon="res://icon.png"
boot_splash/minimum_display_time=2000
[autoload]
GlobalInput="*res://plugins/GlobalInput/GlobalInputGDScript.tscn"
GlobalConfig="*res://scenes/global_config.tscn"
[display]
window/size/viewport_width=640
window/size/viewport_height=480
window/size/initial_position_type=3
window/size/borderless=true
window/size/always_on_top=true
window/size/transparent=true
window/energy_saving/keep_screen_on=false
window/per_pixel_transparency/allowed=true
window/handheld/orientation=6
window/vsync/vsync_mode=2
[dotnet]
project/assembly_name="FunkPanion"
[editor]
version_control/plugin_name="GitPlugin"
version_control/autoload_on_startup=true
[gui]
theme/custom_font="res://assets/fonts/Lexend.ttf"
[input]
bpm_increase={
"deadzone": 0.5,
"events": []
}
bpm_decrease={
"deadzone": 0.5,
"events": []
}
bpm_tsincrease={
"deadzone": 0.5,
"events": []
}
bpm_tsdecrease={
"deadzone": 0.5,
"events": []
}
bpm_opaincrease={
"deadzone": 0.5,
"events": []
}
bpm_opadecrease={
"deadzone": 0.5,
"events": []
}
bpm_reset={
"deadzone": 0.5,
"events": []
}
mod_enable={
"deadzone": 0.5,
"events": []
}
mod_snap_fine={
"deadzone": 0.5,
"events": []
}
mod_snap_coarse={
"deadzone": 0.5,
"events": []
}
[rendering]
renderer/rendering_method="gl_compatibility"
renderer/rendering_method.mobile="gl_compatibility"

605
scenes/config.tscn Normal file
View file

@ -0,0 +1,605 @@
[gd_scene load_steps=13 format=3 uid="uid://b0m4v3w4sqrfs"]
[ext_resource type="Script" path="res://scripts/config/config_window.gd" id="1_3y2tp"]
[ext_resource type="LabelSettings" uid="uid://2iu8q0tylumo" path="res://assets/config/header_bold.tres" id="1_lbm3n"]
[ext_resource type="FontFile" uid="uid://ce5fs0ro7kp8r" path="res://assets/fonts/Lexend.ttf" id="2_bbfo5"]
[ext_resource type="Script" path="res://scripts/config/form_handler.gd" id="2_ouac2"]
[ext_resource type="FontFile" uid="uid://4e3o2ds5xy7p" path="res://assets/fonts/MatSymOut.ttf" id="2_pm82g"]
[ext_resource type="LabelSettings" uid="uid://c2s3eclr25ots" path="res://assets/config/body.tres" id="3_gn7vd"]
[ext_resource type="FontFile" uid="uid://c6ck52v6qotm" path="res://assets/fonts/B_Lexend.ttf" id="3_qguou"]
[ext_resource type="FontVariation" uid="uid://d1apfvux6r82v" path="res://assets/config/button_icon.tres" id="8_qusr6"]
[ext_resource type="Script" path="res://scripts/config/open_file_dialog.gd" id="9_1o6y4"]
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_3ax2o"]
bg_color = Color(0.12549, 0.12549, 0.12549, 1)
[sub_resource type="LabelSettings" id="LabelSettings_gk6wd"]
font = ExtResource("3_qguou")
font_size = 32
[sub_resource type="LabelSettings" id="LabelSettings_2l8nx"]
font = ExtResource("2_bbfo5")
font_size = 14
font_color = Color(1, 1, 1, 0.501961)
[node name="ScrollContainer" type="ScrollContainer"]
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
size_flags_horizontal = 3
size_flags_vertical = 3
theme_override_styles/panel = SubResource("StyleBoxFlat_3ax2o")
follow_focus = true
horizontal_scroll_mode = 0
script = ExtResource("1_3y2tp")
[node name="MarginContainer" type="MarginContainer" parent="."]
layout_mode = 2
size_flags_horizontal = 3
size_flags_vertical = 3
theme_override_constants/margin_left = 8
theme_override_constants/margin_top = 8
theme_override_constants/margin_right = 8
theme_override_constants/margin_bottom = 8
[node name="Form" type="VBoxContainer" parent="MarginContainer"]
layout_mode = 2
size_flags_horizontal = 3
size_flags_vertical = 3
theme_override_constants/separation = 8
script = ExtResource("2_ouac2")
[node name="Header" type="HBoxContainer" parent="MarginContainer/Form"]
layout_mode = 2
[node name="BackButton" type="Button" parent="MarginContainer/Form/Header"]
custom_minimum_size = Vector2(40, 40)
layout_mode = 2
size_flags_horizontal = 4
size_flags_vertical = 4
tooltip_text = "Save and exit."
theme_override_fonts/font = ExtResource("2_pm82g")
theme_override_font_sizes/font_size = 24
text = "arrow_back"
flat = true
[node name="Header" type="Label" parent="MarginContainer/Form/Header"]
layout_mode = 2
size_flags_horizontal = 3
text = "Config"
label_settings = SubResource("LabelSettings_gk6wd")
[node name="Reset" type="Button" parent="MarginContainer/Form/Header"]
custom_minimum_size = Vector2(40, 40)
layout_mode = 2
size_flags_horizontal = 4
size_flags_vertical = 4
tooltip_text = "Save and exit."
theme_override_fonts/font = ExtResource("2_pm82g")
theme_override_font_sizes/font_size = 24
text = "reset_settings"
[node name="OSD and UI" type="VBoxContainer" parent="MarginContainer/Form"]
layout_mode = 2
[node name="Header" type="Label" parent="MarginContainer/Form/OSD and UI"]
layout_mode = 2
text = "OSD and UI"
label_settings = ExtResource("1_lbm3n")
[node name="Tooltip" type="Label" parent="MarginContainer/Form/OSD and UI"]
layout_mode = 2
size_flags_horizontal = 3
size_flags_vertical = 1
mouse_filter = 0
text = "Configure FunkPanion's user interface."
label_settings = SubResource("LabelSettings_2l8nx")
vertical_alignment = 1
[node name="Controls" type="MarginContainer" parent="MarginContainer/Form/OSD and UI"]
layout_mode = 2
theme_override_constants/margin_left = 4
theme_override_constants/margin_top = 4
theme_override_constants/margin_right = 4
theme_override_constants/margin_bottom = 4
[node name="VBoxContainer" type="VBoxContainer" parent="MarginContainer/Form/OSD and UI/Controls"]
layout_mode = 2
theme_override_constants/separation = 4
[node name="osd_dwell_time" type="HBoxContainer" parent="MarginContainer/Form/OSD and UI/Controls/VBoxContainer"]
custom_minimum_size = Vector2(0, 32)
layout_mode = 2
[node name="Label" type="Label" parent="MarginContainer/Form/OSD and UI/Controls/VBoxContainer/osd_dwell_time"]
layout_mode = 2
size_flags_horizontal = 3
size_flags_vertical = 1
tooltip_text = "How long the OSD will stay visible for."
mouse_filter = 0
text = "OSD Dwell Time"
label_settings = ExtResource("3_gn7vd")
vertical_alignment = 1
[node name="input" type="SpinBox" parent="MarginContainer/Form/OSD and UI/Controls/VBoxContainer/osd_dwell_time"]
custom_minimum_size = Vector2(120, 0)
layout_mode = 2
size_flags_horizontal = 8
size_flags_vertical = 4
min_value = 100.0
max_value = 10000.0
step = 100.0
value = 1000.0
suffix = "ms"
select_all_on_focus = true
[node name="osd_fade_time" type="HBoxContainer" parent="MarginContainer/Form/OSD and UI/Controls/VBoxContainer"]
custom_minimum_size = Vector2(0, 32)
layout_mode = 2
[node name="Label" type="Label" parent="MarginContainer/Form/OSD and UI/Controls/VBoxContainer/osd_fade_time"]
layout_mode = 2
size_flags_horizontal = 3
size_flags_vertical = 1
tooltip_text = "How long the OSD takes to fade out."
mouse_filter = 0
text = "OSD Fade Time"
label_settings = ExtResource("3_gn7vd")
vertical_alignment = 1
[node name="input" type="SpinBox" parent="MarginContainer/Form/OSD and UI/Controls/VBoxContainer/osd_fade_time"]
custom_minimum_size = Vector2(120, 0)
layout_mode = 2
size_flags_horizontal = 8
size_flags_vertical = 4
min_value = 100.0
max_value = 10000.0
step = 100.0
value = 1000.0
suffix = "ms"
select_all_on_focus = true
[node name="osd_opacity" type="HBoxContainer" parent="MarginContainer/Form/OSD and UI/Controls/VBoxContainer"]
custom_minimum_size = Vector2(0, 32)
layout_mode = 2
[node name="Label" type="Label" parent="MarginContainer/Form/OSD and UI/Controls/VBoxContainer/osd_opacity"]
layout_mode = 2
size_flags_horizontal = 3
size_flags_vertical = 1
tooltip_text = "The opacity of the OSD."
mouse_filter = 0
text = "OSD Opacity"
label_settings = ExtResource("3_gn7vd")
vertical_alignment = 1
[node name="value" type="Label" parent="MarginContainer/Form/OSD and UI/Controls/VBoxContainer/osd_opacity"]
layout_mode = 2
text = "100%"
[node name="input" type="HSlider" parent="MarginContainer/Form/OSD and UI/Controls/VBoxContainer/osd_opacity"]
custom_minimum_size = Vector2(120, 0)
layout_mode = 2
size_flags_horizontal = 8
size_flags_vertical = 4
max_value = 1.0
step = 0.01
value = 1.0
[node name="menu_opacity" type="HBoxContainer" parent="MarginContainer/Form/OSD and UI/Controls/VBoxContainer"]
custom_minimum_size = Vector2(0, 32)
layout_mode = 2
[node name="Label" type="Label" parent="MarginContainer/Form/OSD and UI/Controls/VBoxContainer/menu_opacity"]
layout_mode = 2
size_flags_horizontal = 3
size_flags_vertical = 1
tooltip_text = "The opacity of the menu button."
mouse_filter = 0
text = "Menu Opacity"
label_settings = ExtResource("3_gn7vd")
vertical_alignment = 1
[node name="value" type="Label" parent="MarginContainer/Form/OSD and UI/Controls/VBoxContainer/menu_opacity"]
layout_mode = 2
text = "100%"
[node name="input" type="HSlider" parent="MarginContainer/Form/OSD and UI/Controls/VBoxContainer/menu_opacity"]
custom_minimum_size = Vector2(120, 0)
layout_mode = 2
size_flags_horizontal = 8
size_flags_vertical = 4
max_value = 1.0
step = 0.01
value = 1.0
[node name="background_opacity" type="HBoxContainer" parent="MarginContainer/Form/OSD and UI/Controls/VBoxContainer"]
custom_minimum_size = Vector2(0, 32)
layout_mode = 2
[node name="Label" type="Label" parent="MarginContainer/Form/OSD and UI/Controls/VBoxContainer/background_opacity"]
layout_mode = 2
size_flags_horizontal = 3
size_flags_vertical = 1
tooltip_text = "The opacity of the application's background."
mouse_filter = 0
text = "Background Opacity"
label_settings = ExtResource("3_gn7vd")
vertical_alignment = 1
[node name="value" type="Label" parent="MarginContainer/Form/OSD and UI/Controls/VBoxContainer/background_opacity"]
layout_mode = 2
text = "100%"
[node name="input" type="HSlider" parent="MarginContainer/Form/OSD and UI/Controls/VBoxContainer/background_opacity"]
custom_minimum_size = Vector2(120, 0)
layout_mode = 2
size_flags_horizontal = 8
size_flags_vertical = 4
max_value = 1.0
step = 0.01
value = 1.0
[node name="Tempo" type="VBoxContainer" parent="MarginContainer/Form"]
layout_mode = 2
[node name="Header" type="Label" parent="MarginContainer/Form/Tempo"]
layout_mode = 2
text = "Tempo"
label_settings = ExtResource("1_lbm3n")
[node name="Controls" type="MarginContainer" parent="MarginContainer/Form/Tempo"]
layout_mode = 2
theme_override_constants/margin_left = 4
theme_override_constants/margin_top = 4
theme_override_constants/margin_right = 4
theme_override_constants/margin_bottom = 4
[node name="VBoxContainer" type="VBoxContainer" parent="MarginContainer/Form/Tempo/Controls"]
layout_mode = 2
theme_override_constants/separation = 4
[node name="tempo_default" type="HBoxContainer" parent="MarginContainer/Form/Tempo/Controls/VBoxContainer"]
custom_minimum_size = Vector2(0, 32)
layout_mode = 2
[node name="Label" type="Label" parent="MarginContainer/Form/Tempo/Controls/VBoxContainer/tempo_default"]
layout_mode = 2
size_flags_horizontal = 3
size_flags_vertical = 1
tooltip_text = "The tempo that the application starts with."
mouse_filter = 0
text = "Default Tempo"
label_settings = ExtResource("3_gn7vd")
vertical_alignment = 1
[node name="input" type="SpinBox" parent="MarginContainer/Form/Tempo/Controls/VBoxContainer/tempo_default"]
custom_minimum_size = Vector2(120, 0)
layout_mode = 2
size_flags_horizontal = 8
size_flags_vertical = 4
min_value = 60.0
max_value = 10000.0
value = 120.0
suffix = "bpm"
custom_arrow_step = 5.0
select_all_on_focus = true
[node name="tempo_numerator" type="HBoxContainer" parent="MarginContainer/Form/Tempo/Controls/VBoxContainer"]
custom_minimum_size = Vector2(0, 32)
layout_mode = 2
[node name="Label" type="Label" parent="MarginContainer/Form/Tempo/Controls/VBoxContainer/tempo_numerator"]
layout_mode = 2
size_flags_horizontal = 3
size_flags_vertical = 1
tooltip_text = "The time signature that the application starts with."
mouse_filter = 0
text = "Default Time Signature"
label_settings = ExtResource("3_gn7vd")
vertical_alignment = 1
[node name="input" type="SpinBox" parent="MarginContainer/Form/Tempo/Controls/VBoxContainer/tempo_numerator"]
custom_minimum_size = Vector2(120, 0)
layout_mode = 2
size_flags_horizontal = 8
size_flags_vertical = 4
min_value = 2.0
max_value = 16.0
value = 4.0
suffix = "/ 4"
select_all_on_focus = true
[node name="Sprites" type="VBoxContainer" parent="MarginContainer/Form"]
layout_mode = 2
[node name="HBoxContainer" type="HBoxContainer" parent="MarginContainer/Form/Sprites"]
layout_mode = 2
theme_override_constants/separation = 4
[node name="Header" type="Label" parent="MarginContainer/Form/Sprites/HBoxContainer"]
layout_mode = 2
size_flags_horizontal = 3
text = "Sprites"
label_settings = ExtResource("1_lbm3n")
[node name="ImportButton" type="Button" parent="MarginContainer/Form/Sprites/HBoxContainer"]
visible = false
custom_minimum_size = Vector2(32, 32)
layout_mode = 2
theme_override_fonts/font = ExtResource("8_qusr6")
text = "file_open"
[node name="ExportButton" type="Button" parent="MarginContainer/Form/Sprites/HBoxContainer"]
visible = false
custom_minimum_size = Vector2(32, 32)
layout_mode = 2
theme_override_fonts/font = ExtResource("8_qusr6")
text = "save"
[node name="Controls" type="MarginContainer" parent="MarginContainer/Form/Sprites"]
layout_mode = 2
theme_override_constants/margin_left = 4
theme_override_constants/margin_top = 4
theme_override_constants/margin_right = 4
theme_override_constants/margin_bottom = 4
[node name="VBoxContainer" type="VBoxContainer" parent="MarginContainer/Form/Sprites/Controls"]
layout_mode = 2
theme_override_constants/separation = 4
[node name="spritesheet_image" type="HBoxContainer" parent="MarginContainer/Form/Sprites/Controls/VBoxContainer"]
custom_minimum_size = Vector2(0, 32)
layout_mode = 2
script = ExtResource("9_1o6y4")
[node name="Label" type="Label" parent="MarginContainer/Form/Sprites/Controls/VBoxContainer/spritesheet_image"]
layout_mode = 2
size_flags_horizontal = 3
size_flags_vertical = 1
tooltip_text = "A link to a sprite atlas."
mouse_filter = 0
text = "Spritesheet Image"
label_settings = ExtResource("3_gn7vd")
vertical_alignment = 1
[node name="switch" type="Button" parent="MarginContainer/Form/Sprites/Controls/VBoxContainer/spritesheet_image"]
custom_minimum_size = Vector2(32, 32)
layout_mode = 2
theme_override_fonts/font = ExtResource("8_qusr6")
text = "folder_open"
[node name="value" type="LineEdit" parent="MarginContainer/Form/Sprites/Controls/VBoxContainer/spritesheet_image"]
layout_mode = 2
size_flags_horizontal = 3
editable = false
[node name="save" type="Button" parent="MarginContainer/Form/Sprites/Controls/VBoxContainer/spritesheet_image"]
custom_minimum_size = Vector2(32, 32)
layout_mode = 2
tooltip_text = "Save the selected file to FunkPanion's application storage."
theme_override_fonts/font = ExtResource("8_qusr6")
text = "upload"
[node name="spritesheet_data" type="HBoxContainer" parent="MarginContainer/Form/Sprites/Controls/VBoxContainer"]
custom_minimum_size = Vector2(0, 32)
layout_mode = 2
script = ExtResource("9_1o6y4")
[node name="Label" type="Label" parent="MarginContainer/Form/Sprites/Controls/VBoxContainer/spritesheet_data"]
layout_mode = 2
size_flags_horizontal = 3
size_flags_vertical = 1
tooltip_text = "A link to the file that provides frames for the sprite atlas."
mouse_filter = 0
text = "Spritesheet Data"
label_settings = ExtResource("3_gn7vd")
vertical_alignment = 1
[node name="switch" type="Button" parent="MarginContainer/Form/Sprites/Controls/VBoxContainer/spritesheet_data"]
custom_minimum_size = Vector2(32, 32)
layout_mode = 2
theme_override_fonts/font = ExtResource("8_qusr6")
text = "folder_open"
[node name="value" type="LineEdit" parent="MarginContainer/Form/Sprites/Controls/VBoxContainer/spritesheet_data"]
layout_mode = 2
size_flags_horizontal = 3
editable = false
[node name="save" type="Button" parent="MarginContainer/Form/Sprites/Controls/VBoxContainer/spritesheet_data"]
custom_minimum_size = Vector2(32, 32)
layout_mode = 2
tooltip_text = "Save the selected file to FunkPanion's application storage."
theme_override_fonts/font = ExtResource("8_qusr6")
text = "upload"
[node name="spritesheet_anims" type="VBoxContainer" parent="MarginContainer/Form/Sprites/Controls/VBoxContainer"]
custom_minimum_size = Vector2(0, 32)
layout_mode = 2
theme_override_constants/separation = 4
[node name="Label" type="Label" parent="MarginContainer/Form/Sprites/Controls/VBoxContainer/spritesheet_anims"]
layout_mode = 2
size_flags_horizontal = 3
size_flags_vertical = 1
mouse_filter = 0
text = "Spritesheet Animations"
label_settings = ExtResource("3_gn7vd")
vertical_alignment = 1
[node name="Tree" type="Tree" parent="MarginContainer/Form/Sprites/Controls/VBoxContainer/spritesheet_anims"]
custom_minimum_size = Vector2(0, 150)
layout_mode = 2
size_flags_vertical = 3
columns = 3
column_titles_visible = true
allow_search = false
hide_root = true
select_mode = 1
[node name="AddNew" type="HBoxContainer" parent="MarginContainer/Form/Sprites/Controls/VBoxContainer/spritesheet_anims"]
layout_mode = 2
[node name="name" type="LineEdit" parent="MarginContainer/Form/Sprites/Controls/VBoxContainer/spritesheet_anims/AddNew"]
layout_mode = 2
size_flags_horizontal = 3
placeholder_text = "Animation Name"
[node name="switch" type="Button" parent="MarginContainer/Form/Sprites/Controls/VBoxContainer/spritesheet_anims/AddNew"]
layout_mode = 2
text = "Add"
[node name="spritesheet_anchor" type="HBoxContainer" parent="MarginContainer/Form/Sprites/Controls/VBoxContainer"]
custom_minimum_size = Vector2(0, 32)
layout_mode = 2
[node name="Label" type="Label" parent="MarginContainer/Form/Sprites/Controls/VBoxContainer/spritesheet_anchor"]
layout_mode = 2
size_flags_horizontal = 3
size_flags_vertical = 1
tooltip_text = "Where the sprite is anchored.
If the spritesheet frames are different sizes,
this can stop the animation from jittering."
mouse_filter = 0
text = "Sprite Anchor"
label_settings = ExtResource("3_gn7vd")
vertical_alignment = 1
[node name="input" type="OptionButton" parent="MarginContainer/Form/Sprites/Controls/VBoxContainer/spritesheet_anchor"]
layout_mode = 2
selected = 7
item_count = 9
popup/item_0/text = "Top Left"
popup/item_1/text = "Top"
popup/item_1/id = 1
popup/item_2/text = "Top Right"
popup/item_2/id = 2
popup/item_3/text = "Left"
popup/item_3/id = 3
popup/item_4/text = "Center"
popup/item_4/id = 4
popup/item_5/text = "Right"
popup/item_5/id = 5
popup/item_6/text = "Bottom Left"
popup/item_6/id = 6
popup/item_7/text = "Bottom"
popup/item_7/id = 7
popup/item_8/text = "Bottom Right"
popup/item_8/id = 8
[node name="sprite_scale" type="HBoxContainer" parent="MarginContainer/Form/Sprites/Controls/VBoxContainer"]
custom_minimum_size = Vector2(0, 32)
layout_mode = 2
[node name="Label" type="Label" parent="MarginContainer/Form/Sprites/Controls/VBoxContainer/sprite_scale"]
layout_mode = 2
size_flags_horizontal = 3
size_flags_vertical = 1
tooltip_text = "How big the sprite is compared to its default size."
mouse_filter = 0
text = "Sprite Scale"
label_settings = ExtResource("3_gn7vd")
vertical_alignment = 1
[node name="input" type="SpinBox" parent="MarginContainer/Form/Sprites/Controls/VBoxContainer/sprite_scale"]
custom_minimum_size = Vector2(120, 0)
layout_mode = 2
size_flags_horizontal = 8
size_flags_vertical = 4
min_value = 0.1
max_value = 10.0
step = 0.1
value = 1.0
suffix = "x"
custom_arrow_step = 0.5
select_all_on_focus = true
[node name="sprite_flip" type="HBoxContainer" parent="MarginContainer/Form/Sprites/Controls/VBoxContainer"]
custom_minimum_size = Vector2(0, 32)
layout_mode = 2
[node name="Label" type="Label" parent="MarginContainer/Form/Sprites/Controls/VBoxContainer/sprite_flip"]
layout_mode = 2
size_flags_horizontal = 3
size_flags_vertical = 1
tooltip_text = "How big the sprite is compared to its default size."
mouse_filter = 0
text = "Flip Sprite"
label_settings = ExtResource("3_gn7vd")
vertical_alignment = 1
[node name="input" type="CheckButton" parent="MarginContainer/Form/Sprites/Controls/VBoxContainer/sprite_flip"]
layout_mode = 2
size_flags_horizontal = 8
size_flags_vertical = 4
[node name="spritesheet_default_opacity" type="HBoxContainer" parent="MarginContainer/Form/Sprites/Controls/VBoxContainer"]
custom_minimum_size = Vector2(0, 32)
layout_mode = 2
[node name="Label" type="Label" parent="MarginContainer/Form/Sprites/Controls/VBoxContainer/spritesheet_default_opacity"]
layout_mode = 2
size_flags_horizontal = 3
size_flags_vertical = 1
tooltip_text = "The opacity of the sprite."
mouse_filter = 0
text = "Default Sprite Opacity"
label_settings = ExtResource("3_gn7vd")
vertical_alignment = 1
[node name="value" type="Label" parent="MarginContainer/Form/Sprites/Controls/VBoxContainer/spritesheet_default_opacity"]
layout_mode = 2
text = "100%"
[node name="input" type="HSlider" parent="MarginContainer/Form/Sprites/Controls/VBoxContainer/spritesheet_default_opacity"]
custom_minimum_size = Vector2(120, 0)
layout_mode = 2
size_flags_horizontal = 8
size_flags_vertical = 4
max_value = 1.0
step = 0.01
value = 1.0
[node name="Binds" type="VBoxContainer" parent="MarginContainer/Form"]
layout_mode = 2
[node name="Header" type="Label" parent="MarginContainer/Form/Binds"]
layout_mode = 2
text = "Binds"
label_settings = ExtResource("1_lbm3n")
[node name="Tooltip" type="Label" parent="MarginContainer/Form/Binds"]
layout_mode = 2
size_flags_horizontal = 3
size_flags_vertical = 1
mouse_filter = 0
text = "Configure FunkPanion's keybinds."
label_settings = SubResource("LabelSettings_2l8nx")
vertical_alignment = 1
[node name="Controls" type="MarginContainer" parent="MarginContainer/Form/Binds"]
layout_mode = 2
theme_override_constants/margin_left = 4
theme_override_constants/margin_top = 4
theme_override_constants/margin_right = 4
theme_override_constants/margin_bottom = 4
[node name="VBoxContainer" type="VBoxContainer" parent="MarginContainer/Form/Binds/Controls"]
layout_mode = 2
theme_override_constants/separation = 4
[node name="Tree" type="Tree" parent="MarginContainer/Form/Binds/Controls/VBoxContainer"]
custom_minimum_size = Vector2(0, 300)
layout_mode = 2
size_flags_vertical = 3
columns = 3
allow_search = false
hide_root = true
select_mode = 1
[connection signal="pressed" from="MarginContainer/Form/Header/BackButton" to="." method="_on_back_button_pressed"]
[connection signal="pressed" from="MarginContainer/Form/Header/BackButton" to="MarginContainer/Form" method="_on_back_button_pressed"]
[connection signal="pressed" from="MarginContainer/Form/Header/Reset" to="." method="_on_reset_pressed"]

View file

@ -0,0 +1,6 @@
[gd_scene load_steps=2 format=3 uid="uid://gi5oyfgmhnjn"]
[ext_resource type="Script" path="res://scripts/GlobalConfigPreInit.gd" id="1_ausyg"]
[node name="GlobalConfig" type="Node"]
script = ExtResource("1_ausyg")

84
scenes/main.tscn Normal file
View file

@ -0,0 +1,84 @@
[gd_scene load_steps=11 format=3 uid="uid://d0hedjnfwtu0"]
[ext_resource type="Script" path="res://scripts/window.gd" id="1_6nwqw"]
[ext_resource type="Script" path="res://scripts/animator.gd" id="2_hov7x"]
[ext_resource type="PackedScene" uid="uid://qnb6qrsgpbwc" path="res://scenes/osd.tscn" id="2_m7sf8"]
[ext_resource type="AudioStream" uid="uid://bj6b8h153h1bn" path="res://assets/beep.ogg" id="3_tvnah"]
[ext_resource type="AudioStream" uid="uid://8ij8fr2uqb65" path="res://assets/tap.wav" id="3_xnh3p"]
[ext_resource type="Texture2D" uid="uid://b6x537wsl3853" path="res://assets/BOYFRIEND.png" id="4_fraqq"]
[ext_resource type="Theme" uid="uid://e62vyqlhf1v1" path="res://osd.tres" id="7_bx315"]
[ext_resource type="FontFile" uid="uid://4e3o2ds5xy7p" path="res://assets/fonts/MatSymOut.ttf" id="7_q7jy6"]
[ext_resource type="Script" path="res://scripts/menu.gd" id="8_3lc1r"]
[sub_resource type="AtlasTexture" id="AtlasTexture_y0egr"]
atlas = ExtResource("4_fraqq")
region = Rect2(0, 0, 1, 1)
[node name="Control" type="ColorRect"]
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
color = Color(0.501961, 0.501961, 0.501961, 0.12549)
script = ExtResource("1_6nwqw")
[node name="Beep" type="AudioStreamPlayer" parent="."]
stream = ExtResource("3_tvnah")
[node name="Tap" type="AudioStreamPlayer" parent="."]
stream = ExtResource("3_xnh3p")
[node name="vert_align" type="BoxContainer" parent="."]
layout_mode = 1
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
alignment = 2
vertical = true
metadata/_edit_use_anchors_ = true
[node name="horiz_align" type="BoxContainer" parent="vert_align"]
layout_mode = 2
alignment = 1
[node name="scale" type="Control" parent="vert_align/horiz_align"]
custom_minimum_size = Vector2(413, 411)
layout_mode = 2
mouse_filter = 2
[node name="TextureRect" type="TextureRect" parent="vert_align/horiz_align/scale"]
layout_mode = 1
anchors_preset = 8
anchor_left = 0.5
anchor_top = 0.5
anchor_right = 0.5
anchor_bottom = 0.5
offset_left = -0.5
offset_top = -0.5
offset_right = 0.5
offset_bottom = 0.5
grow_horizontal = 2
grow_vertical = 2
texture = SubResource("AtlasTexture_y0egr")
script = ExtResource("2_hov7x")
[node name="OSD" parent="." instance=ExtResource("2_m7sf8")]
layout_mode = 1
[node name="MenuButton" type="MenuButton" parent="."]
custom_minimum_size = Vector2(48, 48)
layout_mode = 0
offset_right = 8.0
offset_bottom = 8.0
theme = ExtResource("7_bx315")
theme_override_fonts/font = ExtResource("7_q7jy6")
theme_override_font_sizes/font_size = 32
text = "menu"
item_count = 2
popup/item_0/text = "Config"
popup/item_1/text = "Exit"
popup/item_1/id = 1
script = ExtResource("8_3lc1r")

59
scenes/osd.tscn Normal file
View file

@ -0,0 +1,59 @@
[gd_scene load_steps=6 format=3 uid="uid://qnb6qrsgpbwc"]
[ext_resource type="Theme" uid="uid://e62vyqlhf1v1" path="res://osd.tres" id="1_gvcqe"]
[ext_resource type="FontFile" uid="uid://c6ck52v6qotm" path="res://assets/fonts/B_Lexend.ttf" id="2_3mso8"]
[ext_resource type="Script" path="res://scripts/osd.gd" id="2_vrpyu"]
[sub_resource type="LabelSettings" id="LabelSettings_h5r2p"]
font_color = Color(1, 1, 1, 0.501961)
[sub_resource type="LabelSettings" id="LabelSettings_58gdk"]
font = ExtResource("2_3mso8")
font_size = 24
[node name="OSD" type="PanelContainer"]
visible = false
clip_contents = true
anchors_preset = 8
anchor_left = 0.5
anchor_top = 0.5
anchor_right = 0.5
anchor_bottom = 0.5
offset_left = -100.0
offset_top = -50.0
offset_right = 100.0
offset_bottom = 50.0
grow_horizontal = 2
grow_vertical = 2
size_flags_horizontal = 4
size_flags_vertical = 4
theme = ExtResource("1_gvcqe")
script = ExtResource("2_vrpyu")
[node name="OSDTagline" type="Label" parent="."]
custom_minimum_size = Vector2(0, 31)
layout_mode = 2
size_flags_horizontal = 3
size_flags_vertical = 0
text = "BPM"
label_settings = SubResource("LabelSettings_h5r2p")
horizontal_alignment = 1
vertical_alignment = 1
justification_flags = 0
text_overrun_behavior = 3
[node name="OSDTitle" type="Label" parent="."]
layout_mode = 2
size_flags_horizontal = 3
text = "120"
label_settings = SubResource("LabelSettings_58gdk")
horizontal_alignment = 1
vertical_alignment = 1
justification_flags = 0
text_overrun_behavior = 3
[node name="OSDActionBar" type="HBoxContainer" parent="."]
layout_mode = 2
size_flags_vertical = 8
mouse_filter = 2
alignment = 1

53
scenes/osd_action.tscn Normal file
View file

@ -0,0 +1,53 @@
[gd_scene load_steps=3 format=3 uid="uid://4er5u7okv1gr"]
[ext_resource type="FontFile" uid="uid://4e3o2ds5xy7p" path="res://assets/fonts/MatSymOut.ttf" id="1_wgmk7"]
[sub_resource type="LabelSettings" id="LabelSettings_dy2ef"]
font = ExtResource("1_wgmk7")
[node name="OSDAction" type="Button"]
custom_minimum_size = Vector2(0, 24)
anchors_preset = 14
anchor_top = 0.5
anchor_right = 1.0
anchor_bottom = 0.5
offset_top = -4.0
offset_bottom = 4.0
grow_horizontal = 2
grow_vertical = 2
size_flags_horizontal = 3
size_flags_vertical = 4
mouse_filter = 1
keep_pressed_outside = true
text_overrun_behavior = 3
[node name="Icon" type="Label" parent="."]
custom_minimum_size = Vector2(24, 24)
layout_mode = 1
anchors_preset = 9
anchor_bottom = 1.0
offset_right = 16.0
grow_vertical = 2
text = "add"
label_settings = SubResource("LabelSettings_dy2ef")
horizontal_alignment = 1
vertical_alignment = 1
justification_flags = 0
[node name="Title" type="Label" parent="."]
layout_mode = 1
anchors_preset = 8
anchor_left = 0.5
anchor_top = 0.5
anchor_right = 0.5
anchor_bottom = 0.5
offset_left = -39.5
offset_top = -10.0
offset_right = 39.5
offset_bottom = 10.0
grow_horizontal = 2
grow_vertical = 2
text = "More BPM"
horizontal_alignment = 1
vertical_alignment = 1
justification_flags = 0

18
scripts/ArrayUtils.gd Normal file
View file

@ -0,0 +1,18 @@
class_name ArrayUtils
static func get_sclosest(array:Array, target:Variant, error = 0):
var floor = 0
var ceil = array.size() - 1
var closest = error
while floor <= ceil:
var searchPoint = floor((floor + ceil) / 2)
var num = array[searchPoint]
if num <= target:
closest = searchPoint
floor = searchPoint + 1
else:
ceil = searchPoint - 1
return closest

190
scripts/Config.gd Normal file
View file

@ -0,0 +1,190 @@
class_name Config
extends Node
enum SpritesheetAnimType {
DEFAULT,
IDLE
}
static var SpritesheetAnchorIndices = [
"TOP_LEFT",
"TOP",
"TOP_RIGHT",
"LEFT",
"CENTER",
"RIGHT",
"BOTTOM_LEFT",
"BOTTOM",
"BOTTOM_RIGHT"
]
static var SpritesheetAnchor = {
TOP_LEFT = [BoxContainer.AlignmentMode.ALIGNMENT_BEGIN, BoxContainer.AlignmentMode.ALIGNMENT_BEGIN],
TOP = [BoxContainer.AlignmentMode.ALIGNMENT_CENTER, BoxContainer.AlignmentMode.ALIGNMENT_BEGIN],
TOP_RIGHT = [BoxContainer.AlignmentMode.ALIGNMENT_END, BoxContainer.AlignmentMode.ALIGNMENT_BEGIN],
LEFT = [BoxContainer.AlignmentMode.ALIGNMENT_BEGIN, BoxContainer.AlignmentMode.ALIGNMENT_CENTER],
CENTER = [BoxContainer.AlignmentMode.ALIGNMENT_CENTER, BoxContainer.AlignmentMode.ALIGNMENT_CENTER],
RIGHT = [BoxContainer.AlignmentMode.ALIGNMENT_END, BoxContainer.AlignmentMode.ALIGNMENT_CENTER],
BOTTOM_LEFT = [BoxContainer.AlignmentMode.ALIGNMENT_BEGIN, BoxContainer.AlignmentMode.ALIGNMENT_END],
BOTTOM = [BoxContainer.AlignmentMode.ALIGNMENT_CENTER, BoxContainer.AlignmentMode.ALIGNMENT_END],
BOTTOM_RIGHT = [BoxContainer.AlignmentMode.ALIGNMENT_END, BoxContainer.AlignmentMode.ALIGNMENT_END]
}
# OSD and UI
var osd_dwell_time = 2000
var osd_fade_time = 1000
var osd_opacity = 1.0
var menu_opacity = 1.0
var background_opacity = 0.1
# BPM snap
var coarse_bpm_snap = 10.0
var fine_bpm_snap = 0.5
# Tempo
var tempo_default = 120.0
var tempo_numerator = 4
# Sparrow spritesheet data
var spritesheet_data = "res://assets/BOYFRIEND.xml"
var spritesheet_image = "res://assets/BOYFRIEND.png"
var spritesheet_anims = {
"BF idle dance" = {
alias = null,
type = SpritesheetAnimType.IDLE
},
"BF NOTE LEFT" = {
alias = "left",
type = SpritesheetAnimType.DEFAULT
},
"BF NOTE DOWN" = {
alias = "down",
type = SpritesheetAnimType.DEFAULT
},
"BF NOTE UP" = {
alias = "up",
type = SpritesheetAnimType.DEFAULT
},
"BF NOTE RIGHT" = {
alias = "right",
type = SpritesheetAnimType.DEFAULT
},
"BF HEY!!" = {
alias = "special",
type = SpritesheetAnimType.DEFAULT
}
}
var spritesheet_anchor = SpritesheetAnchor.BOTTOM
var sprite_scale = 1.0
var sprite_flip = false
var spritesheet_default_opacity = 1.0
# Keybinds
# Bind change keys
var bpm_is_global = true
var bpm_needs_enable = true
var bpm_increase:Array[Key] = [ KEY_R ]
var bpm_decrease:Array[Key] = [ KEY_F ]
var bpm_tsincrease:Array[Key] = [ KEY_T ]
var bpm_tsdecrease:Array[Key] = [ KEY_G ]
var bpm_opaincrease:Array[Key] = [ KEY_BRACELEFT ]
var bpm_opadecrease:Array[Key] = [ KEY_BRACERIGHT ]
var bpm_reset:Array[Key] = [ KEY_V ]
# Bind modifiers
var mod_enable:Array[Key] = [ KEY_SHIFT ]
var mod_snap_fine:Array[Key] = [ KEY_TAB ]
var mod_snap_coarse:Array[Key] = [ KEY_CTRL ]
# Bind animations
var anim_is_global = true
var anim_needs_enable = false
var anim_binds = {
left = [ KEY_A, KEY_LEFT ],
down = [ KEY_S, KEY_DOWN ],
up = [ KEY_W, KEY_UP ],
right = [ KEY_D, KEY_RIGHT ],
special = [ KEY_Q ]
}
static func new_clear() -> Config:
var config:Config = Config.new()
config.spritesheet_anims = {}
config.bpm_increase = []
config.bpm_decrease = []
config.bpm_tsincrease = []
config.bpm_tsdecrease = []
config.bpm_opaincrease = []
config.bpm_opadecrease = []
config.bpm_reset = []
config.mod_enable = []
config.mod_snap_fine = []
config.mod_snap_coarse = []
config.anim_binds = {}
return config
func clone_config(config) -> void:
self.osd_dwell_time = config.osd_dwell_time
self.osd_fade_time = config.osd_fade_time
self.osd_opacity = config.osd_opacity
self.menu_opacity = config.menu_opacity
self.background_opacity = config.background_opacity
self.coarse_bpm_snap = config.coarse_bpm_snap
self.fine_bpm_snap = config.fine_bpm_snap
self.tempo_default = config.tempo_default
self.tempo_numerator = config.tempo_numerator
self.spritesheet_data = config.spritesheet_data
self.spritesheet_image = config.spritesheet_image
self.spritesheet_anims = config.spritesheet_anims.duplicate(true)
self.spritesheet_anchor = config.spritesheet_anchor
self.sprite_scale = config.sprite_scale
self.sprite_flip = config.sprite_flip
self.spritesheet_default_opacity = config.spritesheet_default_opacity
self.bpm_is_global = config.bpm_is_global
self.bpm_needs_enable = config.bpm_needs_enable
self.bpm_increase = config.bpm_increase.duplicate(true)
self.bpm_decrease = config.bpm_decrease.duplicate(true)
self.bpm_tsincrease = config.bpm_tsincrease.duplicate(true)
self.bpm_tsdecrease = config.bpm_tsdecrease.duplicate(true)
self.bpm_opaincrease = config.bpm_opaincrease.duplicate(true)
self.bpm_opadecrease = config.bpm_opadecrease.duplicate(true)
self.bpm_reset = config.bpm_reset.duplicate(true)
self.mod_enable = config.mod_enable.duplicate(true)
self.mod_snap_fine = config.mod_snap_fine.duplicate(true)
self.mod_snap_coarse = config.mod_snap_coarse.duplicate(true)
self.anim_is_global = config.anim_is_global
self.anim_needs_enable = config.anim_needs_enable
self.anim_binds = config.anim_binds.duplicate(true)
func format_config() -> Dictionary:
var dict = {}
dict.osd_dwell_time = self.osd_dwell_time
dict.osd_fade_time = self.osd_fade_time
dict.osd_opacity = self.osd_opacity
dict.menu_opacity = self.menu_opacity
dict.background_opacity = self.background_opacity
dict.coarse_bpm_snap = self.coarse_bpm_snap
dict.fine_bpm_snap = self.fine_bpm_snap
dict.tempo_default = self.tempo_default
dict.tempo_numerator = self.tempo_numerator
dict.spritesheet_data = self.spritesheet_data
dict.spritesheet_image = self.spritesheet_image
dict.spritesheet_anims = self.spritesheet_anims.duplicate(true)
dict.sprite_scale = self.sprite_scale
dict.sprite_flip = self.sprite_flip
dict.spritesheet_anchor = self.spritesheet_anchor
dict.spritesheet_default_opacity = self.spritesheet_default_opacity
dict.bpm_is_global = self.bpm_is_global
dict.bpm_needs_enable = self.bpm_needs_enable
dict.bpm_increase = self.bpm_increase.duplicate(true)
dict.bpm_decrease = self.bpm_decrease.duplicate(true)
dict.bpm_tsincrease = self.bpm_tsincrease.duplicate(true)
dict.bpm_tsdecrease = self.bpm_tsdecrease.duplicate(true)
dict.bpm_opaincrease = self.bpm_opaincrease.duplicate(true)
dict.bpm_opadecrease = self.bpm_opadecrease.duplicate(true)
dict.bpm_reset = self.bpm_reset.duplicate(true)
dict.mod_enable = self.mod_enable.duplicate(true)
dict.mod_snap_fine = self.mod_snap_fine.duplicate(true)
dict.mod_snap_coarse = self.mod_snap_coarse.duplicate(true)
dict.anim_is_global = self.anim_is_global
dict.anim_needs_enable = self.anim_needs_enable
dict.anim_binds = self.anim_binds.duplicate(true)
return dict

View file

@ -0,0 +1,61 @@
class_name GlobalConfigPreInit
extends Config
# Called when the node enters the scene tree for the first time.
func _ready() -> void:
self.clone_config(Config.new_clear())
load_from_file()
func bind_keys() -> void:
bind_all_keys(self.bpm_increase, "bpm_increase")
bind_all_keys(self.bpm_decrease, "bpm_decrease")
bind_all_keys(self.bpm_tsincrease, "bpm_tsincrease")
bind_all_keys(self.bpm_tsdecrease, "bpm_tsdecrease")
bind_all_keys(self.bpm_opaincrease, "bpm_opaincrease")
bind_all_keys(self.bpm_opadecrease, "bpm_opadecrease")
bind_all_keys(self.bpm_reset, "bpm_reset")
bind_all_keys(self.mod_enable, "mod_enable")
bind_all_keys(self.mod_snap_fine, "mod_snap_fine")
bind_all_keys(self.mod_snap_coarse, "mod_snap_coarse")
for action in self.anim_binds:
if not InputMap.has_action("anim_" + action):
InputMap.add_action("anim_" + action)
bind_all_keys(self.anim_binds[action], "anim_" + action)
func bind_all_keys(array, action) -> void:
InputMap.action_erase_events(action)
for key in array:
var ev = InputEventKey.new()
ev.physical_keycode = key
InputMap.action_add_event(action, ev)
func reset_settings() -> void:
var config = ConfigFile.new()
GlobalConfig.clone_config(Config.new())
config.save("user://config.cfg")
bind_keys()
func save_to_file() -> void:
var dict = self.format_config()
var config = ConfigFile.new()
for key in dict:
config.set_value("FunkPanion", key, dict[key])
config.save("user://config.cfg")
bind_keys()
func load_from_file() -> void:
var config = ConfigFile.new()
var err = config.load("user://config.cfg")
if err != OK:
return
for key in config.get_section_keys("FunkPanion"):
var value = config.get_value("FunkPanion", key)
if value != null:
self[key] = value
bind_keys()

9
scripts/MathUtils.gd Normal file
View file

@ -0,0 +1,9 @@
class_name MathUtils
static func average(numbers: Array) -> float:
var sum = 0.0
var size = numbers.size() - 1
for n in size:
var diff = numbers[n + 1] - numbers[n]
sum += diff
return sum / size

View file

@ -0,0 +1,101 @@
class_name SpritesheetParser
var spritesheet
var max_dimensions : Vector2i
var _parser = XMLParser.new()
var _filename_regex = RegEx.new()
func parse_spritesheet(path):
var animations = {}
max_dimensions = Vector2i(0, 0)
_parser.open(path)
_filename_regex.compile("^(.+?)(\\d{1,4})$")
while _parser.read() != ERR_FILE_EOF:
if _parser.get_node_type() != XMLParser.NODE_ELEMENT:
continue
var node_name = _parser.get_node_name()
if node_name != "SubTexture":
continue
var frame_search = _filename_regex.search(_parser.get_named_attribute_value_safe("name"))
var frame_name = frame_search.get_string(1)
var frame_no = frame_search.get_string(2).to_int()
var frame_x = _parser.get_named_attribute_value_safe("x")
var frame_y = _parser.get_named_attribute_value_safe("y")
var frame_width = _parser.get_named_attribute_value_safe("width")
var frame_height = _parser.get_named_attribute_value_safe("height")
var frame_frame_x = _parser.get_named_attribute_value_safe("frameX")
var frame_frame_y = _parser.get_named_attribute_value_safe("frameY")
var frame_frame_width = _parser.get_named_attribute_value_safe("frameWidth")
var frame_frame_height = _parser.get_named_attribute_value_safe("frameHeight")
if not animations.has(frame_name):
animations[frame_name] = []
var array = animations[frame_name]
var frame_data = {}
if frame_x.is_valid_int() and frame_y.is_valid_int():
frame_data.pos = Vector2i(frame_x.to_int(), frame_y.to_int())
else:
frame_data.pos = Vector2i.ZERO
if frame_width.is_valid_int() and frame_height.is_valid_int():
frame_data.size = Vector2i(frame_width.to_int(), frame_height.to_int())
if frame_width.to_int() > max_dimensions.x:
max_dimensions.x = frame_width.to_int()
if frame_height.to_int() > max_dimensions.y:
max_dimensions.y = frame_height.to_int()
else:
frame_data.size = Vector2i.ZERO
if frame_frame_x.is_valid_int() and frame_frame_y.is_valid_int():
frame_data.frame_pos = Vector2i(frame_frame_x.to_int(), frame_frame_y.to_int())
else:
frame_data.frame_pos = Vector2i.ZERO
if frame_frame_width.is_valid_int() and frame_frame_height.is_valid_int():
frame_data.frame_size = Vector2i(frame_frame_width.to_int(), frame_frame_height.to_int())
if frame_frame_width.to_int() > max_dimensions.x:
max_dimensions.x = frame_frame_width.to_int()
if frame_frame_height.to_int() > max_dimensions.y:
max_dimensions.y = frame_frame_height.to_int()
else:
frame_data.frame_size = frame_data.size
if frame_no >= array.size():
array.resize(frame_no + 1)
array[frame_no] = frame_data
for animation in animations:
var anim_frames: Array = animations[animation]
while anim_frames.has(null):
anim_frames.erase(null)
spritesheet = animations
func get_props_of_animation_frame(anim:String, frameno:int):
var anim_frames = spritesheet[anim]
frameno = clamp(frameno, 0, anim_frames.size() - 1)
var frame = anim_frames[frameno]
return {
region = Rect2(frame.pos, frame.size),
margin = Rect2(-frame.frame_pos, frame.frame_size - frame.size)
}
static func load_image(path: String):
if path.begins_with('res'):
return load(path)
else:
var file = FileAccess.open(path, FileAccess.READ)
if FileAccess.get_open_error() != OK:
print(str("Could not load image at: ",path))
return
var buffer = file.get_buffer(file.get_length())
var image = Image.new()
var error = image.load_png_from_buffer(buffer)
if error != OK:
print(str("Could not load image at: ",path," with error: ",error))
return
var texture = ImageTexture.create_from_image(image)
return texture

13
scripts/Tempo.gd Normal file
View file

@ -0,0 +1,13 @@
class_name Tempo
static func get_crotchet(bpm):
return ((60 / bpm) * 1000)
static func get_bpm(crotchet):
return ((1000 / crotchet) * 60)
static func beat_at_time(time, bpm):
return time / get_crotchet(bpm)
static func time_at_beat(beat, bpm):
return beat * get_crotchet(bpm)

58
scripts/animator.gd Normal file
View file

@ -0,0 +1,58 @@
extends TextureRect
var spritesheet_parser: SpritesheetParser = SpritesheetParser.new()
var bpm = float(GlobalConfig.tempo_default)
var anims = [
]
var active_anims = []
func _ready() -> void:
texture = AtlasTexture.new()
texture.atlas = SpritesheetParser.load_image(GlobalConfig.spritesheet_image)
texture.region = Rect2(0, 0, 1, 1)
spritesheet_parser.parse_spritesheet(GlobalConfig.spritesheet_data)
self.item_rect_changed.connect(func():
self.get_parent().custom_minimum_size = self.size * self.scale
self.position = Vector2.ZERO)
var sprani = GlobalConfig.spritesheet_anims
for animation in sprani:
anims.append({
name = animation,
key = "anim_" + sprani[animation].alias if sprani[animation].alias else null,
tstamp = 0.0,
active = sprani[animation].type == Config.SpritesheetAnimType.IDLE,
keydown = sprani[animation].type == Config.SpritesheetAnimType.IDLE,
type = sprani[animation].type
})
func _process(delta: float) -> void:
var time = Time.get_ticks_msec()
var current_animation = active_anims.front()
if current_animation == null:
return
if not spritesheet_parser.spritesheet.has(current_animation.name):
return
var animation = spritesheet_parser.spritesheet[current_animation.name]
var beat_percentage = Tempo.beat_at_time(time - current_animation.tstamp, bpm)
if beat_percentage >= 1 and current_animation.active:
if current_animation.type == Config.SpritesheetAnimType.IDLE:
current_animation.tstamp = time
beat_percentage = 0
elif current_animation.type == Config.SpritesheetAnimType.DEFAULT and current_animation.keydown:
beat_percentage = 1
var anim_current = floor(beat_percentage * animation.size())
var anim_current_props = spritesheet_parser.get_props_of_animation_frame(current_animation.name, anim_current)
self.texture.region = anim_current_props.region
self.texture.margin = anim_current_props.margin
self.size = anim_current_props.margin.size

View file

@ -0,0 +1,31 @@
extends ScrollContainer
var main_window
var exiting_to_config = false
# Called when the node enters the scene tree for the first time.
func _enter_tree() -> void:
print("enter tree")
main_window = get_tree().root
main_window.borderless = false
main_window.always_on_top = false
main_window.transparent = false
main_window.min_size = Vector2i(640, 480)
main_window.size = Vector2i(640, 480)
ProjectSettings.set_setting("display/window/subwindows/embed_subwindows", false)
func _exit_tree() -> void:
if exiting_to_config: return
main_window.borderless = true
main_window.always_on_top = true
main_window.transparent = true
main_window.min_size = Vector2i(100, 100)
ProjectSettings.set_setting("display/window/subwindows/embed_subwindows", true)
func _on_back_button_pressed() -> void:
get_tree().change_scene_to_file("res://scenes/main.tscn")
func _on_reset_pressed() -> void:
GlobalConfig.reset_settings()
exiting_to_config = true
get_tree().reload_current_scene()

View file

@ -0,0 +1,387 @@
extends VBoxContainer
@onready var osd_dwell_time = $"OSD and UI/Controls/VBoxContainer/osd_dwell_time"
@onready var osd_fade_time = $"OSD and UI/Controls/VBoxContainer/osd_fade_time"
@onready var osd_opacity = $"OSD and UI/Controls/VBoxContainer/osd_opacity"
@onready var menu_opacity = $"OSD and UI/Controls/VBoxContainer/menu_opacity"
@onready var background_opacity = $"OSD and UI/Controls/VBoxContainer/background_opacity"
@onready var tempo_default = $"Tempo/Controls/VBoxContainer/tempo_default"
@onready var tempo_numerator = $"Tempo/Controls/VBoxContainer/tempo_numerator"
@onready var spritesheet_image = $"Sprites/Controls/VBoxContainer/spritesheet_image"
@onready var spritesheet_data = $"Sprites/Controls/VBoxContainer/spritesheet_data"
@onready var spritesheet_anims = $"Sprites/Controls/VBoxContainer/spritesheet_anims"
@onready var spritesheet_anchor = $"Sprites/Controls/VBoxContainer/spritesheet_anchor"
@onready var sprite_scale = $"Sprites/Controls/VBoxContainer/sprite_scale"
@onready var sprite_flip = $"Sprites/Controls/VBoxContainer/sprite_flip"
@onready var spritesheet_default_opacity = $"Sprites/Controls/VBoxContainer/spritesheet_default_opacity"
@onready var anims = $"Binds/Controls/VBoxContainer"
@onready var matsymout = load("res://assets/fonts/MatSymOut.ttf")
@onready var close_icon = load("res://assets/icons/close.png")
@onready var add_icon = load("res://assets/icons/add.png")
var temp_config = Config.new_clear()
func _parse_form_values() -> void:
pass
# Called when the node enters the scene tree for the first time.
func _ready() -> void:
temp_config.clone_config(GlobalConfig)
link_range_to_property(osd_dwell_time, "osd_dwell_time")
link_range_to_property(osd_fade_time, "osd_fade_time")
link_value_to_slider(osd_opacity)
link_range_to_property(osd_opacity, "osd_opacity")
link_value_to_slider(menu_opacity)
link_range_to_property(menu_opacity, "menu_opacity")
link_value_to_slider(background_opacity)
link_range_to_property(background_opacity, "background_opacity")
link_range_to_property(tempo_default, "tempo_default")
link_range_to_property(tempo_numerator, "tempo_numerator")
link_filebox_to_property(spritesheet_image, "spritesheet_image")
link_filebox_to_property(spritesheet_data, "spritesheet_data")
link_optionbutton_to_property(spritesheet_anchor, "spritesheet_anchor", Config.SpritesheetAnchor)
link_range_to_property(sprite_scale, "sprite_scale")
link_toggleable_to_property(sprite_flip, "sprite_flip")
link_value_to_slider(spritesheet_default_opacity)
link_range_to_property(spritesheet_default_opacity, "spritesheet_default_opacity")
fuckwith_anims()
fuckwith_spritesheet_anims()
func _on_back_button_pressed() -> void:
GlobalConfig.clone_config(temp_config)
GlobalConfig.save_to_file()
var unlock_func = null
func _input(event:InputEvent) -> void:
if unlock_func and event is InputEventKey:
unlock_func.call(event.physical_keycode)
func link_value_to_slider(obj:BoxContainer) -> void:
var input:HSlider = obj.get_node("input")
var value:Label = obj.get_node("value")
input.value_changed.connect(func(va: float):
value.text = str(va * 100) + "%")
func link_range_to_property(obj:BoxContainer, property:String) -> void:
var input:Range = obj.get_node("input")
input.value = temp_config[property]
input.value_changed.connect(func(va: float):
temp_config[property] = va)
func link_toggleable_to_property(obj:BoxContainer, property:String) -> void:
var input:BaseButton = obj.get_node("input")
input.button_pressed = temp_config[property]
input.toggled.connect(func(toggled_on: bool):
temp_config[property] = toggled_on)
func link_textbox_to_property(obj:BoxContainer, property:String) -> void:
var input:LineEdit = obj.get_node("value")
input.text = temp_config[property]
input.text_changed.connect(func(va: String):
temp_config[property] = va)
func link_filebox_to_property(obj:BoxContainer, property:String) -> void:
var input:LineEdit = obj.get_node("value")
input.text = temp_config[property]
obj.file_changed.connect(func(va: String):
temp_config[property] = va)
func link_optionbutton_to_property(obj:BoxContainer, property:String, enu:Dictionary) -> void:
var input:OptionButton = obj.get_node("input")
input.select(
Config.SpritesheetAnchorIndices.find(
enu.find_key(temp_config[property])
)
)
input.item_selected.connect(func(index: int):
temp_config[property] = enu[Config.SpritesheetAnchorIndices[index]])
func fuckwith_spritesheet_anims() -> void:
var tree:Tree = spritesheet_anims.get_node("Tree")
var add_new_name:LineEdit = spritesheet_anims.get_node("AddNew/name")
var add_new_switch:Button = spritesheet_anims.get_node("AddNew/switch")
var tree_anims:Tree = anims.get_node("Tree")
tree.set_column_title(0, "Animation Name")
tree.set_column_title(1, "Alias")
tree.set_column_title(2, "Type")
var tree_root = tree.create_item()
var tree_anims_root = tree_anims.get_root()
var tree_anims_root_anims = tree_anims.get_root().get_child(0)
var tree_anims_root_functions = tree_anims.get_root().get_child(1)
var keep_updated = func():
temp_config.spritesheet_anims = {}
for child in tree_root.get_children():
var child_name = child.get_text(0)
var child_alias = child.get_text(1)
var child_type = child.get_range(2)
temp_config.spritesheet_anims[child_name] = {
alias = child_alias if child_alias.length() > 0 else null,
type = child_type
}
var has_thing = false
for alias in tree_anims_root_anims.get_children():
if child_alias.length() < 1 or alias.get_text(0) == child_alias:
has_thing = true
break
if not has_thing:
var anims_child = tree_anims.create_item(tree_anims_root_anims)
anims_child.set_cell_mode(0, TreeItem.CELL_MODE_STRING)
anims_child.set_editable(0, false)
anims_child.set_text(0, child_alias)
temp_config.anim_binds[child_alias] = []
anims_child.add_button(2, add_icon, 1)
for alias in tree_anims_root_anims.get_children():
var has_thing = false
for child in tree_root.get_children():
var child_alias = child.get_text(1)
if child_alias.length() > 0 and alias.get_text(0) == child_alias:
has_thing = true
break
if not has_thing:
temp_config.anim_binds.erase(alias.get_text(0))
alias.free()
spritesheet_data.file_changed.connect(func(path: String):
var spritesheet_parser = SpritesheetParser.new()
spritesheet_parser.parse_spritesheet(path)
for animation in spritesheet_parser.spritesheet:
for child in tree_root.get_children():
if child.get_text(0) == animation:
return
var child = tree.create_item(tree_root)
child.set_cell_mode(0, TreeItem.CELL_MODE_STRING)
child.set_editable(0, true)
child.set_text(0, animation)
child.set_cell_mode(1, TreeItem.CELL_MODE_STRING)
child.set_editable(1, true)
child.set_text(1, "")
if animation.containsn("left"):
child.set_text(1, "left")
elif animation.containsn("down"):
child.set_text(1, "down")
elif animation.containsn("up"):
child.set_text(1, "up")
elif animation.containsn("right"):
child.set_text(1, "right")
child.set_cell_mode(2, TreeItem.CELL_MODE_RANGE)
child.set_editable(2, true)
child.set_text(2, "Default,Idle")
child.add_button(2, close_icon)
child.set_range(2, animation.containsn("idle"))
keep_updated.call()
)
tree.item_edited.connect(keep_updated)
tree.button_clicked.connect(func(item:TreeItem, column:int, _id, _mbi):
var item_name = item.get_text(0)
if column == 2:
item.free()
keep_updated.call()
)
for animation in temp_config.spritesheet_anims:
var child = tree.create_item(tree_root)
child.set_cell_mode(0, TreeItem.CELL_MODE_STRING)
child.set_editable(0, true)
child.set_text(0, animation)
child.set_cell_mode(1, TreeItem.CELL_MODE_STRING)
child.set_editable(1, true)
var alias = temp_config.spritesheet_anims.get(animation).alias
child.set_text(1, alias if alias else "")
child.set_cell_mode(2, TreeItem.CELL_MODE_RANGE)
child.set_editable(2, true)
child.set_text(2, "Default,Idle")
var type = temp_config.spritesheet_anims.get(animation).type
child.set_range(2, type)
child.add_button(2, close_icon)
add_new_switch.pressed.connect(func():
if add_new_name.text.length() > 0:
for child in tree_root.get_children():
if child.get_text(0) == add_new_name.text:
return
var child = tree.create_item(tree_root)
child.set_cell_mode(0, TreeItem.CELL_MODE_STRING)
child.set_editable(0, true)
child.set_text(0, add_new_name.text)
child.set_cell_mode(1, TreeItem.CELL_MODE_STRING)
child.set_editable(1, true)
child.set_text(1, "")
child.set_cell_mode(2, TreeItem.CELL_MODE_RANGE)
child.set_editable(2, true)
child.set_text(2, "Default,Idle")
child.add_button(2, close_icon)
add_new_name.text = ""
keep_updated.call()
)
func fuckwith_anims() -> void:
var tree:Tree = anims.get_node("Tree")
tree.set_column_expand(1, false)
tree.set_column_custom_minimum_width(1, 150)
tree.set_column_expand(2, false)
tree.set_column_custom_minimum_width(2, 150)
var tree_root = tree.create_item()
var anims_root = tree.create_item(tree_root)
anims_root.set_cell_mode(0, TreeItem.CELL_MODE_STRING)
anims_root.set_editable(0, false)
anims_root.set_text(0, "Animation aliases")
anims_root.set_cell_mode(1, TreeItem.CELL_MODE_CHECK)
anims_root.set_editable(1, true)
anims_root.set_checked(1, temp_config.anim_is_global)
anims_root.set_text(1, "Global capture")
anims_root.set_tooltip_text(1, "If animation keypresses should be captured\noutside of the application.")
anims_root.set_cell_mode(2, TreeItem.CELL_MODE_CHECK)
anims_root.set_editable(2, true)
anims_root.set_checked(2, temp_config.anim_needs_enable)
anims_root.set_text(2, "Requires Enable")
anims_root.set_tooltip_text(2, "If animation keypresses should be ignored\nunless (Modifier) Enable is pressed.")
var functions_root = tree.create_item(tree_root)
functions_root.set_cell_mode(0, TreeItem.CELL_MODE_STRING)
functions_root.set_editable(0, false)
functions_root.set_text(0, "Functions and modifiers")
functions_root.set_cell_mode(1, TreeItem.CELL_MODE_CHECK)
functions_root.set_editable(1, true)
functions_root.set_checked(1, temp_config.bpm_is_global)
functions_root.set_text(1, "Global capture")
functions_root.set_tooltip_text(1, "If function keypresses should be captured\noutside of the application.")
functions_root.set_cell_mode(2, TreeItem.CELL_MODE_CHECK)
functions_root.set_editable(2, true)
functions_root.set_checked(2, temp_config.bpm_needs_enable)
functions_root.set_text(2, "Requires Enable")
functions_root.set_tooltip_text(2, "if function keypresses should be ignored\nunless (Modifier) Enable is pressed.\nModifiers are not affected.")
var functions_index_to_key = {}
var add_tree_item_for_function = func(key: String, label: String):
var anims_child = tree.create_item(functions_root)
anims_child.set_cell_mode(0, TreeItem.CELL_MODE_STRING)
anims_child.set_editable(0, false)
anims_child.set_text(0, label)
anims_child.add_button(2, add_icon, 1)
functions_index_to_key[anims_child.get_index()] = key
for phykey in temp_config[key]:
var child = tree.create_item(anims_child)
child.set_cell_mode(0, TreeItem.CELL_MODE_CUSTOM)
child.set_editable(0, false)
child.set_text(0, OS.get_keycode_string(DisplayServer.keyboard_get_keycode_from_physical(phykey)))
child.add_button(2, close_icon, 2)
add_tree_item_for_function.call("bpm_increase", "Increase Tempo")
add_tree_item_for_function.call("bpm_decrease", "Decrease Tempo")
add_tree_item_for_function.call("bpm_tsincrease", "Increase Time Signature")
add_tree_item_for_function.call("bpm_tsdecrease", "Decrease Time Signature")
add_tree_item_for_function.call("bpm_opaincrease", "Increase Character Opacity")
add_tree_item_for_function.call("bpm_opadecrease", "Decrease Character Opacity")
add_tree_item_for_function.call("bpm_reset", "Sync Tempo")
add_tree_item_for_function.call("mod_enable", "(Modifier) Enable")
add_tree_item_for_function.call("mod_snap_coarse", "(Modifier) Snap Coarse")
add_tree_item_for_function.call("mod_snap_fine", "(Modifier) Snap Fine")
tree.item_edited.connect(func():
temp_config.anim_is_global = anims_root.is_checked(1)
temp_config.anim_needs_enable = anims_root.is_checked(2)
temp_config.bpm_is_global = functions_root.is_checked(1)
temp_config.bpm_needs_enable = functions_root.is_checked(2)
)
tree.item_activated.connect(func():
var selected = tree.get_selected()
var level = 0
var last_parent = selected
while last_parent != tree_root:
last_parent = last_parent.get_parent()
level += 1
if level == 3:
var parent = selected.get_parent()
if unlock_func:
selected.set_text(0, "Double-click to set key")
if parent.get_parent() == anims_root:
temp_config.anim_binds[parent.get_text(0)][selected.get_index()] = -1
elif parent.get_parent() == functions_root:
var key = functions_index_to_key[parent.get_index()]
temp_config[key][selected.get_index()] = -1
unlock_func = null
else:
selected.set_text(0, "Press any key...")
unlock_func = func(keycode: Key):
selected.set_text(0, OS.get_keycode_string(DisplayServer.keyboard_get_keycode_from_physical(keycode)))
if parent.get_parent() == anims_root:
temp_config.anim_binds[parent.get_text(0)][selected.get_index()] = keycode
elif parent.get_parent() == functions_root:
var key = functions_index_to_key[parent.get_index()]
temp_config[key][selected.get_index()] = keycode
unlock_func = null
)
for keybind in temp_config.anim_binds:
var anims_child = tree.create_item(anims_root)
anims_child.set_cell_mode(0, TreeItem.CELL_MODE_STRING)
anims_child.set_editable(0, false)
anims_child.set_text(0, keybind)
anims_child.add_button(2, add_icon, 1)
for key in temp_config.anim_binds.get(keybind):
var child = tree.create_item(anims_child)
child.set_cell_mode(0, TreeItem.CELL_MODE_CUSTOM)
child.set_editable(0, false)
child.set_text(0, OS.get_keycode_string(DisplayServer.keyboard_get_keycode_from_physical(key)))
child.add_button(2, close_icon, 2)
tree.button_clicked.connect(func(item:TreeItem, column:int, id:int, _mbi):
if column == 2:
var parent = item.get_parent()
if id == 1:
var child = tree.create_item(item)
if parent == anims_root:
temp_config.anim_binds[item.get_text(0)].insert(child.get_index(), -1)
elif parent == functions_root:
var key = functions_index_to_key[item.get_index()]
temp_config[key].insert(child.get_index(), -1)
child.set_cell_mode(0, TreeItem.CELL_MODE_CUSTOM)
child.set_editable(0, false)
child.set_text(0, "Double-click to set key")
child.add_button(2, close_icon, 2)
if id == 2:
if parent.get_parent() == anims_root:
temp_config.anim_binds[parent.get_text(0)].remove_at(item.get_index())
elif parent.get_parent() == functions_root:
var key = functions_index_to_key[parent.get_index()]
temp_config[key].remove_at(item.get_index())
item.free()
)

View file

@ -0,0 +1,43 @@
extends HBoxContainer
signal file_changed(path: String)
@onready var root = get_tree().root
@onready var open_file = $"switch"
@onready var path = $"value"
@onready var upload_file = $"save"
# Called when the node enters the scene tree for the first time.
func _ready() -> void:
print("User data dir located in " + OS.get_data_dir())
open_file.pressed.connect(func():
var file_dialog = FileDialog.new()
file_dialog.use_native_dialog = true
file_dialog.file_mode = FileDialog.FILE_MODE_OPEN_FILE
file_dialog.access = FileDialog.ACCESS_FILESYSTEM
file_dialog.current_path = OS.get_data_dir().path_join("FunkPanion/")
file_dialog.file_selected.connect(func(path_string: String):
var localized = path_string.simplify_path().replace(OS.get_data_dir().path_join("FunkPanion/"), "user://")
path.text = localized
file_changed.emit(localized)
file_dialog.queue_free()
)
file_dialog.canceled.connect(func(path_string: String):
root.remove_child(file_dialog)
file_dialog.queue_free()
)
root.add_child(file_dialog)
file_dialog.popup()
)
upload_file.pressed.connect(func():
if path.text.length() > 0:
print("path text yes", path.text)
if FileAccess.file_exists(path.text) and path.text.findn("user://") != 0 and ProjectSettings.localize_path(path.text).findn("user://") != 0:
print("path exists")
if not DirAccess.dir_exists_absolute("user://uploads/"):
DirAccess.make_dir_absolute("user://uploads/")
var new_path = "user://uploads/".path_join(path.text.get_file())
DirAccess.copy_absolute(path.text, new_path)
path.text = new_path
file_changed.emit(new_path)
)

18
scripts/menu.gd Normal file
View file

@ -0,0 +1,18 @@
extends MenuButton
var popup:PopupMenu
func _index_pressed(idx: int):
if idx == 0:
get_tree().change_scene_to_file("res://scenes/config.tscn")
elif idx == 1:
get_tree().quit()
# Called when the node enters the scene tree for the first time.
func _ready() -> void:
popup = get_popup()
popup.index_pressed.connect(_index_pressed)
# Called every frame. 'delta' is the elapsed time since the previous frame.
func _process(delta: float) -> void:
self_modulate.a = 1 if popup.visible else GlobalConfig.menu_opacity

112
scripts/osd.gd Normal file
View file

@ -0,0 +1,112 @@
extends PanelContainer
const res_action = preload("res://scenes/osd_action.tscn")
enum ICON_POSITION {
LEFT,
CENTER,
RIGHT
}
@onready var gui_tagline := $"OSDTagline"
@onready var gui_title := $"OSDTitle"
@onready var gui_actionbar := $"OSDActionBar"
@onready var tagline:
get: gui_tagline.text
set(value):
gui_tagline.text = value
@onready var title:
get: gui_title.text
set(value):
gui_title.text = value
var last_shown = -(GlobalConfig.osd_dwell_time + GlobalConfig.osd_fade_time)
func show_osd(a_tagline: String, a_title: String, a_actions: Array):
# Clear actions
for n in gui_actionbar.get_children():
gui_actionbar.remove_child(n)
n.queue_free()
tagline = a_tagline
title = a_title
for action in a_actions:
var button = res_action.instantiate()
var title: Label = button.get_node("Title")
var icon: Label = button.get_node("Icon")
title.text = action.title
if action.icon != null:
icon.text = action.icon
if action.icon_pos == ICON_POSITION.LEFT:
icon.set_anchors_preset(Control.PRESET_LEFT_WIDE)
icon.set_position(Vector2(0,-12))
elif action.icon_pos == ICON_POSITION.CENTER:
icon.set_anchors_preset(Control.PRESET_VCENTER_WIDE)
icon.set_position(Vector2(-12,-12))
else:
icon.set_anchors_preset(Control.PRESET_RIGHT_WIDE)
icon.set_position(Vector2(-24,-12))
if action.toggles:
button.toggle_mode = true
button.toggled.connect(action.action)
else:
button.pressed.connect(action.action)
gui_actionbar.add_child(button)
last_shown = Time.get_ticks_msec()
visible = true
modulate.a = GlobalConfig.osd_opacity
mouse_filter = Control.MOUSE_FILTER_STOP
for n in gui_actionbar.get_children():
gui_actionbar.mouse_filter = Control.MOUSE_FILTER_STOP
func hide_osd():
last_shown = -(GlobalConfig.osd_dwell_time + GlobalConfig.osd_fade_time)
visible = false
modulate.a = GlobalConfig.osd_opacity
mouse_filter = Control.MOUSE_FILTER_IGNORE
for n in gui_actionbar.get_children():
gui_actionbar.mouse_filter = Control.MOUSE_FILTER_IGNORE
var mouse_inside = false
var mouse_just_inside = false
func _ready() -> void:
mouse_entered.connect(func(): mouse_inside = true; mouse_just_inside = true)
mouse_exited.connect(func(): mouse_inside = false)
func _process(delta: float) -> void:
var ft = GlobalConfig.osd_dwell_time + GlobalConfig.osd_fade_time
var time_since_shown = Time.get_ticks_msec() - last_shown
if mouse_inside and time_since_shown >= GlobalConfig.osd_dwell_time and time_since_shown < ft:
if mouse_just_inside:
mouse_just_inside = false
visible = true
modulate.a = GlobalConfig.osd_opacity
mouse_filter = Control.MOUSE_FILTER_STOP
for n in gui_actionbar.get_children():
gui_actionbar.mouse_filter = Control.MOUSE_FILTER_PASS
last_shown = Time.get_ticks_msec()
time_since_shown = 0
if time_since_shown >= ft and visible:
modulate.a = GlobalConfig.osd_opacity
visible = false
mouse_filter = Control.MOUSE_FILTER_IGNORE
for n in gui_actionbar.get_children():
gui_actionbar.mouse_filter = Control.MOUSE_FILTER_IGNORE
elif time_since_shown >= GlobalConfig.osd_dwell_time and time_since_shown < ft:
var percentage = min(1, float(time_since_shown - GlobalConfig.osd_dwell_time) / GlobalConfig.osd_fade_time)
modulate.a = (1 - percentage) * GlobalConfig.osd_opacity
visible = true
elif time_since_shown < GlobalConfig.osd_dwell_time and not visible:
modulate.a = GlobalConfig.osd_opacity
visible = true
mouse_filter = Control.MOUSE_FILTER_STOP
for n in gui_actionbar.get_children():
gui_actionbar.mouse_filter = Control.MOUSE_FILTER_STOP

254
scripts/window.gd Normal file
View file

@ -0,0 +1,254 @@
extends ColorRect
@onready var main_window = get_tree().root
@onready var character := $"vert_align/horiz_align/scale/TextureRect"
@onready var osd = $"OSD"
@onready var beepplayer := $"Beep"
@onready var tapplayer := $"Tap"
@onready var vert_align = $"vert_align"
@onready var horiz_align = $"vert_align/horiz_align"
@onready var scale_node = $"vert_align/horiz_align/scale"
var dragging = false
var dragging_start_position:Vector2i
var old_window_position:Vector2i
var signal_offset = false
var signal_change = false
var signal_beep_num = false
var signal_beep_bpm = false
var bpm_snap = 1
var character_opacity = 100.0
var numerator = int(GlobalConfig.tempo_numerator)
var change_array = []
func _ready() -> void:
horiz_align.alignment = GlobalConfig.spritesheet_anchor[0]
vert_align.alignment = GlobalConfig.spritesheet_anchor[1]
main_window.min_size = Vector2i(100, 100)
main_window.size = character.spritesheet_parser.max_dimensions * GlobalConfig.sprite_scale
character.scale = Vector2(GlobalConfig.sprite_scale, GlobalConfig.sprite_scale)
character_opacity = GlobalConfig.spritesheet_default_opacity * 100
character.flip_h = GlobalConfig.sprite_flip
self.color.a = GlobalConfig.background_opacity
func _gui_input(event: InputEvent) -> void:
if event is InputEventMouseButton:
if event.get_button_index() == 1:
dragging = event.is_pressed()
dragging_start_position = DisplayServer.mouse_get_position()
old_window_position = main_window.get_position()
func _process(_delta: float) -> void:
set_default_cursor_shape(Control.CURSOR_DRAG if dragging else Control.CURSOR_ARROW)
if dragging:
main_window.set_position(old_window_position + (DisplayServer.mouse_get_position() - dragging_start_position))
character.modulate.a = character_opacity / 100
if not GlobalConfig.anim_is_global:
_anim_process(Input)
if not GlobalConfig.bpm_is_global:
_input_functions(Input)
func _physics_process(_delta: float) -> void:
if GlobalConfig.anim_is_global:
_anim_process(GlobalInput)
if GlobalConfig.bpm_is_global:
_input_functions(GlobalInput)
func _input_functions(input) -> void:
if GlobalConfig.bpm_needs_enable and not input.is_action_pressed("mod_enable"):
return
bpm_snap = 1
if input.is_action_pressed("mod_snap_fine"):
bpm_snap *= 0.5
if input.is_action_pressed("mod_snap_coarse"):
bpm_snap *= 10
if input.is_action_just_pressed("bpm_decrease"):
_run_bpmchange(-bpm_snap)
_run_offset()
if input.is_action_just_pressed("bpm_increase"):
_run_bpmchange(bpm_snap)
_run_offset()
if input.is_action_just_pressed("bpm_opadecrease"):
_run_opacitychange(-bpm_snap)
if input.is_action_just_pressed("bpm_opaincrease"):
_run_opacitychange(bpm_snap)
if input.is_action_just_pressed("bpm_reset"):
_run_offset()
_run_tapper()
if input.is_action_just_pressed("bpm_tsdecrease"):
_run_numeratorchange(-1)
if input.is_action_just_pressed("bpm_tsincrease"):
_run_numeratorchange(1)
var time = 0.0
func _anim_process(input) -> void:
var process_key_input = input.is_action_pressed("mod_enable") or not GlobalConfig.anim_needs_enable
var prev_time = time
time = Time.get_ticks_msec()
for animation in character.anims:
if animation.key != null:
var kd_before = animation.keydown
animation.keydown = process_key_input and input.is_action_pressed(animation.key)
if animation.keydown and not kd_before:
animation.tstamp = time
animation.active = animation.keydown or Tempo.beat_at_time(time - animation.tstamp, character.bpm) <= 1
var prev_active_anim = character.active_anims.front()
character.active_anims = character.anims.filter(func(a): return a.active)
character.active_anims.sort_custom(func(a, b): return a.tstamp > b.tstamp)
var active_anim = character.active_anims.front()
if active_anim and active_anim != prev_active_anim:
active_anim.tstamp = time
func _osd_opacity_change():
osd.show_osd("Character opacity", str(character_opacity) + "%", [
{
title = "",
icon = "remove",
icon_pos = osd.ICON_POSITION.CENTER,
toggles = false,
action = (func():
_run_opacitychange(-bpm_snap))
},
{
title = "",
icon = "add",
icon_pos = osd.ICON_POSITION.CENTER,
toggles = false,
action = (func():
_run_opacitychange(bpm_snap))
}
])
func _osd_bpm_change():
osd.show_osd("Tempo", str(character.bpm) + "bpm", [
{
title = "",
icon = "remove",
icon_pos = osd.ICON_POSITION.CENTER,
toggles = false,
action = (func():
_run_bpmchange(-bpm_snap)
_run_offset())
},
{
title = "",
icon = "touch_app",
icon_pos = osd.ICON_POSITION.CENTER,
toggles = false,
action = (func():
_run_offset()
_run_tapper())
},
{
title = "",
icon = "add",
icon_pos = osd.ICON_POSITION.CENTER,
toggles = false,
action = (func():
_run_bpmchange(bpm_snap)
_run_offset())
}
])
func _osd_num_change():
osd.show_osd("Time signature", str(numerator) + "/4", [
{
title = "",
icon = "remove",
icon_pos = osd.ICON_POSITION.CENTER,
toggles = false,
action = (func():
_run_numeratorchange(-1))
},
{
title = "",
icon = "add",
icon_pos = osd.ICON_POSITION.CENTER,
toggles = false,
action = (func():
_run_numeratorchange(1))
}
])
func _osd_bpm_reset():
osd.show_osd(str(numerator) + " taps for Tapper", "Sync", [
{
title = "Reset/Tap",
icon = "touch_app",
icon_pos = osd.ICON_POSITION.RIGHT,
toggles = false,
action = (func():
_run_offset()
_run_tapper())
}
])
func _run_opacitychange(delta: float):
if character_opacity + delta < 0.0:
character_opacity = 0.0
elif character_opacity + delta > 100.0:
character_opacity = 100.0
else:
character_opacity += delta
_osd_opacity_change()
func _run_bpmchange(delta: float):
if character.bpm + delta < 60.0:
character.bpm = 60.0
elif character.bpm + delta > 1000.0:
character.bpm = 1000.0
else:
character.bpm += delta
beepplayer.play(0)
_osd_bpm_change()
func _run_numeratorchange(delta: int):
if numerator + delta < 2:
numerator = 2
elif numerator + delta > 16:
numerator = 16
else:
numerator += delta
beepplayer.play(0)
_osd_num_change()
func _run_offset():
for anim in character.anims:
if anim.type == GlobalConfig.SpritesheetAnimType.IDLE:
anim.tstamp = Time.get_ticks_msec()
func _run_tapper():
var time = Time.get_ticks_msec()
if change_array.size() > 0:
var last_time = change_array.back()
var time_offset = time - last_time
if time_offset <= 2000.0:
change_array.append(time)
else:
change_array = [Time.get_ticks_msec()]
else:
change_array = [Time.get_ticks_msec()]
var avg = MathUtils.average(change_array)
if change_array.size() >= numerator:
character.bpm = floor(Tempo.get_bpm(avg) / bpm_snap) * bpm_snap
_osd_bpm_change()
else: _osd_bpm_reset()
if (change_array.size() - 1) % numerator == 0:
tapplayer.pitch_scale = 1.25
else:
tapplayer.pitch_scale = 1
tapplayer.play(0)