Author SHA1 Message Date
⍚~NexandFuro 0d9360f0ff Bring dev/scripted-game-modes 2026-01-21 18:17:48 +01:00
⍚~Nex 1cfe6ca468 forgor 2026-01-21 17:16:31 +01:00
⍚~Nex 3bbeafcc3e restarting again
i hate git
2026-01-21 17:09:15 +01:00
123 changed files with 228003 additions and 25313 deletions
+2 -4
View File
@@ -12,8 +12,6 @@ jobs:
steps: steps:
- name: Pulling the new commit - name: Pulling the new commit
uses: actions/checkout@v4 uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setting up Haxe - name: Setting up Haxe
uses: krdlab/setup-haxe@v2 uses: krdlab/setup-haxe@v2
with: with:
@@ -37,7 +35,7 @@ jobs:
haxe -cp commandline -D analyzer-optimize --run Main setup -s haxe -cp commandline -D analyzer-optimize --run Main setup -s
- name: Building the game - name: Building the game
run: | run: |
haxelib run lime build linux -DCOMPILE_EXPERIMENTAL haxelib run lime build linux
# - name: Tar files # - name: Tar files
# run: tar -zcvf CodenameEngine.tar.gz -C export/release/linux/bin . # run: tar -zcvf CodenameEngine.tar.gz -C export/release/linux/bin .
- name: Uploading artifact (executable) - name: Uploading artifact (executable)
@@ -146,4 +144,4 @@ jobs:
path: | path: |
.haxelib/ .haxelib/
export/debug/linux/haxe/ export/debug/linux/haxe/
export/debug/linux/obj/ export/debug/linux/obj/
+2 -4
View File
@@ -12,8 +12,6 @@ jobs:
steps: steps:
- name: Pulling the new commit - name: Pulling the new commit
uses: actions/checkout@v4 uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setting up Haxe - name: Setting up Haxe
uses: krdlab/setup-haxe@v2 uses: krdlab/setup-haxe@v2
with: with:
@@ -34,7 +32,7 @@ jobs:
haxe -cp commandline -D analyzer-optimize --run Main setup -s haxe -cp commandline -D analyzer-optimize --run Main setup -s
- name: Building the game - name: Building the game
run: | run: |
arch -x86_64 haxelib run lime build mac -DCOMPILE_EXPERIMENTAL arch -x86_64 haxelib run lime build mac
- name: Tar files - name: Tar files
run: tar -zcvf CodenameEngine.tar.gz -C export/release/macos/bin . run: tar -zcvf CodenameEngine.tar.gz -C export/release/macos/bin .
- name: Uploading artifact (executable) - name: Uploading artifact (executable)
@@ -140,4 +138,4 @@ jobs:
path: | path: |
.haxelib/ .haxelib/
export/debug/macos/haxe/ export/debug/macos/haxe/
export/debug/macos/obj/ export/debug/macos/obj/
-2
View File
@@ -22,8 +22,6 @@ jobs:
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Download Windows Full Build - name: Download Windows Full Build
uses: dawidd6/action-download-artifact@v6 uses: dawidd6/action-download-artifact@v6
+2 -4
View File
@@ -12,8 +12,6 @@ jobs:
steps: steps:
- name: Pulling the new commit - name: Pulling the new commit
uses: actions/checkout@v4 uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setting up Haxe - name: Setting up Haxe
uses: krdlab/setup-haxe@v2 uses: krdlab/setup-haxe@v2
with: with:
@@ -34,7 +32,7 @@ jobs:
haxe -cp commandline -D analyzer-optimize --run Main setup -s --no-vscheck haxe -cp commandline -D analyzer-optimize --run Main setup -s --no-vscheck
- name: Building the game - name: Building the game
run: | run: |
haxelib run lime build windows -DCOMPILE_EXPERIMENTAL haxelib run lime build windows
- name: Uploading artifact (executable) - name: Uploading artifact (executable)
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v4
with: with:
@@ -136,4 +134,4 @@ jobs:
path: | path: |
.haxelib/ .haxelib/
export/debug/windows/haxe/ export/debug/windows/haxe/
export/debug/windows/obj/ export/debug/windows/obj/
+3 -3
View File
@@ -71,11 +71,11 @@ _**QOL = Quality of Life**_
- Characters are located in `data/weeks/characters`. - Characters are located in `data/weeks/characters`.
- Weeks are located in `data/weeks/weeks/` - Weeks are located in `data/weeks/weeks/`
- If you need to rearrange the weeks in-game, you can use the `data/weeks/weeks.txt` file. - If you need to rearrange the weeks in-game, you can use the `data/weeks/weeks.txt` file.
- Editors for Charts and Characters (Stage coming soon) - Editors for Charts and Characters
- Undos/Redos supported - Undos/Redos supported
- Warning on closing unsaved work. - Warning on closing unsaved work
- Clean UI (for ocd freaks) - Clean UI (for ocd freaks)
- Mature Chart editor (Character editor rework soon) - Mature Chart editor
- Features not found in other editors! - Features not found in other editors!
- Every single state & substate can be modified via HScript (`data/states/StateName.hx`) - Every single state & substate can be modified via HScript (`data/states/StateName.hx`)
- **Instances launched via `lime test windows` will automatically use assets from source.** - **Instances launched via `lime test windows` will automatically use assets from source.**
+7
View File
@@ -2,6 +2,13 @@
<character x="115" y="325" sprite="gf-christmas" icon="gf" color="#A5004D"> <character x="115" y="325" sprite="gf-christmas" icon="gf" color="#A5004D">
<anim name="danceLeft" anim="GF Dancing Beat" x="0" y="-9" fps="24" loop="false" indices="0..14"/> <anim name="danceLeft" anim="GF Dancing Beat" x="0" y="-9" fps="24" loop="false" indices="0..14"/>
<anim name="danceRight" anim="GF Dancing Beat" x="0" y="-9" fps="24" loop="false" indices="15..30"/> <anim name="danceRight" anim="GF Dancing Beat" x="0" y="-9" fps="24" loop="false" indices="15..30"/>
<anim name="singUP" anim="GF Up Note" x="0" y="-9" fps="24" loop="false"/>
<anim name="singDOWN" anim="GF Down Note" x="0" y="-9" fps="24" loop="false"/>
<anim name="singLEFT" anim="GF left note" x="0" y="-9" fps="24" loop="false"/>
<anim name="singRIGHT" anim="GF Right Note" x="0" y="-9" fps="24" loop="false"/>
<anim name="scared" anim="GF FEAR" x="0" y="-9" fps="24" loop="true"/>
<anim name="hairBlow" anim="GF Dancing Beat Hair blowing" x="0" y="-9" fps="24" loop="false" indices="0..3"/>
<anim name="hairFall" anim="GF Dancing Beat Hair Landing" x="0" y="-9" fps="24" loop="false" indices="0..11"/>
<anim name="cheer" anim="GF Cheer" x="0" y="-9" fps="24" loop="false"/> <anim name="cheer" anim="GF Cheer" x="0" y="-9" fps="24" loop="false"/>
<anim name="sad" anim="gf sad" x="-51" y="306" fps="24" loop="true" indices="0..12"/> <anim name="sad" anim="gf sad" x="-51" y="306" fps="24" loop="true" indices="0..12"/>
</character> </character>
+12 -12
View File
@@ -1,14 +1,14 @@
<!DOCTYPE codename-engine-character> <!DOCTYPE codename-engine-character>
<character x="100" y="275" color="#A5004D"> <character x="100" y="275" sprite="gf" icon="gf" color="#A5004D">
<anim name="cheer" anim="GF Cheer"/> <anim name="cheer" anim="GF Cheer" x="0" y="0" fps="24" loop="false"/>
<anim name="singUP" anim="GF Up Note"/> <anim name="singUP" anim="GF Up Note" x="0" y="0" fps="24" loop="false"/>
<anim name="singLEFT" anim="GF left note"/> <anim name="singLEFT" anim="GF left note" x="0" y="0" fps="24" loop="false"/>
<anim name="singRIGHT" anim="GF Right Note"/> <anim name="singRIGHT" anim="GF Right Note" x="0" y="0" fps="24" loop="false"/>
<anim name="singDOWN" anim="GF Down Note"/> <anim name="singDOWN" anim="GF Down Note" x="0" y="0" fps="24" loop="false"/>
<anim name="danceLeft" anim="GF Dancing Beat" indices="0..14"/> <anim name="danceLeft" anim="GF Dancing Beat" x="0" y="0" fps="24" loop="false" indices="0..14"/>
<anim name="danceRight" anim="GF Dancing Beat" indices="15..30"/> <anim name="danceRight" anim="GF Dancing Beat" x="0" y="0" fps="24" loop="false" indices="15..30"/>
<anim name="hairBlow" anim="GF Dancing Beat Hair blowing" loop="true" indices="0..3"/> <anim name="hairBlow" anim="GF Dancing Beat Hair blowing" x="0" y="0" fps="24" loop="true" indices="0,1,2,3"/>
<anim name="hairFall" anim="GF Dancing Beat Hair Landing" indices="0..11"/> <anim name="hairFall" anim="GF Dancing Beat Hair Landing" x="0" y="0" fps="24" loop="false" indices="0..11"/>
<anim name="scared" anim="GF FEAR " loop="true"/> <anim name="scared" anim="GF FEAR" x="0" y="0" fps="24" loop="true"/>
<anim name="sad" anim="gf sad" x="-51" y="315" loop="true" indices="0..12"/> <anim name="sad" anim="gf sad" x="0" y="0" fps="24" loop="true" indices="0..12"/>
</character> </character>
+3
View File
@@ -1,3 +1,6 @@
# THIS FILE ISN'T NECESSARY,
# BUT YOU CAN USE IT TO SORT AND WHITELIST FREEPLAY SONGS
test test
tutorial tutorial
+8
View File
@@ -0,0 +1,8 @@
# THIS FILE ISN'T NECESSARY,
# BUT YOU CAN USE IT TO SORT AND WHITELIST GAME MODES
solo
opponent
coop
coop-switched
botplay
@@ -1,5 +1,5 @@
# THIS FILE ISN'T NECESSARY, # THIS FILE ISN'T NECESSARY,
# BUT YOU CAN USE IT TO SORT WEEKS # BUT YOU CAN USE IT TO SORT AND WHITELIST WEEKS
tutorial tutorial
week1 week1
+4
View File
@@ -0,0 +1,4 @@
{
"displayName": "Botplay Mode",
"modeID": "codename.botplay"
}
+2
View File
@@ -0,0 +1,2 @@
<!DOCTYPE codename-engine-game-mode>
<mode name="Botplay Mode" id="codename.botplay"/>
+5
View File
@@ -0,0 +1,5 @@
{
"displayName": "Co-Op Mode (Switched)",
"modeID": "codename.coop-opponent",
"scripts": ["opponent", "coop"]
}
+11
View File
@@ -0,0 +1,11 @@
<!DOCTYPE codename-engine-game-mode>
<mode name="Co-Op Mode (Switched)" id="codename.coop-opponent">
<script>coop</script>
<script>opponent</script>
<!--
just a small example of what you could do with fields!!
<field name="switchStrums" type="bool" val="true"/>
<field name="strumSize" type="float" val="0.6"/>
-->
</mode>
+4
View File
@@ -0,0 +1,4 @@
{
"displayName": "Co-Op Mode",
"modeID": "codename.coop"
}
+2
View File
@@ -0,0 +1,2 @@
<!DOCTYPE codename-engine-game-mode>
<mode name="Co-Op Mode" id="codename.coop"/>
+5
View File
@@ -0,0 +1,5 @@
solo
opponent
coop
coop-switched
botplay
+4
View File
@@ -0,0 +1,4 @@
{
"displayName": "Opponent Mode",
"modeID": "codename.opponent"
}
+2
View File
@@ -0,0 +1,2 @@
<!DOCTYPE codename-engine-game-mode>
<mode name="Opponent Mode" id="codename.opponent"/>
+4
View File
@@ -0,0 +1,4 @@
{
"displayName": "Solo Mode",
"modeID": "codename.solo"
}
+2
View File
@@ -0,0 +1,2 @@
<!DOCTYPE codename-engine-game-mode>
<mode name="Solo Mode" id="codename.solo"/>
+1 -1
View File
@@ -11,7 +11,7 @@
<sprite name="fgSnow" x="-600" y="680" sprite="fgSnow"/> <sprite name="fgSnow" x="-600" y="680" sprite="fgSnow"/>
<girlfriend x="440" y="110"/> <girlfriend x="540" y="110"/>
<dad/> <dad/>
<boyfriend x="1030" camyoffset="-150" camxoffset="-150"/> <boyfriend x="1030" camyoffset="-150" camxoffset="-150"/>
File diff suppressed because it is too large Load Diff
+27 -27
View File
@@ -1,28 +1,28 @@
{"ATLAS":{"SPRITES":[ {"ATLAS": {"SPRITES":[
{"SPRITE":{"name":"0","x":1662,"y":282,"w":194,"h":117,"rotated":false}}, {"SPRITE" : {"name": "0000","x":1636,"y":275,"w":183,"h":115,"rotated": false}},
{"SPRITE":{"name":"1","x":1790,"y":417,"w":92,"h":136,"rotated":false}}, {"SPRITE" : {"name": "0001","x":215,"y":360,"w":84,"h":140,"rotated": false}},
{"SPRITE":{"name":"2","x":1193,"y":539,"w":259,"h":123,"rotated":false}}, {"SPRITE" : {"name": "0002","x":419,"y":358,"w":251,"h":121,"rotated": false}},
{"SPRITE":{"name":"3","x":483,"y":553,"w":125,"h":68,"rotated":false}}, {"SPRITE" : {"name": "0003","x":1636,"y":394,"w":120,"h":65,"rotated": false}},
{"SPRITE":{"name":"4","x":1662,"y":417,"w":110,"h":127,"rotated":false}}, {"SPRITE" : {"name": "0004","x":4,"y":360,"w":108,"h":126,"rotated": false}},
{"SPRITE":{"name":"5","x":1886,"y":0,"w":105,"h":149,"rotated":false}}, {"SPRITE" : {"name": "0005","x":674,"y":358,"w":102,"h":147,"rotated": false}},
{"SPRITE":{"name":"6","x":1886,"y":167,"w":97,"h":130,"rotated":false}}, {"SPRITE" : {"name": "0006","x":116,"y":360,"w":95,"h":130,"rotated": false}},
{"SPRITE":{"name":"7","x":1398,"y":0,"w":470,"h":264,"rotated":false}}, {"SPRITE" : {"name": "0007","x":2038,"y":4,"w":1,"h":4,"rotated": false}},
{"SPRITE":{"name":"8","x":867,"y":0,"w":513,"h":254,"rotated":false}}, {"SPRITE" : {"name": "0008","x":4,"y":4,"w":411,"h":352,"rotated": false}},
{"SPRITE":{"name":"9","x":0,"y":372,"w":465,"h":270,"rotated":false}}, {"SPRITE" : {"name": "0009","x":419,"y":4,"w":398,"h":350,"rotated": false}},
{"SPRITE":{"name":"10","x":1900,"y":315,"w":101,"h":118,"rotated":false}}, {"SPRITE" : {"name": "0010","x":1303,"y":275,"w":329,"h":162,"rotated": false}},
{"SPRITE":{"name":"11","x":867,"y":272,"w":308,"h":367,"rotated":false}}, {"SPRITE" : {"name": "0011","x":303,"y":360,"w":90,"h":103,"rotated": false}},
{"SPRITE":{"name":"12","x":483,"y":371,"w":338,"h":164,"rotated":false}}, {"SPRITE" : {"name": "0012","x":1823,"y":4,"w":211,"h":236,"rotated": false}},
{"SPRITE":{"name":"13","x":0,"y":0,"w":422,"h":354,"rotated":false}}, {"SPRITE" : {"name": "0013","x":1823,"y":244,"w":208,"h":235,"rotated": false}},
{"SPRITE":{"name":"14","x":440,"y":0,"w":409,"h":353,"rotated":false}}, {"SPRITE" : {"name": "0014","x":821,"y":258,"w":478,"h":262,"rotated": false}},
{"SPRITE":{"name":"15","x":1900,"y":451,"w":92,"h":103,"rotated":false}}, {"SPRITE" : {"name": "0015","x":821,"y":4,"w":521,"h":250,"rotated": false}},
{"SPRITE":{"name":"16","x":1193,"y":282,"w":218,"h":239,"rotated":false}}, {"SPRITE" : {"name": "0016","x":1346,"y":4,"w":473,"h":267,"rotated": false}}
{"SPRITE":{"name":"17","x":1429,"y":282,"w":215,"h":237,"rotated":false}}]}, ]},
"meta":{ "meta": {
"app":"Adobe Animate (Better TA Extension)", "app": "Adobe Animate",
"version":"24.0.2.12", "version": "22.0.5.191",
"image":"spritemap1.png", "image": "spritemap1.png",
"format":"RGBA8888", "format": "RGBA8888",
"size":{"w":2031,"h":662}, "size": {"w":2043,"h":524},
"resolution":"1" "resolution": "1"
}
} }
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 134 KiB

After

Width:  |  Height:  |  Size: 74 KiB

File diff suppressed because it is too large Load Diff
@@ -1,40 +1,58 @@
{"ATLAS":{"SPRITES":[ {"ATLAS": {"SPRITES":[
{"SPRITE":{"name":"0","x":349,"y":867,"w":254,"h":136,"rotated":false}}, {"SPRITE" : {"name": "0000","x":994,"y":1029,"w":187,"h":118,"rotated": false}},
{"SPRITE":{"name":"1","x":1648,"y":328,"w":287,"h":363,"rotated":false}}, {"SPRITE" : {"name": "0001","x":1953,"y":524,"w":84,"h":140,"rotated": false}},
{"SPRITE":{"name":"2","x":1571,"y":709,"w":185,"h":117,"rotated":false}}, {"SPRITE" : {"name": "0002","x":471,"y":430,"w":258,"h":137,"rotated": false}},
{"SPRITE":{"name":"3","x":1686,"y":855,"w":86,"h":136,"rotated":false}}, {"SPRITE" : {"name": "0003","x":1300,"y":641,"w":122,"h":66,"rotated": false}},
{"SPRITE":{"name":"4","x":349,"y":1021,"w":122,"h":68,"rotated":false}}, {"SPRITE" : {"name": "0004","x":1825,"y":1078,"w":108,"h":126,"rotated": false}},
{"SPRITE":{"name":"5","x":1774,"y":709,"w":110,"h":128,"rotated":false}}, {"SPRITE" : {"name": "0005","x":360,"y":695,"w":103,"h":149,"rotated": false}},
{"SPRITE":{"name":"6","x":621,"y":867,"w":105,"h":148,"rotated":false}}, {"SPRITE" : {"name": "0006","x":1945,"y":867,"w":95,"h":130,"rotated": false}},
{"SPRITE":{"name":"7","x":1571,"y":844,"w":97,"h":131,"rotated":false}}, {"SPRITE" : {"name": "0007","x":2034,"y":4,"w":1,"h":4,"rotated": false}},
{"SPRITE":{"name":"8","x":800,"y":1,"w":543,"h":308,"rotated":false}}, {"SPRITE" : {"name": "0008","x":943,"y":650,"w":309,"h":375,"rotated": false}},
{"SPRITE":{"name":"9","x":800,"y":1,"w":543,"h":308,"rotated":false}}, {"SPRITE" : {"name": "0009","x":4,"y":4,"w":778,"h":422,"rotated": false}},
{"SPRITE":{"name":"10","x":800,"y":1,"w":543,"h":308,"rotated":false}}, {"SPRITE" : {"name": "0010","x":786,"y":4,"w":761,"h":393,"rotated": false}},
{"SPRITE":{"name":"11","x":800,"y":1,"w":543,"h":308,"rotated":false}}, {"SPRITE" : {"name": "0011","x":1551,"y":4,"w":411,"h":352,"rotated": false}},
{"SPRITE":{"name":"12","x":800,"y":1,"w":543,"h":308,"rotated":false}}, {"SPRITE" : {"name": "0012","x":1551,"y":360,"w":398,"h":350,"rotated": false}},
{"SPRITE":{"name":"13","x":800,"y":1,"w":543,"h":308,"rotated":false}}, {"SPRITE" : {"name": "0013","x":4,"y":1028,"w":329,"h":162,"rotated": false}},
{"SPRITE":{"name":"14","x":800,"y":1,"w":543,"h":308,"rotated":false}}, {"SPRITE" : {"name": "0014","x":1945,"y":1001,"w":90,"h":103,"rotated": false}},
{"SPRITE":{"name":"15","x":800,"y":1,"w":543,"h":308,"rotated":false}}, {"SPRITE" : {"name": "0015","x":1300,"y":401,"w":211,"h":236,"rotated": false}},
{"SPRITE":{"name":"16","x":1363,"y":1,"w":543,"h":308,"rotated":false}}, {"SPRITE" : {"name": "0016","x":782,"y":1029,"w":208,"h":235,"rotated": false}},
{"SPRITE":{"name":"17","x":1,"y":444,"w":771,"h":404,"rotated":false}}, {"SPRITE" : {"name": "0017","x":782,"y":910,"w":117,"h":83,"rotated": false}},
{"SPRITE":{"name":"18","x":791,"y":700,"w":302,"h":369,"rotated":false}}, {"SPRITE" : {"name": "0018","x":994,"y":1151,"w":117,"h":83,"rotated": false}},
{"SPRITE":{"name":"19","x":1111,"y":957,"w":120,"h":86,"rotated":false}}, {"SPRITE" : {"name": "0019","x":1937,"y":1108,"w":103,"h":83,"rotated": false}},
{"SPRITE":{"name":"20","x":1790,"y":855,"w":120,"h":86,"rotated":false}}, {"SPRITE" : {"name": "0020","x":1115,"y":1151,"w":117,"h":83,"rotated": false}},
{"SPRITE":{"name":"21","x":1790,"y":959,"w":106,"h":86,"rotated":false}}, {"SPRITE" : {"name": "0021","x":1654,"y":714,"w":287,"h":360,"rotated": false}},
{"SPRITE":{"name":"22","x":1249,"y":957,"w":120,"h":86,"rotated":false}}, {"SPRITE" : {"name": "0022","x":471,"y":571,"w":179,"h":67,"rotated": false}},
{"SPRITE":{"name":"23","x":0,"y":0,"w":781,"h":425,"rotated":false}}, {"SPRITE" : {"name": "0023","x":654,"y":571,"w":118,"h":75,"rotated": false}},
{"SPRITE":{"name":"24","x":0,"y":867,"w":331,"h":164,"rotated":false}}, {"SPRITE" : {"name": "0024","x":1966,"y":223,"w":55,"h":112,"rotated": false}},
{"SPRITE":{"name":"25","x":799,"y":328,"w":413,"h":354,"rotated":false}}, {"SPRITE" : {"name": "0025","x":1966,"y":4,"w":64,"h":106,"rotated": false}},
{"SPRITE":{"name":"26","x":1230,"y":328,"w":400,"h":353,"rotated":false}}, {"SPRITE" : {"name": "0026","x":1185,"y":1029,"w":67,"h":70,"rotated": false}},
{"SPRITE":{"name":"27","x":1387,"y":954,"w":90,"h":103,"rotated":false}}, {"SPRITE" : {"name": "0027","x":337,"y":1182,"w":122,"h":62,"rotated": false}},
{"SPRITE":{"name":"28","x":1111,"y":700,"w":213,"h":239,"rotated":false}}, {"SPRITE" : {"name": "0028","x":1647,"y":1078,"w":174,"h":97,"rotated": false}},
{"SPRITE":{"name":"29","x":1342,"y":699,"w":211,"h":237,"rotated":false}}]}, {"SPRITE" : {"name": "0029","x":360,"y":870,"w":82,"h":14,"rotated": false}},
"meta":{ {"SPRITE" : {"name": "0030","x":1647,"y":1179,"w":128,"h":61,"rotated": false}},
"app":"Adobe Animate (Better TA Extension)", {"SPRITE" : {"name": "0031","x":463,"y":1182,"w":124,"h":58,"rotated": false}},
"version":"24.0.2.12", {"SPRITE" : {"name": "0032","x":1966,"y":114,"w":59,"h":105,"rotated": false}},
"image":"spritemap1.png", {"SPRITE" : {"name": "0033","x":1953,"y":360,"w":87,"h":160,"rotated": false}},
"format":"RGBA8888", {"SPRITE" : {"name": "0034","x":1945,"y":714,"w":92,"h":149,"rotated": false}},
"size":{"w":1965,"h":1089}, {"SPRITE" : {"name": "0035","x":1426,"y":641,"w":104,"h":42,"rotated": false}},
"resolution":"1" {"SPRITE" : {"name": "0036","x":1953,"y":692,"w":73,"h":18,"rotated": false}},
{"SPRITE" : {"name": "0037","x":1426,"y":687,"w":72,"h":19,"rotated": false}},
{"SPRITE" : {"name": "0038","x":360,"y":848,"w":72,"h":18,"rotated": false}},
{"SPRITE" : {"name": "0039","x":1953,"y":668,"w":73,"h":20,"rotated": false}},
{"SPRITE" : {"name": "0040","x":471,"y":650,"w":468,"h":256,"rotated": false}},
{"SPRITE" : {"name": "0041","x":786,"y":401,"w":510,"h":245,"rotated": false}},
{"SPRITE" : {"name": "0042","x":4,"y":430,"w":463,"h":261,"rotated": false}},
{"SPRITE" : {"name": "0043","x":360,"y":910,"w":418,"h":268,"rotated": false}},
{"SPRITE" : {"name": "0044","x":1256,"y":1008,"w":387,"h":271,"rotated": false}},
{"SPRITE" : {"name": "0045","x":1256,"y":714,"w":394,"h":290,"rotated": false}},
{"SPRITE" : {"name": "0046","x":4,"y":695,"w":352,"h":329,"rotated": false}}
]},
"meta": {
"app": "Adobe Animate",
"version": "22.0.5.191",
"image": "spritemap1.png",
"format": "RGBA8888",
"size": {"w":2044,"h":1283},
"resolution": "1"
}
} }
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 453 KiB

After

Width:  |  Height:  |  Size: 228 KiB

File diff suppressed because it is too large Load Diff
+56 -54
View File
@@ -1,55 +1,57 @@
{"ATLAS":{"SPRITES":[ {"ATLAS": {"SPRITES":[
{"SPRITE":{"name":"0","x":1129,"y":977,"w":86,"h":17,"rotated":false}}, {"SPRITE" : {"name": "0000","x":1623,"y":602,"w":287,"h":360,"rotated": false}},
{"SPRITE":{"name":"1","x":1690,"y":1012,"w":86,"h":17,"rotated":false}}, {"SPRITE" : {"name": "0001","x":1310,"y":269,"w":309,"h":375,"rotated": false}},
{"SPRITE":{"name":"2","x":1656,"y":852,"w":126,"h":64,"rotated":false}}, {"SPRITE" : {"name": "0002","x":4,"y":4,"w":420,"h":359,"rotated": false}},
{"SPRITE":{"name":"3","x":1915,"y":841,"w":121,"h":77,"rotated":false}}, {"SPRITE" : {"name": "0003","x":428,"y":4,"w":406,"h":358,"rotated": false}},
{"SPRITE":{"name":"4","x":1382,"y":980,"w":131,"h":64,"rotated":false}}, {"SPRITE" : {"name": "0004","x":4,"y":639,"w":336,"h":165,"rotated": false}},
{"SPRITE":{"name":"5","x":1132,"y":283,"w":420,"h":270,"rotated":false}}, {"SPRITE" : {"name": "0005","x":125,"y":808,"w":90,"h":103,"rotated": false}},
{"SPRITE":{"name":"6","x":1570,"y":277,"w":389,"h":273,"rotated":false}}, {"SPRITE" : {"name": "0006","x":1819,"y":4,"w":215,"h":242,"rotated": false}},
{"SPRITE":{"name":"7","x":0,"y":743,"w":397,"h":292,"rotated":false}}, {"SPRITE" : {"name": "0007","x":1217,"y":648,"w":213,"h":240,"rotated": false}},
{"SPRITE":{"name":"8","x":431,"y":267,"w":354,"h":332,"rotated":false}}, {"SPRITE" : {"name": "0008","x":606,"y":660,"w":191,"h":120,"rotated": false}},
{"SPRITE":{"name":"9","x":1592,"y":568,"w":190,"h":117,"rotated":false}}, {"SPRITE" : {"name": "0009","x":606,"y":784,"w":90,"h":151,"rotated": false}},
{"SPRITE":{"name":"10","x":1444,"y":826,"w":86,"h":136,"rotated":false}}, {"SPRITE" : {"name": "0010","x":344,"y":660,"w":258,"h":124,"rotated": false}},
{"SPRITE":{"name":"11","x":723,"y":852,"w":260,"h":123,"rotated":false}}, {"SPRITE" : {"name": "0011","x":448,"y":859,"w":122,"h":67,"rotated": false}},
{"SPRITE":{"name":"12","x":1548,"y":947,"w":124,"h":68,"rotated":false}}, {"SPRITE" : {"name": "0012","x":1914,"y":755,"w":108,"h":126,"rotated": false}},
{"SPRITE":{"name":"13","x":1001,"y":852,"w":110,"h":128,"rotated":false}}, {"SPRITE" : {"name": "0013","x":1914,"y":602,"w":103,"h":149,"rotated": false}},
{"SPRITE":{"name":"14","x":1933,"y":0,"w":106,"h":148,"rotated":false}}, {"SPRITE" : {"name": "0014","x":700,"y":784,"w":95,"h":130,"rotated": false}},
{"SPRITE":{"name":"15","x":1129,"y":828,"w":97,"h":131,"rotated":false}}, {"SPRITE" : {"name": "0015","x":2038,"y":4,"w":1,"h":4,"rotated": false}},
{"SPRITE":{"name":"16","x":803,"y":283,"w":311,"h":369,"rotated":false}}, {"SPRITE" : {"name": "0016","x":838,"y":253,"w":468,"h":256,"rotated": false}},
{"SPRITE":{"name":"17","x":1592,"y":703,"w":167,"h":101,"rotated":false}}, {"SPRITE" : {"name": "0017","x":838,"y":4,"w":510,"h":245,"rotated": false}},
{"SPRITE":{"name":"18","x":1835,"y":852,"w":57,"h":105,"rotated":false}}, {"SPRITE" : {"name": "0018","x":1352,"y":4,"w":463,"h":261,"rotated": false}},
{"SPRITE":{"name":"19","x":1977,"y":270,"w":66,"h":104,"rotated":false}}, {"SPRITE" : {"name": "0019","x":4,"y":367,"w":418,"h":268,"rotated": false}},
{"SPRITE":{"name":"20","x":1910,"y":936,"w":70,"h":73,"rotated":false}}, {"SPRITE" : {"name": "0020","x":826,"y":513,"w":387,"h":271,"rotated": false}},
{"SPRITE":{"name":"21","x":1244,"y":828,"w":182,"h":69,"rotated":false}}, {"SPRITE" : {"name": "0021","x":428,"y":366,"w":394,"h":290,"rotated": false}},
{"SPRITE":{"name":"22","x":1690,"y":934,"w":127,"h":60,"rotated":false}}, {"SPRITE" : {"name": "0022","x":1623,"y":269,"w":352,"h":329,"rotated": false}},
{"SPRITE":{"name":"23","x":418,"y":617,"w":287,"h":363,"rotated":false}}, {"SPRITE" : {"name": "0023","x":1143,"y":788,"w":67,"h":70,"rotated": false}},
{"SPRITE":{"name":"24","x":1244,"y":915,"w":120,"h":86,"rotated":false}}, {"SPRITE" : {"name": "0024","x":1033,"y":875,"w":122,"h":62,"rotated": false}},
{"SPRITE":{"name":"25","x":1777,"y":748,"w":120,"h":86,"rotated":false}}, {"SPRITE" : {"name": "0025","x":1217,"y":513,"w":64,"h":106,"rotated": false}},
{"SPRITE":{"name":"26","x":1933,"y":166,"w":106,"h":86,"rotated":false}}, {"SPRITE" : {"name": "0026","x":1979,"y":359,"w":55,"h":112,"rotated": false}},
{"SPRITE":{"name":"27","x":1915,"y":737,"w":120,"h":86,"rotated":false}}, {"SPRITE" : {"name": "0027","x":799,"y":788,"w":98,"h":118,"rotated": false}},
{"SPRITE":{"name":"28","x":1800,"y":568,"w":89,"h":162,"rotated":false}}, {"SPRITE" : {"name": "0028","x":1979,"y":250,"w":59,"h":105,"rotated": false}},
{"SPRITE":{"name":"29","x":1907,"y":568,"w":95,"h":151,"rotated":false}}, {"SPRITE" : {"name": "0029","x":1434,"y":749,"w":87,"h":160,"rotated": false}},
{"SPRITE":{"name":"30","x":1977,"y":392,"w":61,"h":107,"rotated":false}}, {"SPRITE" : {"name": "0030","x":1525,"y":749,"w":92,"h":149,"rotated": false}},
{"SPRITE":{"name":"31","x":415,"y":998,"w":107,"h":45,"rotated":false}}, {"SPRITE" : {"name": "0031","x":219,"y":887,"w":104,"h":42,"rotated": false}},
{"SPRITE":{"name":"32","x":727,"y":993,"w":77,"h":22,"rotated":false}}, {"SPRITE" : {"name": "0032","x":527,"y":811,"w":73,"h":18,"rotated": false}},
{"SPRITE":{"name":"33","x":634,"y":998,"w":75,"h":23,"rotated":false}}, {"SPRITE" : {"name": "0033","x":527,"y":788,"w":72,"h":19,"rotated": false}},
{"SPRITE":{"name":"34","x":822,"y":993,"w":75,"h":22,"rotated":false}}, {"SPRITE" : {"name": "0034","x":527,"y":833,"w":72,"h":18,"rotated": false}},
{"SPRITE":{"name":"35","x":540,"y":998,"w":76,"h":24,"rotated":false}}, {"SPRITE" : {"name": "0035","x":1217,"y":623,"w":73,"h":20,"rotated": false}},
{"SPRITE":{"name":"36","x":1445,"y":0,"w":470,"h":259,"rotated":false}}, {"SPRITE" : {"name": "0036","x":344,"y":788,"w":179,"h":67,"rotated": false}},
{"SPRITE":{"name":"37","x":431,"y":0,"w":513,"h":249,"rotated":false}}, {"SPRITE" : {"name": "0037","x":219,"y":808,"w":118,"h":75,"rotated": false}},
{"SPRITE":{"name":"38","x":962,"y":0,"w":465,"h":265,"rotated":false}}, {"SPRITE" : {"name": "0038","x":901,"y":875,"w":128,"h":61,"rotated": false}},
{"SPRITE":{"name":"39","x":723,"y":670,"w":331,"h":164,"rotated":false}}, {"SPRITE" : {"name": "0039","x":1914,"y":885,"w":124,"h":58,"rotated": false}},
{"SPRITE":{"name":"40","x":0,"y":0,"w":413,"h":354,"rotated":false}}, {"SPRITE" : {"name": "0040","x":901,"y":788,"w":117,"h":83,"rotated": false}},
{"SPRITE":{"name":"41","x":0,"y":372,"w":400,"h":353,"rotated":false}}, {"SPRITE" : {"name": "0041","x":1022,"y":788,"w":117,"h":83,"rotated": false}},
{"SPRITE":{"name":"42","x":1548,"y":826,"w":90,"h":103,"rotated":false}}, {"SPRITE" : {"name": "0042","x":341,"y":859,"w":103,"h":83,"rotated": false}},
{"SPRITE":{"name":"43","x":1132,"y":571,"w":213,"h":239,"rotated":false}}, {"SPRITE" : {"name": "0043","x":4,"y":808,"w":117,"h":83,"rotated": false}},
{"SPRITE":{"name":"44","x":1363,"y":571,"w":211,"h":237,"rotated":false}}]}, {"SPRITE" : {"name": "0044","x":1434,"y":648,"w":174,"h":97,"rotated": false}},
"meta":{ {"SPRITE" : {"name": "0045","x":1819,"y":250,"w":82,"h":14,"rotated": false}}
"app":"Adobe Animate (Better TA Extension)", ]},
"version":"24.0.2.12", "meta": {
"image":"spritemap1.png", "app": "Adobe Animate",
"format":"RGBA8888", "version": "21.0.1.37179",
"size":{"w":2064,"h":1065}, "image": "spritemap1.png",
"resolution":"1" "format": "RGBA8888",
"size": {"w":2043,"h":966},
"resolution": "1"
}
} }
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 265 KiB

After

Width:  |  Height:  |  Size: 165 KiB

File diff suppressed because it is too large Load Diff
@@ -1,60 +1,60 @@
{"ATLAS":{"SPRITES":[ {"ATLAS": {"SPRITES":[
{"SPRITE":{"name":"0","x":2834,"y":332,"w":12,"h":15,"rotated":false}}, {"SPRITE" : {"name": "0000","x":4076,"y":2,"w":9,"h":12,"rotated": false}},
{"SPRITE":{"name":"1","x":1476,"y":532,"w":527,"h":503,"rotated":false}}, {"SPRITE" : {"name": "0001","x":1957,"y":2,"w":524,"h":501,"rotated": false}},
{"SPRITE":{"name":"2","x":733,"y":0,"w":725,"h":623,"rotated":false}}, {"SPRITE" : {"name": "0002","x":716,"y":2,"w":721,"h":621,"rotated": false}},
{"SPRITE":{"name":"3","x":0,"y":659,"w":741,"h":304,"rotated":false}}, {"SPRITE" : {"name": "0003","x":2331,"y":505,"w":139,"h":109,"rotated": false}},
{"SPRITE":{"name":"4","x":2311,"y":0,"w":349,"h":540,"rotated":false}}, {"SPRITE" : {"name": "0004","x":3244,"y":725,"w":303,"h":170,"rotated": false}},
{"SPRITE":{"name":"5","x":759,"y":641,"w":583,"h":373,"rotated":false}}, {"SPRITE" : {"name": "0005","x":1691,"y":516,"w":248,"h":277,"rotated": false}},
{"SPRITE":{"name":"6","x":2021,"y":0,"w":272,"h":702,"rotated":false}}, {"SPRITE" : {"name": "0006","x":2495,"y":843,"w":173,"h":229,"rotated": false}},
{"SPRITE":{"name":"7","x":1476,"y":0,"w":518,"h":514,"rotated":false}}, {"SPRITE" : {"name": "0007","x":2,"y":642,"w":262,"h":221,"rotated": false}},
{"SPRITE":{"name":"8","x":0,"y":0,"w":715,"h":641,"rotated":false}}, {"SPRITE" : {"name": "0008","x":2331,"y":616,"w":118,"h":117,"rotated": false}},
{"SPRITE":{"name":"9","x":619,"y":1032,"w":205,"h":122,"rotated":false}}, {"SPRITE" : {"name": "0009","x":3549,"y":865,"w":261,"h":139,"rotated": false}},
{"SPRITE":{"name":"10","x":842,"y":1032,"w":205,"h":122,"rotated":false}}, {"SPRITE" : {"name": "0010","x":3209,"y":897,"w":202,"h":122,"rotated": false}},
{"SPRITE":{"name":"11","x":2311,"y":558,"w":115,"h":112,"rotated":false}}, {"SPRITE" : {"name": "0011","x":580,"y":913,"w":202,"h":122,"rotated": false}},
{"SPRITE":{"name":"12","x":2801,"y":947,"w":305,"h":172,"rotated":false}}, {"SPRITE" : {"name": "0012","x":2831,"y":304,"w":45,"h":42,"rotated": false}},
{"SPRITE":{"name":"13","x":2678,"y":0,"w":375,"h":314,"rotated":false}}, {"SPRITE" : {"name": "0013","x":1957,"y":505,"w":372,"h":311,"rotated": false}},
{"SPRITE":{"name":"14","x":2870,"y":332,"w":252,"h":328,"rotated":false}}, {"SPRITE" : {"name": "0014","x":1439,"y":516,"w":250,"h":325,"rotated": false}},
{"SPRITE":{"name":"15","x":3071,"y":0,"w":239,"h":290,"rotated":false}}, {"SPRITE" : {"name": "0015","x":716,"y":625,"w":235,"h":286,"rotated": false}},
{"SPRITE":{"name":"16","x":3135,"y":678,"w":220,"h":246,"rotated":false}}, {"SPRITE" : {"name": "0016","x":953,"y":625,"w":245,"h":249,"rotated": false}},
{"SPRITE":{"name":"17","x":3597,"y":248,"w":173,"h":231,"rotated":false}}, {"SPRITE" : {"name": "0017","x":3644,"y":373,"w":136,"h":133,"rotated": false}},
{"SPRITE":{"name":"18","x":3769,"y":0,"w":225,"h":190,"rotated":false}}, {"SPRITE" : {"name": "0018","x":2331,"y":735,"w":150,"h":91,"rotated": false}},
{"SPRITE":{"name":"19","x":1290,"y":1053,"w":131,"h":81,"rotated":false}}, {"SPRITE" : {"name": "0019","x":3644,"y":508,"w":151,"h":95,"rotated": false}},
{"SPRITE":{"name":"20","x":3905,"y":814,"w":132,"h":85,"rotated":false}}, {"SPRITE" : {"name": "0020","x":784,"y":913,"w":140,"h":90,"rotated": false}},
{"SPRITE":{"name":"21","x":1733,"y":1053,"w":122,"h":80,"rotated":false}}, {"SPRITE" : {"name": "0021","x":3644,"y":605,"w":149,"h":92,"rotated": false}},
{"SPRITE":{"name":"22","x":3905,"y":917,"w":129,"h":82,"rotated":false}}, {"SPRITE" : {"name": "0022","x":2670,"y":932,"w":144,"h":87,"rotated": false}},
{"SPRITE":{"name":"23","x":1589,"y":1053,"w":126,"h":78,"rotated":false}}, {"SPRITE" : {"name": "0023","x":2670,"y":843,"w":152,"h":87,"rotated": false}},
{"SPRITE":{"name":"24","x":1439,"y":1053,"w":132,"h":77,"rotated":false}}, {"SPRITE" : {"name": "0024","x":4087,"y":2,"w":1,"h":4,"rotated": false}},
{"SPRITE":{"name":"25","x":3778,"y":814,"w":109,"h":107,"rotated":false}}, {"SPRITE" : {"name": "0025","x":2831,"y":373,"w":411,"h":352,"rotated": false}},
{"SPRITE":{"name":"26","x":3124,"y":1123,"w":3,"h":7,"rotated":false}}, {"SPRITE" : {"name": "0026","x":3244,"y":373,"w":398,"h":350,"rotated": false}},
{"SPRITE":{"name":"27","x":3145,"y":1123,"w":3,"h":7,"rotated":false}}, {"SPRITE" : {"name": "0027","x":266,"y":642,"w":329,"h":162,"rotated": false}},
{"SPRITE":{"name":"28","x":3673,"y":497,"w":260,"h":141,"rotated":false}}, {"SPRITE" : {"name": "0028","x":597,"y":642,"w":90,"h":103,"rotated": false}},
{"SPRITE":{"name":"29","x":3788,"y":208,"w":237,"h":161,"rotated":false}}, {"SPRITE" : {"name": "0029","x":1200,"y":625,"w":211,"h":236,"rotated": false}},
{"SPRITE":{"name":"30","x":3542,"y":660,"w":218,"h":144,"rotated":false}}, {"SPRITE" : {"name": "0030","x":2831,"y":727,"w":208,"h":235,"rotated": false}},
{"SPRITE":{"name":"31","x":3124,"y":947,"w":301,"h":158,"rotated":false}}, {"SPRITE" : {"name": "0031","x":2483,"y":2,"w":738,"h":300,"rotated": false}},
{"SPRITE":{"name":"32","x":3371,"y":498,"w":284,"h":144,"rotated":false}}, {"SPRITE" : {"name": "0032","x":2483,"y":304,"w":346,"h":537,"rotated": false}},
{"SPRITE":{"name":"33","x":0,"y":981,"w":295,"h":150,"rotated":false}}, {"SPRITE" : {"name": "0033","x":2,"y":865,"w":235,"h":158,"rotated": false}},
{"SPRITE":{"name":"34","x":313,"y":981,"w":288,"h":145,"rotated":false}}, {"SPRITE" : {"name": "0034","x":3812,"y":865,"w":216,"h":141,"rotated": false}},
{"SPRITE":{"name":"35","x":3443,"y":942,"w":182,"h":212,"rotated":false}}, {"SPRITE" : {"name": "0035","x":2000,"y":818,"w":299,"h":155,"rotated": false}},
{"SPRITE":{"name":"36","x":3371,"y":255,"w":208,"h":225,"rotated":false}}, {"SPRITE" : {"name": "0036","x":1200,"y":863,"w":179,"h":208,"rotated": false}},
{"SPRITE":{"name":"37","x":3373,"y":660,"w":151,"h":264,"rotated":false}}, {"SPRITE" : {"name": "0037","x":1691,"y":818,"w":307,"h":154,"rotated": false}},
{"SPRITE":{"name":"38","x":3778,"y":656,"w":206,"h":140,"rotated":false}}, {"SPRITE" : {"name": "0038","x":3644,"y":702,"w":320,"h":161,"rotated": false}},
{"SPRITE":{"name":"39","x":3557,"y":0,"w":194,"h":230,"rotated":false}}, {"SPRITE" : {"name": "0039","x":266,"y":806,"w":312,"h":155,"rotated": false}},
{"SPRITE":{"name":"40","x":2678,"y":485,"w":47,"h":44,"rotated":false}}, {"SPRITE" : {"name": "0040","x":239,"y":963,"w":224,"h":108,"rotated": false}},
{"SPRITE":{"name":"41","x":2870,"y":678,"w":247,"h":251,"rotated":false}}, {"SPRITE" : {"name": "0041","x":3223,"y":2,"w":580,"h":369,"rotated": false}},
{"SPRITE":{"name":"42","x":2678,"y":332,"w":138,"h":135,"rotated":false}}, {"SPRITE" : {"name": "0042","x":3805,"y":2,"w":269,"h":698,"rotated": false}},
{"SPRITE":{"name":"43","x":1065,"y":1053,"w":207,"h":101,"rotated":false}}, {"SPRITE" : {"name": "0043","x":1413,"y":843,"w":205,"h":222,"rotated": false}},
{"SPRITE":{"name":"44","x":2452,"y":947,"w":331,"h":164,"rotated":false}}, {"SPRITE" : {"name": "0044","x":3041,"y":727,"w":166,"h":292,"rotated": false}},
{"SPRITE":{"name":"45","x":2021,"y":720,"w":413,"h":354,"rotated":false}}, {"SPRITE" : {"name": "0045","x":953,"y":876,"w":203,"h":137,"rotated": false}},
{"SPRITE":{"name":"46","x":2452,"y":558,"w":400,"h":353,"rotated":false}}, {"SPRITE" : {"name": "0046","x":1439,"y":2,"w":516,"h":512,"rotated": false}},
{"SPRITE":{"name":"47","x":3951,"y":387,"w":90,"h":103,"rotated":false}}, {"SPRITE" : {"name": "0047","x":2,"y":2,"w":712,"h":638,"rotated": false}},
{"SPRITE":{"name":"48","x":3140,"y":308,"w":213,"h":239,"rotated":false}}, {"SPRITE" : {"name": "0048","x":2301,"y":843,"w":192,"h":227,"rotated": false}}
{"SPRITE":{"name":"49","x":3328,"y":0,"w":211,"h":237,"rotated":false}}]}, ]},
"meta":{ "meta": {
"app":"Adobe Animate (Better TA Extension)", "app": "Adobe Animate",
"version":"24.0.2.12", "version": "21.0.1.37179",
"image":"spritemap1.png", "image": "spritemap1.png",
"format":"RGBA8888", "format": "RGBA8888",
"size":{"w":4061,"h":1154}, "size": {"w":4090,"h":1074},
"resolution":"1" "resolution": "1"
}
} }
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 535 KiB

After

Width:  |  Height:  |  Size: 344 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

After

Width:  |  Height:  |  Size: 804 B

File diff suppressed because it is too large Load Diff
@@ -1,241 +1,145 @@
{"ATLAS":{"SPRITES":[ {"ATLAS": {"SPRITES":[
{"SPRITE":{"name":"0","x":2564,"y":2,"w":23,"h":144,"rotated":false}}, {"SPRITE" : {"name": "0000","x":2847,"y":969,"w":327,"h":397,"rotated": false}},
{"SPRITE":{"name":"1","x":3024,"y":522,"w":42,"h":85,"rotated":false}}, {"SPRITE" : {"name": "0001","x":2441,"y":894,"w":110,"h":159,"rotated": false}},
{"SPRITE":{"name":"2","x":2598,"y":1211,"w":67,"h":60,"rotated":false}}, {"SPRITE" : {"name": "0002","x":1709,"y":1631,"w":197,"h":185,"rotated": false}},
{"SPRITE":{"name":"3","x":3964,"y":932,"w":93,"h":51,"rotated":false}}, {"SPRITE" : {"name": "0003","x":408,"y":1773,"w":92,"h":155,"rotated": false}},
{"SPRITE":{"name":"4","x":3691,"y":1016,"w":91,"h":43,"rotated":false}}, {"SPRITE" : {"name": "0004","x":236,"y":1639,"w":274,"h":132,"rotated": false}},
{"SPRITE":{"name":"5","x":3877,"y":270,"w":111,"h":95,"rotated":false}}, {"SPRITE" : {"name": "0005","x":3427,"y":1495,"w":133,"h":74,"rotated": false}},
{"SPRITE":{"name":"6","x":3449,"y":1124,"w":113,"h":127,"rotated":false}}, {"SPRITE" : {"name": "0006","x":3270,"y":540,"w":121,"h":162,"rotated": false}},
{"SPRITE":{"name":"7","x":367,"y":1129,"w":382,"h":123,"rotated":false}}, {"SPRITE" : {"name": "0007","x":359,"y":649,"w":518,"h":294,"rotated": false}},
{"SPRITE":{"name":"8","x":2,"y":1122,"w":364,"h":131,"rotated":false}}, {"SPRITE" : {"name": "0008","x":1957,"y":2,"w":775,"h":483,"rotated": false}},
{"SPRITE":{"name":"9","x":2,"y":1122,"w":364,"h":131,"rotated":false}}, {"SPRITE" : {"name": "0009","x":1014,"y":2,"w":941,"h":607,"rotated": false}},
{"SPRITE":{"name":"10","x":2437,"y":1136,"w":31,"h":31,"rotated":false}}, {"SPRITE" : {"name": "0010","x":2,"y":2,"w":1010,"h":645,"rotated": false}},
{"SPRITE":{"name":"11","x":1599,"y":1133,"w":350,"h":113,"rotated":false}}, {"SPRITE" : {"name": "0011","x":4059,"y":2,"w":20,"h":142,"rotated": false}},
{"SPRITE":{"name":"12","x":1599,"y":1133,"w":350,"h":113,"rotated":false}}, {"SPRITE" : {"name": "0012","x":4035,"y":616,"w":40,"h":83,"rotated": false}},
{"SPRITE":{"name":"13","x":2670,"y":1175,"w":142,"h":94,"rotated":false}}, {"SPRITE" : {"name": "0013","x":2755,"y":1508,"w":64,"h":57,"rotated": false}},
{"SPRITE":{"name":"14","x":3877,"y":366,"w":122,"h":82,"rotated":false}}, {"SPRITE" : {"name": "0014","x":3176,"y":1171,"w":91,"h":48,"rotated": false}},
{"SPRITE":{"name":"15","x":1162,"y":1112,"w":436,"h":151,"rotated":false}}, {"SPRITE" : {"name": "0015","x":3245,"y":1737,"w":88,"h":41,"rotated": false}},
{"SPRITE":{"name":"16","x":1599,"y":985,"w":435,"h":147,"rotated":false}}, {"SPRITE" : {"name": "0016","x":3064,"y":1368,"w":109,"h":93,"rotated": false}},
{"SPRITE":{"name":"17","x":1599,"y":985,"w":435,"h":147,"rotated":false}}, {"SPRITE" : {"name": "0017","x":3402,"y":2,"w":655,"h":434,"rotated": false}},
{"SPRITE":{"name":"18","x":779,"y":692,"w":440,"h":344,"rotated":false}}, {"SPRITE" : {"name": "0018","x":1957,"y":487,"w":626,"h":405,"rotated": false}},
{"SPRITE":{"name":"19","x":1550,"y":711,"w":388,"h":273,"rotated":false}}, {"SPRITE" : {"name": "0019","x":3402,"y":438,"w":631,"h":438,"rotated": false}},
{"SPRITE":{"name":"20","x":2106,"y":2,"w":376,"h":155,"rotated":false}}, {"SPRITE" : {"name": "0020","x":1170,"y":1211,"w":393,"h":287,"rotated": false}},
{"SPRITE":{"name":"21","x":2,"y":2,"w":932,"h":689,"rotated":false}}, {"SPRITE" : {"name": "0021","x":2847,"y":540,"w":421,"h":427,"rotated": false}},
{"SPRITE":{"name":"22","x":3907,"y":1171,"w":48,"h":36,"rotated":false}}, {"SPRITE" : {"name": "0022","x":2734,"y":2,"w":666,"h":536,"rotated": false}},
{"SPRITE":{"name":"23","x":3907,"y":1171,"w":48,"h":36,"rotated":false}}, {"SPRITE" : {"name": "0023","x":542,"y":1480,"w":224,"h":221,"rotated": false}},
{"SPRITE":{"name":"24","x":3858,"y":1206,"w":48,"h":40,"rotated":false}}, {"SPRITE" : {"name": "0024","x":3657,"y":1736,"w":186,"h":175,"rotated": false}},
{"SPRITE":{"name":"25","x":3762,"y":1093,"w":48,"h":64,"rotated":false}}, {"SPRITE" : {"name": "0025","x":4035,"y":764,"w":56,"h":52,"rotated": false}},
{"SPRITE":{"name":"26","x":3713,"y":1060,"w":48,"h":66,"rotated":false}}, {"SPRITE" : {"name": "0026","x":502,"y":1876,"w":126,"h":104,"rotated": false}},
{"SPRITE":{"name":"27","x":3885,"y":1095,"w":48,"h":67,"rotated":false}}, {"SPRITE" : {"name": "0027","x":1709,"y":1818,"w":135,"h":104,"rotated": false}},
{"SPRITE":{"name":"28","x":2106,"y":158,"w":48,"h":69,"rotated":false}}, {"SPRITE" : {"name": "0028","x":2,"y":1440,"w":232,"h":236,"rotated": false}},
{"SPRITE":{"name":"29","x":2481,"y":498,"w":48,"h":71,"rotated":false}}, {"SPRITE" : {"name": "0029","x":3938,"y":1437,"w":139,"h":109,"rotated": false}},
{"SPRITE":{"name":"30","x":1162,"y":1037,"w":48,"h":73,"rotated":false}}, {"SPRITE" : {"name": "0030","x":2755,"y":1627,"w":235,"h":158,"rotated": false}},
{"SPRITE":{"name":"31","x":4018,"y":188,"w":48,"h":76,"rotated":false}}, {"SPRITE" : {"name": "0031","x":1147,"y":1500,"w":198,"h":233,"rotated": false}},
{"SPRITE":{"name":"32","x":3455,"y":856,"w":48,"h":78,"rotated":false}}, {"SPRITE" : {"name": "0032","x":2,"y":1860,"w":118,"h":117,"rotated": false}},
{"SPRITE":{"name":"33","x":3785,"y":1011,"w":48,"h":81,"rotated":false}}, {"SPRITE" : {"name": "0033","x":1565,"y":1398,"w":262,"h":221,"rotated": false}},
{"SPRITE":{"name":"34","x":4002,"y":1164,"w":48,"h":82,"rotated":false}}, {"SPRITE" : {"name": "0034","x":3845,"y":1736,"w":222,"h":145,"rotated": false}},
{"SPRITE":{"name":"35","x":3953,"y":1083,"w":48,"h":87,"rotated":false}}, {"SPRITE" : {"name": "0035","x":979,"y":1480,"w":166,"h":292,"rotated": false}},
{"SPRITE":{"name":"36","x":3904,"y":1004,"w":48,"h":90,"rotated":false}}, {"SPRITE" : {"name": "0036","x":3657,"y":1592,"w":276,"h":142,"rotated": false}},
{"SPRITE":{"name":"37","x":4013,"y":1070,"w":48,"h":93,"rotated":false}}, {"SPRITE" : {"name": "0037","x":925,"y":1774,"w":203,"h":138,"rotated": false}},
{"SPRITE":{"name":"38","x":3964,"y":984,"w":48,"h":98,"rotated":false}}, {"SPRITE" : {"name": "0038","x":236,"y":1467,"w":304,"h":170,"rotated": false}},
{"SPRITE":{"name":"39","x":1550,"y":985,"w":48,"h":103,"rotated":false}}, {"SPRITE" : {"name": "0039","x":4081,"y":2,"w":1,"h":4,"rotated": false}},
{"SPRITE":{"name":"40","x":3848,"y":894,"w":50,"h":109,"rotated":false}}, {"SPRITE" : {"name": "0040","x":2441,"y":1055,"w":135,"h":127,"rotated": false}},
{"SPRITE":{"name":"41","x":3797,"y":894,"w":50,"h":116,"rotated":false}}, {"SPRITE" : {"name": "0041","x":2,"y":1678,"w":195,"h":180,"rotated": false}},
{"SPRITE":{"name":"42","x":2777,"y":452,"w":50,"h":121,"rotated":false}}, {"SPRITE" : {"name": "0042","x":2751,"y":1787,"w":160,"h":144,"rotated": false}},
{"SPRITE":{"name":"43","x":4002,"y":585,"w":50,"h":119,"rotated":false}}, {"SPRITE" : {"name": "0043","x":713,"y":945,"w":243,"h":261,"rotated": false}},
{"SPRITE":{"name":"44","x":3913,"y":886,"w":50,"h":117,"rotated":false}}, {"SPRITE" : {"name": "0044","x":2375,"y":1508,"w":378,"h":121,"rotated": false}},
{"SPRITE":{"name":"45","x":3059,"y":2,"w":52,"h":129,"rotated":false}}, {"SPRITE" : {"name": "0045","x":3064,"y":1495,"w":361,"h":128,"rotated": false}},
{"SPRITE":{"name":"46","x":3964,"y":886,"w":123,"h":45,"rotated":false}}, {"SPRITE" : {"name": "0046","x":713,"y":1211,"w":455,"h":267,"rotated": false}},
{"SPRITE":{"name":"47","x":1770,"y":228,"w":123,"h":43,"rotated":false}}, {"SPRITE" : {"name": "0047","x":2,"y":1112,"w":272,"h":326,"rotated": false}},
{"SPRITE":{"name":"48","x":3424,"y":486,"w":99,"h":35,"rotated":false}}, {"SPRITE" : {"name": "0048","x":3710,"y":878,"w":249,"h":557,"rotated": false}},
{"SPRITE":{"name":"49","x":2979,"y":1141,"w":99,"h":34,"rotated":false}}, {"SPRITE" : {"name": "0049","x":2585,"y":540,"w":260,"h":701,"rotated": false}},
{"SPRITE":{"name":"50","x":2979,"y":1141,"w":99,"h":34,"rotated":false}}, {"SPRITE" : {"name": "0050","x":1014,"y":611,"w":291,"h":598,"rotated": false}},
{"SPRITE":{"name":"51","x":2590,"y":360,"w":99,"h":36,"rotated":false}}, {"SPRITE" : {"name": "0051","x":1307,"y":611,"w":315,"h":540,"rotated": false}},
{"SPRITE":{"name":"52","x":3709,"y":783,"w":35,"h":21,"rotated":false}}, {"SPRITE" : {"name": "0052","x":2,"y":649,"w":355,"h":461,"rotated": false}},
{"SPRITE":{"name":"53","x":1220,"y":711,"w":329,"h":400,"rotated":false}}, {"SPRITE" : {"name": "0053","x":359,"y":945,"w":352,"h":373,"rotated": false}},
{"SPRITE":{"name":"54","x":3042,"y":979,"w":112,"h":161,"rotated":false}}, {"SPRITE" : {"name": "0054","x":3064,"y":1625,"w":347,"h":110,"rotated": false}},
{"SPRITE":{"name":"55","x":2929,"y":163,"w":199,"h":188,"rotated":false}}, {"SPRITE" : {"name": "0055","x":2039,"y":1248,"w":379,"h":216,"rotated": false}},
{"SPRITE":{"name":"56","x":2175,"y":574,"w":96,"h":158,"rotated":false}}, {"SPRITE" : {"name": "0056","x":2827,"y":1368,"w":235,"h":257,"rotated": false}},
{"SPRITE":{"name":"57","x":1623,"y":570,"w":277,"h":134,"rotated":false}}, {"SPRITE" : {"name": "0057","x":2100,"y":1879,"w":140,"h":92,"rotated": false}},
{"SPRITE":{"name":"58","x":1550,"y":1089,"w":38,"h":22,"rotated":false}}, {"SPRITE" : {"name": "0058","x":776,"y":1886,"w":119,"h":79,"rotated": false}},
{"SPRITE":{"name":"59","x":3666,"y":152,"w":124,"h":165,"rotated":false}}, {"SPRITE" : {"name": "0059","x":1565,"y":1249,"w":434,"h":147,"rotated": false}},
{"SPRITE":{"name":"60","x":1623,"y":272,"w":309,"h":297,"rotated":false}}, {"SPRITE" : {"name": "0060","x":276,"y":1320,"w":433,"h":145,"rotated": false}},
{"SPRITE":{"name":"61","x":3801,"y":2,"w":121,"h":91,"rotated":false}}, {"SPRITE" : {"name": "0061","x":3270,"y":878,"w":438,"h":342,"rotated": false}},
{"SPRITE":{"name":"62","x":3281,"y":522,"w":320,"h":77,"rotated":false}}, {"SPRITE" : {"name": "0062","x":3176,"y":1222,"w":385,"h":271,"rotated": false}},
{"SPRITE":{"name":"63","x":3921,"y":755,"w":17,"h":22,"rotated":false}}, {"SPRITE" : {"name": "0063","x":3563,"y":1437,"w":373,"h":153,"rotated": false}},
{"SPRITE":{"name":"64","x":1351,"y":272,"w":162,"h":74,"rotated":false}}, {"SPRITE" : {"name": "0064","x":3245,"y":1786,"w":202,"h":122,"rotated": false}},
{"SPRITE":{"name":"65","x":3801,"y":94,"w":69,"h":50,"rotated":false}}, {"SPRITE" : {"name": "0065","x":3449,"y":1786,"w":202,"h":122,"rotated": false}},
{"SPRITE":{"name":"66","x":2273,"y":574,"w":277,"h":174,"rotated":false}}, {"SPRITE" : {"name": "0066","x":3064,"y":1861,"w":150,"h":91,"rotated": false}},
{"SPRITE":{"name":"67","x":2261,"y":1136,"w":175,"h":123,"rotated":false}}, {"SPRITE" : {"name": "0067","x":3938,"y":1548,"w":151,"h":95,"rotated": false}},
{"SPRITE":{"name":"68","x":4058,"y":932,"w":32,"h":49,"rotated":false}}, {"SPRITE" : {"name": "0068","x":3845,"y":1883,"w":140,"h":90,"rotated": false}},
{"SPRITE":{"name":"69","x":3791,"y":270,"w":66,"h":38,"rotated":false}}, {"SPRITE" : {"name": "0069","x":2913,"y":1861,"w":149,"h":92,"rotated": false}},
{"SPRITE":{"name":"70","x":3079,"y":1141,"w":71,"h":40,"rotated":false}}, {"SPRITE" : {"name": "0070","x":630,"y":1886,"w":144,"h":87,"rotated": false}},
{"SPRITE":{"name":"71","x":2690,"y":360,"w":82,"h":29,"rotated":false}}, {"SPRITE" : {"name": "0071","x":3935,"y":1645,"w":152,"h":87,"rotated": false}},
{"SPRITE":{"name":"72","x":3602,"y":516,"w":88,"h":69,"rotated":false}}, {"SPRITE" : {"name": "0072","x":2441,"y":1243,"w":384,"h":263,"rotated": false}},
{"SPRITE":{"name":"73","x":4022,"y":806,"w":69,"h":27,"rotated":false}}, {"SPRITE" : {"name": "0073","x":1624,"y":611,"w":248,"h":277,"rotated": false}},
{"SPRITE":{"name":"74","x":1894,"y":228,"w":30,"h":40,"rotated":false}}, {"SPRITE" : {"name": "0074","x":1624,"y":894,"w":413,"h":353,"rotated": false}},
{"SPRITE":{"name":"75","x":3987,"y":654,"w":10,"h":13,"rotated":false}}, {"SPRITE" : {"name": "0075","x":2039,"y":894,"w":400,"h":352,"rotated": false}},
{"SPRITE":{"name":"76","x":3896,"y":1084,"w":7,"h":7,"rotated":false}}, {"SPRITE" : {"name": "0076","x":1829,"y":1466,"w":330,"h":163,"rotated": false}},
{"SPRITE":{"name":"77","x":3834,"y":1074,"w":9,"h":9,"rotated":false}}, {"SPRITE" : {"name": "0077","x":3987,"y":1883,"w":90,"h":103,"rotated": false}},
{"SPRITE":{"name":"78","x":3885,"y":1084,"w":10,"h":10,"rotated":false}}, {"SPRITE" : {"name": "0078","x":2161,"y":1466,"w":212,"h":238,"rotated": false}},
{"SPRITE":{"name":"79","x":3441,"y":736,"w":12,"h":12,"rotated":false}}, {"SPRITE" : {"name": "0079","x":768,"y":1480,"w":209,"h":236,"rotated": false}},
{"SPRITE":{"name":"80","x":3811,"y":1128,"w":19,"h":17,"rotated":false}}, {"SPRITE" : {"name": "0080","x":2242,"y":1879,"w":86,"h":84,"rotated": false}},
{"SPRITE":{"name":"81","x":3971,"y":654,"w":15,"h":14,"rotated":false}}, {"SPRITE" : {"name": "0081","x":879,"y":649,"w":126,"h":148,"rotated": false}},
{"SPRITE":{"name":"82","x":3858,"y":1150,"w":7,"h":7,"rotated":false}}, {"SPRITE" : {"name": "0082","x":1908,"y":1631,"w":216,"h":168,"rotated": false}},
{"SPRITE":{"name":"83","x":3794,"y":452,"w":5,"h":5,"rotated":false}}, {"SPRITE" : {"name": "0083","x":2575,"y":1631,"w":174,"h":192,"rotated": false}},
{"SPRITE":{"name":"84","x":3326,"y":751,"w":32,"h":57,"rotated":false}}, {"SPRITE" : {"name": "0084","x":1130,"y":1901,"w":106,"h":75,"rotated": false}},
{"SPRITE":{"name":"85","x":2583,"y":147,"w":6,"h":7,"rotated":false}}, {"SPRITE" : {"name": "0085","x":3961,"y":1367,"w":129,"h":63,"rotated": false}},
{"SPRITE":{"name":"86","x":935,"y":617,"w":198,"h":66,"rotated":false}}, {"SPRITE" : {"name": "0086","x":1829,"y":1398,"w":158,"h":60,"rotated": false}},
{"SPRITE":{"name":"87","x":426,"y":692,"w":352,"h":436,"rotated":false}}, {"SPRITE" : {"name": "0087","x":3270,"y":704,"w":123,"h":148,"rotated": false}},
{"SPRITE":{"name":"88","x":3814,"y":452,"w":156,"h":69,"rotated":false}}, {"SPRITE" : {"name": "0088","x":3961,"y":878,"w":123,"h":148,"rotated": false}},
{"SPRITE":{"name":"89","x":2829,"y":452,"w":194,"h":197,"rotated":false}}, {"SPRITE" : {"name": "0089","x":199,"y":1773,"w":207,"h":142,"rotated": false}},
{"SPRITE":{"name":"90","x":2670,"y":733,"w":181,"h":216,"rotated":false}}, {"SPRITE" : {"name": "0090","x":1238,"y":1901,"w":91,"h":53,"rotated": false}},
{"SPRITE":{"name":"91","x":3791,"y":150,"w":93,"h":119,"rotated":false}}, {"SPRITE" : {"name": "0091","x":276,"y":1112,"w":65,"h":96,"rotated": false}},
{"SPRITE":{"name":"92","x":4000,"y":372,"w":86,"h":75,"rotated":false}}, {"SPRITE" : {"name": "0092","x":276,"y":1210,"w":65,"h":96,"rotated": false}},
{"SPRITE":{"name":"93","x":3587,"y":320,"w":113,"h":195,"rotated":false}}, {"SPRITE" : {"name": "0093","x":2518,"y":1825,"w":136,"h":102,"rotated": false}},
{"SPRITE":{"name":"94","x":2483,"y":2,"w":80,"h":151,"rotated":false}}, {"SPRITE" : {"name": "0094","x":1537,"y":1857,"w":136,"h":102,"rotated": false}},
{"SPRITE":{"name":"95","x":3493,"y":2,"w":177,"h":149,"rotated":false}}, {"SPRITE" : {"name": "0095","x":3427,"y":1592,"w":228,"h":192,"rotated": false}},
{"SPRITE":{"name":"96","x":3327,"y":183,"w":9,"h":8,"rotated":false}}, {"SPRITE" : {"name": "0096","x":1541,"y":1621,"w":166,"h":234,"rotated": false}},
{"SPRITE":{"name":"97","x":3787,"y":452,"w":6,"h":6,"rotated":false}}, {"SPRITE" : {"name": "0097","x":512,"y":1703,"w":205,"h":171,"rotated": false}},
{"SPRITE":{"name":"98","x":4002,"y":705,"w":57,"h":48,"rotated":false}}, {"SPRITE" : {"name": "0098","x":2126,"y":1706,"w":205,"h":171,"rotated": false}},
{"SPRITE":{"name":"99","x":2574,"y":147,"w":8,"h":8,"rotated":false}}, {"SPRITE" : {"name": "0099","x":719,"y":1718,"w":204,"h":166,"rotated": false}},
{"SPRITE":{"name":"100","x":3814,"y":605,"w":8,"h":12,"rotated":false}}, {"SPRITE" : {"name": "0100","x":1147,"y":1735,"w":206,"h":164,"rotated": false}},
{"SPRITE":{"name":"101","x":1589,"y":1089,"w":9,"h":10,"rotated":false}}, {"SPRITE" : {"name": "0101","x":1874,"y":611,"w":79,"h":185,"rotated": false}},
{"SPRITE":{"name":"102","x":3701,"y":318,"w":85,"h":140,"rotated":false}}, {"SPRITE" : {"name": "0102","x":3176,"y":969,"w":83,"h":200,"rotated": false}},
{"SPRITE":{"name":"103","x":2,"y":692,"w":423,"h":429,"rotated":false}}, {"SPRITE" : {"name": "0103","x":3563,"y":1222,"w":86,"h":180,"rotated": false}},
{"SPRITE":{"name":"104","x":3533,"y":152,"w":132,"h":167,"rotated":false}}, {"SPRITE" : {"name": "0104","x":3961,"y":1028,"w":89,"h":186,"rotated": false}},
{"SPRITE":{"name":"105","x":3249,"y":961,"w":66,"h":16,"rotated":false}}, {"SPRITE" : {"name": "0105","x":2375,"y":1631,"w":198,"h":183,"rotated": false}},
{"SPRITE":{"name":"106","x":3576,"y":808,"w":52,"h":43,"rotated":false}}, {"SPRITE" : {"name": "0106","x":1908,"y":1801,"w":190,"h":120,"rotated": false}},
{"SPRITE":{"name":"107","x":3858,"y":1163,"w":46,"h":42,"rotated":false}}, {"SPRITE" : {"name": "0107","x":2656,"y":1825,"w":86,"h":145,"rotated": false}},
{"SPRITE":{"name":"108","x":3834,"y":1011,"w":13,"h":62,"rotated":false}}, {"SPRITE" : {"name": "0108","x":1355,"y":1724,"w":180,"h":170,"rotated": false}},
{"SPRITE":{"name":"109","x":3654,"y":1025,"w":34,"h":29,"rotated":false}}, {"SPRITE" : {"name": "0109","x":3961,"y":1216,"w":111,"h":149,"rotated": false}},
{"SPRITE":{"name":"110","x":3811,"y":1150,"w":46,"h":65,"rotated":false}}, {"SPRITE" : {"name": "0110","x":4035,"y":516,"w":39,"h":98,"rotated": false}},
{"SPRITE":{"name":"111","x":3701,"y":459,"w":112,"h":46,"rotated":false}}, {"SPRITE" : {"name": "0111","x":1307,"y":1153,"w":118,"h":47,"rotated": false}},
{"SPRITE":{"name":"112","x":2035,"y":898,"w":226,"h":223,"rotated":false}}, {"SPRITE" : {"name": "0112","x":1427,"y":1153,"w":120,"h":43,"rotated": false}},
{"SPRITE":{"name":"113","x":3233,"y":351,"w":190,"h":170,"rotated":false}}, {"SPRITE" : {"name": "0113","x":2441,"y":1184,"w":120,"h":41,"rotated": false}},
{"SPRITE":{"name":"114","x":3654,"y":1060,"w":58,"h":55,"rotated":false}}, {"SPRITE" : {"name": "0114","x":3216,"y":1910,"w":95,"h":33,"rotated": false}},
{"SPRITE":{"name":"115","x":3885,"y":94,"w":112,"h":94,"rotated":false}}, {"SPRITE" : {"name": "0115","x":3563,"y":1404,"w":95,"h":31,"rotated": false}},
{"SPRITE":{"name":"116","x":3576,"y":706,"w":132,"h":101,"rotated":false}}, {"SPRITE" : {"name": "0116","x":3563,"y":1404,"w":95,"h":31,"rotated": false}},
{"SPRITE":{"name":"117","x":1939,"y":493,"w":235,"h":239,"rotated":false}}, {"SPRITE" : {"name": "0117","x":2330,"y":1906,"w":95,"h":34,"rotated": false}},
{"SPRITE":{"name":"118","x":3242,"y":1150,"w":141,"h":111,"rotated":false}}, {"SPRITE" : {"name": "0118","x":2585,"y":487,"w":131,"h":47,"rotated": false}},
{"SPRITE":{"name":"119","x":2822,"y":2,"w":236,"h":160,"rotated":false}}, {"SPRITE" : {"name": "0119","x":4059,"y":258,"w":31,"h":18,"rotated": false}},
{"SPRITE":{"name":"120","x":2475,"y":749,"w":194,"h":236,"rotated":false}}, {"SPRITE" : {"name": "0120","x":1355,"y":1896,"w":122,"h":66,"rotated": false}},
{"SPRITE":{"name":"121","x":3455,"y":736,"w":120,"h":119,"rotated":false}}, {"SPRITE" : {"name": "0121","x":2992,"y":1737,"w":251,"h":122,"rotated": false}},
{"SPRITE":{"name":"122","x":2551,"y":398,"w":225,"h":189,"rotated":false}}, {"SPRITE" : {"name": "0122","x":879,"y":799,"w":114,"h":133,"rotated": false}},
{"SPRITE":{"name":"123","x":3923,"y":2,"w":130,"h":81,"rotated":false}}, {"SPRITE" : {"name": "0123","x":1347,"y":1500,"w":192,"h":222,"rotated": false}},
{"SPRITE":{"name":"124","x":3691,"y":621,"w":132,"h":83,"rotated":false}}, {"SPRITE" : {"name": "0124","x":4035,"y":818,"w":39,"h":34,"rotated": false}},
{"SPRITE":{"name":"125","x":3531,"y":1025,"w":122,"h":80,"rotated":false}}, {"SPRITE" : {"name": "0125","x":4035,"y":701,"w":50,"h":61,"rotated": false}},
{"SPRITE":{"name":"126","x":3814,"y":522,"w":129,"h":82,"rotated":false}}, {"SPRITE" : {"name": "0126","x":1874,"y":798,"w":64,"h":78,"rotated": false}},
{"SPRITE":{"name":"127","x":3709,"y":705,"w":125,"h":77,"rotated":false}}, {"SPRITE" : {"name": "0127","x":4035,"y":438,"w":52,"h":76,"rotated": false}},
{"SPRITE":{"name":"128","x":3885,"y":189,"w":132,"h":76,"rotated":false}}, {"SPRITE" : {"name": "0128","x":958,"y":934,"w":46,"h":63,"rotated": false}},
{"SPRITE":{"name":"129","x":2035,"y":1122,"w":225,"h":142,"rotated":false}}, {"SPRITE" : {"name": "0129","x":4059,"y":146,"w":30,"h":41,"rotated": false}},
{"SPRITE":{"name":"130","x":2777,"y":187,"w":151,"h":264,"rotated":false}}, {"SPRITE" : {"name": "0130","x":4059,"y":189,"w":23,"h":35,"rotated": false}},
{"SPRITE":{"name":"131","x":2551,"y":588,"w":277,"h":144,"rotated":false}}, {"SPRITE" : {"name": "0131","x":4059,"y":226,"w":20,"h":30,"rotated": false}},
{"SPRITE":{"name":"132","x":3327,"y":197,"w":205,"h":140,"rotated":false}}, {"SPRITE" : {"name": "0132","x":4059,"y":278,"w":17,"h":22,"rotated": false}},
{"SPRITE":{"name":"133","x":2175,"y":401,"w":305,"h":172,"rotated":false}}, {"SPRITE" : {"name": "0133","x":2333,"y":1816,"w":183,"h":88,"rotated": false}}
{"SPRITE":{"name":"134","x":2841,"y":1136,"w":137,"h":129,"rotated":false}}, ]},
{"SPRITE":{"name":"135","x":3129,"y":172,"w":197,"h":178,"rotated":false}}, "meta": {
{"SPRITE":{"name":"136","x":2,"y":1122,"w":364,"h":131,"rotated":false}}, "app": "Adobe Animate",
{"SPRITE":{"name":"137","x":3424,"y":338,"w":162,"h":147,"rotated":false}}, "version": "21.0.1.37179",
{"SPRITE":{"name":"138","x":1933,"y":228,"w":223,"h":264,"rotated":false}}, "image": "spritemap1.png",
{"SPRITE":{"name":"139","x":1351,"y":2,"w":418,"h":269,"rotated":false}}, "format": "RGBA8888",
{"SPRITE":{"name":"140","x":1599,"y":1133,"w":350,"h":113,"rotated":false}}, "size": {"w":4093,"h":1988},
{"SPRITE":{"name":"141","x":1599,"y":985,"w":435,"h":147,"rotated":false}}, "resolution": "1"
{"SPRITE":{"name":"142","x":3921,"y":670,"w":80,"h":84,"rotated":false}}, }
{"SPRITE":{"name":"143","x":2564,"y":147,"w":9,"h":8,"rotated":false}},
{"SPRITE":{"name":"144","x":2437,"y":1168,"w":31,"h":27,"rotated":false}},
{"SPRITE":{"name":"145","x":3664,"y":808,"w":110,"h":88,"rotated":false}},
{"SPRITE":{"name":"146","x":3024,"y":608,"w":43,"h":39,"rotated":false}},
{"SPRITE":{"name":"147","x":3563,"y":1106,"w":55,"h":58,"rotated":false}},
{"SPRITE":{"name":"148","x":3971,"y":619,"w":19,"h":34,"rotated":false}},
{"SPRITE":{"name":"149","x":3416,"y":1250,"w":30,"h":23,"rotated":false}},
{"SPRITE":{"name":"150","x":1939,"y":898,"w":82,"h":85,"rotated":false}},
{"SPRITE":{"name":"151","x":4054,"y":39,"w":34,"h":41,"rotated":false}},
{"SPRITE":{"name":"152","x":3691,"y":516,"w":122,"h":104,"rotated":false}},
{"SPRITE":{"name":"153","x":3762,"y":1060,"w":17,"h":32,"rotated":false}},
{"SPRITE":{"name":"154","x":3745,"y":783,"w":28,"h":20,"rotated":false}},
{"SPRITE":{"name":"155","x":3524,"y":486,"w":45,"h":35,"rotated":false}},
{"SPRITE":{"name":"156","x":4000,"y":266,"w":74,"h":105,"rotated":false}},
{"SPRITE":{"name":"157","x":3775,"y":836,"w":137,"h":57,"rotated":false}},
{"SPRITE":{"name":"158","x":3384,"y":1250,"w":31,"h":23,"rotated":false}},
{"SPRITE":{"name":"159","x":3504,"y":908,"w":24,"h":24,"rotated":false}},
{"SPRITE":{"name":"160","x":4013,"y":984,"w":55,"h":85,"rotated":false}},
{"SPRITE":{"name":"161","x":4054,"y":2,"w":40,"h":36,"rotated":false}},
{"SPRITE":{"name":"162","x":3775,"y":783,"w":163,"h":52,"rotated":false}},
{"SPRITE":{"name":"163","x":1950,"y":1133,"w":73,"h":115,"rotated":false}},
{"SPRITE":{"name":"164","x":3531,"y":962,"w":159,"h":62,"rotated":false}},
{"SPRITE":{"name":"165","x":3811,"y":1093,"w":20,"h":34,"rotated":false}},
{"SPRITE":{"name":"166","x":4067,"y":230,"w":27,"h":32,"rotated":false}},
{"SPRITE":{"name":"167","x":4067,"y":188,"w":24,"h":41,"rotated":false}},
{"SPRITE":{"name":"168","x":3504,"y":856,"w":26,"h":51,"rotated":false}},
{"SPRITE":{"name":"169","x":2929,"y":352,"w":86,"h":98,"rotated":false}},
{"SPRITE":{"name":"170","x":3824,"y":605,"w":146,"h":64,"rotated":false}},
{"SPRITE":{"name":"171","x":1589,"y":1100,"w":9,"h":10,"rotated":false}},
{"SPRITE":{"name":"172","x":3327,"y":172,"w":8,"h":10,"rotated":false}},
{"SPRITE":{"name":"173","x":3939,"y":806,"w":82,"h":27,"rotated":false}},
{"SPRITE":{"name":"174","x":3944,"y":522,"w":141,"h":62,"rotated":false}},
{"SPRITE":{"name":"175","x":3024,"y":352,"w":208,"h":169,"rotated":false}},
{"SPRITE":{"name":"176","x":3129,"y":2,"w":208,"h":169,"rotated":false}},
{"SPRITE":{"name":"177","x":3042,"y":814,"w":206,"h":164,"rotated":false}},
{"SPRITE":{"name":"178","x":3072,"y":522,"w":208,"h":161,"rotated":false}},
{"SPRITE":{"name":"179","x":779,"y":1037,"w":382,"h":218,"rotated":false}},
{"SPRITE":{"name":"180","x":935,"y":357,"w":237,"h":259,"rotated":false}},
{"SPRITE":{"name":"181","x":3155,"y":979,"w":86,"h":203,"rotated":false}},
{"SPRITE":{"name":"182","x":3364,"y":751,"w":90,"h":183,"rotated":false}},
{"SPRITE":{"name":"183","x":3357,"y":961,"w":91,"h":188,"rotated":false}},
{"SPRITE":{"name":"184","x":2852,"y":814,"w":185,"h":122,"rotated":false}},
{"SPRITE":{"name":"185","x":3787,"y":318,"w":89,"h":133,"rotated":false}},
{"SPRITE":{"name":"186","x":2590,"y":187,"w":183,"h":172,"rotated":false}},
{"SPRITE":{"name":"187","x":3242,"y":979,"w":114,"h":151,"rotated":false}},
{"SPRITE":{"name":"188","x":4047,"y":834,"w":42,"h":36,"rotated":false}},
{"SPRITE":{"name":"189","x":1134,"y":617,"w":53,"h":63,"rotated":false}},
{"SPRITE":{"name":"190","x":3166,"y":1183,"w":67,"h":80,"rotated":false}},
{"SPRITE":{"name":"191","x":3848,"y":1004,"w":55,"h":79,"rotated":false}},
{"SPRITE":{"name":"192","x":3834,"y":1084,"w":50,"h":65,"rotated":false}},
{"SPRITE":{"name":"193","x":3629,"y":808,"w":33,"h":43,"rotated":false}},
{"SPRITE":{"name":"194","x":3493,"y":152,"w":26,"h":38,"rotated":false}},
{"SPRITE":{"name":"195","x":3971,"y":585,"w":23,"h":33,"rotated":false}},
{"SPRITE":{"name":"196","x":2530,"y":498,"w":20,"h":24,"rotated":false}},
{"SPRITE":{"name":"197","x":3939,"y":755,"w":121,"h":50,"rotated":false}},
{"SPRITE":{"name":"198","x":3913,"y":836,"w":133,"h":49,"rotated":false}},
{"SPRITE":{"name":"199","x":3971,"y":449,"w":119,"h":69,"rotated":false}},
{"SPRITE":{"name":"200","x":3072,"y":684,"w":253,"h":125,"rotated":false}},
{"SPRITE":{"name":"201","x":3441,"y":600,"w":116,"h":135,"rotated":false}},
{"SPRITE":{"name":"202","x":2475,"y":986,"w":194,"h":224,"rotated":false}},
{"SPRITE":{"name":"203","x":1770,"y":2,"w":335,"h":225,"rotated":false}},
{"SPRITE":{"name":"204","x":2157,"y":158,"w":217,"h":242,"rotated":false}},
{"SPRITE":{"name":"205","x":3249,"y":810,"w":114,"h":150,"rotated":false}},
{"SPRITE":{"name":"206","x":3326,"y":600,"w":114,"h":150,"rotated":false}},
{"SPRITE":{"name":"207","x":3835,"y":670,"w":85,"h":87,"rotated":false}},
{"SPRITE":{"name":"208","x":3671,"y":2,"w":129,"h":147,"rotated":false}},
{"SPRITE":{"name":"209","x":2852,"y":650,"w":219,"h":163,"rotated":false}},
{"SPRITE":{"name":"210","x":3338,"y":2,"w":154,"h":194,"rotated":false}},
{"SPRITE":{"name":"211","x":1514,"y":272,"w":108,"h":68,"rotated":false}},
{"SPRITE":{"name":"212","x":3664,"y":897,"w":132,"h":64,"rotated":false}},
{"SPRITE":{"name":"213","x":2437,"y":1211,"w":160,"h":62,"rotated":false}},
{"SPRITE":{"name":"214","x":3449,"y":935,"w":81,"h":188,"rotated":false}},
{"SPRITE":{"name":"215","x":2841,"y":950,"w":200,"h":185,"rotated":false}},
{"SPRITE":{"name":"216","x":3384,"y":1150,"w":63,"h":99,"rotated":false}},
{"SPRITE":{"name":"217","x":2481,"y":398,"w":63,"h":99,"rotated":false}},
{"SPRITE":{"name":"218","x":3558,"y":600,"w":132,"h":105,"rotated":false}},
{"SPRITE":{"name":"219","x":3531,"y":856,"w":132,"h":105,"rotated":false}},
{"SPRITE":{"name":"220","x":2590,"y":2,"w":231,"h":184,"rotated":false}},
{"SPRITE":{"name":"221","x":2670,"y":950,"w":170,"h":224,"rotated":false}},
{"SPRITE":{"name":"222","x":2273,"y":749,"w":198,"h":144,"rotated":false}},
{"SPRITE":{"name":"223","x":3691,"y":962,"w":93,"h":53,"rotated":false}},
{"SPRITE":{"name":"224","x":2979,"y":1183,"w":186,"h":91,"rotated":false}},
{"SPRITE":{"name":"225","x":1939,"y":733,"w":333,"h":164,"rotated":false}},
{"SPRITE":{"name":"226","x":935,"y":2,"w":415,"h":354,"rotated":false}},
{"SPRITE":{"name":"227","x":1220,"y":357,"w":402,"h":353,"rotated":false}},
{"SPRITE":{"name":"228","x":3998,"y":84,"w":90,"h":103,"rotated":false}},
{"SPRITE":{"name":"229","x":2375,"y":158,"w":214,"h":239,"rotated":false}},
{"SPRITE":{"name":"230","x":2262,"y":898,"w":212,"h":237,"rotated":false}}]},
"meta":{
"app":"Adobe Animate (Better TA Extension)",
"version":"22.0.3.179",
"image":"spritemap1.png",
"format":"RGBA8888",
"size":{"w":4096,"h":1280},
"resolution":"1"
} }
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 MiB

After

Width:  |  Height:  |  Size: 642 KiB

+3 -11
View File
@@ -203,7 +203,6 @@
<str id="paste">Paste</str> <str id="paste">Paste</str>
<str id="cut">Cut</str> <str id="cut">Cut</str>
<str id="delete">Delete</str> <str id="delete">Delete</str>
<str id="deletestacked">Delete Stacked Notes</str>
</group> </group>
<str id="topBar.chart">Chart</str> <str id="topBar.chart">Chart</str>
@@ -224,7 +223,6 @@
<str id="resetZoom">Reset Zoom</str> <str id="resetZoom">Reset Zoom</str>
<str id="showSectionsSeparator">Show Sections Separator</str> <str id="showSectionsSeparator">Show Sections Separator</str>
<str id="showBeatsSeparator">Show Beats Separator</str> <str id="showBeatsSeparator">Show Beats Separator</str>
<str id="showCameraHighlights">Show Camera Highlights</str>
<str id="rainbowWaveforms">Rainbow Waveforms</str> <str id="rainbowWaveforms">Rainbow Waveforms</str>
<str id="lowDetailWaveforms">Low Detail Waveforms</str> <str id="lowDetailWaveforms">Low Detail Waveforms</str>
<str id="scrollLeft">Scroll Left</str> <str id="scrollLeft">Scroll Left</str>
@@ -238,9 +236,8 @@
<str id="goEnd">Go forward to the end</str> <!-- used to be "Go to the end" --> <str id="goEnd">Go forward to the end</str> <!-- used to be "Go to the end" -->
<str id="addOpponentCamera">Add camera on Opponent</str> <str id="addOpponentCamera">Add camera on Opponent</str>
<str id="addPlayerCamera">Add camera on Player</str> <str id="addPlayerCamera">Add camera on Player</str>
<str id="inst">Instrumental</str> <str id="muteInst">Mute instrumental</str>
<str id="voices">Voices</str> <str id="muteVoices">Mute voices</str>
<str id="hitsounds">Hitsounds</str>
</group> </group>
<group name="BookmarkMenu" prefix="bookmarks."> <group name="BookmarkMenu" prefix="bookmarks.">
@@ -253,7 +250,6 @@
<str id="editBookmarkListTitle">Bookmark List</str> <str id="editBookmarkListTitle">Bookmark List</str>
<str id="editBookmarksTitle">Edit Bookmarks</str> <str id="editBookmarksTitle">Edit Bookmarks</str>
<str id="newBookmarkName">New Bookmark</str> <str id="newBookmarkName">New Bookmark</str>
<str id="bookmarkList">Bookmark List</str>
</group> </group>
<str id="topBar.note">Note</str> <str id="topBar.note">Note</str>
@@ -262,7 +258,6 @@
<str id="subtractSustainLength">Subtract sustain length</str> <str id="subtractSustainLength">Subtract sustain length</str>
<str id="selectAll">Select all</str> <str id="selectAll">Select all</str>
<str id="selectMeasure">Select measure</str> <str id="selectMeasure">Select measure</str>
<str id="noteTypesList">Note Types List</str>
<str id="editNoteTypesList">Edit Note Types List</str> <str id="editNoteTypesList">Edit Note Types List</str>
</group> </group>
<str id="topBar.snap">Snap</str> <str id="topBar.snap">Snap</str>
@@ -313,9 +308,8 @@
<group name="StrumlineOptions" prefix="strumLine."> <group name="StrumlineOptions" prefix="strumLine.">
<str id="button-name">Options ↓</str> <str id="button-name">Options ↓</str>
<str id="waveforms">Waveforms</str>
<str id="hitsounds">Hitsounds</str> <str id="hitsounds">Hitsounds</str>
<str id="vocals">Vocals</str> <str id="muteVocals">Mute Vocals</str>
<str id="edit">Edit</str> <str id="edit">Edit</str>
<str id="delete">Delete</str> <str id="delete">Delete</str>
@@ -439,8 +433,6 @@
<str id="position">Position (X, Y)</str> <str id="position">Position (X, Y)</str>
<str id="fps">FPS</str> <str id="fps">FPS</str>
<str id="indices">Indices (Frames)</str> <str id="indices">Indices (Frames)</str>
<str id="looping">Looping?</str>
<str id="label">Label</str>
</group> </group>
<group name="CharacterSpriteScreen" prefix="characterSpriteScreen."> <group name="CharacterSpriteScreen" prefix="characterSpriteScreen.">
+1 -2
View File
@@ -16,7 +16,7 @@
<str id="animation">Animación</str> <str id="animation">Animación</str>
<str id="atlas">Atlas</str> <str id="atlas">Atlas</str>
<str id="spritemap">Mapa de sprites</str> <str id="spritemap">Mapa de sprites</str>
<str id="directory">Ubicación ({0}/)</str> <str id="directory">Ubicación ({0}/)</str>
<str id="found">{0} {1} Encontrado</str> <str id="found">{0} {1} Encontrado</str>
<str id="foundplural">{0} {1} Encontrados</str> <str id="foundplural">{0} {1} Encontrados</str>
@@ -188,7 +188,6 @@
<str id="paste">Pegar</str> <str id="paste">Pegar</str>
<str id="cut">Cortar</str> <str id="cut">Cortar</str>
<str id="delete">Eliminar</str> <str id="delete">Eliminar</str>
<str id="deletestacked">Eliminar Notas Apiladas</str>
</group> </group>
<str id="topBar.chart">Chart</str> <str id="topBar.chart">Chart</str>
-1
View File
@@ -194,7 +194,6 @@
<str id="paste">Incolla</str> <str id="paste">Incolla</str>
<str id="cut">Taglia</str> <str id="cut">Taglia</str>
<str id="delete">Elimina</str> <str id="delete">Elimina</str>
<str id="deletestacked">Elimina Note Impilate</str>
</group> </group>
<str id="topBar.chart">Chart</str> <str id="topBar.chart">Chart</str>
+3 -4
View File
@@ -18,7 +18,7 @@
<str id="animation">Animacja</str> <str id="animation">Animacja</str>
<str id="atlas">Atlas</str> <str id="atlas">Atlas</str>
<str id="spritemap">Mapa sprite'ów</str> <str id="spritemap">Mapa sprite'ów</str>
<str id="directory">Folder ({0}/)</str> <str id="directory">Folder ({0}/)</str>
<str id="found">{0} {1} Znaleziono</str> <str id="found">{0} {1} Znaleziono</str>
<str id="foundplural">{0} {1} Znaleziono</str> <str id="foundplural">{0} {1} Znaleziono</str>
@@ -87,7 +87,7 @@
<group name="CharterEventScreen" prefix="charterEventScreen."> <group name="CharterEventScreen" prefix="charterEventScreen.">
<str id="title-creating">Stwórz Grupę Wydarzeń</str> <str id="title-creating">Stwórz Grupę Wydarzeń</str>
<str id="title-editing">Edytuj Grupę Wydarzeń</str> <str id="title-editing">Edytuj Grupę Wydarzeń</str>
<str id="noEvent">Brak Wydarzenia</str> <str id="noEvent">Brak Wydarzenia</str>
<str id="strumLine.format">Struma #{0} ({1})</str> <str id="strumLine.format">Struma #{0} ({1})</str>
@@ -197,7 +197,6 @@
<str id="paste">Wklej</str> <str id="paste">Wklej</str>
<str id="cut">Wytnij</str> <str id="cut">Wytnij</str>
<str id="delete">Usuń</str> <str id="delete">Usuń</str>
<str id="deletestacked">Usuń Notatki Ułożone w Stos</str>
</group> </group>
<str id="topBar.chart">Mapa</str> <str id="topBar.chart">Mapa</str>
@@ -224,7 +223,7 @@
<str id="scrollRight">Przewiń w Prawo</str> <str id="scrollRight">Przewiń w Prawo</str>
<str id="scrollReset">Resetuj Przewinięcie</str> <str id="scrollReset">Resetuj Przewinięcie</str>
</group> </group>
<str id="topBar.song">Ścieżka</str> <str id="topBar.song">Ścieżka</str>
<group name="SongMenu" prefix="song."> <group name="SongMenu" prefix="song.">
<str id="goStart">Wróć do początku</str> <str id="goStart">Wróć do początku</str>
-1
View File
@@ -203,7 +203,6 @@
<str id="paste">Colar</str> <str id="paste">Colar</str>
<str id="cut">Cortar</str> <str id="cut">Cortar</str>
<str id="delete">Apagar</str> <str id="delete">Apagar</str>
<str id="deletestacked">Apagar Notas Empilhadas</str>
</group> </group>
<str id="topBar.chart">Mapa</str> <str id="topBar.chart">Mapa</str>
+2 -2
View File
@@ -12,7 +12,7 @@ function create() {
tankman = new FunkinSprite(game.dad.x + game.dad.globalOffset.x + 520, game.dad.y + game.dad.globalOffset.y + 225); tankman = new FunkinSprite(game.dad.x + game.dad.globalOffset.x + 520, game.dad.y + game.dad.globalOffset.y + 225);
tankman.antialiasing = true; tankman.antialiasing = true;
tankman.loadSprite(Paths.image('game/cutscenes/tank/guns-tankman')); tankman.loadSprite(Paths.image('game/cutscenes/tank/guns-tankman'));
tankman.addAnim('tank', 'TANK TALK 2', 0, false); tankman.animateAtlas.anim.addBySymbol('tank', 'TANK TALK 2', 0, false);
game.insert(game.members.indexOf(game.dad), tankman); game.insert(game.members.indexOf(game.dad), tankman);
game.dad.visible = false; game.dad.visible = false;
@@ -65,4 +65,4 @@ function destroy() {
for(thing in [tankman, tankTalk]) thing.destroy(); for(thing in [tankman, tankTalk]) thing.destroy();
if(destroyDistorto) distorto.destroy(); if(destroyDistorto) distorto.destroy();
FlxTween.tween(FlxG.camera, {zoom: game.defaultCamZoom}, 0.7, {ease: FlxEase.quadInOut, startDelay: 0}); FlxTween.tween(FlxG.camera, {zoom: game.defaultCamZoom}, 0.7, {ease: FlxEase.quadInOut, startDelay: 0});
} }
+9 -13
View File
@@ -33,20 +33,20 @@ function create() {
tankman = new FunkinSprite(game.dad.x + game.dad.globalOffset.x + 520, game.dad.y + game.dad.globalOffset.y + 225); tankman = new FunkinSprite(game.dad.x + game.dad.globalOffset.x + 520, game.dad.y + game.dad.globalOffset.y + 225);
tankman.antialiasing = true; tankman.antialiasing = true;
tankman.loadSprite(Paths.image('game/cutscenes/tank/stress-tankman')); tankman.loadSprite(Paths.image('game/cutscenes/tank/stress-tankman'));
tankman.addAnim('p1', 'TANK TALK 3 P1 UNCUT', 0, false); tankman.animateAtlas.anim.addBySymbol('p1', 'TANK TALK 3 P1 UNCUT', 0, false);
tankman.addAnim('p2', 'TANK TALK 3 P2 UNCUT', 0, false); tankman.animateAtlas.anim.addBySymbol('p2', 'TANK TALK 3 P2 UNCUT', 0, false);
tankman.playAnim('p1'); tankman.playAnim('p1');
pico = new FunkinSprite(game.gf.x + game.gf.globalOffset.x - 615, game.gf.y + game.gf.globalOffset.y - 130); pico = new FunkinSprite(game.gf.x + game.gf.globalOffset.x + 150, game.gf.y + game.gf.globalOffset.y + 395);
pico.antialiasing = true; pico.antialiasing = true;
pico.loadSprite(Paths.image('game/cutscenes/tank/stress-pico')); pico.loadSprite(Paths.image('game/cutscenes/tank/stress-pico'));
pico.addAnim('die', 'die', 24, false, null, null, 0, 0, null, true); pico.animateAtlas.anim.addBySymbol('die', 'GF Time to Die sequence', 24, false);
pico.addAnim('saves', 'saves', 24, false, null, null, 0, 0, null, true); pico.animateAtlas.anim.addBySymbol('saves', 'Pico Saves them sequence', 24, false);
pico.addAnim('idle', 'idle', 24, true, null, null, 0, 0, null, true); pico.animateAtlas.anim.addBySymbol('idle', 'Pico Dual Wield on Speaker idle', 24, true);
pico.scrollFactor.set(0.95, 0.95); pico.scrollFactor.set(0.95, 0.95);
pico.playAnim("idle"); pico.playAnim("idle");
pico.visible = false; pico.visible = false;
game.insert(game.members.indexOf(game.gf) + 2, pico); game.insert(game.members.indexOf(game.gf) + 1, pico);
game.insert(game.members.indexOf(game.dad) + 1, tankman); game.insert(game.members.indexOf(game.dad) + 1, tankman);
game.dad.visible = false; game.dad.visible = false;
@@ -59,11 +59,7 @@ function update(elapsed) {
lipSync(tankman, 0, 16750); lipSync(tankman, 0, 16750);
if (stressCutscene.time > 15100) { if (stressCutscene.time > 15100) {
step = 1; step = 1;
focusOn(game.gf);
//focusOn(game.gf);
game.camFollow.x += 350;
game.camFollow.y -= 200;
pico.visible = true; pico.visible = true;
pico.playAnim('die', true); pico.playAnim('die', true);
@@ -122,7 +118,7 @@ function update(elapsed) {
} }
function lipSync(char:FunkinSprite, begin:Float, end:Float) { function lipSync(char:FunkinSprite, begin:Float, end:Float) {
char.anim.curAnim.curFrame = Std.int(FlxMath.remapToRange(stressCutscene.time, begin, end, 0, char.anim.curAnim.numFrames - 1)); char.animateAtlas.anim.curFrame = Std.int(FlxMath.remapToRange(stressCutscene.time, begin, end, 0, char.animateAtlas.anim.length-1));
} }
function focusOn(char, snap:Bool = false) { function focusOn(char, snap:Bool = false) {
+3 -3
View File
@@ -12,8 +12,8 @@ function create() {
tankman = new FunkinSprite(game.dad.x + game.dad.globalOffset.x + 520, game.dad.y + game.dad.globalOffset.y + 225); tankman = new FunkinSprite(game.dad.x + game.dad.globalOffset.x + 520, game.dad.y + game.dad.globalOffset.y + 225);
tankman.antialiasing = true; tankman.antialiasing = true;
tankman.loadSprite(Paths.image('game/cutscenes/tank/ugh-tankman')); tankman.loadSprite(Paths.image('game/cutscenes/tank/ugh-tankman'));
tankman.addAnim('1', 'TANK TALK 1 P1', 0, false); tankman.animateAtlas.anim.addBySymbol('1', 'TANK TALK 1 P1', 0, false);
tankman.addAnim('2', 'TANK TALK 1 P2', 0, false); tankman.animateAtlas.anim.addBySymbol('2', 'TANK TALK 1 P2', 0, false);
game.insert(game.members.indexOf(game.dad), tankman); game.insert(game.members.indexOf(game.dad), tankman);
game.dad.visible = false; game.dad.visible = false;
@@ -77,4 +77,4 @@ function destroy() {
for(timer in timers) timer.cancel(); for(timer in timers) timer.cancel();
for(thing in [tankTalk1, tankTalk2, bfBeep, tankman]) thing.destroy(); for(thing in [tankTalk1, tankTalk2, bfBeep, tankman]) thing.destroy();
if(destroyDistorto) distorto.destroy(); if(destroyDistorto) distorto.destroy();
} }
+9 -8
View File
@@ -4,18 +4,21 @@
<print pretty="true">Preparing installation...</print> <print pretty="true">Preparing installation...</print>
<!-- OpenFL & Lime (Required for Flixel) --> <!-- OpenFL & Lime (Required for Flixel) -->
<git name="openfl" url="https://github.com/CodenameCrew/cne-openfl" ref="old" /> <git name="openfl" url="https://github.com/CodenameCrew/cne-openfl" />
<lib name="lime" version="8.1.2" /> <lib name="lime" version="8.1.2" />
<!-- <git name="lime" url="https://github.com/CodenameCrew/cne-lime" /> disabled for now until fixed -->
<!-- Flixel --> <!-- Flixel -->
<git name="flixel" url="https://github.com/CodenameCrew/cne-flixel" ref="old" /> <git name="flixel" url="https://github.com/CodenameCrew/cne-flixel" />
<git name="flixel-addons" url="https://github.com/CodenameCrew/cne-flixel-addons" ref="old" /> <git name="flixel-addons" url="https://github.com/CodenameCrew/cne-flixel-addons" />
<!-- Other Libraries --> <!-- Other Libraries -->
<git name="hscript-improved" url="https://github.com/CodenameCrew/hscript-improved" ref="codename-dev" /> <git name="hscript-improved" url="https://github.com/CodenameCrew/hscript-improved" ref="codename-dev" />
<git name="hxdiscord_rpc" url="https://github.com/CodenameCrew/cne-hxdiscord_rpc" ref="old" skipDeps="true" /> <git name="flxanimate" url="https://github.com/CodenameCrew/cne-flxanimate" />
<lib name="funkin-modchart" skipDeps="true" /> <git name="hxdiscord_rpc" url="https://github.com/CodenameCrew/cne-hxdiscord_rpc" skipDeps="true" />
<lib name="funkin-modchart" version="1.2.4" skipDeps="true" />
<lib name="hxvlc" version="1.9.3" skipDeps="true" /> <lib name="hxvlc" version="1.9.3" skipDeps="true" />
<git name="bin-serializer" url="https://github.com/CodenameCrew/bin-serializer" />
<!-- Documentation and other features --> <!-- Documentation and other features -->
<git name="away3d" url="https://github.com/CodenameCrew/away3d" /> <git name="away3d" url="https://github.com/CodenameCrew/away3d" />
@@ -29,9 +32,7 @@
<lib global="true" name="hxp" /> <lib name="hxp" /> <lib global="true" name="hxp" /> <lib name="hxp" />
<lib global="true" name="format" /> <lib name="format" /> <lib global="true" name="format" /> <lib name="format" />
<git name="hxcpp" url="https://github.com/CodenameCrew/cne-hxcpp" ref="old" /> <git name="hxcpp" url="https://github.com/CodenameCrew/cne-hxcpp" />
<git name="flixel-animate" url="https://github.com/CodenameCrew/cne-flixel-animate/" ref="old" skipDeps="true"/>
</if> </if>
<!-- Hxcpp Building --> <!-- Hxcpp Building -->
+7 -12
View File
@@ -3,19 +3,16 @@
<!-- _________________________ Application Settings _________________________ --> <!-- _________________________ Application Settings _________________________ -->
<app <app
title="Friday Night Funkin' - Codename Engine" main="funkin.backend.system.Main" title="Friday Night Funkin' - Codename Engine" main="funkin.backend.system.Main"
file="CodenameEngine" packageName="com.yoshman29.codenameengine" file="CodenameEngine" packageName="com.codenamecrew.codenameengine"
package="com.yoshman29.codenameengine" package="com.codenamecrew.codenameengine"
version="1.0.1" company="Yoshman29" /> version="1.0.1" company="CodenameCrew" />
<!-- <!--
CHANGE THE SAVE PATH & NAME FOR YOUR MOD HERE! CHANGE THE SAVE PATH & NAME FOR YOUR HARDCODED MOD HERE!
--> -->
<haxedef name="SAVE_PATH" value="CodenameEngine"/> <haxedef name="SAVE_PATH" value="CodenameCrew/CodenameEngine"/>
<haxedef name="SAVE_NAME" value="save-default"/> <haxedef name="SAVE_NAME" value="save-default"/>
<haxedef name="SAVE_OPTIONS_PATH" value="CodenameEngine"/>
<haxedef name="SAVE_OPTIONS_NAME" value="options"/>
<!--Switch Export with Unique ApplicationID and Icon--> <!--Switch Export with Unique ApplicationID and Icon-->
<set name="APP_ID" value="0x0100f6c013bbc000" /> <set name="APP_ID" value="0x0100f6c013bbc000" />
@@ -74,9 +71,6 @@
Reduces compilation time at the cost of limited HScript flexibility. !--> Reduces compilation time at the cost of limited HScript flexibility. !-->
<define name="CUSTOM_CLASSES" unless="STRIPPED_COMPILE" /> <define name="CUSTOM_CLASSES" unless="STRIPPED_COMPILE" />
<!-- Comment this out to disable abstract support in hscript. !-->
<haxedef name="HSCRIPT_ABSTRACT_SUPPORT" unless="STRIPPED_COMPILE" />
<!-- Comment this out to disable multithreading !--> <!-- Comment this out to disable multithreading !-->
<haxedef name="ALLOW_MULTITHREADING" unless="web || flash" /> <haxedef name="ALLOW_MULTITHREADING" unless="web || flash" />
@@ -133,7 +127,8 @@
<haxelib name="hxvlc" if="VIDEO_CUTSCENES" /> <haxelib name="hxvlc" if="VIDEO_CUTSCENES" />
<haxelib name="away3d" if="THREE_D_SUPPORT" /> <haxelib name="away3d" if="THREE_D_SUPPORT" />
<haxelib name="format" /> <haxelib name="format" />
<haxelib name="flixel-animate" /> <haxelib name="flxanimate" />
<haxelib name="bin-serializer" />
<haxelib name="nape-haxe4" if="NAPE_ENABLED"/> <haxelib name="nape-haxe4" if="NAPE_ENABLED"/>
<haxelib name="hscript-improved" /> <haxelib name="hscript-improved" />
+92
View File
@@ -0,0 +1,92 @@
package funkin.backend;
import flixel.graphics.frames.FlxFrame;
import flixel.math.FlxAngle;
import flixel.math.FlxMatrix;
import openfl.display.BlendMode;
import openfl.geom.ColorTransform;
class FlxAnimate extends flxanimate.FlxAnimate {
static var rMatrix = new FlxMatrix();
override function drawLimb(limb:FlxFrame, _rMatrix:FlxMatrix, ?colorTransform:ColorTransform, ?blendMode:BlendMode)
{
if (alpha == 0 || colorTransform != null && (colorTransform.alphaMultiplier == 0 || colorTransform.alphaOffset == -255) || limb == null || limb.type == EMPTY)
return;
if (blendMode == null)
blendMode = BlendMode.NORMAL;
for (camera in cameras)
{
rMatrix.identity();
limb.prepareMatrix(rMatrix, FlxFrameAngle.ANGLE_0, _checkFlipX() != camera.flipX, _checkFlipY() != camera.flipY);
rMatrix.concat(_rMatrix);
if (!camera.visible || !camera.exists || !limbOnScreen(limb, _rMatrix, camera))
return;
getScreenPosition(_point, camera).subtractPoint(offset);
rMatrix.translate(-origin.x, -origin.y);
if (limb != _pivot) {
if (frameOffsetAngle != null && frameOffsetAngle != angle)
{
var angleOff = (frameOffsetAngle - angle) * FlxAngle.TO_RAD;
var cos = Math.cos(angleOff);
var sin = Math.sin(angleOff);
// cos doesn't need to be negated
rMatrix.rotateWithTrig(cos, -sin);
rMatrix.translate(-frameOffset.x, -frameOffset.y);
rMatrix.rotateWithTrig(cos, sin);
}
else
{
rMatrix.translate(-frameOffset.x, -frameOffset.y);
}
rMatrix.scale(scale.x, scale.y);
if (!matrixExposed && bakedRotationAngle <= 0)
{
updateTrig();
if (angle != 0)
rMatrix.rotateWithTrig(_cosAngle, _sinAngle);
}
}
else
rMatrix.a = rMatrix.d = 0.7 / camera.zoom;
if (matrixExposed)
{
rMatrix.concat(transformMatrix);
}
else
{
rMatrix.concat(@:privateAccess flxanimate.FlxAnimate._skewMatrix);
}
_point.addPoint(origin);
if (isPixelPerfectRender(camera))
{
_point.floor();
}
rMatrix.translate(_point.x, _point.y);
camera.drawPixels(limb, null, rMatrix, colorTransform, blendMode, antialiasing, shaderEnabled ? shader : null);
#if FLX_DEBUG
FlxBasic.visibleCount++;
#end
}
// doesn't work, needs to be remade
// #if FLX_DEBUG
// if (FlxG.debugger.drawDebug)
// drawDebug();
// #end
}
override function limbOnScreen(limb:FlxFrame, m:FlxMatrix, ?Camera:FlxCamera)
{
// TODO: ACTUAL OPTIMIZATION
return true;
}
}
+144 -76
View File
@@ -1,7 +1,5 @@
package funkin.backend; package funkin.backend;
import animate.FlxAnimate;
import animate.FlxAnimateController.FlxAnimateAnimation;
import flixel.addons.effects.FlxSkewedSprite; import flixel.addons.effects.FlxSkewedSprite;
import flixel.animation.FlxAnimation; import flixel.animation.FlxAnimation;
import flixel.math.FlxMatrix; import flixel.math.FlxMatrix;
@@ -9,6 +7,7 @@ import flixel.math.FlxPoint;
import flixel.math.FlxRect; import flixel.math.FlxRect;
import flixel.system.FlxAssets.FlxGraphicAsset; import flixel.system.FlxAssets.FlxGraphicAsset;
import flixel.util.typeLimit.OneOfTwo; import flixel.util.typeLimit.OneOfTwo;
import flxanimate.animate.FlxAnim.FlxSymbolAnimation;
import funkin.backend.scripting.events.sprite.PlayAnimContext; import funkin.backend.scripting.events.sprite.PlayAnimContext;
import funkin.backend.system.interfaces.IBeatReceiver; import funkin.backend.system.interfaces.IBeatReceiver;
import funkin.backend.system.interfaces.IOffsetCompatible; import funkin.backend.system.interfaces.IOffsetCompatible;
@@ -16,10 +15,6 @@ import funkin.backend.utils.XMLUtil.AnimData;
import funkin.backend.utils.XMLUtil.BeatAnim; import funkin.backend.utils.XMLUtil.BeatAnim;
import funkin.backend.utils.XMLUtil.IXMLEvents; import funkin.backend.utils.XMLUtil.IXMLEvents;
import haxe.io.Path; import haxe.io.Path;
import flixel.graphics.frames.FlxFrame;
import flixel.math.FlxAngle;
import animate.internal.RenderTexture;
import animate.FlxAnimateFrames;
enum abstract XMLAnimType(Int) enum abstract XMLAnimType(Int)
{ {
@@ -48,7 +43,7 @@ enum abstract XMLAnimType(Int)
} }
} }
class FunkinSprite extends FlxAnimate implements IBeatReceiver implements IOffsetCompatible implements IXMLEvents class FunkinSprite extends FlxSkewedSprite implements IBeatReceiver implements IOffsetCompatible implements IXMLEvents
{ {
public var extra:Map<String, Dynamic> = []; public var extra:Map<String, Dynamic> = [];
@@ -61,9 +56,6 @@ class FunkinSprite extends FlxAnimate implements IBeatReceiver implements IOffse
public var animEnabled:Bool = true; public var animEnabled:Bool = true;
public var zoomFactorEnabled:Bool = true; public var zoomFactorEnabled:Bool = true;
//Backwards compatibility
public var animateAtlas(get, never):FunkinSprite;
public var globalCurFrame(get, set):Int; public var globalCurFrame(get, set):Int;
/** /**
@@ -74,7 +66,9 @@ class FunkinSprite extends FlxAnimate implements IBeatReceiver implements IOffse
public var beatOffset:Int = 0; public var beatOffset:Int = 0;
public var skipNegativeBeats:Bool = false; public var skipNegativeBeats:Bool = false;
public var animateSettings:FlxAnimateSettings = {}; public var animateAtlas:FlxAnimate;
@:noCompletion public var atlasPlayingAnim:String;
@:noCompletion public var atlasPath:String;
var _rect2:FlxRect; var _rect2:FlxRect;
@@ -91,7 +85,6 @@ class FunkinSprite extends FlxAnimate implements IBeatReceiver implements IOffse
} }
moves = false; moves = false;
applyStageMatrix = true;
} }
/** /**
@@ -107,6 +100,8 @@ class FunkinSprite extends FlxAnimate implements IBeatReceiver implements IOffse
@:privateAccess { @:privateAccess {
spr.setPosition(source.x, source.y); spr.setPosition(source.x, source.y);
spr.frames = source.frames; spr.frames = source.frames;
if (casted != null && casted.animateAtlas != null && casted.atlasPath != null)
spr.loadSprite(casted.atlasPath);
spr.animation.copyFrom(source.animation); spr.animation.copyFrom(source.animation);
spr.visible = source.visible; spr.visible = source.visible;
spr.alpha = source.alpha; spr.alpha = source.alpha;
@@ -116,6 +111,8 @@ class FunkinSprite extends FlxAnimate implements IBeatReceiver implements IOffse
if (casted != null) { if (casted != null) {
spr.skew.set(casted.skew.x, casted.skew.y); spr.skew.set(casted.skew.x, casted.skew.y);
spr.transformMatrix = casted.transformMatrix;
spr.matrixExposed = casted.matrixExposed;
spr.animOffsets = casted.animOffsets.copy(); spr.animOffsets = casted.animOffsets.copy();
spr.zoomFactor = casted.zoomFactor; spr.zoomFactor = casted.zoomFactor;
} }
@@ -126,6 +123,8 @@ class FunkinSprite extends FlxAnimate implements IBeatReceiver implements IOffse
public override function update(elapsed:Float) public override function update(elapsed:Float)
{ {
super.update(elapsed); super.update(elapsed);
if (animateAtlas != null)
animateAtlas.update(elapsed);
// hate how it looks like but hey at least its optimized and fast - Nex // hate how it looks like but hey at least its optimized and fast - Nex
if (!debugMode && isAnimFinished()) { if (!debugMode && isAnimFinished()) {
@@ -143,7 +142,15 @@ class FunkinSprite extends FlxAnimate implements IBeatReceiver implements IOffse
public function loadSprite(path:String, Unique:Bool = false, Key:String = null) public function loadSprite(path:String, Unique:Bool = false, Key:String = null)
{ {
var noExt = Path.withoutExtension(path); var noExt = Path.withoutExtension(path);
frames = Paths.getFrames(path, true, null, null, animateSettings); if (Assets.exists('$noExt/Animation.json'))
{
atlasPath = noExt;
animateAtlas = new FlxAnimate(x, y, noExt);
}
else
{
frames = Paths.getFrames(path, true);
}
return this; return this;
} }
@@ -173,22 +180,50 @@ class FunkinSprite extends FlxAnimate implements IBeatReceiver implements IOffse
{ {
} }
public override function draw() {
// re-implementing the `onDraw` functionality from `FlxSprite` since `FlxAnimate` didn't have this, so we have to add it back in ourselves
if (this.isAnimate && this.__drawOverrided) {
this.__drawOverrided = false;
this.onDraw(this);
this.__drawOverrided = true;
return;
}
super.draw();
}
// ANIMATE ATLAS DRAWING // ANIMATE ATLAS DRAWING
#if REGION #if REGION
public override function draw()
{
if (animateAtlas != null)
{
copyAtlasValues();
animateAtlas.draw();
}
else
{
super.draw();
}
}
public function copyAtlasValues()
{
@:privateAccess {
animateAtlas.cameras = cameras; // investigate if we can use _cameras
animateAtlas.scrollFactor = scrollFactor;
animateAtlas.scale = scale;
animateAtlas.offset = offset;
animateAtlas.frameOffset = frameOffset;
animateAtlas.x = x;
animateAtlas.y = y;
animateAtlas.angle = angle;
animateAtlas.alpha = alpha;
animateAtlas.visible = visible;
animateAtlas.flipX = flipX;
animateAtlas.flipY = flipY;
animateAtlas.shader = shader;
animateAtlas.shaderEnabled = shaderEnabled;
animateAtlas.antialiasing = antialiasing;
animateAtlas.skew = skew;
animateAtlas.transformMatrix = transformMatrix;
animateAtlas.matrixExposed = matrixExposed;
animateAtlas.colorTransform = colorTransform;
}
}
public override function destroy() public override function destroy()
{ {
animateAtlas = FlxDestroyUtil.destroy(animateAtlas);
if (animOffsets != null) { if (animOffsets != null) {
for (key in animOffsets.keys()) { for (key in animOffsets.keys()) {
final point = animOffsets[key]; final point = animOffsets[key];
@@ -225,6 +260,25 @@ class FunkinSprite extends FlxAnimate implements IBeatReceiver implements IOffse
); );
} }
public override function getScreenBounds(?newRect:FlxRect, ?camera:FlxCamera):FlxRect
{
if (camera == null)
camera = FlxG.camera;
newRect = super.getScreenBounds(newRect, camera);
if(__shouldDoZoomFactor()) {
__prepareZoomFactor(_rect2, camera);
newRect.set(
(newRect.x - _rect2.x) * _rect2.width + _rect2.x,
(newRect.y - _rect2.y) * _rect2.height + _rect2.y,
newRect.width * _rect2.width,
newRect.height * _rect2.height,
);
}
return newRect;
}
override public function isOnScreen(?camera:FlxCamera):Bool override public function isOnScreen(?camera:FlxCamera):Bool
{ {
if (forceIsOnScreen) if (forceIsOnScreen)
@@ -239,6 +293,22 @@ class FunkinSprite extends FlxAnimate implements IBeatReceiver implements IOffse
return camera.containsRect(bounds); return camera.containsRect(bounds);
} }
// ZOOM FACTOR RENDERING
public override function doAdditionalMatrixStuff(matrix:FlxMatrix, camera:FlxCamera)
{
// no need to...
//super.doAdditionalMatrixStuff(matrix, camera);
if(__shouldDoZoomFactor()) {
__prepareZoomFactor(_rect, camera);
matrix.setTo(
matrix.a * _rect.width, matrix.b * _rect.height,
matrix.c * _rect.width, matrix.d * _rect.height,
(matrix.tx - _rect.x) * _rect.width + _rect.x,
(matrix.ty - _rect.y) * _rect.height + _rect.y,
);
}
}
// OFFSETTING // OFFSETTING
#if REGION #if REGION
public var animOffsets:Map<String, FlxPoint> = new Map<String, FlxPoint>(); public var animOffsets:Map<String, FlxPoint> = new Map<String, FlxPoint>();
@@ -270,7 +340,13 @@ class FunkinSprite extends FlxAnimate implements IBeatReceiver implements IOffse
Force = anim != null && anim.forced; Force = anim != null && anim.forced;
} }
animation.play(AnimName, Force, Reversed, Frame); if (animateAtlas != null)
{
@:privateAccess
animateAtlas.anim.play(AnimName, Force, Reversed, Frame);
atlasPlayingAnim = AnimName;
}
else animation.play(AnimName, Force, Reversed, Frame);
var daOffset = getAnimOffset(AnimName); var daOffset = getAnimOffset(AnimName);
frameOffset.set(daOffset.x, daOffset.y); frameOffset.set(daOffset.x, daOffset.y);
@@ -279,7 +355,7 @@ class FunkinSprite extends FlxAnimate implements IBeatReceiver implements IOffse
lastAnimContext = Context; lastAnimContext = Context;
} }
public inline function addAnim(name:String, prefix:String, frameRate:Float = 24, ?looped:Bool, ?forced:Bool, ?indices:Array<Int>, x:Float = 0, y:Float = 0, animType:XMLAnimType = NONE, animateAtlasLabel:Bool = false) public inline function addAnim(name:String, prefix:String, frameRate:Float = 24, ?looped:Bool, ?forced:Bool, ?indices:Array<Int>, x:Float = 0, y:Float = 0, animType:XMLAnimType = NONE)
{ {
return XMLUtil.addAnimToSprite(this, { return XMLUtil.addAnimToSprite(this, {
name: name, name: name,
@@ -290,16 +366,22 @@ class FunkinSprite extends FlxAnimate implements IBeatReceiver implements IOffse
x: x, x: x,
y: y, y: y,
indices: indices, indices: indices,
forced: forced, forced: forced
label: animateAtlasLabel
}); });
} }
public inline function removeAnim(name:String) { public inline function removeAnim(name:String)
animation.remove(name); {
if (animateAtlas != null)
@:privateAccess animateAtlas.anim.animsMap.remove(name);
else
animation.remove(name);
} }
public function getAnim(name:String):OneOfTwo<FlxAnimation, FlxAnimateAnimation> { public function getAnim(name:String):OneOfTwo<FlxAnimation, FlxSymbolAnimation>
{
if(animateAtlas != null)
return animateAtlas.anim.getByName(name);
return animation.getByName(name); return animation.getByName(name);
} }
@@ -310,26 +392,40 @@ class FunkinSprite extends FlxAnimate implements IBeatReceiver implements IOffse
return FlxPoint.weak(0, 0); return FlxPoint.weak(0, 0);
} }
public inline function hasAnim(AnimName:String):Bool public inline function hasAnim(AnimName:String):Bool @:privateAccess
return animation.exists(AnimName); return animateAtlas != null ? (animateAtlas.anim.animsMap.exists(AnimName)
|| animateAtlas.anim.symbolDictionary.exists(AnimName)) : animation.exists(AnimName);
public inline function getAnimName() public inline function getAnimName() {
return animation.name; return (animateAtlas != null) ? atlasPlayingAnim : animation.name;
}
public inline function isAnimReversed():Bool public inline function isAnimReversed():Bool {
return animation.curAnim?.reversed ?? false; return animateAtlas != null ? animateAtlas.anim.reversed : animation.curAnim != null ? animation.curAnim.reversed : false;
}
public inline function getNameList():Array<String> public inline function getNameList():Array<String> {
return animation.getNameList(); if (animateAtlas != null)
return [for (name in @:privateAccess animateAtlas.anim.animsMap.keys()) name];
else
return animation.getNameList();
}
public inline function stopAnim() public inline function stopAnim()
animation.stop(); {
if (animateAtlas != null)
animateAtlas.anim.pause();
else
animation.stop();
}
public inline function isAnimFinished() public inline function isAnimFinished() {
return animation.curAnim?.finished ?? true; return animateAtlas != null ? animateAtlas.anim.finished : (animation.curAnim != null ? animation.curAnim.finished : true);
}
public inline function isAnimAtEnd() public inline function isAnimAtEnd() {
return animation.curAnim?.isAtEnd ?? false; return animateAtlas != null ? animateAtlas.anim.isAtEnd : (animation.curAnim != null ? animation.curAnim.isAtEnd : false);
}
override function updateAnimation(elapsed:Float) { override function updateAnimation(elapsed:Float) {
if (animEnabled) if (animEnabled)
@@ -351,38 +447,10 @@ class FunkinSprite extends FlxAnimate implements IBeatReceiver implements IOffse
return beatInterval = v; return beatInterval = v;
} }
@:noCompletion @:noCompletion private inline function get_globalCurFrame() {
@:deprecated("`FunkinSprite.animateAtlas` is deprecated, just use `FunkinSprite` instead") return animateAtlas != null ? (animateAtlas.anim.curFrame) : (animation.curAnim != null ? animation.curAnim.curFrame : 0);
public function get_animateAtlas():FunkinSprite }
return isAnimate ? this : null;
@:noCompletion private inline function get_globalCurFrame()
return animation.curAnim?.curFrame ?? 0;
@:noCompletion private inline function set_globalCurFrame(val:Int) { @:noCompletion private inline function set_globalCurFrame(val:Int) {
if (animation.curAnim != null) return animateAtlas != null ? (animateAtlas.anim.curFrame = val) : (animation.curAnim != null ? animation.curAnim.curFrame = val : val);
animation.curAnim.curFrame = val;
return val;
}
override function prepareDrawMatrix(matrix:FlxMatrix, camera:FlxCamera):Void {
super.prepareDrawMatrix(matrix, camera);
if (__shouldDoZoomFactor()) {
__prepareZoomFactor(_rect2, camera);
matrix.setTo(
matrix.a * _rect2.width, matrix.b * _rect2.height,
matrix.c * _rect2.width, matrix.d * _rect2.height,
(matrix.tx - _rect2.x) * _rect2.width + _rect2.x,
(matrix.ty - _rect2.y) * _rect2.height + _rect2.y,
);
}
}
override function checkFlipX() {
return super.checkFlipX() != camera.flipX;
}
override function checkFlipY() {
return super.checkFlipY() != camera.flipY;
} }
} }
+6 -2
View File
@@ -114,8 +114,12 @@ class MusicBeatTransition extends MusicBeatSubstate {
} }
if (transitionSprite != null) { if (transitionSprite != null) {
transitionSprite.setGraphicSize(transitionCamera.width, transitionCamera.height); if (transitionSprite.animateAtlas == null) {
transitionSprite.updateHitbox(); transitionSprite.setGraphicSize(transitionCamera.width, transitionCamera.height);
transitionSprite.updateHitbox();
} else {
transitionSprite.screenCenter();
}
} }
} }
@@ -5,22 +5,9 @@ import funkin.backend.assets.TranslatedAssetLibrary;
#end #end
import funkin.backend.assets.IModsAssetLibrary; import funkin.backend.assets.IModsAssetLibrary;
import lime.utils.AssetLibrary; import lime.utils.AssetLibrary;
import haxe.ds.Map;
class AssetsLibraryList extends AssetLibrary { class AssetsLibraryList extends AssetLibrary {
public var libraries:Array<AssetLibrary> = []; public var libraries:Array<AssetLibrary> = [];
public var cleanLibraries(get, never):Array<AssetLibrary>;
function get_cleanLibraries():Array<AssetLibrary> {
return [for (l in libraries) getCleanLibrary(l)];
}
// is true if any library in `libraries` contains some kind of compressed library.
public var hasCompressedLibrary(get, never):Bool;
function get_hasCompressedLibrary():Bool {
for (l in libraries) if (getCleanLibrary(l).isCompressed) return true;
return false;
}
@:allow(funkin.backend.system.Main) @:allow(funkin.backend.system.Main)
@:allow(funkin.backend.system.MainState) @:allow(funkin.backend.system.MainState)
@@ -154,16 +141,6 @@ class AssetsLibraryList extends AssetLibrary {
public override inline function getAsset(id:String, type:String):Dynamic public override inline function getAsset(id:String, type:String):Dynamic
return getSpecificAsset(id, type, BOTH); return getSpecificAsset(id, type, BOTH);
public override function list(type:String):Array<String> {
// idk if there's a more efficient way tbh, correct if u find better
var files:Map<String, Bool> = [];
for(k=>l in libraries) {
for(f in l.list(type))
files.set(f, false);
}
return [for(k=>e in files) k];
}
public override function isLocal(id:String, type:String) { public override function isLocal(id:String, type:String) {
return true; return true;
} }
+21 -13
View File
@@ -83,11 +83,10 @@ class ModsFolder {
*/ */
public static function loadModLib(path:String, force:Bool = false, ?modName:String) { public static function loadModLib(path:String, force:Bool = false, ?modName:String) {
#if MOD_SUPPORT #if MOD_SUPPORT
for (ext in Flags.ALLOWED_ZIP_EXTENSIONS) { if (FileSystem.exists('$path.zip'))
if (!FileSystem.exists('$path.$ext')) continue; return loadLibraryFromZip('$path'.toLowerCase(), '$path.zip', force, modName);
return loadLibraryFromZip('$path'.toLowerCase(), '$path.$ext', force, modName); else
} return loadLibraryFromFolder('$path'.toLowerCase(), '$path', force, modName);
return loadLibraryFromFolder('$path'.toLowerCase(), '$path', force, modName);
#else #else
return null; return null;
@@ -97,16 +96,27 @@ class ModsFolder {
public static function getModsList():Array<String> { public static function getModsList():Array<String> {
var mods:Array<String> = []; var mods:Array<String> = [];
#if MOD_SUPPORT #if MOD_SUPPORT
// Mods directory does not exist yet, create it if (!FileSystem.exists(modsPath)) {
if (!FileSystem.exists(modsPath)) FileSystem.createDirectory(modsPath); // Mods directory does not exist yet, create it
FileSystem.createDirectory(modsPath);
}
final modsList:Array<String> = FileSystem.readDirectory(modsPath); final modsList:Array<String> = FileSystem.readDirectory(modsPath);
if (modsList == null || modsList.length <= 0) return mods; if (modsList == null || modsList.length <= 0)
return mods;
for (modFolder in modsList) { for (modFolder in modsList) {
if (FileSystem.isDirectory(modsPath + modFolder)) mods.push(modFolder); if (FileSystem.isDirectory(modsPath + modFolder)) {
else if (Flags.ALLOWED_ZIP_EXTENSIONS.contains(Path.extension(modFolder))) mods.push(Path.withoutExtension(modFolder)); mods.push(modFolder);
} else {
var ext = Path.extension(modFolder).toLowerCase();
switch(ext) {
case 'zip':
// is a zip mod!!
mods.push(Path.withoutExtension(modFolder));
}
}
} }
#end #end
return mods; return mods;
@@ -118,9 +128,7 @@ class ModsFolder {
#if TRANSLATIONS_SUPPORT #if TRANSLATIONS_SUPPORT
if(skipTranslated && (l is TranslatedAssetLibrary)) continue; if(skipTranslated && (l is TranslatedAssetLibrary)) continue;
#end #end
// No need to check for it being a `ScriptedAssetLibrary`, if `ScriptedAssetLibrary` extends ModsFolderLibrary, which implements `IModsAssetLibrary` if (l is ScriptedAssetLibrary || l is IModsAssetLibrary) libs.push(cast(l, IModsAssetLibrary));
// If you have to revert this change then uhhhhh wasn't me, trust 🙏
if (/*l is ScriptedAssetLibrary ||*/ l is IModsAssetLibrary) libs.push(cast(l, IModsAssetLibrary));
} }
return libs; return libs;
} }
@@ -149,22 +149,6 @@ class ModsFolderLibrary extends AssetLibrary implements IModsAssetLibrary {
} }
return true; return true;
} }
public override function list(type:String):Array<String> {
var result = [];
__listAppend(result, '');
return result;
}
function __listAppend(arr:Array<String>, folder:String) {
for(file in FileSystem.readDirectory('$basePath/$folder')) {
var fullPath = '$basePath/$folder/$file';
if (FileSystem.isDirectory(fullPath))
__listAppend(arr, '$folder$file/');
else
arr.push('$prefix$folder$file');
}
}
#end #end
// Backwards compat // Backwards compat
+3 -9
View File
@@ -8,7 +8,6 @@ import funkin.backend.scripting.Script;
import haxe.io.Path; import haxe.io.Path;
import lime.utils.AssetLibrary; import lime.utils.AssetLibrary;
import openfl.utils.Assets as OpenFlAssets; import openfl.utils.Assets as OpenFlAssets;
import animate.FlxAnimateFrames;
using StringTools; using StringTools;
@@ -175,9 +174,6 @@ class Paths
inline static public function getSparrowAtlas(key:String, ?library:String, ?ext:String) inline static public function getSparrowAtlas(key:String, ?library:String, ?ext:String)
return FlxAtlasFrames.fromSparrow(image(key, library, ext), file('images/$key.xml', library)); return FlxAtlasFrames.fromSparrow(image(key, library, ext), file('images/$key.xml', library));
inline static public function getAnimateAtlasAlt(key:String, ?settings:FlxAnimateSettings)
return FlxAnimateFrames.fromAnimate(key, null, null, null, false, settings);
inline static public function getSparrowAtlasAlt(key:String, ?ext:String) inline static public function getSparrowAtlasAlt(key:String, ?ext:String)
return FlxAtlasFrames.fromSparrow('$key.${ext != null ? ext : Flags.IMAGE_EXT}', '$key.xml'); return FlxAtlasFrames.fromSparrow('$key.${ext != null ? ext : Flags.IMAGE_EXT}', '$key.xml');
@@ -201,7 +197,7 @@ class Paths
* @param key Path to the frames * @param key Path to the frames
* @param library (Additional) library to load the frames from. * @param library (Additional) library to load the frames from.
*/ */
public static function getFrames(key:String, assetsPath:Bool = false, ?library:String, ?ext:String = null, ?animateSettings:FlxAnimateSettings) { public static function getFrames(key:String, assetsPath:Bool = false, ?library:String, ?ext:String = null) {
if (tempFramesCache.exists(key)) { if (tempFramesCache.exists(key)) {
var frames = tempFramesCache[key]; var frames = tempFramesCache[key];
if (frames != null && frames.parent != null && frames.parent.bitmap != null && frames.parent.bitmap.readable) if (frames != null && frames.parent != null && frames.parent.bitmap != null && frames.parent.bitmap.readable)
@@ -209,7 +205,7 @@ class Paths
else else
tempFramesCache.remove(key); tempFramesCache.remove(key);
} }
return tempFramesCache[key] = loadFrames(assetsPath ? key : Paths.image(key, library, true, ext), false, null, false, ext, animateSettings); return tempFramesCache[key] = loadFrames(assetsPath ? key : Paths.image(key, library, true, ext), false, null, false, ext);
} }
/** /**
@@ -246,7 +242,7 @@ class Paths
* @param Ext Extension of the image. * @param Ext Extension of the image.
* @return FlxFramesCollection Frames * @return FlxFramesCollection Frames
*/ */
static function loadFrames(path:String, Unique:Bool = false, Key:String = null, SkipAtlasCheck:Bool = false, SkipMultiCheck:Bool = false, ?Ext:String = null, ?animateSettings:FlxAnimateSettings):FlxFramesCollection { static function loadFrames(path:String, Unique:Bool = false, Key:String = null, SkipAtlasCheck:Bool = false, SkipMultiCheck:Bool = false, ?Ext:String = null):FlxFramesCollection {
var noExt = Path.withoutExtension(path); var noExt = Path.withoutExtension(path);
var ext = Ext != null ? Ext : Flags.IMAGE_EXT; var ext = Ext != null ? Ext : Flags.IMAGE_EXT;
@@ -267,8 +263,6 @@ class Paths
cur++; cur++;
} }
return finalFrames; return finalFrames;
} else if (Assets.exists('$noExt/Animation.json')) {
return Paths.getAnimateAtlasAlt(noExt, animateSettings);
} else if (Assets.exists('$noExt.xml')) { } else if (Assets.exists('$noExt.xml')) {
return Paths.getSparrowAtlasAlt(noExt, ext); return Paths.getSparrowAtlasAlt(noExt, ext);
} else if (Assets.exists('$noExt.txt')) { } else if (Assets.exists('$noExt.txt')) {
@@ -108,8 +108,6 @@ class TranslatedAssetLibrary extends AssetLibrary implements IModsAssetLibrary {
return null; return null;
} }
// TODO: list support for TranslatedAssetLibrary (idk how it works)
#if MOD_SUPPORT #if MOD_SUPPORT
public var _parsedAsset:String = null; // Theres no need to actually make this work - Nex public var _parsedAsset:String = null; // Theres no need to actually make this work - Nex
@@ -1,14 +1,11 @@
package funkin.backend.assets; package funkin.backend.assets;
import funkin.backend.system.Flags;
import haxe.io.Path; import haxe.io.Path;
import lime.graphics.Image; import lime.graphics.Image;
import lime.media.AudioBuffer; import lime.media.AudioBuffer;
import lime.text.Font; import lime.text.Font;
import lime.utils.Bytes; import lime.utils.Bytes;
import openfl.utils.AssetLibrary; import openfl.utils.AssetLibrary;
import sys.io.File;
#if MOD_SUPPORT #if MOD_SUPPORT
import funkin.backend.utils.SysZip.SysZipEntry; import funkin.backend.utils.SysZip.SysZipEntry;
@@ -18,16 +15,15 @@ class ZipFolderLibrary extends AssetLibrary implements IModsAssetLibrary {
public var basePath:String; public var basePath:String;
public var modName:String; public var modName:String;
public var libName:String; public var libName:String;
public var useImageCache:Bool = false;
public var prefix = 'assets/'; public var prefix = 'assets/';
public var zip:SysZip; public var zip:SysZip;
public var assets:Map<String, SysZipEntry> = []; public var assets:Map<String, SysZipEntry> = [];
public var lowerCaseAssets:Map<String, SysZipEntry> = []; public var lowerCaseAssets:Map<String, SysZipEntry> = [];
public var nameMap:Map<String, String> = []; public var nameMap:Map<String, String> = [];
public var PRELOAD_VIDEOS:Bool = true; public function new(basePath:String, libName:String, ?modName:String) {
public function new(basePath:String, libName:String, ?modName:String, ?preloadVideos:Bool = true) {
this.libName = libName; this.libName = libName;
this.basePath = basePath; this.basePath = basePath;
@@ -35,59 +31,21 @@ class ZipFolderLibrary extends AssetLibrary implements IModsAssetLibrary {
this.modName = (modName == null) ? libName : modName; this.modName = (modName == null) ? libName : modName;
zip = SysZip.openFromFile(basePath); zip = SysZip.openFromFile(basePath);
zip.read();
for(entry in zip.entries) { for(entry in zip.entries) {
if (entry.fileName.length < 0 || entry.fileName.endsWith("/")) continue; lowerCaseAssets[entry.fileName.toLowerCase()] = assets[entry.fileName.toLowerCase()] = assets[entry.fileName] = entry;
nameMap.set(entry.fileName.toLowerCase(), entry.fileName);
var name:String = entry.fileName.toLowerCase(); // calling .toLowerCase a million times is never the solution
lowerCaseAssets[name] = assets[name] = assets[entry.fileName] = entry;
nameMap.set(name, entry.fileName);
} }
super(); super();
isCompressed = true;
// don't override default value of true if the file exists.
// by default `PRELOAD_VIDEOS` is true so you will never need to add this file, but in the case of it being false this is a backup method.
PRELOAD_VIDEOS = (!PRELOAD_VIDEOS) ? exists("assets/data/PRECACHE_VIDEOS", "TEXT") : PRELOAD_VIDEOS;
// if (PRELOAD_VIDEOS) precacheVideos(); // we do this in `MainState` now to handle for `Flags.VIDEO_EXT` :)
}
public function precacheVideos() {
_videoExtensions = [Flags.VIDEO_EXT];
videoCacheRemap = [];
for (entry in zip.entries) {
var name = entry.fileName.toLowerCase();
if (_videoExtensions.contains(Path.extension(name))) getPath(prefix+name);
}
var count:Int = 0;
for (_ in videoCacheRemap.keys()) count++;
if (count <= 0) return;
trace('Precached $count video${(count == 1) ? "" : "s"}');
}
// Now we have supports for videos in ZIP!!
public var _videoExtensions:Array<String> = [Flags.VIDEO_EXT];
public var videoCacheRemap:Map<String, String> = [];
public function getVideoRemap(originalPath:String):String {
if (!_videoExtensions.contains(Path.extension(_parsedAsset))) return originalPath;
if (videoCacheRemap.exists(originalPath)) return videoCacheRemap.get(originalPath);
// We adding the length of the string to counteract folder in folder naming duplicates.
var newPath = './.temp/${_parsedAsset.length}-zipvideo-${_parsedAsset.split("/").pop()}';
File.saveBytes(newPath, unzip(assets[_parsedAsset]));
videoCacheRemap.set(originalPath, newPath);
return newPath;
} }
function toString():String { function toString():String {
return '(ZipFolderLibrary: $libName/$modName | ${zip.entries.length} entries | Detected Video Extensions: ${_videoExtensions.join(", ")})'; return '(ZipFolderLibrary: $libName/$modName)';
} }
public var _parsedAsset:String; public var _parsedAsset:String;
public override function getAudioBuffer(id:String):AudioBuffer { public override function getAudioBuffer(id:String):AudioBuffer {
__parseAsset(id); __parseAsset(id);
return AudioBuffer.fromBytes(unzip(assets[_parsedAsset])); return AudioBuffer.fromBytes(unzip(assets[_parsedAsset]));
@@ -110,12 +68,15 @@ class ZipFolderLibrary extends AssetLibrary implements IModsAssetLibrary {
return getAssetPath(); return getAssetPath();
} }
public inline function unzip(f:SysZipEntry) return (f == null) ? null : zip.unzipEntry(f);
public inline function unzip(f:SysZipEntry)
return f == null ? null : zip.unzipEntry(f);
public function __parseAsset(asset:String):Bool { public function __parseAsset(asset:String):Bool {
if (!asset.startsWith(prefix)) return false; if (!asset.startsWith(prefix)) return false;
_parsedAsset = asset.substr(prefix.length); _parsedAsset = asset.substr(prefix.length);
if (ModsFolder.useLibFile) { if(ModsFolder.useLibFile) {
var file = new haxe.io.Path(_parsedAsset); var file = new haxe.io.Path(_parsedAsset);
if(file.file.startsWith("LIB_")) { if(file.file.startsWith("LIB_")) {
var library = file.file.substr(4); var library = file.file.substr(4);
@@ -126,7 +87,8 @@ class ZipFolderLibrary extends AssetLibrary implements IModsAssetLibrary {
} }
_parsedAsset = _parsedAsset.toLowerCase(); _parsedAsset = _parsedAsset.toLowerCase();
if (nameMap.exists(_parsedAsset)) _parsedAsset = nameMap.get(_parsedAsset); if(nameMap.exists(_parsedAsset))
_parsedAsset = nameMap.get(_parsedAsset);
return true; return true;
} }
@@ -141,8 +103,9 @@ class ZipFolderLibrary extends AssetLibrary implements IModsAssetLibrary {
return assets[_parsedAsset] != null; return assets[_parsedAsset] != null;
} }
private inline function getAssetPath() { private function getAssetPath() {
return getVideoRemap('$basePath/$_parsedAsset'); trace('[ZIP]$basePath/$_parsedAsset');
return '[ZIP]$basePath/$_parsedAsset';
} }
// TODO: rewrite this to 1 function, like ModsFolderLibrary // TODO: rewrite this to 1 function, like ModsFolderLibrary
@@ -191,6 +154,14 @@ class ZipFolderLibrary extends AssetLibrary implements IModsAssetLibrary {
return content; return content;
} }
public override function list(type:String):Array<String> { return [for(k=>e in nameMap) '$prefix$e']; } // Backwards compat
@:noCompletion public var zipPath(get, set):String;
@:noCompletion private inline function get_zipPath():String {
return basePath;
}
@:noCompletion private inline function set_zipPath(value:String):String {
return basePath = value;
}
} }
#end #end
+38 -7
View File
@@ -97,6 +97,41 @@ class Chart {
data.setFieldDefault("vocalsSuffix", ""); data.setFieldDefault("vocalsSuffix", "");
data.setFieldDefault("needsVoices", true); data.setFieldDefault("needsVoices", true);
data.setFieldDefault("difficulties", []); data.setFieldDefault("difficulties", []);
var songNameLower = songName.toLowerCase();
var metaPath = Paths.file('songs/${songNameLower}/meta.json');
var metaDiffPath = Paths.file('songs/${songNameLower}/meta-${difficulty.toLowerCase()}.json');
var blacklist:Array<String> = [];
var data:ChartMetaData = null;
var fromMods:Bool = fromMods;
for (path in [metaDiffPath, metaPath]) {
if (Assets.exists(path)) {
fromMods = Paths.assetsTree.existsSpecific(path, "TEXT", MODS);
try {
var temp = CoolUtil.parseJson(path);
// Backwards compatibility (they both can be null so != true) - Nex
var coopExlc = false;
if (Reflect.hasField(temp, "coopAllowed") && Reflect.field(temp, "coopAllowed") != true) {
blacklist = blacklist.concat(["codename.coop", "codename.coop-opponent"]);
Reflect.deleteField(temp, "coopAllowed");
coopExlc = true;
}
if (Reflect.hasField(temp, "opponentModeAllowed") && Reflect.field(temp, "opponentModeAllowed") != true) {
if (!coopExlc) blacklist.push("codename.coop-opponent");
blacklist.push("codename.opponent");
Reflect.deleteField(temp, "opponentModeAllowed");
}
data = temp;
} catch(e) {
Logs.trace('Failed to load song metadata for ${songName} ($path): ${Std.string(e)}', ERROR);
}
if (data != null) break;
}
}
data.setFieldDefault("excludedGameModes", blacklist);
data.setFieldDefault("variants", []); data.setFieldDefault("variants", []);
data.setFieldDefault("metas", []); data.setFieldDefault("metas", []);
@@ -278,13 +313,9 @@ class Chart {
var filteredChart = filterChartForSaving(chart, saveSettings.saveMetaInChart, saveSettings.saveLocalEvents, saveSettings.saveGlobalEvents && saveSettings.seperateGlobalEvents != true); var filteredChart = filterChartForSaving(chart, saveSettings.saveMetaInChart, saveSettings.saveLocalEvents, saveSettings.saveGlobalEvents && saveSettings.seperateGlobalEvents != true);
#if sys #if sys
var songPath = saveSettings.songFolder == null ? 'songs/${chart.meta.name}' : saveSettings.songFolder, variantSuffix = variant != null && variant != "" ? '-$variant' : "", difficultySuffix = difficulty != null && difficulty != "" ? '-$difficulty' : ""; var songPath = saveSettings.songFolder == null ? 'songs/${chart.meta.name}' : saveSettings.songFolder, variantSuffix = variant != null && variant != "" ? '-$variant' : "";
var metaPath = 'meta$variantSuffix.json', altMetaPath = 'meta${variantSuffix}${difficultySuffix}.json', prettyPrint = saveSettings.prettyPrint == true ? Flags.JSON_PRETTY_PRINT : null, temp:String; var metaPath = 'meta$variantSuffix.json', prettyPrint = saveSettings.prettyPrint == true ? Flags.JSON_PRETTY_PRINT : null, temp:String;
if ((temp = Paths.assetsTree.getPath('assets/$songPath/$altMetaPath')) != null) { //check for difficulty specific if ((temp = Paths.assetsTree.getPath('assets/$songPath/$metaPath')) != null) {
songPath = temp.substr(0, temp.length - altMetaPath.length - 1);
metaPath = temp;
}
else if ((temp = Paths.assetsTree.getPath('assets/$songPath/$metaPath')) != null) {
songPath = temp.substr(0, temp.length - metaPath.length - 1); songPath = temp.substr(0, temp.length - metaPath.length - 1);
metaPath = temp; metaPath = temp;
} }
+1 -2
View File
@@ -32,8 +32,7 @@ typedef ChartMetaData = {
public var ?icon:String; public var ?icon:String;
public var ?color:FlxColor; public var ?color:FlxColor;
public var ?coopAllowed:Bool; public var ?excludedGameModes:Array<String>;
public var ?opponentModeAllowed:Bool;
public var ?metas:Map<String, ChartMetaData>; public var ?metas:Map<String, ChartMetaData>;
public var ?instSuffix:String; public var ?instSuffix:String;
+1 -1
View File
@@ -75,7 +75,7 @@ class EventsData {
defValue: "In" defValue: "In"
}, },
{name: "Mode", type: TDropDown(['direct', 'stage']), defValue: "direct"}, {name: "Mode", type: TDropDown(['direct', 'stage']), defValue: "direct"},
{name: "Multiplicative?", type: TBool, defValue: false} {name: "Multiplicative?", type: TBool, defValue: true}
], ],
"Camera Modulo Change" => [ "Camera Modulo Change" => [
{name: "Modulo Interval", type: TInt(1, 9999999, 1), defValue: 4}, {name: "Modulo Interval", type: TInt(1, 9999999, 1), defValue: 4},
@@ -106,15 +106,12 @@ class GlobalScript {
public static function onModSwitch(newMod:String) { public static function onModSwitch(newMod:String) {
destroy(); destroy();
scripts = new ScriptPack("GlobalScript"); scripts = new ScriptPack("GlobalScript");
for (lib in funkin.backend.assets.ModsFolder.getLoadedModsLibs()) { for (i in funkin.backend.assets.ModsFolder.getLoadedMods()) {
var modName = lib.modName; var path = Paths.script('data/global/LIB_$i');
var path = Paths.script('data/global/LIB_$modName');
var script = Script.create(path); var script = Script.create(path);
if (script is DummyScript) continue; if (script is DummyScript)
script.remappedNames.set(script.fileName, '$modName:${script.fileName}'); continue;
// so you can get the current mod's library in GloablScript :) script.remappedNames.set(script.fileName, '$i:${script.fileName}');
// you should not make this a static variable then all scripts will try to reference the 1 static variable, which will be overwritten :yoikes:
script.set("MOD_LIBRARY", lib);
scripts.add(script); scripts.add(script);
script.load(); script.load();
} }
+2 -2
View File
@@ -91,7 +91,7 @@ class Script extends FlxBasic implements IFlxDestroyable {
"FunkinShader" => funkin.backend.shaders.FunkinShader, "FunkinShader" => funkin.backend.shaders.FunkinShader,
"CustomShader" => funkin.backend.shaders.CustomShader, "CustomShader" => funkin.backend.shaders.CustomShader,
"FunkinText" => funkin.backend.FunkinText, "FunkinText" => funkin.backend.FunkinText,
"FlxAnimate" => animate.FlxAnimate, "FlxAnimate" => funkin.backend.FlxAnimate,
"FunkinSprite" => funkin.backend.FunkinSprite, "FunkinSprite" => funkin.backend.FunkinSprite,
"Alphabet" => funkin.menus.ui.Alphabet, "Alphabet" => funkin.menus.ui.Alphabet,
"Flags" => funkin.backend.system.Flags, "Flags" => funkin.backend.system.Flags,
@@ -402,4 +402,4 @@ class Script extends FlxBasic implements IFlxDestroyable {
* Called when the script is loaded. * Called when the script is loaded.
*/ */
public function onLoad() {} public function onLoad() {}
} }
@@ -4,6 +4,7 @@ import flixel.util.FlxDestroyUtil.IFlxDestroyable;
@:allow(funkin.backend.scripting.ScriptPack) @:allow(funkin.backend.scripting.ScriptPack)
@:autoBuild(funkin.backend.system.macros.EventMacro.build()) @:autoBuild(funkin.backend.system.macros.EventMacro.build())
@:noCustomClass
class CancellableEvent implements IFlxDestroyable { class CancellableEvent implements IFlxDestroyable {
@:dox(hide) public var cancelled:Bool = false; @:dox(hide) public var cancelled:Bool = false;
@:dox(hide) private var __continueCalls:Bool = true; @:dox(hide) private var __continueCalls:Bool = true;
@@ -53,4 +54,4 @@ class CancellableEvent implements IFlxDestroyable {
public function destroy() { public function destroy() {
data = null; data = null;
} }
} }
@@ -1,5 +1,7 @@
package funkin.backend.scripting.events.menu.freeplay; package funkin.backend.scripting.events.menu.freeplay;
import funkin.menus.FreeplayState.FreeplayGameMode;
final class FreeplaySongSelectEvent extends CancellableEvent { final class FreeplaySongSelectEvent extends CancellableEvent {
/** /**
* Song name that is about to be played * Song name that is about to be played
@@ -14,11 +16,26 @@ final class FreeplaySongSelectEvent extends CancellableEvent {
*/ */
public var variant:String; public var variant:String;
/** /**
* Whenever opponent mode is enabled or not. * Used game mode's data.
*/ */
public var opponentMode:Bool; public var gameMode:FreeplayGameMode;
/**
* Whenever coop mode is enabled.
*/ // Backwards compat
public var coopMode:Bool; @:noCompletion public var opponentMode(get, set):Bool;
@:noCompletion private function get_opponentMode() return gameMode.modeID == "codename.opponent" || gameMode.modeID == "codename.coop-opponent";
@:noCompletion private function set_opponentMode(val:Bool) {
gameMode = coopMode ?
(val ? new FreeplayGameMode("Co-Op Mode (Switched)", "codename.coop-opponent", ["coop-switched", "opponent", "coop"]) : new FreeplayGameMode("Opponent Mode", "codename.opponent", ["opponent"])) :
(val ? new FreeplayGameMode("Opponent Mode", "codename.opponent", ["opponent"]) : null);
return val;
}
@:noCompletion public var coopMode(get, set):Bool;
@:noCompletion private function get_coopMode() return gameMode.modeID == "codename.coop" || gameMode.modeID == "codename.coop-opponent";
@:noCompletion private function set_coopMode(val:Bool) {
gameMode = opponentMode ?
(val ? new FreeplayGameMode("Co-Op Mode (Switched)", "codename.coop-opponent", ["coop-switched", "opponent", "coop"]) : new FreeplayGameMode("Co-Op Mode", "codename.coop", ["coop"])) :
(val ? new FreeplayGameMode("Co-Op Mode", "codename.coop", ["coop"]) : null);
return val;
}
} }
+10 -10
View File
@@ -13,16 +13,14 @@ import lime.utils.AssetType;
/** /**
* A class that reads the `flags.ini` file, allowing to read settable Flags (customs too). * A class that reads the `flags.ini` file, allowing to read settable Flags (customs too).
*/ */
@:build(funkin.backend.system.macros.FlagMacro.build()) @:build(funkin.backend.system.macros.FlagMacro.build("onReset"))
class Flags { class Flags {
public static var overridenFlags:Map<String, Bool> = []; public static var overridenFlags:Map<String, Bool> = [];
// -- Codename's Addon Config -- // -- Codename's Addon Config --
@:bypass public static var addonFlags:Map<String, Dynamic> = []; @:bypass public static var addonFlags:Map<String, Dynamic> = [];
public static var CURRENT_API_VERSION:Int = 2;
// -- Codename's ZipFolderLibrary Config -- public static var CURRENT_API_VERSION:Int = 2;
public static var ALLOWED_ZIP_EXTENSIONS:Array<String> = ["zip"];
// -- Codename's Mod Config -- // -- Codename's Mod Config --
public static var MOD_NAME:String = ""; public static var MOD_NAME:String = "";
@@ -159,12 +157,10 @@ class Flags {
public static var DEFAULT_HUD_ZOOM_LERP:Float = 0.05; public static var DEFAULT_HUD_ZOOM_LERP:Float = 0.05;
public static var USE_LEGACY_ZOOM_FACTOR:Null<Bool> = null; public static var USE_LEGACY_ZOOM_FACTOR:Null<Bool> = null;
// Font configuration // Font configuration
public static var DEFAULT_FONT:String = "vcr.ttf"; public static var DEFAULT_FONT:String = "vcr.ttf";
public static var DEFAULT_FONT_SIZE:Int = 16; public static var DEFAULT_FONT_SIZE:Int = 16;
public static var DEFAULT_ALT_ANIM_SUFFIX:String = "-alt";
// to translate these you need to convert them into ids // to translate these you need to convert them into ids
// Resume -> pause.resume // Resume -> pause.resume
@@ -316,6 +312,11 @@ class Flags {
if (SUSTAINS_AS_ONE_NOTE == null) SUSTAINS_AS_ONE_NOTE = MOD_API_VERSION >= 2; if (SUSTAINS_AS_ONE_NOTE == null) SUSTAINS_AS_ONE_NOTE = MOD_API_VERSION >= 2;
} }
private static function onReset() {
var currentModFolder = ModsFolder.currentModFolder;
if (currentModFolder != null) SAVE_NAME = currentModFolder;
}
public static function loadFromDatas(datas:Array<String>):Map<String, String> { public static function loadFromDatas(datas:Array<String>):Map<String, String> {
var flags:Map<String, String> = []; var flags:Map<String, String> = [];
for (data in datas) { for (data in datas) {
@@ -336,9 +337,8 @@ class Flags {
if (!(parsed = parse(name, value))) customFlags.set(name, value); if (!(parsed = parse(name, value))) customFlags.set(name, value);
if (!overridenFlags.exists(name)) overridenFlags.set(name, parsed); if (!overridenFlags.exists(name)) overridenFlags.set(name, parsed);
} }
#if MODCHARTING_FEATURES
Options.modchartingHoldSubdivisions = DEFAULT_MODCHART_HOLD_SUBDIVISIONS; Options.modchartingHoldSubdivisions = DEFAULT_MODCHART_HOLD_SUBDIVISIONS;
#end
} }
/** /**
@@ -389,4 +389,4 @@ class Flags {
} }
loadPost(); loadPost();
} }
} }
+14 -43
View File
@@ -7,14 +7,12 @@ import flixel.FlxState;
import funkin.backend.assets.AssetsLibraryList; import funkin.backend.assets.AssetsLibraryList;
import funkin.backend.assets.ModsFolder; import funkin.backend.assets.ModsFolder;
import funkin.backend.assets.ModsFolderLibrary; import funkin.backend.assets.ModsFolderLibrary;
import funkin.backend.assets.ZipFolderLibrary;
import funkin.backend.chart.EventsData; import funkin.backend.chart.EventsData;
import funkin.backend.system.framerate.Framerate; import funkin.backend.system.framerate.Framerate;
import funkin.editors.ModConfigWarning; import funkin.editors.ModConfigWarning;
import funkin.menus.TitleState; import funkin.menus.TitleState;
import haxe.io.Path; import haxe.io.Path;
@dox(hide) @dox(hide)
typedef AddonInfo = { typedef AddonInfo = {
var name:String; var name:String;
@@ -59,32 +57,12 @@ class MainState extends FlxState {
var _highPriorityAddons:Array<AddonInfo> = []; var _highPriorityAddons:Array<AddonInfo> = [];
var _noPriorityAddons:Array<AddonInfo> = []; var _noPriorityAddons:Array<AddonInfo> = [];
var quick_modsPath = ModsFolder.modsPath + ModsFolder.currentModFolder;
// handing if the loading mod (before it's properly loaded) is a compressed mod
// we just need to use `Paths.assetsTree.hasCompressedLibrary` to complete valid checks for actual loaded compressed mods
var isZipMod = false;
// If we know it's a compressed mod, then we can check if it's using the `cnemod` folder path.
// All it is really is a folder with the mod's name, then a compressed file called "cnemod.[zip|7z|rar|etc]"
var isCneMod = false;
// We are doing it like this because think about it: it's 1 for loop lol
// We just need to know if any of these values is true, so if only one is true and we are not close to being done in the loop, that's fine.
//
for (ext in Flags.ALLOWED_ZIP_EXTENSIONS) {
if (FileSystem.exists(quick_modsPath+"."+ext)) isZipMod = true;
if (FileSystem.exists(quick_modsPath+"/cnemod."+ext)) isCneMod = true;
if (isZipMod && isCneMod) break;
}
// We get the addons folder from relative space (`./`) and then our mod's addons.
var addonPaths = [ var addonPaths = [
ModsFolder.addonsPath, ModsFolder.addonsPath,
// So to check the mod's addons folder, we need to decompress it. Which is impossible* in this stage of the loading library process. (
// TODO: Write a function when the library is loaded to decompress the contents and then load the libraries :) ModsFolder.currentModFolder != null ?
( (ModsFolder.currentModFolder != null && !isZipMod) ? ModsFolder.modsPath + ModsFolder.currentModFolder + "/addons/" :
quick_modsPath + "/addons/" : null null
) )
]; ];
@@ -94,8 +72,12 @@ class MainState extends FlxState {
for (addon in FileSystem.readDirectory(path)) { for (addon in FileSystem.readDirectory(path)) {
if (!FileSystem.isDirectory(path + addon)) { if (!FileSystem.isDirectory(path + addon)) {
if (Flags.ALLOWED_ZIP_EXTENSIONS.contains(Path.extension(addon))) addon = Path.withoutExtension(addon); switch(Path.extension(addon).toLowerCase()) {
else continue; case 'zip':
addon = Path.withoutExtension(addon);
default:
continue;
}
} }
var data:AddonInfo = { var data:AddonInfo = {
@@ -118,14 +100,9 @@ class MainState extends FlxState {
#if MOD_SUPPORT #if MOD_SUPPORT
for (addon in _lowPriorityAddons) for (addon in _lowPriorityAddons)
loadLib(addon.path, ltrim(addon.name, "[LOW]")); loadLib(addon.path, ltrim(addon.name, "[LOW]"));
if (ModsFolder.currentModFolder != null) { if (ModsFolder.currentModFolder != null)
// isCneMod is a guarentee to be a zip mod because we just checked for it, so this will always load as a CompressedLibrary loadLib(ModsFolder.modsPath + ModsFolder.currentModFolder, ModsFolder.currentModFolder);
if (isCneMod)
loadLib(quick_modsPath + "/cnemod", ModsFolder.currentModFolder);
else
loadLib(quick_modsPath, ModsFolder.currentModFolder);
}
for (addon in _noPriorityAddons) for (addon in _noPriorityAddons)
loadLib(addon.path, addon.name); loadLib(addon.path, addon.name);
@@ -157,15 +134,9 @@ class MainState extends FlxState {
CoolUtil.safeAddAttributes('./.temp/', NativeAPI.FileAttribute.HIDDEN); CoolUtil.safeAddAttributes('./.temp/', NativeAPI.FileAttribute.HIDDEN);
#end #end
for (lib in ModsFolder.getLoadedModsLibs()) {
if (!(lib is ZipFolderLibrary)) continue;
if (cast(lib, ZipFolderLibrary).PRELOAD_VIDEOS) cast(lib, ZipFolderLibrary).precacheVideos();
}
var startState:Class<FlxState> = Flags.DISABLE_WARNING_SCREEN ? TitleState : funkin.menus.WarningState; var startState:Class<FlxState> = Flags.DISABLE_WARNING_SCREEN ? TitleState : funkin.menus.WarningState;
// In this case if the mod we just loaded a compressed modpack, we can't edit or modify files without decompressing it. if (Options.devMode && Options.allowConfigWarning) {
if (Options.devMode && Options.allowConfigWarning && !isZipMod) {
var lib:ModsFolderLibrary; var lib:ModsFolderLibrary;
for (e in Paths.assetsTree.libraries) if ((lib = cast AssetsLibraryList.getCleanLibrary(e)) is ModsFolderLibrary for (e in Paths.assetsTree.libraries) if ((lib = cast AssetsLibraryList.getCleanLibrary(e)) is ModsFolderLibrary
&& lib.modName == ModsFolder.currentModFolder) && lib.modName == ModsFolder.currentModFolder)
@@ -13,13 +13,8 @@ class CodenameBuildField extends TextField {
} }
public function reload() { public function reload() {
#if COMPILE_EXPERIMENTAL
text = '${Flags.VERSION_MESSAGE} (Experimental Build)';
#else
text = '${Flags.VERSION_MESSAGE}'; text = '${Flags.VERSION_MESSAGE}';
#end #if debug
#if (debug || COMPILE_EXPERIMENTAL)
text += '\n${Flags.COMMIT_MESSAGE}'; text += '\n${Flags.COMMIT_MESSAGE}';
#end #end
} }
@@ -53,6 +53,25 @@ class SystemInfo extends FramerateCategory {
if (osName != "") if (osName != "")
osInfo = '${osName} ${osVersion}'.trim(); osInfo = '${osName} ${osVersion}'.trim();
} }
#elseif windows
var windowsCurrentVersionPath = "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion";
var buildNumber = Std.parseInt(RegistryUtil.get(HKEY_LOCAL_MACHINE, windowsCurrentVersionPath, "CurrentBuildNumber"));
var edition = RegistryUtil.get(HKEY_LOCAL_MACHINE, windowsCurrentVersionPath, "ProductName");
var lcuKey = "WinREVersion"; // Last Cumulative Update Key On Older Windows Versions
if (buildNumber >= 22000) { // Windows 11 Initial Release Build Number
edition = edition.replace("Windows 10", "Windows 11");
lcuKey = "LCUVer"; // Last Cumulative Update Key On Windows 11
}
var lcuVersion = RegistryUtil.get(HKEY_LOCAL_MACHINE, windowsCurrentVersionPath, lcuKey);
osInfo = edition;
if (lcuVersion != null && lcuVersion != "")
osInfo += ' ${lcuVersion}';
else if (lime.system.System.platformVersion != null && lime.system.System.platformVersion != "")
osInfo += ' ${lime.system.System.platformVersion}';
#else #else
if (lime.system.System.platformLabel != null && lime.system.System.platformLabel != "" && lime.system.System.platformVersion != null && lime.system.System.platformVersion != "") if (lime.system.System.platformLabel != null && lime.system.System.platformLabel != "" && lime.system.System.platformVersion != null && lime.system.System.platformVersion != "")
osInfo = '${lime.system.System.platformLabel.replace(lime.system.System.platformVersion, "").trim()} ${lime.system.System.platformVersion}'; osInfo = '${lime.system.System.platformLabel.replace(lime.system.System.platformVersion, "").trim()} ${lime.system.System.platformVersion}';
@@ -62,10 +81,7 @@ class SystemInfo extends FramerateCategory {
try { try {
#if windows #if windows
var process = new HiddenProcess("wmic", ["cpu", "get", "name"]); cpuName = RegistryUtil.get(HKEY_LOCAL_MACHINE, "HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0", "ProcessorNameString");
if (process.exitCode() != 0) throw 'Could not fetch CPU information';
cpuName = process.stdout.readAll().toString().trim().split("\n")[1].trim();
#elseif mac #elseif mac
var process = new HiddenProcess("sysctl -a | grep brand_string"); // Somehow this isn't able to use the args but it still works var process = new HiddenProcess("sysctl -a | grep brand_string"); // Somehow this isn't able to use the args but it still works
if (process.exitCode() != 0) throw 'Could not fetch CPU information'; if (process.exitCode() != 0) throw 'Could not fetch CPU information';
@@ -1,134 +0,0 @@
package funkin.backend.system.macros;
#if macro
import sys.io.File;
import haxe.macro.ComplexTypeTools;
import haxe.macro.Printer;
import haxe.macro.Expr.Position;
import haxe.macro.Context;
import haxe.macro.Expr.Field;
import haxe.macro.Expr;
class AliasMacro {
public static var aliasMetadata:Metadata = [{
name: ":keep",
pos: Context.currentPos()
},{
name: ":dox",
pos: Context.currentPos(),
params: [
{
expr: EConst(CIdent("hide")),
pos: Context.currentPos()
}
]
}];
public static function build():Array<Field> {
#if display
return Context.getBuildFields();
#end
var fields = Context.getBuildFields();
var ogFieldCount = fields.length;
for(i in 0...ogFieldCount) {
var field = fields[i];
if (field.meta == null) continue;
var previousAliases:Array<{name:String, pos:Position}> = [];
for(meta in field.meta) {
if (meta.name == ":alias" && meta.params != null) {
for(p in meta.params) {
switch(p.expr) {
case EConst(CString(s, kind)):
previousAliases.push({
name: s,
pos: p.pos
});
default:
}
}
}
}
if (previousAliases.length == 0) continue;
var ghostAccess = field.access.copy();
ghostAccess.remove(AOverride);
ghostAccess.remove(APublic);
for(alias in previousAliases) {
var ghostField:Field = {
name: alias.name,
pos: alias.pos,
kind: null,
access: ghostAccess,
meta: aliasMetadata
};
switch(field.kind) {
case FFun(f):
var args:Array<Expr> = [for(a in f.args) {
expr: EConst(CIdent(a.name)),
pos: Context.currentPos()
}];
ghostField.kind = FFun({
args: f.args,
params: f.params,
ret: f.ret,
expr: macro return $i{field.name}($a{args})
});
default:
var type = null;
switch(field.kind) {
case FVar(t, e):
type = t;
case FProp(get, set, t, e):
type = t;
default:
}
ghostField.kind = FProp("get", "set", type, null);
fields.push({
name: 'get_${alias.name}',
kind: FFun({
args: [],
expr: macro return $i{field.name},
ret: type
}),
pos: alias.pos,
meta: aliasMetadata
});
fields.push({
name: 'set_${alias.name}',
kind: FFun({
args: [{
name: '_${field.name}',
type: type
}],
expr: macro return ($i{field.name} = $i{'_${field.name}'}),
ret: type
}),
pos: alias.pos,
meta: aliasMetadata
});
}
fields.push(ghostField);
}
var docFooter = '_Aliases: ${[for(alias in previousAliases) '`${alias.name}`'].join(", ")}_';
if (field.doc != null)
field.doc += '\n\n$docFooter';
else
field.doc = docFooter;
}
trace(fields);
return fields;
}
}
#end
@@ -19,7 +19,7 @@ class FlagMacro {
return false; return false;
} }
public static function build():Array<Field> { public static function build(resetCallback:String):Array<Field> {
var fields = Context.getBuildFields(); var fields = Context.getBuildFields();
var clRef = Context.getLocalClass(); var clRef = Context.getLocalClass();
@@ -248,7 +248,10 @@ class FlagMacro {
access: [APublic, AStatic], access: [APublic, AStatic],
kind: FFun({ kind: FFun({
args: [], args: [],
expr: macro $b{resetExprs}, expr: macro {
$b{resetExprs};
$i{resetCallback}();
},
ret: macro: Void ret: macro: Void
}), }),
pos: Context.currentPos(), pos: Context.currentPos(),
@@ -23,7 +23,7 @@ class Macros {
#if VIDEO_CUTSCENES "hxvlc.flixel", "hxvlc.openfl", #end #if VIDEO_CUTSCENES "hxvlc.flixel", "hxvlc.openfl", #end
#if NAPE_ENABLED "nape", "flixel.addons.nape", #end #if NAPE_ENABLED "nape", "flixel.addons.nape", #end
// BASE HAXE // BASE HAXE
"DateTools", "EReg", "Lambda", "StringBuf", "haxe.crypto", "haxe.display", "haxe.exceptions", "haxe.extern", "scripting", "animate" "DateTools", "EReg", "Lambda", "StringBuf", "haxe.crypto", "haxe.display", "haxe.exceptions", "haxe.extern", "scripting"
]) ])
Compiler.include(inc); Compiler.include(inc);
@@ -69,7 +69,6 @@ class Macros {
final fields:Array<Field> = Context.getBuildFields(), pos:Position = Context.currentPos(); final fields:Array<Field> = Context.getBuildFields(), pos:Position = Context.currentPos();
fields.push({name: 'tag', access: [APublic], pos: pos, kind: FVar(macro :funkin.backend.assets.AssetSource)}); fields.push({name: 'tag', access: [APublic], pos: pos, kind: FVar(macro :funkin.backend.assets.AssetSource)});
fields.push({name: 'isCompressed', access: [APublic], pos: pos, kind: FVar(macro :Bool, macro false)});
return fields; return fields;
} }
+16 -50
View File
@@ -21,6 +21,7 @@ import flixel.util.FlxAxes;
import flixel.util.FlxColor; import flixel.util.FlxColor;
import flixel.util.typeLimit.OneOfThree; import flixel.util.typeLimit.OneOfThree;
import flixel.util.typeLimit.OneOfTwo; import flixel.util.typeLimit.OneOfTwo;
import flxanimate.data.AnimationData.AnimAtlas;
import funkin.backend.system.Conductor; import funkin.backend.system.Conductor;
import funkin.backend.utils.XMLUtil.TextFormat; import funkin.backend.utils.XMLUtil.TextFormat;
import haxe.CallStack; import haxe.CallStack;
@@ -33,8 +34,6 @@ import haxe.xml.Access;
import lime.utils.Assets; import lime.utils.Assets;
import openfl.display.BitmapData; import openfl.display.BitmapData;
import openfl.geom.ColorTransform; import openfl.geom.ColorTransform;
import animate.FlxAnimateJson;
import flixel.animation.FlxAnimationController;
using StringTools; using StringTools;
@@ -440,9 +439,11 @@ final class CoolUtil
* @param fadeIn * @param fadeIn
*/ */
@:noUsing public static function playMenuSong(fadeIn:Bool = false) { @:noUsing public static function playMenuSong(fadeIn:Bool = false) {
if (FlxG.sound.music == null || !FlxG.sound.music.playing) { if (FlxG.sound.music == null || !FlxG.sound.music.playing)
{
playMusic(Paths.music(Flags.DEFAULT_MENU_MUSIC), true, fadeIn ? 0 : 1, true, 102); playMusic(Paths.music(Flags.DEFAULT_MENU_MUSIC), true, fadeIn ? 0 : 1, true, 102);
if (fadeIn) FlxG.sound.music.fadeIn(4, 0, 1); if (fadeIn)
FlxG.sound.music.fadeIn(4, 0, 0.7);
} }
} }
@@ -573,29 +574,6 @@ final class CoolUtil
anim2.frames = old; anim2.frames = old;
} }
/**
* Swaps two animations on an animation controller.
* @param animation Animation controller
* @param anim1 First animation
* @param anim2 Second animation
*/
public static function swapAnims(animation:FlxAnimationController, anim1:String, anim2:String) @:privateAccess {
var flxAnim1 = animation.getByName(anim1);
animation._animations.remove(anim1);
var flxAnim2 = animation.getByName(anim2);
animation._animations.remove(anim2);
if (flxAnim1 != null) {
flxAnim1.name = anim2;
animation._animations.set(anim2, flxAnim1);
}
if (flxAnim2 != null) {
flxAnim2.name = anim1;
animation._animations.set(anim1, flxAnim2);
}
}
/** /**
* Allows you to set a graphic size (ex: 150x150), with proper hitbox without a stretched sprite. * Allows you to set a graphic size (ex: 150x150), with proper hitbox without a stretched sprite.
* @param sprite Sprite to apply the new graphic size to * @param sprite Sprite to apply the new graphic size to
@@ -878,7 +856,7 @@ final class CoolUtil
*/ */
public static inline function browsePath(path:String) { public static inline function browsePath(path:String) {
var formattedPath:String = Path.normalize(path); var formattedPath:String = Path.normalize(path);
#if windows #if windows
formattedPath = formattedPath.replace("/", "\\"); formattedPath = formattedPath.replace("/", "\\");
Sys.command("explorer", [formattedPath]); Sys.command("explorer", [formattedPath]);
@@ -1025,20 +1003,6 @@ final class CoolUtil
return result; return result;
} }
/**
* Returns if the mouse is overlapping the sprite on a given camera, taking the camera's position, scroll and zoom into account.
*
* @param sprite Any `FlxObject`
* @param camera The camera you want to check overlap on. Uses the sprite's camera by default.
* @return Bool
*/
public static function mouseOverlaps(sprite:FlxObject, ?camera:FlxCamera) {
var camToCheck:FlxCamera = camera ?? sprite.camera;
var posthing:FlxPoint = FlxG.mouse.getWorldPosition(camToCheck);
return posthing != null && FlxMath.inBounds(posthing.x, sprite.x, sprite.x + sprite.width) && FlxMath.inBounds(posthing.y, sprite.y, sprite.y + sprite.height);
}
/** /**
* Sorts an array alphabetically. * Sorts an array alphabetically.
* @param array Array to sort * @param array Array to sort
@@ -1089,7 +1053,7 @@ final class CoolUtil
r.add(str); r.add(str);
return r.toString(); return r.toString();
} }
public static inline function bound(Value:Float, Min:Float, Max:Float):Float { public static inline function bound(Value:Float, Min:Float, Max:Float):Float {
#if cpp #if cpp
var _hx_tmp1:Float = Value; var _hx_tmp1:Float = Value;
@@ -1236,8 +1200,8 @@ final class CoolUtil
/** /**
* ! REQUIRES FULL PATH!!! * ! REQUIRES FULL PATH!!!
* @param path * @param path
* @return Bool * @return Bool
*/ */
public static function imageHasFrameData(path:String):String { public static function imageHasFrameData(path:String):String {
if (FileSystem.exists(Path.withExtension(path, "xml"))) return "xml"; if (FileSystem.exists(Path.withExtension(path, "xml"))) return "xml";
@@ -1288,20 +1252,23 @@ final class CoolUtil
return animsList; return animsList;
} }
public static function getAnimsListFromAtlas(atlas:AnimationJson):Array<String> { public static function getAnimsListFromAtlas(atlas:AnimAtlas):Array<String> {
if (atlas == null) return []; if (atlas == null) return [];
var animsList:Array<String> = []; var animsList:Array<String> = [];
if (atlas.AN.SN != null) animsList.push(atlas.AN.SN); if (atlas.AN.SN != null) animsList.push(atlas.AN.SN);
if (atlas.SD != null) if (atlas.SD != null)
for (symbol in atlas.SD) for (symbol in atlas.SD.S)
if (symbol.SN != null) animsList.push(symbol.SN); if (symbol.SN != null) animsList.push(symbol.SN);
return animsList; return animsList;
} }
public static function getAnimsListFromSprite(spr:FunkinSprite):Array<String> { public static function getAnimsListFromSprite(spr:FunkinSprite):Array<String> {
return getAnimsListFromFrames(spr.frames); if (spr.animateAtlas != null) {
return [for (symbol => timeline in spr.animateAtlas.anim.symbolDictionary) symbol];
} else
return getAnimsListFromFrames(spr.frames);
} }
// TODO: check this for bugs // TODO: check this for bugs
@@ -1454,7 +1421,6 @@ final class CoolUtil
return toProperty.setValue(fromProperty.getValue()); return toProperty.setValue(fromProperty.getValue());
} }
} }
class PropertyInfo { class PropertyInfo {
@@ -1529,4 +1495,4 @@ enum abstract CoolSfx(Int) from Int {
var CHECKED = 3; var CHECKED = 3;
var UNCHECKED = 4; var UNCHECKED = 4;
var WARNING = 5; var WARNING = 5;
} }
+1 -1
View File
@@ -541,4 +541,4 @@ typedef DEvents =
var ?joinGame:String->Void; var ?joinGame:String->Void;
var ?spectateGame:String->Void; var ?spectateGame:String->Void;
var ?joinRequest:DUser->Void; var ?joinRequest:DUser->Void;
} }
+180 -200
View File
@@ -3,220 +3,200 @@ package funkin.backend.utils;
import haxe.macro.Expr; import haxe.macro.Expr;
final class MathUtil { final class MathUtil {
public static inline var EULER:Float = 2.718281828459; /**
* Returns the maximum value in the arguments.
* @param args Array of values
*
* @return The maximum value
**/
public static function maxInt(...args:Int):Int {
var max = args[0];
for(i in 1...args.length) {
var arg = args[i];
if(arg > max)
max = arg;
}
return max;
}
/** /**
* Returns the maximum value in the arguments. * Returns the minimum value in the arguments.
* @param args Array of values * @param args Array of values
* *
* @return The maximum value * @return The minimum value
**/ **/
public static function maxInt(...args:Int):Int { public static function minInt(...args:Int):Int {
var max = args[0]; var min = args[0];
for(i in 1...args.length) { for(i in 1...args.length) {
var arg = args[i]; var arg = args[i];
if(arg > max) if(arg < min)
max = arg; min = arg;
} }
return max; return min;
} }
/** /**
* Returns the minimum value in the arguments. * Returns the maximum value in the arguments.
* @param args Array of values *
* * NOTE: If you are using this in compile time, you should use `MathUtil.maxSmart` instead of this for better performance.
* @return The minimum value *
**/ * @param args Array of values
public static function minInt(...args:Int):Int { *
var min = args[0]; * @return The maximum value
for(i in 1...args.length) { **/
var arg = args[i]; public static function max(...args:Float):Float {
if(arg < min) var max = args[0];
min = arg; for(i in 1...args.length) {
} var arg = args[i];
return min; if(arg > max)
} max = arg;
}
return max;
}
/** /**
* Returns the maximum value in the arguments. * Returns the minimum value in the arguments.
* *
* NOTE: If you are using this in compile time, you should use `MathUtil.maxSmart` instead of this for better performance. * NOTE: If you are using this in compile time, you should use `MathUtil.minSmart` instead of this for better performance.
* *
* @param args Array of values * @param args Array of values
* *
* @return The maximum value * @return The minimum value
**/ **/
public static function max(...args:Float):Float { public static function min(...args:Float):Float {
var max = args[0]; var min = args[0];
for(i in 1...args.length) { for(i in 1...args.length) {
var arg = args[i]; var arg = args[i];
if(arg > max) if(arg < min)
max = arg; min = arg;
} }
return max; return min;
} }
/** /**
* Returns the minimum value in the arguments. * Checks if a is less than b with considering a margin of error.
* *
* NOTE: If you are using this in compile time, you should use `MathUtil.minSmart` instead of this for better performance. * @param a Float
* * @param b Float
* @param args Array of values * @param margin Float (Default: EPSILON)
* *
* @return The minimum value * @return Bool
**/ **/
public static function min(...args:Float):Float { public static function lessThan(a:Float, b:Float, margin:Float = 0.0000001):Bool {
var min = args[0]; return a < b - margin;
for(i in 1...args.length) { }
var arg = args[i];
if(arg < min)
min = arg;
}
return min;
}
/** /**
* Checks if a is less than b with considering a margin of error. * Checks if a is less than or equally b with considering a margin of error.
* * @param a Float *
* @param b Float * @param a Float
* @param margin Float (Default: EPSILON) * @param b Float
* * @return Bool * @param margin Float (Default: EPSILON)
**/ *
public static function lessThan(a:Float, b:Float, margin:Float = 0.0000001):Bool { * @return Bool
return a < b - margin; **/
} public static function lessThanEqual(a:Float, b:Float, margin:Float = 0.0000001):Bool {
return a <= b - margin;
}
/** /**
* Checks if a is less than or equally b with considering a margin of error. * Checks if a is greater than b with considering a margin of error.
* * @param a Float *
* @param b Float * @param a Float
* @param margin Float (Default: EPSILON) * @param b Float
* * @return Bool * @param margin Float (Default: EPSILON)
**/ *
public static function lessThanEqual(a:Float, b:Float, margin:Float = 0.0000001):Bool { * @return Bool
return a <= b - margin; **/
} public static function greaterThan(a:Float, b:Float, margin:Float = 0.0000001):Bool {
return a > b + margin;
}
/** /**
* Checks if a is greater than b with considering a margin of error. * Checks if a is greater than or equally b with considering a margin of error.
* * @param a Float *
* @param b Float * @param a Float
* @param margin Float (Default: EPSILON) * @param b Float
* * @return Bool * @param margin Float (Default: EPSILON)
**/ *
public static function greaterThan(a:Float, b:Float, margin:Float = 0.0000001):Bool { * @return Bool
return a > b + margin; **/
} public static function greaterThanEqual(a:Float, b:Float, margin:Float = 0.0000001):Bool {
return a >= b + margin;
}
/** /**
* Checks if a is greater than or equally b with considering a margin of error. * Checks if a is approximately equal to b.
* * @param a Float *
* @param b Float * @param a Float
* @param margin Float (Default: EPSILON) * @param b Float
* * @return Bool * @param margin Float (Default: EPSILON)
**/ *
public static function greaterThanEqual(a:Float, b:Float, margin:Float = 0.0000001):Bool { * @return Bool
return a >= b + margin; **/
} public static function equal(a:Float, b:Float, margin:Float = 0.0000001):Bool {
return Math.abs(a - b) <= margin;
}
/** /**
* Checks if a is approximately equal to b. * Checks if a are not approximately equal to b.
* * @param a Float *
* @param b Float * @param a Float
* @param margin Float (Default: EPSILON) * @param b Float
* * @return Bool * @param margin Float (Default: EPSILON)
**/ *
public static function equal(a:Float, b:Float, margin:Float = 0.0000001):Bool { * @return Bool
return Math.abs(a - b) <= margin; **/
} public static function notEqual(a:Float, b:Float, margin:Float = 0.0000001):Bool {
return Math.abs(a - b) > margin;
}
/** /**
* Checks if a are not approximately equal to b. * Shortcut to `Math.max` but with infinite amount of arguments
* * @param a Float *
* @param b Float * Might not preserve the order of arguments, please test this.
* @param margin Float (Default: EPSILON) *
* * @return Bool * Dont use this in hscript, it doesnt work, it only works on compile time
**/ **/
public static function notEqual(a:Float, b:Float, margin:Float = 0.0000001):Bool { @:dox(hide) public static macro function maxSmart(..._args:Expr):Expr {
return Math.abs(a - b) > margin; return genericMinMaxSmart(_args.toArray(), "Math.max");
} }
/** /**
* @param edge0 Float * Shortcut to `Math.min` but with infinite amount of arguments
* @param edge1 Float *
* @param x Float * Might not preserve the order of arguments, please test this.
* @return Float *
**/ * Dont use this in hscript, it doesnt work, it only works on compile time
public static function smoothStep(edge0:Float, edge1:Float, x:Float):Float { **/
var t = (x - edge0) / (edge1 - edge0); @:dox(hide) public static macro function minSmart(..._args:Expr):Expr {
var clamped = t < 0.0 ? 0.0 : (t > 1.0 ? 1.0 : t); return genericMinMaxSmart(_args.toArray(), "Math.min");
return clamped * clamped * (3.0 - 2.0 * clamped); }
}
/** #if macro
* @param a Float @:dox(hide) private static function genericMinMaxSmart(_args:Array<Expr>, funcPath:String):Expr {
* @param b Float var args = _args.copy();
* @param v Float if (args.length == 0) return macro 0;
* @return Float
**/
public static function inverseLerp(a:Float, b:Float, v:Float):Float {
return (v - a) / (b - a);
}
/** var func = funcPath.split(".");
* @param v Float
* @return Float
**/
public static function fract(v:Float):Float {
return v - Math.floor(v);
}
/** function nested(lst:Array<Expr>):Expr {
* Shortcut to `Math.max` but with infinite amount of arguments if (lst.length == 1) {
* return macro ${lst[0]};
* Might not preserve the order of arguments, please test this. } else if (lst.length == 2) {
* return macro $p{func}(${lst[0]}, ${lst[1]});
* Dont use this in hscript, it doesnt work, it only works on compile time } else {
**/ var mid = Std.int(lst.length / 2);
@:dox(hide) public static macro function maxSmart(..._args:Expr):Expr { return macro $p{func}(${nested(lst.slice(0, mid))}, ${nested(lst.slice(mid, lst.length))});
return genericMinMaxSmart(_args.toArray(), "Math.max"); }
} }
/** var expr = nested(args);
* Shortcut to `Math.min` but with infinite amount of arguments
*
* Might not preserve the order of arguments, please test this.
*
* Dont use this in hscript, it doesnt work, it only works on compile time
**/
@:dox(hide) public static macro function minSmart(..._args:Expr):Expr {
return genericMinMaxSmart(_args.toArray(), "Math.min");
}
#if macro //var printer = new haxe.macro.Printer();
@:dox(hide) private static function genericMinMaxSmart(_args:Array<Expr>, funcPath:String):Expr { //trace(printer.printExpr(expr));
var args = _args.copy();
if (args.length == 0) return macro 0;
var func = funcPath.split("."); return macro $expr;
}
function nested(lst:Array<Expr>):Expr { #end
if (lst.length == 1) { }
return macro ${lst[0]};
} else if (lst.length == 2) {
return macro $p{func}(${lst[0]}, ${lst[1]});
} else {
var mid = Std.int(lst.length / 2);
return macro $p{func}(${nested(lst.slice(0, mid))}, ${nested(lst.slice(mid, lst.length))});
}
}
var expr = nested(args);
//var printer = new haxe.macro.Printer();
//trace(printer.printExpr(expr));
return macro $expr;
}
#end
}
+136 -8
View File
@@ -34,23 +34,151 @@ final class MatrixUtil {
//if(_height == -1) _height = sprite.height; //if(_height == -1) _height = sprite.height;
if(camera == null) camera = sprite.camera; if(camera == null) camera = sprite.camera;
if(points is FlxBasePoint) points = [points]; if(points is FlxBasePoint) points = [points];
var isFunkinSprite = sprite is FunkinSprite;
var funkinSprite:FunkinSprite = null;
if(isFunkinSprite) funkinSprite = cast sprite;
var isAnimateAtlas = isFunkinSprite && funkinSprite.animateAtlas != null;
var nc:FakeCamera = FakeCamera.instance; var nc:FakeCamera = isAnimateAtlas ? FakeCallCamera.instance : FakeCamera.instance;
nc.zoom = camera.zoom; nc.zoom = camera.zoom;
nc.scroll.set(camera.scroll.x, camera.scroll.y); nc.scroll.set(camera.scroll.x, camera.scroll.y);
nc.pixelPerfectRender = camera.pixelPerfectRender; nc.pixelPerfectRender = camera.pixelPerfectRender;
var points:Array<FlxPoint> = cast points; var points:Array<FlxPoint> = cast points;
if(sprite is IPrePostDraw) { if(isAnimateAtlas) {
var postDraw = cast(sprite, IPrePostDraw); var cnc = FakeCallCamera.instance;
postDraw.preDraw(); var sprite = funkinSprite;
sprite.drawComplex(nc); var oldOnDraw = cnc.onDraw;
postDraw.postDraw();
// TODO: fix rotation
// TODO: fix skew
var boundsTopLeft = new FlxPoint(Math.POSITIVE_INFINITY, Math.POSITIVE_INFINITY);
var boundsTopRight = new FlxPoint(Math.NEGATIVE_INFINITY, Math.POSITIVE_INFINITY);
var boundsBottomLeft = new FlxPoint(Math.POSITIVE_INFINITY, Math.NEGATIVE_INFINITY);
var boundsBottomRight = new FlxPoint(Math.NEGATIVE_INFINITY, Math.NEGATIVE_INFINITY);
cnc.onDraw = function(?frame:FlxFrame, ?pixels:BitmapData, matrix:FlxMatrix, ?transform:ColorTransform, ?blend:BlendMode, ?smoothing:Bool = false, ?shader:FlxShader) {
// cnc is already perfect rn
// so we need to manually process the limb
var points = [
// corners
FlxPoint.get(0, 0),
FlxPoint.get(1, 0),
FlxPoint.get(0, 1),
FlxPoint.get(1, 1)
];
rawTransformPoints(points, matrix, frame.sourceSize.x, frame.sourceSize.y);
// sort the points, incase like they were transformed with a scale -1 matrix
var topLeft:FlxPoint = points[0];
var topRight:FlxPoint = points[1];
var bottomLeft:FlxPoint = points[2];
var bottomRight:FlxPoint = points[3];
if (points[0].y > points[1].y) {
topLeft = points[1];
topRight = points[0];
}
if (points[2].y > points[3].y) {
bottomLeft = points[3];
bottomRight = points[2];
}
if (topLeft.x > topRight.x) {
var temp = topLeft;
topLeft = topRight;
topRight = temp;
}
if (bottomLeft.x > bottomRight.x) {
var temp = bottomLeft;
bottomLeft = bottomRight;
bottomRight = temp;
}
// points should now contain the corners of the limb
// trace("Corners of limb: " + points);
// set the max bounds of each corner of the limb
if(topLeft.x < boundsTopLeft.x) boundsTopLeft.x = topLeft.x;
if(topLeft.y < boundsTopLeft.y) boundsTopLeft.y = topLeft.y;
if(topRight.x > boundsTopRight.x) boundsTopRight.x = topRight.x;
if(topRight.y < boundsTopRight.y) boundsTopRight.y = topRight.y;
if(bottomLeft.x < boundsBottomLeft.x) boundsBottomLeft.x = bottomLeft.x;
if(bottomLeft.y > boundsBottomLeft.y) boundsBottomLeft.y = bottomLeft.y;
if(bottomRight.x > boundsBottomRight.x) boundsBottomRight.x = bottomRight.x;
if(bottomRight.y > boundsBottomRight.y) boundsBottomRight.y = bottomRight.y;
// recycle the points
for(point in points) point.put();
}
var cameras = sprite._cameras;
var oldVisible = cnc.visible;
cnc.visible = true;
sprite._cameras = [cnc];
sprite.draw();
sprite._cameras = cameras;
cnc.visible = oldVisible;
cnc.onDraw = oldOnDraw;
// fake transform
//trace("");
//trace("topLeft: " + boundsTopLeft);
//trace("topRight: " + boundsTopRight);
//trace("bottomLeft: " + boundsBottomLeft);
//trace("bottomRight: " + boundsBottomRight);
//trace("Before transform");
//trace(points);
for(point in points) {
//var x = matrix.__transformX(point.x * _width, point.y * _height);
//var y = matrix.__transformY(point.x * _width, point.y * _height);
// apply using boundsTopLeft, boundsTopRight, boundsBottomLeft, boundsBottomRight
// matrix doesnt work for this
var x = FlxMath.lerp(
FlxMath.lerp(boundsTopLeft.x, boundsTopRight.x, point.x),
FlxMath.lerp(boundsBottomLeft.x, boundsBottomRight.x, point.x),
point.y
);
var y = FlxMath.lerp(
FlxMath.lerp(boundsTopLeft.y, boundsTopRight.y, point.x),
FlxMath.lerp(boundsBottomLeft.y, boundsBottomRight.y, point.x),
point.y
);
//trace("(" + point.x + ", " + point.y + ") -> (" + x + ", " + y + ")");
// reset to ingame coords
x += camera.scroll.x;
y += camera.scroll.y;
if(isFunkinSprite) {
var ratio = 1 - FlxMath.lerp(1 / camera.zoom, 1, funkinSprite.zoomFactor);
x += camera.width / 2 * ratio;
y += camera.height / 2 * ratio;
}
point.set(x, y);
}
//trace("After transform");
//trace(points);
} else { } else {
sprite.drawComplex(nc); if(sprite is IPrePostDraw) {
var postDraw = cast(sprite, IPrePostDraw);
postDraw.preDraw();
sprite.drawComplex(nc);
postDraw.postDraw();
} else {
sprite.drawComplex(nc);
}
transformPoints(sprite, points, sprite._matrix, camera, _width, _height);
} }
transformPoints(sprite, points, sprite._matrix, camera, _width, _height);
return points; return points;
} }
+14 -4
View File
@@ -127,7 +127,7 @@ final class MemoryUtil {
public static function getMemType():String { public static function getMemType():String {
#if windows #if windows
var memoryMap:Map<Int, String> = [ var memoryMap:Map<Int, String> = [
0 => "Unknown", 0 => null,
1 => "Other", 1 => "Other",
2 => "DRAM", 2 => "DRAM",
3 => "Synchronous DRAM", 3 => "Synchronous DRAM",
@@ -152,13 +152,23 @@ final class MemoryUtil {
22 => "DDR2 FB-DIMM", 22 => "DDR2 FB-DIMM",
24 => "DDR3", 24 => "DDR3",
25 => "FBD2", 25 => "FBD2",
26 => "DDR4" 26 => "DDR4",
27 => "LPDDR",
28 => "LPDDR2",
29 => "LPDDR3",
30 => "LPDDR4",
31 => "Logical Non-volatile device",
32 => "HBM",
33 => "HBM2",
34 => "DDR5",
35 => "LPDDR5",
36 => "HBM3",
]; ];
var memoryOutput:Int = -1; var memoryOutput:Int = -1;
var process = new HiddenProcess("wmic", ["memorychip", "get", "SMBIOSMemoryType"]); var process = new HiddenProcess("powershell", ["-Command", "Get-CimInstance Win32_PhysicalMemory | Select-Object -ExpandProperty SMBIOSMemoryType" ]);
if (process.exitCode() == 0) memoryOutput = Std.int(Std.parseFloat(process.stdout.readAll().toString().trim().split("\n")[1])); if (process.exitCode() == 0) memoryOutput = Std.int(Std.parseFloat(process.stdout.readAll().toString().trim().split("\n")[1]));
if (memoryOutput != -1) return memoryMap[memoryOutput]; if (memoryOutput != -1) return memoryMap[memoryOutput] == null ? 'Unknown ($memoryOutput)' : memoryMap[memoryOutput];
#elseif mac #elseif mac
var process = new HiddenProcess("system_profiler", ["SPMemoryDataType"]); var process = new HiddenProcess("system_profiler", ["SPMemoryDataType"]);
var reg = ~/Type: (.+)/; var reg = ~/Type: (.+)/;
+120
View File
@@ -0,0 +1,120 @@
package funkin.backend.utils;
enum abstract RegistryHive(Int) {
var HKEY_CLASSES_ROOT = 0x80000000;
var HKEY_CURRENT_USER = 0x80000001;
var HKEY_LOCAL_MACHINE = 0x80000002;
var HKEY_USERS = 0x80000003;
var HKEY_CURRENT_CONFIG = 0x80000005;
}
#if windows
@:cppFileCode('
#include <windows.h>
#include <tchar.h>
#include <string>
#include <vector>
')
#end
class RegistryUtil {
#if windows
@:functionCode('
HKEY hKey;
LONG result;
DWORD dataSize = 0;
DWORD dataType = 0;
std::wstring subkey = std::wstring(key.wchar_str());
std::wstring valname = std::wstring(string.wchar_str());
result = RegOpenKeyExW((HKEY)reinterpret_cast<HKEY>(static_cast<uintptr_t>(hive)), subkey.c_str(), 0, KEY_READ, &hKey);
if (result != ERROR_SUCCESS) return null();
result = RegQueryValueExW(hKey, valname.c_str(), NULL, &dataType, NULL, &dataSize);
if (result != ERROR_SUCCESS || dataSize == 0) {
RegCloseKey(hKey);
return null();
}
std::vector<wchar_t> buffer(dataSize / sizeof(wchar_t));
result = RegQueryValueExW(hKey, valname.c_str(), NULL, NULL, (LPBYTE)buffer.data(), &dataSize);
RegCloseKey(hKey);
if (result == ERROR_SUCCESS) {
return ::String(buffer.data());
}
return null();
')
#end
public static function get(hive:RegistryHive, key:String, string:String):Null<String>
{
return null;
}
#if windows
@:functionCode('
HKEY hKey;
LONG result;
std::wstring subkey = std::wstring(key.wchar_str());
std::wstring valname = std::wstring(string.wchar_str());
std::wstring data = std::wstring(value.wchar_str());
result = RegCreateKeyExW((HKEY)reinterpret_cast<HKEY>(static_cast<uintptr_t>(hive)), subkey.c_str(), 0, NULL, 0, KEY_WRITE, NULL, &hKey, NULL);
if (result != ERROR_SUCCESS) return false;
result = RegSetValueExW(hKey, valname.c_str(), 0, REG_SZ, (const BYTE*)data.c_str(), (DWORD)((data.length() + 1) * sizeof(wchar_t)));
RegCloseKey(hKey);
return result == ERROR_SUCCESS;
')
#end
public static function set(hive:RegistryHive, key:String, string:String, value:String):Bool
{
return false;
}
#if windows
@:functionCode('
HKEY hKey;
LONG result;
std::wstring subkey = std::wstring(key.wchar_str());
std::wstring valname = std::wstring(string.wchar_str());
result = RegOpenKeyExW((HKEY)reinterpret_cast<HKEY>(static_cast<uintptr_t>(hive)), subkey.c_str(), 0, KEY_READ, &hKey);
if (result != ERROR_SUCCESS) return false;
DWORD dataType = 0;
result = RegQueryValueExW(hKey, valname.c_str(), NULL, &dataType, NULL, NULL);
RegCloseKey(hKey);
return result == ERROR_SUCCESS;
')
#end
public static function exists(hive:RegistryHive, key:String, string:String):Bool
{
return false;
}
#if windows
@:functionCode('
HKEY hKey;
LONG result;
std::wstring subkey = std::wstring(key.wchar_str());
std::wstring valname = std::wstring(string.wchar_str());
result = RegOpenKeyExW((HKEY)reinterpret_cast<HKEY>(static_cast<uintptr_t>(hive)), subkey.c_str(), 0, KEY_SET_VALUE, &hKey);
if (result != ERROR_SUCCESS) return false;
result = RegDeleteValueW(hKey, valname.c_str());
RegCloseKey(hKey);
return result == ERROR_SUCCESS;
')
#end
public static function delete(hive:RegistryHive, key:String, string:String):Bool {
return false;
}
}
+111 -97
View File
@@ -2,143 +2,157 @@ package funkin.backend.utils;
#if sys #if sys
import haxe.io.Input; import haxe.io.Input;
import haxe.zip.Entry;
import haxe.zip.InflateImpl;
import haxe.zip.Reader; import haxe.zip.Reader;
import sys.io.File; import sys.io.File;
import sys.io.FileInput; import sys.io.FileInput;
import haxe.io.Bytes;
/** /**
* Class that extends Reader allowing you to load ZIP entries without blowing your RAM up!! * Class that extends Reader allowing you to load ZIP entries without blowing your RAM up!!
* ~~Half of the code is taken from haxe libraries btw~~ Reworked by ItsLJcool to actually work for zip files. * Half of the code is taken from haxe libraries btw
*/ */
class SysZip { class SysZip extends Reader {
var input:Input;
var fileInput:FileInput; var fileInput:FileInput;
var filePath:String;
public var entries:List<SysZipEntry> = new List(); public var entries:List<SysZipEntry>;
/** /**
* Opens a zip from a specified path. * Opens a zip from a specified path.
* @param path Path to the zip file. (With the extension) * @param path Path to the zip file.
*/ */
public static function openFromFile(path:String) { return new SysZip(path); } // keeping for compatibility. public static function openFromFile(path:String) {
return new SysZip(File.read(path, true));
}
/** /**
* Creates a new SysZip from a specified path. * Creates a new SysZip from a specified file input.
* @param path Path to the zip file. (With the extension) * @param input File input.
*/ */
public function new(path:String) { public function new(input:FileInput) {
this.filePath = path; super(input);
fileInput = File.read(path, true); fileInput = input;
}
updateEntries(); // automatic but if you feel like you don't want it to be automatic, you can remove this. /**
* Reads all the data present in a specified entry.
* NOTE: If the entry is compressed, the data won't be decompressed. For decompression, use `unzipEntry`.
* @param e Entry
*/
public function readEntryData(e:SysZipEntry) {
var bytes:haxe.io.Bytes = null;
var buf = null;
var tmp = null;
fileInput.seek(e.seekPos, SeekBegin);
if (e.crc32 == null) {
if (e.compressed) {
#if neko
// enter progressive mode : we use a different input which has
// a temporary buffer, this is necessary since we have to uncompress
// progressively, and after that we might have pending read data
// that needs to be processed
var bufSize = 65536;
if (buf == null) {
buf = new haxe.io.BufferInput(i, haxe.io.Bytes.alloc(bufSize));
tmp = haxe.io.Bytes.alloc(bufSize);
i = buf;
}
var out = new haxe.io.BytesBuffer();
var z = new neko.zip.Uncompress(-15);
z.setFlushMode(neko.zip.Flush.SYNC);
while (true) {
if (buf.available == 0)
buf.refill();
var p = bufSize - buf.available;
if (p != buf.pos) {
// because of lack of "srcLen" in zip api, we need to always be stuck to the buffer end
buf.buf.blit(p, buf.buf, buf.pos, buf.available);
buf.pos = p;
}
var r = z.execute(buf.buf, buf.pos, tmp, 0);
out.addBytes(tmp, 0, r.write);
buf.pos += r.read;
buf.available -= r.read;
if (r.done)
break;
}
bytes = out.getBytes();
#else
var bufSize = 65536;
if (tmp == null)
tmp = haxe.io.Bytes.alloc(bufSize);
var out = new haxe.io.BytesBuffer();
var z = new InflateImpl(i, false, false);
while (true) {
var n = z.readBytes(tmp, 0, bufSize);
out.addBytes(tmp, 0, n);
if (n < bufSize)
break;
}
bytes = out.getBytes();
#end
} else
bytes = i.read(e.dataSize);
e.crc32 = i.readInt32();
if (e.crc32 == 0x08074b50)
e.crc32 = i.readInt32();
e.dataSize = i.readInt32();
e.fileSize = i.readInt32();
// set data to uncompressed
e.dataSize = e.fileSize;
e.compressed = false;
} else
bytes = i.read(e.dataSize);
return bytes;
} }
/** /**
* Unzips and returns all of the data present in an entry. * Unzips and returns all of the data present in an entry.
* @param f Entry to read from. * @param f Entry to read from.
*/ */
public function unzipEntry(f:SysZipEntry):Bytes { public function unzipEntry(f:SysZipEntry) {
if (f.fileSize <= 0) return Bytes.alloc(0); var data = readEntryData(f);
fileInput.seek(f.seekPos, SeekBegin);
var data = fileInput.read(f.compressedSize);
if (!f.compressed) return data;
if (!f.compressed)
return data;
var c = new haxe.zip.Uncompress(-15); var c = new haxe.zip.Uncompress(-15);
var s = Bytes.alloc(f.fileSize); var s = haxe.io.Bytes.alloc(f.fileSize);
var r = c.execute(data, 0, s, 0); var r = c.execute(data, 0, s, 0);
c.close(); c.close();
if (!r.done || r.read != data.length || r.write != f.fileSize)
if (!r.done || r.read != data.length || r.write != f.fileSize) throw 'Invalid compressed data for ${f.fileName} | ${f.compressedSize} -> ${f.fileSize}'; throw "Invalid compressed data for " + f.fileName;
return s; data = s;
return data;
} }
/** public override function read():List<Entry> {
* Updates the `entries` list with the current contents of the zip file. if (entries != null)
* This is done when the zip is read from SysZip the first time, but if you REALLY need to re-update the entries, you can call this again. return entries;
* entries = new List();
* Note: Calling this function will hold up the game as it has to read the ENTIRE zip, so if it's large like 1GiB or more, it might take a second or more.
*/
public function updateEntries() {
if (entries.length > 0) {
entries.clear();
entries = new List();
}
// --- locate End of Central Directory (EOCD) ---
var fileSize:Int = sys.FileSystem.stat(this.filePath).size; // probably need a better way to check the size of the file.
var scanSize:Int = (65535 < fileSize) ? 65535 : fileSize;
// It seems this usually ends up being 0 anyways, but for cases where it might not be?? I'd just make sure. but Someone do some digging I don't know if this required.
fileInput.seek(fileSize - scanSize, SeekBegin);
var buf = fileInput.read(scanSize);
var b = new haxe.io.BytesInput(buf);
// I LOVE USING MAGIC NUMBERS AND FORGETTING WHAT THEY DO 🔥🔥🔥🔥🔥🔥
b.position = (buf.length - 22) + 16; // offset to start of central directory
// --- read central directory ---
fileInput.seek(b.readInt32(), SeekBegin);
while (true) { while (true) {
if (fileInput.readInt32() != 0x02014b50) break; // central dir file header signature var e = readEntryHeader();
if (e == null)
break;
fileInput.seek(6, SeekCur); // version/flags var zipEntry:SysZipEntry = cast e;
var compression_method = fileInput.readUInt16(); zipEntry.seekPos = fileInput.tell();
fileInput.seek(8, SeekCur); // time/date + CRC32 (4, 4)
var compressed_size = fileInput.readInt32();
var uncompressed_size = fileInput.readInt32();
var nameLen = fileInput.readUInt16();
var extraLen = fileInput.readUInt16();
var commentLen = fileInput.readUInt16();
fileInput.seek(8, SeekCur); // skip disk number/start attrs
var localHeaderOffset = fileInput.readInt32();
var name = fileInput.read(nameLen).toString();
// skip central directory extra/comment
fileInput.seek(extraLen + commentLen, SeekCur);
// --- compute correct seekPos using local header ---
var curPos = fileInput.tell();
// I also forgor what the `+ 26` is for, so uh my b chat
fileInput.seek(localHeaderOffset + 26, SeekBegin);
var localNameLen = fileInput.readUInt16();
var localExtraLen = fileInput.readUInt16();
fileInput.seek(curPos, SeekBegin);
// I completely forgot that we don't really need to log the FOLDER of the content because we only care about where the contents are.
// the folders are labled as 0 bytes anyways so this will save on storing non-required data.
if (name.endsWith("/")) continue;
var zipEntry:SysZipEntry = {
fileName: name,
fileSize: uncompressed_size,
// I don't remember what the `+ 30` is for, but probably to offset something
seekPos: (localHeaderOffset + 30 + localNameLen + localExtraLen),
compressedSize: compressed_size,
compressed: (compression_method == 8),
};
entries.add(zipEntry); entries.add(zipEntry);
fileInput.seek(e.dataSize, SeekCur);
} }
return entries;
} }
/**
* calling `dispose` doesn't actually kill the class, you can still access the entries.
* disposing of SysZip will free the compressed file from being used by the engine.
*/
public function dispose() { public function dispose() {
if (fileInput != null) fileInput.close(); if (input != null)
input.close();
} }
} }
typedef SysZipEntry = { typedef SysZipEntry = {
var fileName:String; > Entry,
var fileSize:Int;
var seekPos:Int; var seekPos:Int;
var compressedSize:Int;
var compressed:Bool;
} }
#end #end
+8 -24
View File
@@ -14,7 +14,6 @@ import funkin.backend.scripting.ScriptPack;
import flixel.util.typeLimit.OneOfTwo; import flixel.util.typeLimit.OneOfTwo;
import funkin.backend.system.interfaces.IOffsetCompatible; import funkin.backend.system.interfaces.IOffsetCompatible;
import haxe.xml.Access; import haxe.xml.Access;
import animate.FlxAnimateFrames;
using StringTools; using StringTools;
@@ -128,9 +127,6 @@ final class XMLUtil {
spr.spriteAnimType = XMLAnimType.fromString(node.att.type, spr.spriteAnimType); spr.spriteAnimType = XMLAnimType.fromString(node.att.type, spr.spriteAnimType);
} }
if (node.has.applyStageMatrix) spr.applyStageMatrix = node.att.applyStageMatrix == "true";
if (node.has.useRenderTexture) spr.useRenderTexture = node.att.useRenderTexture == "true";
if(node.has.x) { if(node.has.x) {
var x:Null<Float> = Std.parseFloat(node.att.x); var x:Null<Float> = Std.parseFloat(node.att.x);
if (x.isNotNull()) spr.x = x; if (x.isNotNull()) spr.x = x;
@@ -229,8 +225,7 @@ final class XMLUtil {
animType: spr.spriteAnimType, animType: spr.spriteAnimType,
x: 0, x: 0,
y: 0, y: 0,
indices: [for(i in 0...spr.frames.frames.length) i], indices: [for(i in 0...spr.frames.frames.length) i]
label: false
}); });
} }
@@ -266,8 +261,7 @@ final class XMLUtil {
animType: animType, animType: animType,
x: 0, x: 0,
y: 0, y: 0,
indices: [], indices: []
label: false
}; };
if (anim.has.name) animData.name = anim.att.name; if (anim.has.name) animData.name = anim.att.name;
@@ -279,7 +273,6 @@ final class XMLUtil {
if (anim.has.loop) animData.loop = anim.att.loop == "true"; if (anim.has.loop) animData.loop = anim.att.loop == "true";
if (anim.has.forced) animData.forced = anim.att.forced == "true"; if (anim.has.forced) animData.forced = anim.att.forced == "true";
if (anim.has.indices) animData.indices = CoolUtil.parseNumberRange(anim.att.indices); if (anim.has.indices) animData.indices = CoolUtil.parseNumberRange(anim.att.indices);
if (anim.has.label) animData.label = anim.att.label == "true";
return animData; return animData;
} }
@@ -306,23 +299,15 @@ final class XMLUtil {
if (animData.name != null) { if (animData.name != null) {
if (animData.fps <= 0 #if web || animData.fps == null #end) animData.fps = 24; if (animData.fps <= 0 #if web || animData.fps == null #end) animData.fps = 24;
if (sprite.frames is FlxAnimateFrames) { if (sprite is FunkinSprite && cast(sprite, FunkinSprite).animateAtlas != null) {
var animateAnim = cast(sprite, FunkinSprite).animateAtlas.anim;
if(animData.anim == null) if(animData.anim == null)
return MISSING_PROPERTY; return MISSING_PROPERTY;
var animateAnim = cast(sprite, FunkinSprite).anim; if (animData.indices != null && animData.indices.length > 0)
animateAnim.addBySymbolIndices(animData.name, animData.anim, animData.indices, animData.fps, animData.loop);
if (animData.label) { else
if (animData.indices != null && animData.indices.length > 0) animateAnim.addBySymbol(animData.name, animData.anim, animData.fps, animData.loop);
animateAnim.addByFrameLabelIndices(animData.name, animData.anim, animData.indices, animData.fps, animData.loop);
else
animateAnim.addByFrameLabel(animData.name, animData.anim, animData.fps, animData.loop);
} else {
if (animData.indices != null && animData.indices.length > 0)
animateAnim.addBySymbolIndices(animData.name, animData.anim, animData.indices, animData.fps, animData.loop);
else
animateAnim.addBySymbol(animData.name, animData.anim, animData.fps, animData.loop);
}
} else { } else {
if (animData.indices != null && animData.indices.length > 0) { if (animData.indices != null && animData.indices.length > 0) {
if (animData.anim == null) if (animData.anim == null)
@@ -478,7 +463,6 @@ typedef AnimData = {
var y:Float; var y:Float;
var indices:Array<Int>; var indices:Array<Int>;
var animType:XMLAnimType; var animType:XMLAnimType;
var label:Bool;
var ?forced:Bool; var ?forced:Bool;
} }
-17
View File
@@ -20,8 +20,6 @@ class EditorTreeMenu extends funkin.options.TreeMenu {
bg.antialiasing = true; bg.antialiasing = true;
setBackgroundRotation(-5); setBackgroundRotation(-5);
super.createPost(); super.createPost();
if (Paths.assetsTree.hasCompressedLibrary) warnCompressLibrary();
} }
public inline function setBackgroundRotation(rotation:Float) { public inline function setBackgroundRotation(rotation:Float) {
@@ -60,21 +58,6 @@ class EditorTreeMenu extends funkin.options.TreeMenu {
bg.colorTransform.greenMultiplier = FlxMath.lerp(1, color.greenFloat, 0.25); bg.colorTransform.greenMultiplier = FlxMath.lerp(1, color.greenFloat, 0.25);
bg.colorTransform.blueMultiplier = FlxMath.lerp(1, color.blueFloat, 0.25); bg.colorTransform.blueMultiplier = FlxMath.lerp(1, color.blueFloat, 0.25);
} }
private function warnCompressLibrary() {
var warningMessage = "It seems you have libraries loaded that are compressed, and can not have files written to them.\n
This is just a friendly reminder that if you're loading a Mod and wish to edit files, you need to uncompress it to be able to use any editors!\n\nCompressed Libraries: ";
var compressedList = Paths.assetsTree.libraries.filter(l -> funkin.backend.assets.AssetsLibraryList.getCleanLibrary(l).isCompressed);
var modNameList = [for (l in compressedList) {
l = funkin.backend.assets.AssetsLibraryList.getCleanLibrary(l);
if (l is funkin.backend.assets.IModsAssetLibrary) cast(l, funkin.backend.assets.IModsAssetLibrary).modName;
}];
warningMessage += modNameList.join(", ");
var zipLibraryWarning = new funkin.editors.ui.UIWarningSubstate("Compressed Library Detected!", warningMessage, [{label: "Ok", color: 0x969533, onClick: (state) -> {} }], false);
openSubState(zipLibraryWarning);
}
} }
class EditorTreeMenuScreen extends funkin.options.TreeMenuScreen { class EditorTreeMenuScreen extends funkin.options.TreeMenuScreen {
@@ -2,13 +2,18 @@ package funkin.editors.character;
import flixel.text.FlxText.FlxTextFormat; import flixel.text.FlxText.FlxTextFormat;
import flixel.text.FlxText.FlxTextFormatMarkerPair; import flixel.text.FlxText.FlxTextFormatMarkerPair;
import flxanimate.animate.FlxAnim.FlxSymbolAnimation;
import flxanimate.animate.FlxSymbol;
import flxanimate.animate.FlxElement;
import flxanimate.animate.SymbolParameters;
import flxanimate.animate.FlxKeyFrame;
import flxanimate.animate.FlxTimeline;
import flixel.graphics.frames.FlxFrame; import flixel.graphics.frames.FlxFrame;
import flixel.animation.FlxAnimation; import flixel.animation.FlxAnimation;
import openfl.geom.Rectangle; import openfl.geom.Rectangle;
import funkin.backend.utils.XMLUtil.AnimData; import funkin.backend.utils.XMLUtil.AnimData;
import flixel.math.FlxPoint; import flixel.math.FlxPoint;
import flixel.util.FlxColor; import flixel.util.FlxColor;
import funkin.editors.character.CharacterAnimsWindow;
using StringTools; using StringTools;
@@ -21,7 +26,6 @@ class CharacterAnimButton extends UIButton {
public var animationDisplayBG:UISliceSprite; public var animationDisplayBG:UISliceSprite;
public var nameTextBox:UITextBox; public var nameTextBox:UITextBox;
public var animTextBox:UIAutoCompleteTextBox; public var animTextBox:UIAutoCompleteTextBox;
public var animLabelCheckbox:UICheckbox;
public var positionXStepper:UINumericStepper; public var positionXStepper:UINumericStepper;
public var positionYStepper:UINumericStepper; public var positionYStepper:UINumericStepper;
public var fpsStepper:UINumericStepper; public var fpsStepper:UINumericStepper;
@@ -112,20 +116,13 @@ class CharacterAnimButton extends UIButton {
foldableButtons.push(fpsStepper); foldableButtons.push(fpsStepper);
addLabelOn(fpsStepper, translate("fps"), 12); addLabelOn(fpsStepper, translate("fps"), 12);
loopedCheckbox = new UICheckbox(fpsStepper.x + 82 - 32 + 26, fpsStepper.y, translate("looping"), animData.loop, 0, true); loopedCheckbox = new UICheckbox(fpsStepper.x + 82 - 32 + 26, fpsStepper.y, "Looping?", animData.loop, 0, true);
loopedCheckbox.onChecked = (newLooping:Bool) -> {this.changeLooping(newLooping);}; loopedCheckbox.onChecked = (newLooping:Bool) -> {this.changeLooping(newLooping);};
members.push(loopedCheckbox); members.push(loopedCheckbox);
foldableButtons.push(loopedCheckbox); foldableButtons.push(loopedCheckbox);
loopedCheckbox.x += 8; loopedCheckbox.y += 6; loopedCheckbox.x += 8; loopedCheckbox.y += 6;
if (parent.character.isAnimate) {
animLabelCheckbox = new UICheckbox(loopedCheckbox.x, animTextBox.y + 26, translate("label"), animData.label, 0, true);
animLabelCheckbox.onChecked = (newLabel:Bool) -> {this.changeLabel(newLabel);};
members.push(animLabelCheckbox);
foldableButtons.push(animLabelCheckbox);
}
indicesTextBox = new UITextBox(nameTextBox.x, nameTextBox.y, CoolUtil.formatNumberRange(animData.indices.getDefault([]), ", "), 278, 22, false, true); indicesTextBox = new UITextBox(nameTextBox.x, nameTextBox.y, CoolUtil.formatNumberRange(animData.indices.getDefault([]), ", "), 278, 22, false, true);
indicesTextBox.onChange = (text:String) -> { indicesTextBox.onChange = (text:String) -> {
this.changeIndicies(CoolUtil.parseNumberRange(text)); this.changeIndicies(CoolUtil.parseNumberRange(text));
@@ -207,7 +204,6 @@ class CharacterAnimButton extends UIButton {
fpsStepper.follow(this, 282, 118); fpsStepper.follow(this, 282, 118);
loopedCheckbox.follow(this, 336, 122); loopedCheckbox.follow(this, 336, 122);
animLabelCheckbox?.follow(this, 336, 98);
indicesTextBox.follow(this, 158, 164); indicesTextBox.follow(this, 158, 164);
@@ -235,12 +231,18 @@ class CharacterAnimButton extends UIButton {
} }
var oldName:String = anim; var oldName:String = anim;
if (parent.character.animateAtlas != null) {
var flxAnimation:FlxAnimation = __getFlxAnimation(); var animSymbol:FlxSymbolAnimation = __getAnimationSymbol();
flxAnimation.name = newName;
parent.character.animation._animations.remove(anim); parent.character.animateAtlas.anim.animsMap.remove(anim);
parent.character.animation._animations.set(newName, flxAnimation); parent.character.animateAtlas.anim.animsMap.set(newName, animSymbol);
} else {
var flxAnimation:FlxAnimation = __getFlxAnimation();
flxAnimation.name = newName;
parent.character.animation._animations.remove(anim);
parent.character.animation._animations.set(newName, flxAnimation);
}
var animData:AnimData = parent.character.animDatas[anim]; var animData:AnimData = parent.character.animDatas[anim];
animData.name = newName; animData.name = newName;
@@ -252,7 +254,7 @@ class CharacterAnimButton extends UIButton {
parent.character.animOffsets.remove(anim); parent.character.animOffsets.remove(anim);
parent.character.animOffsets.set(newName, animOffset); parent.character.animOffsets.set(newName, animOffset);
var displayFrame:DisplayAnimFrameEntry = parent.displayAnimsFramesList[anim]; var displayFrame:{scale:Float, animBounds:Rectangle, frame:Int} = parent.displayAnimsFramesList[anim];
parent.displayAnimsFramesList.remove(anim); parent.displayAnimsFramesList.remove(anim);
parent.displayAnimsFramesList.set(newName, displayFrame); parent.displayAnimsFramesList.set(newName, displayFrame);
@@ -274,20 +276,23 @@ class CharacterAnimButton extends UIButton {
var oldAnim:String = animData.anim; var oldAnim:String = animData.anim;
animData.anim = newAnim; animData.anim = newAnim;
var flxAnimation:FlxAnimation = __getFlxAnimation(); if (parent.character.animateAtlas != null)
flxAnimation.prefix = newAnim; __refreshAnimation();
else {
var flxAnimation:FlxAnimation = __getFlxAnimation();
flxAnimation.prefix = newAnim;
refreshAnimation(__getFlxAnimation(), data); refreshFlxAnimationFrames(flxAnimation, animData);
if (valid) { if (valid) {
parent.buildAnimDisplay(anim, data); parent.buildAnimDisplay(anim, data);
animationDisplayBG.alpha = 1; animationDisplayBG.alpha = 1;
} else { } else {
parent.removeAnimDisplay(anim); parent.removeAnimDisplay(anim);
animationDisplayBG.alpha = 0.4; animationDisplayBG.alpha = 0.4;
}
} }
if (parent.character.getAnimName() == anim) if (parent.character.getAnimName() == anim)
CharacterEditor.instance.playAnimation(anim); CharacterEditor.instance.playAnimation(anim);
@@ -325,8 +330,13 @@ class CharacterAnimButton extends UIButton {
var oldFPS:Float = animData.fps; var oldFPS:Float = animData.fps;
animData.fps = newFPS; animData.fps = newFPS;
var flxAnimation:FlxAnimation = __getFlxAnimation(); if (parent.character.animateAtlas != null) {
flxAnimation.frameRate = newFPS; var animSymbol:FlxSymbolAnimation = __getAnimationSymbol();
animSymbol.frameRate = newFPS;
} else {
var flxAnimation:FlxAnimation = __getFlxAnimation();
flxAnimation.frameRate = newFPS;
}
if (parent.character.getAnimName() == anim) if (parent.character.getAnimName() == anim)
CharacterEditor.instance.playAnimation(anim); CharacterEditor.instance.playAnimation(anim);
@@ -341,8 +351,13 @@ class CharacterAnimButton extends UIButton {
animData.loop = newLooping; animData.loop = newLooping;
var flxAnimation:FlxAnimation = __getFlxAnimation(); if (parent.character.animateAtlas != null) {
flxAnimation.looped = animData.loop; var animSymbol:FlxSymbolAnimation = __getAnimationSymbol();
animSymbol.instance.symbol.loop = animData.loop ? Loop : PlayOnce;
} else {
var flxAnimation:FlxAnimation = __getFlxAnimation();
flxAnimation.looped = animData.loop;
}
if (parent.character.getAnimName() == anim) if (parent.character.getAnimName() == anim)
CharacterEditor.instance.playAnimation(anim); CharacterEditor.instance.playAnimation(anim);
@@ -352,19 +367,6 @@ class CharacterAnimButton extends UIButton {
if (addToUndo) CharacterEditor.undos.addToUndo(CAnimEditLooping(ID, newLooping)); if (addToUndo) CharacterEditor.undos.addToUndo(CAnimEditLooping(ID, newLooping));
} }
public function changeLabel(newLabel:Bool, addToUndo:Bool = true) @:privateAccess {
var animData:AnimData = parent.character.animDatas[anim];
animData.label = newLabel;
if (animLabelCheckbox != null)
animLabelCheckbox.checked = newLabel;
__refreshAnimation();
if (addToUndo) CharacterEditor.undos.addToUndo(CAnimEditLabel(ID, newLabel));
}
public function changeIndicies(indicies:Array<Int>, addToUndo:Bool = true) @:privateAccess { public function changeIndicies(indicies:Array<Int>, addToUndo:Bool = true) @:privateAccess {
var animData:AnimData = parent.character.animDatas[anim]; var animData:AnimData = parent.character.animDatas[anim];
var oldIndices:Array<Int> = animData.indices.copy(); var oldIndices:Array<Int> = animData.indices.copy();
@@ -401,14 +403,58 @@ class CharacterAnimButton extends UIButton {
CharacterEditor.undos.addToUndo(CAnimEditIndices(ID, oldIndices, indicies)); CharacterEditor.undos.addToUndo(CAnimEditIndices(ID, oldIndices, indicies));
} }
public inline function refreshFlxAnimationFrames(flxAnimation:FlxAnimation, animData:AnimData) @:privateAccess {
try {
if (animData.indices.length > 0) {
var frameIndices:Array<Int> = new Array<Int>();
parent.character.animation.byIndicesHelper(frameIndices, flxAnimation.prefix, animData.indices, "");
flxAnimation.frames = frameIndices;
} else {
final animFrames:Array<FlxFrame> = new Array<FlxFrame>();
parent.character.animation.findByPrefix(animFrames, flxAnimation.prefix);
final frameIndices:Array<Int> = [];
parent.character.animation.byPrefixHelper(frameIndices, animFrames, flxAnimation.prefix);
flxAnimation.frames = frameIndices;
}
if (flxAnimation.frames.length <= 0) invalidate();
else validate();
} catch (e) {
trace('ERROR REFRESHING FLXANIMATION FRAMES: $e');
invalidate();
}
}
public inline function refreshSymbolKeyFrames(symbol:FlxSymbolAnimation, animData:AnimData) @:privateAccess {
var wasRefreshed:Bool = false;
try {
parent.character.animateAtlas.anim.animsMap.remove(animData.name);
if (animData.indices.length > 0)
parent.character.animateAtlas.anim.addBySymbolIndices(animData.name, animData.anim, animData.indices, animData.fps, animData.loop);
else
parent.character.animateAtlas.anim.addBySymbol(animData.name, animData.anim, animData.fps, animData.loop);
wasRefreshed = parent.character.animateAtlas.anim.animsMap.exists(animData.name);
if (!wasRefreshed) __getAnimationSymbol();
} catch (e) {
trace('ERROR REFRESHING SYMBOL FRAMES: $e');
}
validate(wasRefreshed);
}
public function toggleGhost() { public function toggleGhost() {
if (valid && parent.ghosts.indexOf(anim) == -1) { if (valid && parent.ghosts.indexOf(anim) == -1) {
UIState.playEditorSound(Flags.DEFAULT_CHARACTER_GHOSTENABLE_SOUND); FlxG.sound.play(Paths.sound(Flags.DEFAULT_CHARACTER_GHOSTENABLE_SOUND));
parent.ghosts.push(anim); parent.ghosts.push(anim);
ghostIcon.animation.play("alive", true); ghostIcon.animation.play("alive", true);
ghostIcon.color = 0xFFFFFFFF; ghostIcon.color = 0xFFFFFFFF;
} else { } else {
UIState.playEditorSound(Flags.DEFAULT_CHARACTER_GHOSTDISABLE_SOUND); FlxG.sound.play(Paths.sound(Flags.DEFAULT_CHARACTER_GHOSTDISABLE_SOUND));
parent.ghosts.remove(anim); parent.ghosts.remove(anim);
ghostIcon.animation.play("dead", true); ghostIcon.animation.play("dead", true);
ghostIcon.color = 0xFFADADAD; ghostIcon.color = 0xFFADADAD;
@@ -420,8 +466,8 @@ class CharacterAnimButton extends UIButton {
super.draw(); super.draw();
if (!closed && parent.displayAnimsFramesList.exists(anim)) { if (!closed && parent.displayAnimsFramesList.exists(anim)) {
var displayData:DisplayAnimFrameEntry = parent.displayAnimsFramesList.get(anim); var displayData:{frame:Int, scale:Float, animBounds:Rectangle} = parent.displayAnimsFramesList.get(anim);
parent.displayWindowSprite.frame = displayData.frame; parent.displayWindowSprite.frame = parent.displayWindowSprite.frames.frames[displayData.frame];
parent.displayWindowSprite.scale.x = parent.displayWindowSprite.scale.y = displayData.scale; parent.displayWindowSprite.scale.x = parent.displayWindowSprite.scale.y = displayData.scale;
parent.displayWindowSprite.updateHitbox(); parent.displayWindowSprite.updateHitbox();
@@ -475,26 +521,16 @@ class CharacterAnimButton extends UIButton {
return parent.character.animation._animations[anim]; return parent.character.animation._animations[anim];
} }
public inline function refreshAnimation(anim:FlxAnimation, animData:AnimData) @:privateAccess { public inline function __getAnimationSymbol():Null<FlxSymbolAnimation> @:privateAccess {
var refreshed:Bool = false; if (!parent.character.animateAtlas.anim.animsMap.exists(anim))
XMLUtil.addAnimToSprite(parent.character, data);
parent.character.animation.remove(animData.name); return parent.character.animateAtlas.anim.animsMap[anim];
parent.character.animation._curAnim = null;
XMLUtil.addAnimToSprite(parent.character, animData);
var anim = parent.character.animation.getByName(animData.name);
if (anim != null && anim.frames.length > 0) {
validate();
parent.character.animation.play(animData.name);
}
else
invalidate();
} }
@:noCompletion function __refreshAnimation() @:privateAccess { @:noCompletion function __refreshAnimation() @:privateAccess {
refreshAnimation(__getFlxAnimation(), data); if (parent.character.animateAtlas != null) refreshSymbolKeyFrames(__getAnimationSymbol(), data);
else refreshFlxAnimationFrames(__getFlxAnimation(), data);
if (valid) { if (valid) {
parent.buildAnimDisplay(anim, data); parent.buildAnimDisplay(anim, data);
@@ -8,24 +8,15 @@ import openfl.geom.Rectangle;
import flixel.graphics.frames.FlxFrame; import flixel.graphics.frames.FlxFrame;
import funkin.game.Character; import funkin.game.Character;
import flixel.animation.FlxPrerotatedAnimation; import flixel.animation.FlxPrerotatedAnimation;
import animate.internal.RenderTexture;
import flixel.graphics.frames.FlxFrame;
import funkin.backend.system.Logs;
using funkin.backend.utils.BitmapUtil; using funkin.backend.utils.BitmapUtil;
typedef DisplayAnimFrameEntry = {
scale:Float,
frame:FlxFrame,
renderTexture:RenderTexture
}
class CharacterAnimsWindow extends UIButtonList<CharacterAnimButton> { class CharacterAnimsWindow extends UIButtonList<CharacterAnimButton> {
public var character:CharacterGhost; public var character:CharacterGhost;
public var displayWindowSprite:FlxSprite; public var displayWindowSprite:FlxSprite;
public var displayWindowGraphic:FlxGraphic; public var displayWindowGraphic:FlxGraphic;
public var displayAnimsFramesList:Map<String, DisplayAnimFrameEntry> = []; public var displayAnimsFramesList:Map<String, {scale:Float, animBounds:Rectangle, frame:OneOfTwo<Int, String>}> = [];
public var animButtons:Map<String, CharacterAnimButton> = []; public var animButtons:Map<String, CharacterAnimButton> = [];
public var animsList:Array<String> = []; public var animsList:Array<String> = [];
@@ -39,7 +30,7 @@ class CharacterAnimsWindow extends UIButtonList<CharacterAnimButton> {
buttonCameras.pixelPerfectRender = true; buttonCameras.pixelPerfectRender = true;
if (Assets.exists(Paths.image('characters/${character.sprite}'))) if (Assets.exists(Paths.image('characters/${character.sprite}')) && character.animateAtlas == null)
displayWindowGraphic = FlxG.bitmap.add(Assets.getBitmapData(Paths.image('characters/${character.sprite}'), true, false)); displayWindowGraphic = FlxG.bitmap.add(Assets.getBitmapData(Paths.image('characters/${character.sprite}'), true, false));
displayWindowSprite = new FlxSprite(); displayWindowSprite = new FlxSprite();
@@ -78,48 +69,37 @@ class CharacterAnimsWindow extends UIButtonList<CharacterAnimButton> {
} }
public function buildAnimDisplay(name:String, anim:AnimData) @:privateAccess { public function buildAnimDisplay(name:String, anim:AnimData) @:privateAccess {
var anim:FlxAnimation = character.animation._animations[anim.name]; if (character.animateAtlas == null) {
if (anim == null) return; var anim:FlxAnimation = character.animation._animations[anim.name];
if (anim == null || anim.frames.length <= 0) return;
if (character.isAnimate) {
var renderTex = character.generateRenderTextureForAnim(name);
var frame = renderTex.graphic.imageFrame.frame;
displayAnimsFramesList.set(name, {
frame: frame,
scale: 104/Math.max(frame.frame.width, frame.frame.height),
renderTexture: renderTex
});
} else {
var frameIndex:Int = anim.frames.getDefault([0])[0]; var frameIndex:Int = anim.frames.getDefault([0])[0];
var frame:FlxFrame = displayWindowSprite.frames.frames[frameIndex]; var frame:FlxFrame = displayWindowSprite.frames.frames[frameIndex];
var frameRect:Rectangle = new Rectangle(frame.offset.x, frame.offset.y, frame.sourceSize.x, frame.sourceSize.y); var frameRect:Rectangle = new Rectangle(frame.offset.x, frame.offset.y, frame.sourceSize.x, frame.sourceSize.y);
var animBounds:Rectangle = displayWindowGraphic != null ? displayWindowGraphic.bitmap.bounds(frameRect) : frameRect; var animBounds:Rectangle = displayWindowGraphic != null ? displayWindowGraphic.bitmap.bounds(frameRect) : frameRect;
displayAnimsFramesList.set(name, { displayAnimsFramesList.set(name, {frame: anim.frames.getDefault([0])[0], scale: 104/Math.max(animBounds.width, animBounds.height), animBounds: animBounds});
frame: character.frames.frames[anim.frames.getDefault([0])[0]], } else {
scale: 104/Math.max(animBounds.width, animBounds.height), character.storeAtlasState();
renderTexture: null
}); /*
character.animateAtlas.anim.play(anim.name, true, false, 0);
character.animateAtlas.anim.stop();
var animBounds:Rectangle = MatrixUtil.getBounds(character).copyToFlash();
displayAnimsFramesList.set(name, {frame: anim.anim, scale: 104/animBounds.height, animBounds: animBounds});
*/
character.restoreAtlasState();
} }
} }
public function removeAnimDisplay(name:String) { public function removeAnimDisplay(name:String)
if (displayAnimsFramesList.exists(name))
displayAnimsFramesList[name].renderTexture?.destroy();
displayAnimsFramesList.remove(name); displayAnimsFramesList.remove(name);
}
public function clearDisplayAnims() {
for(k=>e in displayAnimsFramesList)
e.renderTexture?.destroy();
displayAnimsFramesList.clear();
}
public function deleteAnimation(button:CharacterAnimButton, addToUndo:Bool = true) { public function deleteAnimation(button:CharacterAnimButton, addToUndo:Bool = true) {
UIState.playEditorSound(Flags.DEFAULT_EDITOR_DELETE_SOUND); FlxG.sound.play(Paths.sound(Flags.DEFAULT_EDITOR_DELETE_SOUND));
if (buttons.members.length <= 1) return; if (buttons.members.length <= 1) return;
if (character.getAnimName() == button.anim) if (character.getAnimName() == button.anim)
@:privateAccess CharacterEditor.instance._animation_down(null); @:privateAccess CharacterEditor.instance._animation_down(null);
@@ -154,7 +134,6 @@ class CharacterAnimsWindow extends UIButtonList<CharacterAnimButton> {
x: 0, y: 0, x: 0, y: 0,
indices: [], indices: [],
animType: NONE, animType: NONE,
label: false
}; };
addAnimation(animData); addAnimation(animData);
} }
@@ -453,7 +453,7 @@ class CharacterEditor extends UIState {
function _file_save(_) { function _file_save(_) {
#if sys #if sys
UIState.playEditorSound(Flags.DEFAULT_EDITOR_SAVE_SOUND); FlxG.sound.play(Paths.sound('editors/save'));
CoolUtil.safeSaveFile( CoolUtil.safeSaveFile(
'${Paths.getAssetsRoot()}/data/characters/${character.curCharacter}.xml', '${Paths.getAssetsRoot()}/data/characters/${character.curCharacter}.xml',
buildCharacter() buildCharacter()
@@ -465,7 +465,7 @@ class CharacterEditor extends UIState {
} }
function _file_saveas(_) { function _file_saveas(_) {
UIState.playEditorSound(Flags.DEFAULT_EDITOR_SAVE_SOUND); FlxG.sound.play(Paths.sound('editors/save'));
openSubState(new SaveSubstate(buildCharacter(), { openSubState(new SaveSubstate(buildCharacter(), {
defaultSaveFile: '${character.curCharacter}.xml' defaultSaveFile: '${character.curCharacter}.xml'
})); }));
@@ -499,7 +499,7 @@ class CharacterEditor extends UIState {
} }
function _undo(undo:CharacterEditorChange) { function _undo(undo:CharacterEditorChange) {
UIState.playEditorSound(Flags.DEFAULT_EDITOR_UNDO_SOUND); FlxG.sound.play(Paths.sound(Flags.DEFAULT_EDITOR_UNDO_SOUND));
switch (undo) { switch (undo) {
case null: // do nothing case null: // do nothing
case CCharEditPosition(oldPos, newPos): case CCharEditPosition(oldPos, newPos):
@@ -554,9 +554,6 @@ class CharacterEditor extends UIState {
case CAnimEditLooping(animID, newLooping): case CAnimEditLooping(animID, newLooping):
var button:CharacterAnimButton = characterAnimsWindow.buttons.members[animID]; var button:CharacterAnimButton = characterAnimsWindow.buttons.members[animID];
button.changeLooping(!newLooping, false); button.changeLooping(!newLooping, false);
case CAnimEditLabel(animID, newLabel):
var button:CharacterAnimButton = characterAnimsWindow.buttons.members[animID];
button.changeLabel(!newLabel, false);
case CAnimEditIndices(animID, oldIndicies, newIndicies): case CAnimEditIndices(animID, oldIndicies, newIndicies):
var button:CharacterAnimButton = characterAnimsWindow.buttons.members[animID]; var button:CharacterAnimButton = characterAnimsWindow.buttons.members[animID];
button.changeIndicies(oldIndicies, false); button.changeIndicies(oldIndicies, false);
@@ -573,7 +570,7 @@ class CharacterEditor extends UIState {
} }
function _redo(redo:CharacterEditorChange) { function _redo(redo:CharacterEditorChange) {
UIState.playEditorSound(Flags.DEFAULT_EDITOR_REDO_SOUND); FlxG.sound.play(Paths.sound(Flags.DEFAULT_EDITOR_REDO_SOUND));
switch (redo) { switch (redo) {
case null: // do nothing case null: // do nothing
case CCharEditPosition(oldPos, newPos): case CCharEditPosition(oldPos, newPos):
@@ -628,9 +625,6 @@ class CharacterEditor extends UIState {
case CAnimEditLooping(animID, newLooping): case CAnimEditLooping(animID, newLooping):
var button:CharacterAnimButton = characterAnimsWindow.buttons.members[animID]; var button:CharacterAnimButton = characterAnimsWindow.buttons.members[animID];
button.changeLooping(newLooping, false); button.changeLooping(newLooping, false);
case CAnimEditLabel(animID, newLabel):
var button:CharacterAnimButton = characterAnimsWindow.buttons.members[animID];
button.changeLabel(newLabel, false);
case CAnimEditIndices(animID, oldIndicies, newIndicies): case CAnimEditIndices(animID, oldIndicies, newIndicies):
var button:CharacterAnimButton = characterAnimsWindow.buttons.members[animID]; var button:CharacterAnimButton = characterAnimsWindow.buttons.members[animID];
button.changeIndicies(newIndicies, false); button.changeIndicies(newIndicies, false);
@@ -942,7 +936,6 @@ enum CharacterEditorChange {
CAnimEditFPS(animID:Int, oldFPS:Float, newFPS:Float); CAnimEditFPS(animID:Int, oldFPS:Float, newFPS:Float);
CAnimEditLooping(animID:Int, newLooping:Bool); CAnimEditLooping(animID:Int, newLooping:Bool);
CAnimEditIndices(animID:Int, oldIndicies:Array<Int>, newIndicies:Array<Int>); CAnimEditIndices(animID:Int, oldIndicies:Array<Int>, newIndicies:Array<Int>);
CAnimEditLabel(animID:Int, newLabel:Bool);
CCharClearOffsets(oldOffsets:Map<String, FlxPoint>); CCharClearOffsets(oldOffsets:Map<String, FlxPoint>);
} }
@@ -4,8 +4,6 @@ import funkin.backend.system.FakeCamera.FakeCallCamera;
import openfl.geom.ColorTransform; import openfl.geom.ColorTransform;
import flixel.animation.FlxAnimation; import flixel.animation.FlxAnimation;
import funkin.game.Character; import funkin.game.Character;
import haxe.xml.Access;
import animate.internal.RenderTexture;
typedef AtlasState = { typedef AtlasState = {
var oldAnim:String; var oldAnim:String;
@@ -16,35 +14,39 @@ typedef AtlasState = {
class CharacterGhost extends Character { class CharacterGhost extends Character {
public var ghosts:Array<String> = []; public var ghosts:Array<String> = [];
public override function buildCharacter(xml:Access) {
useRenderTexture = true; // per request from maru heh, still overridable
super.buildCharacter(xml);
}
public override function draw() @:privateAccess { public override function draw() @:privateAccess {
ghostDraw = FakeCallCamera.instance.ignoreDraws = true; ghostDraw = FakeCallCamera.instance.ignoreDraws = true;
var wasInvalidFrame:Bool = !colorTransform.__isDefault(false); var wasInvalidFrame:Bool = !colorTransform.__isDefault(false);
colorTransform.__identity(); colorTransform.__identity();
var animName = animation.curAnim?.name ?? null; if (animateAtlas != null) {
var animFrame = animation.curAnim?.curFrame ?? 0; storeAtlasState();
var animFrameTimer = animation.curAnim?._frameTimer ?? 0; for (anim in ghosts) {
animateAtlas.anim.play(anim, true, false, 0);
setAnimOffset(anim);
for (anim in ghosts) @:privateAccess { alpha = 0.4; color = 0xFFAEAEAE;
alpha = 0.4; color = 0xFFAEAEAE; super.draw();
}
var flxanim:FlxAnimation = animation._animations.get(anim); if (ghosts.length > 0) restoreAtlasState();
animation.play(anim, true, false, flxanim.frames.length - 1);
setAnimOffset(anim);
super.draw();
} }
else {
for (anim in ghosts) @:privateAccess {
alpha = 0.4; color = 0xFFAEAEAE;
var flxanim:FlxAnimation = animation._animations.get(anim);
var frameIndex:Int = flxanim.frames.getDefault([0])[flxanim.frames.length - 1];
frame = frames.frames[frameIndex];
setAnimOffset(anim);
super.draw();
}
if (ghosts.length > 0) if (ghosts.length > 0)
frame = frames.frames[animation.frameIndex]; frame = frames.frames[animation.frameIndex];
}
ghostDraw = FakeCallCamera.instance.ignoreDraws = false; ghostDraw = FakeCallCamera.instance.ignoreDraws = false;
alpha = 1; color = 0xFFFFFFFF; alpha = 1; color = 0xFFFFFFFF;
@@ -52,12 +54,8 @@ class CharacterGhost extends Character {
frameOffset.set(0, 0); frameOffset.set(0, 0);
offset.set(globalOffset.x * (isPlayer != playerOffsets ? 1 : -1), -globalOffset.y); offset.set(globalOffset.x * (isPlayer != playerOffsets ? 1 : -1), -globalOffset.y);
colorTransform.color = 0xFFEF0202; colorTransform.color = 0xFFEF0202;
} else { } else
animation.play(animName, true, false, animFrame); setAnimOffset(animateAtlas != null ? atlasPlayingAnim : animation.name);
setAnimOffset(animName);
if (animation.curAnim != null)
animation.curAnim._frameTimer = animFrameTimer;
}
super.draw(); super.draw();
} }
@@ -72,45 +70,22 @@ class CharacterGhost extends Character {
offset.set(globalOffset.x * (isPlayer != playerOffsets ? 1 : -1), -globalOffset.y); offset.set(globalOffset.x * (isPlayer != playerOffsets ? 1 : -1), -globalOffset.y);
} }
public function generateRenderTextureForAnim(anim:String):RenderTexture @:privateAccess { // This gets annoying lmao -lunar
if (!isAnimate) return null; private var atlasState:AtlasState = null;
public function storeAtlasState():AtlasState @:privateAccess {
var wasInvalidFrame:Bool = !colorTransform.__isDefault(false); return atlasState = {
colorTransform.__identity(); oldAnim: atlasPlayingAnim,
oldFrame: animateAtlas.anim.curFrame,
var animName = animation.curAnim?.name ?? null; oldTick: animateAtlas.anim._tick,
var animFrame = animation.curAnim?.curFrame ?? 0; oldPlaying: animateAtlas.anim.isPlaying,
var animFrameTimer = animation.curAnim?._frameTimer ?? 0; };
var oldRenderTexture:RenderTexture = this._renderTexture;
var oldRenderTextureDirty = _renderTextureDirty;
var oldAlpha = alpha;
this._renderTexture = null;
this._renderTextureDirty = true;
this.alpha = 256.0/257.0;
animation.play(anim, true, false, 0);
drawAnimate(FakeCallCamera.instance);
var renderTex = this._renderTexture;
this._renderTexture = oldRenderTexture;
this._renderTextureDirty = oldRenderTextureDirty;
this.alpha = oldAlpha;
if (wasInvalidFrame) {
colorTransform.color = 0xFFEF0202;
} else {
animation.play(animName, true, false, animFrame);
if (animation.curAnim != null)
animation.curAnim._frameTimer = animFrameTimer;
}
return renderTex;
} }
// This gets annoying lmao -lunar public function restoreAtlasState(state:AtlasState = null) @:privateAccess {
// it's gone now <3 -yosh if (state == null) state = atlasState;
animateAtlas.anim.play(state.oldAnim, true, false, state.oldFrame);
animateAtlas.anim._tick = state.oldTick;
animateAtlas.anim.isPlaying = state.oldPlaying;
}
} }
@@ -1,6 +1,7 @@
package funkin.editors.character; package funkin.editors.character;
import funkin.backend.FlxAnimate;
import haxe.io.Path; import haxe.io.Path;
import funkin.editors.character.CharacterInfoScreen.CharacterExtraInfo; import funkin.editors.character.CharacterInfoScreen.CharacterExtraInfo;
import funkin.game.Character; import funkin.game.Character;
@@ -183,15 +184,31 @@ class CharacterPropertiesWindow extends UISliceSprite {
character.sprite = sprite; character.sprite = sprite;
animsWindow.displayWindowSprite.animation.reset(); animsWindow.displayWindowSprite.animation.reset();
animsWindow.clearDisplayAnims(); animsWindow.displayAnimsFramesList.clear();
if (animsWindow.displayWindowGraphic != null) if (animsWindow.displayWindowGraphic != null)
animsWindow.displayWindowGraphic.destroy(); animsWindow.displayWindowGraphic.destroy();
character.frames = Paths.getFrames(path, true); if (Assets.exists('$noExt/Animation.json')) {
if (character.animateAtlas == null) {
character.animation.reset();
character.animateAtlas = new FlxAnimate(character.x, character.y);
} else
character.animateAtlas.anim.stop();
animsWindow.displayWindowSprite.loadGraphicFromSprite(character); character.atlasPath = noExt;
if (Assets.exists(Paths.image('characters/${character.sprite}'))) character.animateAtlas.loadAtlas(noExt);
animsWindow.displayWindowGraphic = FlxG.bitmap.add(Assets.getBitmapData(Paths.image('characters/${character.sprite}'), true, false)); } else {
if (character.animateAtlas != null) {
character.animateAtlas.destroy();
character.animateAtlas = null;
character.atlasPlayingAnim = character.atlasPath = null;
}
character.frames = Paths.getFrames(path, true);
animsWindow.displayWindowSprite.loadGraphicFromSprite(character);
if (Assets.exists(Paths.image('characters/${character.sprite}')))
animsWindow.displayWindowGraphic = FlxG.bitmap.add(Assets.getBitmapData(Paths.image('characters/${character.sprite}'), true, false));
}
character.animDatas.clear(); character.animDatas.clear();
for (anim in animsWindow.buttons) anim.checkValid(); // Re-add all animations for (anim in animsWindow.buttons) anim.checkValid(); // Re-add all animations
+66 -228
View File
@@ -77,10 +77,10 @@ class Charter extends UIState {
public var strumlineLockButton:CharterStrumlineButton; public var strumlineLockButton:CharterStrumlineButton;
public var hitsound:FlxSound; public var hitsound:FlxSound;
public var hitsoundGlobalVolume:Float = 1.0;
public var metronome:FlxSound; public var metronome:FlxSound;
public var vocals:FlxSound; public var vocals:FlxSound;
public var voicesMuted:Bool = false;
public var quant:Int = 16; public var quant:Int = 16;
public var quants:Array<Int> = [4, 8, 12, 16, 20, 24, 32, 48, 64, 192]; // different quants public var quants:Array<Int> = [4, 8, 12, 16, 20, 24, 32, 48, 64, 192]; // different quants
@@ -96,7 +96,6 @@ class Charter extends UIState {
public var rightEventRowText:UIText; public var rightEventRowText:UIText;
public var leftEventsGroup:CharterEventGroup = new CharterEventGroup(); public var leftEventsGroup:CharterEventGroup = new CharterEventGroup();
public var rightEventsGroup:CharterEventGroup = new CharterEventGroup(); public var rightEventsGroup:CharterEventGroup = new CharterEventGroup();
public var cameraMovementChanges:Array<CameraChange> = [];
public var charterCamera:FlxCamera; public var charterCamera:FlxCamera;
public var uiCamera:FlxCamera; public var uiCamera:FlxCamera;
@@ -232,11 +231,6 @@ class Charter extends UIState {
label: translate("edit.delete"), label: translate("edit.delete"),
keybind: [DELETE], keybind: [DELETE],
onSelect: _edit_delete onSelect: _edit_delete
},
{
label: translate("edit.deletestacked"),
keybind: [SHIFT,DELETE],
onSelect: _edit_deletestacked
} }
] ]
}, },
@@ -314,11 +308,6 @@ class Charter extends UIState {
onSelect: _view_showeventBeatSeparator, onSelect: _view_showeventBeatSeparator,
icon: Options.charterShowBeats ? 1 : 0 icon: Options.charterShowBeats ? 1 : 0
}, },
{
label: translate("view.showCameraHighlights"),
onSelect: _view_showeventCameraHighlights,
icon: Options.charterShowCameraHighlights ? 1 : 0
},
null, null,
{ {
label: translate("view.rainbowWaveforms"), label: translate("view.rainbowWaveforms"),
@@ -464,7 +453,7 @@ class Charter extends UIState {
rightEventsGroup.eventsRowText = rightEventRowText; rightEventsGroup.eventsRowText = rightEventRowText;
// thank you neo for pointing out im stupid -lunar // thank you neo for pointing out im stupid -lunar
// this is future lunar i completely forgot what neo pointed out but hes awesome go follow him on twitter // this is future lunar i completely forgot what neo pointed out but hes awesome go follow him on twitter
add(gridBackdropDummy = new CameraHoverDummy(gridBackdrops, FlxPoint.weak(1, 0))); add(gridBackdropDummy = new CameraHoverDummy(gridBackdrops, FlxPoint.weak(1, 0)));
selectionBox = new UISliceSprite(0, 0, 2, 2, 'editors/ui/selection'); selectionBox = new UISliceSprite(0, 0, 2, 2, 'editors/ui/selection');
@@ -526,7 +515,7 @@ class Charter extends UIState {
strumlineLockButton = new CharterStrumlineButton("editors/charter/lock-strumline", translate("lock-unlock")); strumlineLockButton = new CharterStrumlineButton("editors/charter/lock-strumline", translate("lock-unlock"));
strumlineLockButton.onClick = function () { strumlineLockButton.onClick = function () {
UIState.playEditorSound(!strumLines.draggable ? Flags.DEFAULT_CHARTER_STRUMUNLOCK_SOUND : Flags.DEFAULT_CHARTER_STRUMLOCK_SOUND); FlxG.sound.play(Paths.sound(!strumLines.draggable ? Flags.DEFAULT_CHARTER_STRUMUNLOCK_SOUND : Flags.DEFAULT_CHARTER_STRUMLOCK_SOUND));
if (strumLines != null) { if (strumLines != null) {
strumLines.draggable = !strumLines.draggable; strumLines.draggable = !strumLines.draggable;
strumlineLockButton.textTweenColor.color = strumLines.draggable ? 0xFF5C95CA : 0xFFE16565; strumlineLockButton.textTweenColor.color = strumLines.draggable ? 0xFF5C95CA : 0xFFE16565;
@@ -696,7 +685,6 @@ class Charter extends UIState {
CharterGridSeperatorBase.lastConductorSprY = Math.NEGATIVE_INFINITY; CharterGridSeperatorBase.lastConductorSprY = Math.NEGATIVE_INFINITY;
updateWaveforms(); updateWaveforms();
updateCameraChanges();
} }
public function getWavesToGenerate():Array<{name:String, sound:FlxSound}> { public function getWavesToGenerate():Array<{name:String, sound:FlxSound}> {
@@ -752,38 +740,6 @@ class Charter extends UIState {
} }
} }
public function updateCameraChanges() {
if (!Options.charterShowCameraHighlights) return;
cameraMovementChanges = [];
for (grp in [leftEventsGroup, rightEventsGroup]) {
grp.filterEvents();
grp.sortEvents();
for(e in grp.members) {
for(event in e.events) {
if (event.name == "Camera Movement") {
cameraMovementChanges.push({
strumLineID: event.params[0],
step: e.step,
endStep: __endStep
});
}
}
}
}
//need to sort again for both local and global events to be used
cameraMovementChanges.sort(function(e1, e2) {
return FlxSort.byValues(FlxSort.ASCENDING, e1.step, e2.step);
});
//update previous change
if (cameraMovementChanges.length > 0) {
for (i in 1...cameraMovementChanges.length) {
cameraMovementChanges[i-1].endStep = cameraMovementChanges[i].step;
}
}
}
public override function beatHit(curBeat:Int) { public override function beatHit(curBeat:Int) {
super.beatHit(curBeat); super.beatHit(curBeat);
if (FlxG.sound.music.playing) { if (FlxG.sound.music.playing) {
@@ -801,7 +757,6 @@ class Charter extends UIState {
public var mousePos:FlxPoint = new FlxPoint(); public var mousePos:FlxPoint = new FlxPoint();
public var selectionDragging:Bool = false; public var selectionDragging:Bool = false;
public var isSelecting:Bool = false; public var isSelecting:Bool = false;
public var isAltCopyDrag:Bool = false;
public function updateSelectionLogic() { public function updateSelectionLogic() {
function select(s:ICharterSelectable) { function select(s:ICharterSelectable) {
@@ -847,7 +802,7 @@ class Charter extends UIState {
else else
Chart.save(PlayState.SONG, __diff.toLowerCase(), __variant, {saveMetaInChart: true, saveLocalEvents: true, seperateGlobalEvents: true, prettyPrint: Options.editorCharterPrettyPrint}); Chart.save(PlayState.SONG, __diff.toLowerCase(), __variant, {saveMetaInChart: true, saveLocalEvents: true, seperateGlobalEvents: true, prettyPrint: Options.editorCharterPrettyPrint});
UIState.playEditorSound(Flags.DEFAULT_EDITOR_SAVE_SOUND); FlxG.sound.play(Paths.sound('editors/save'));
undos.save(); undos.save();
} }
autoSaveNotif.cancelled = false; autoSaveNotif.cancelled = false;
@@ -966,24 +921,17 @@ class Charter extends UIState {
if (!(verticalChange == 0 && horizontalChange == 0)) { if (!(verticalChange == 0 && horizontalChange == 0)) {
notesGroup.sortNotes(); notesGroup.sortNotes();
var changes:Array<CharterChange> = []; undos.addToUndo(CChangeBundle([
if (isAltCopyDrag) { CSelectionDrag(undoDrags),
changes.push(CCreateSelection(selection.copy())); updateEventsGroups(selection)
isAltCopyDrag = false; ]));
}
changes.push(CSelectionDrag(undoDrags));
changes.push(updateEventsGroups(selection));
undos.addToUndo(CChangeBundle(changes));
} else if (isAltCopyDrag) {
undos.addToUndo(CCreateSelection(selection.copy()));
isAltCopyDrag = false;
} }
gridActionType = NONE; gridActionType = NONE;
currentCursor = ARROW; currentCursor = ARROW;
} }
case NONE: case NONE:
if (FlxG.mouse.justPressed) if (FlxG.mouse.justPressed)
FlxG.mouse.getWorldPosition(charterCamera, dragStartPos); FlxG.mouse.getWorldPosition(charterCamera, dragStartPos);
else if (FlxG.mouse.justPressedRight) { else if (FlxG.mouse.justPressedRight) {
closeCurrentContextMenu(); closeCurrentContextMenu();
@@ -1014,7 +962,7 @@ class Charter extends UIState {
notesGroup.add(note); notesGroup.add(note);
selection = [note]; selection = [note];
undos.addToUndo(CCreateSelection([note])); undos.addToUndo(CCreateSelection([note]));
UIState.playEditorSound(Flags.DEFAULT_CHARTER_NOTEPLACE_SOUND); FlxG.sound.play(Paths.sound(Flags.DEFAULT_CHARTER_NOTEPLACE_SOUND));
} }
isSelecting = false; isSelecting = false;
} }
@@ -1031,32 +979,7 @@ class Charter extends UIState {
} }
if ((Math.abs(mousePos.x - dragStartPos.x) > (noteSusDrag ? 1 : 5) || Math.abs(mousePos.y - dragStartPos.y) > (noteSusDrag ? 1 : 5))) { if ((Math.abs(mousePos.x - dragStartPos.x) > (noteSusDrag ? 1 : 5) || Math.abs(mousePos.y - dragStartPos.y) > (noteSusDrag ? 1 : 5))) {
if (noteHovered) { if (noteHovered) gridActionType = noteHovered ? NOTE_DRAG : INVALID_DRAG;
if (FlxG.keys.pressed.ALT && selection.length > 0) {
var newSelection:Array<ICharterSelectable> = [];
for (s in selection) {
if (s is CharterNote) {
var n:CharterNote = cast s;
var newNote = new CharterNote();
newNote.updatePos(n.step, n.id, n.susLength, n.type, n.strumLine);
notesGroup.add(newNote);
newSelection.push(newNote);
} else if (s is CharterEvent) {
var e:CharterEvent = cast s;
var newEvent = new CharterEvent(e.step, [for (event in e.events) Reflect.copy(event)], e.global);
newEvent.refreshEventIcons();
(e.global ? rightEventsGroup : leftEventsGroup).add(newEvent);
newSelection.push(newEvent);
}
}
for (s in selection) s.selected = false;
selection = newSelection;
for (s in selection) s.selected = true;
isAltCopyDrag = true;
UIState.playEditorSound(Flags.DEFAULT_EDITOR_COPY_SOUND);
}
gridActionType = NOTE_DRAG;
}
if (noteSusDrag) gridActionType = SUSTAIN_DRAG; if (noteSusDrag) gridActionType = SUSTAIN_DRAG;
} }
} }
@@ -1168,7 +1091,7 @@ class Charter extends UIState {
if (selected == null) return selected; if (selected == null) return selected;
if (selected is CharterNote) { if (selected is CharterNote) {
UIState.playEditorSound(Flags.DEFAULT_CHARTER_NOTEDELETE_SOUND); FlxG.sound.play(Paths.sound(Flags.DEFAULT_CHARTER_NOTEDELETE_SOUND));
var note:CharterNote = cast selected; var note:CharterNote = cast selected;
note.strumLineID = strumLines.members.indexOf(note.strumLine); note.strumLineID = strumLines.members.indexOf(note.strumLine);
note.strumLine = null; // For static undos :D note.strumLine = null; // For static undos :D
@@ -1648,20 +1571,20 @@ class Charter extends UIState {
else {undos = null; FlxG.switchState(new CharterSelection()); Charter.instance.__clearStatics();} else {undos = null; FlxG.switchState(new CharterSelection()); Charter.instance.__clearStatics();}
} }
function _file_save_all(_) {saveEverything(); UIState.playEditorSound(Flags.DEFAULT_EDITOR_SAVE_SOUND);} function _file_save_all(_) {saveEverything(); FlxG.sound.play(Paths.sound('editors/save'));}
function _file_save(_) {saveChart(); UIState.playEditorSound(Flags.DEFAULT_EDITOR_SAVE_SOUND);} function _file_save(_) {saveChart(); FlxG.sound.play(Paths.sound('editors/save'));}
function _file_saveas(_) {saveChartAs(); UIState.playEditorSound(Flags.DEFAULT_EDITOR_SAVE_SOUND);} function _file_saveas(_) {saveChartAs(); FlxG.sound.play(Paths.sound('editors/save'));}
function _file_events_save(_) {saveEvents(); UIState.playEditorSound(Flags.DEFAULT_EDITOR_SAVE_SOUND);} function _file_events_save(_) {saveEvents(); FlxG.sound.play(Paths.sound('editors/save'));}
function _file_events_saveas(_) {saveEventsAs(); UIState.playEditorSound(Flags.DEFAULT_EDITOR_SAVE_SOUND);} function _file_events_saveas(_) {saveEventsAs(); FlxG.sound.play(Paths.sound('editors/save'));}
function _file_save_no_events(_) {saveChart(true, false); UIState.playEditorSound(Flags.DEFAULT_EDITOR_SAVE_SOUND);} function _file_save_no_events(_) {saveChart(true, false); FlxG.sound.play(Paths.sound('editors/save'));}
function _file_saveas_no_events(_) {saveChartAs(true, false); UIState.playEditorSound(Flags.DEFAULT_EDITOR_SAVE_SOUND);} function _file_saveas_no_events(_) {saveChartAs(true, false); FlxG.sound.play(Paths.sound('editors/save'));}
function _file_meta_save(_) {saveMeta(); UIState.playEditorSound(Flags.DEFAULT_EDITOR_SAVE_SOUND);} function _file_meta_save(_) {saveMeta(); FlxG.sound.play(Paths.sound('editors/save'));}
function _file_meta_saveas(_) {saveMetaAs(); UIState.playEditorSound(Flags.DEFAULT_EDITOR_SAVE_SOUND);} function _file_meta_saveas(_) {saveMetaAs(); FlxG.sound.play(Paths.sound('editors/save'));}
function _file_saveas_fnflegacy(_) {saveLegacyChartAs(); UIState.playEditorSound(Flags.DEFAULT_EDITOR_SAVE_SOUND);} function _file_saveas_fnflegacy(_) {saveLegacyChartAs(); FlxG.sound.play(Paths.sound('editors/save'));}
function _file_saveas_psych(_) {savePsychChartAs(); UIState.playEditorSound(Flags.DEFAULT_EDITOR_SAVE_SOUND);} function _file_saveas_psych(_) {savePsychChartAs(); FlxG.sound.play(Paths.sound('editors/save'));}
function _edit_copy(_, playSFX=true) { function _edit_copy(_, playSFX=true) {
if (playSFX) UIState.playEditorSound(Flags.DEFAULT_EDITOR_COPY_SOUND); if (playSFX) FlxG.sound.play(Paths.sound(Flags.DEFAULT_EDITOR_COPY_SOUND));
if(selection.length == 0) return; if(selection.length == 0) return;
var minStep:Float = selection[0].step; var minStep:Float = selection[0].step;
@@ -1680,7 +1603,7 @@ class Charter extends UIState {
]; ];
} }
function _edit_paste(_) { function _edit_paste(_) {
UIState.playEditorSound(Flags.DEFAULT_EDITOR_PASTE_SOUND); FlxG.sound.play(Paths.sound(Flags.DEFAULT_EDITOR_PASTE_SOUND));
if (clipboard.length <= 0) return; if (clipboard.length <= 0) return;
var minStep = curStep; var minStep = curStep;
@@ -1708,7 +1631,7 @@ class Charter extends UIState {
} }
function _edit_cut(_) { function _edit_cut(_) {
UIState.playEditorSound(Flags.DEFAULT_EDITOR_CUT_SOUND); FlxG.sound.play(Paths.sound(Flags.DEFAULT_EDITOR_CUT_SOUND));
if (selection == null || selection.length == 0) return; if (selection == null || selection.length == 0) return;
_edit_copy(_, false); _edit_copy(_, false);
@@ -1716,7 +1639,7 @@ class Charter extends UIState {
} }
function _edit_delete(_) { function _edit_delete(_) {
UIState.playEditorSound(Flags.DEFAULT_EDITOR_DELETE_SOUND); FlxG.sound.play(Paths.sound(Flags.DEFAULT_EDITOR_DELETE_SOUND));
if (selection == null || selection.length == 0) return; if (selection == null || selection.length == 0) return;
selection.loop((n:CharterNote) -> { selection.loop((n:CharterNote) -> {
noteDeleteAnims.deleteNotes.push({note: n, time: noteDeleteAnims.deleteTime}); noteDeleteAnims.deleteNotes.push({note: n, time: noteDeleteAnims.deleteTime});
@@ -1724,27 +1647,8 @@ class Charter extends UIState {
selection = deleteSelection(selection, true); selection = deleteSelection(selection, true);
} }
function _edit_deletestacked(_) {
UIState.playEditorSound(Flags.DEFAULT_EDITOR_DELETE_SOUND);
if (notesGroup.members.length == 0) return;
var oldNote:CharterNote = null;
var selectionArray:Array<Dynamic> = ((selection.length != 0) ? selection : notesGroup.members.copy());
var toDelete:Selection = new Selection();
for (note in selectionArray) {
if (oldNote != null && oldNote.step == note.step && oldNote.strumLineID == note.strumLineID && oldNote.id == note.id) {
noteDeleteAnims.deleteNotes.push({note: oldNote, time: noteDeleteAnims.deleteTime});
toDelete.push(oldNote);
}
oldNote = note;
}
if (toDelete.length != 0) {
deleteSelection(toDelete);
if (selection.length != 0) for (i in toDelete) selection.remove(i); //crash prevention
}
}
function _undo(undo:CharterChange) { function _undo(undo:CharterChange) {
UIState.playEditorSound(Flags.DEFAULT_EDITOR_UNDO_SOUND); FlxG.sound.play(Paths.sound(Flags.DEFAULT_EDITOR_UNDO_SOUND));
switch(undo) { switch(undo) {
case null: // do nothing case null: // do nothing
case CDeleteStrumLine(strumLineID, strumLine): case CDeleteStrumLine(strumLineID, strumLine):
@@ -1793,11 +1697,7 @@ class Charter extends UIState {
case CEditSpecNotesType(notes, oldTypes, newTypes): case CEditSpecNotesType(notes, oldTypes, newTypes):
for(i=>note in notes) note.updatePos(note.step, note.id, note.susLength, oldTypes[i]); for(i=>note in notes) note.updatePos(note.step, note.id, note.susLength, oldTypes[i]);
case CChangeBundle(changes): case CChangeBundle(changes):
var i = changes.length - 1; for (change in changes) _undo(change);
while (i >= 0) {
_undo(changes[i]);
i--;
}
} }
} }
@@ -1809,7 +1709,7 @@ class Charter extends UIState {
} }
function _redo(redo:CharterChange) { function _redo(redo:CharterChange) {
UIState.playEditorSound(Flags.DEFAULT_EDITOR_REDO_SOUND); FlxG.sound.play(Paths.sound(Flags.DEFAULT_EDITOR_REDO_SOUND));
switch(redo) { switch(redo) {
case null: // do nothing case null: // do nothing
case CDeleteStrumLine(strumLineID, strumLine): case CDeleteStrumLine(strumLineID, strumLine):
@@ -1908,24 +1808,14 @@ class Charter extends UIState {
function _playback_metronome(t) { function _playback_metronome(t) {
t.icon = (Options.charterMetronomeEnabled = !Options.charterMetronomeEnabled) ? 1 : 0; t.icon = (Options.charterMetronomeEnabled = !Options.charterMetronomeEnabled) ? 1 : 0;
} }
function _song_muteinst(t) {
public function _slider_mutetoggle(t:UIContextMenuOption) { FlxG.sound.music.volume = FlxG.sound.music.volume > 0 ? 0 : 1;
if (t.slider == null) return; t.icon = 1 - Std.int(Math.ceil(FlxG.sound.music.volume));
t.button.slider.value = t.button.slider.value > 0 ? 0 : 1;
} }
function _song_mutevoices(t) {
function _song_instvolume(t) { vocals.volume = (voicesMuted = !voicesMuted) ? 0 : 1;
FlxG.sound.music.volume = t.slider.value; for (strumLine in strumLines.members) strumLine.updateVoicesVolume();
t.icon = t.slider.value > 0.5 ? 7 : (t.slider.value > 0 ? 8 : 9); t.icon = voicesMuted ? 1 : 0;
}
function _song_voicesvolume(t) {
vocals.volume = t.slider.value;
for (strumLine in strumLines.members) strumLine.vocals.volume = t.slider.value * strumLine.vocalsVolume;
t.icon = t.slider.value > 0.5 ? 7 : (t.slider.value > 0 ? 8 : 9);
}
function _song_hitsoundvolume(t) {
hitsoundGlobalVolume = t.slider.value;
t.icon = t.slider.value > 0.5 ? 7 : (t.slider.value > 0 ? 8 : 9);
} }
function _playback_back(_) { function _playback_back(_) {
if (FlxG.sound.music.playing) return; if (FlxG.sound.music.playing) return;
@@ -1970,7 +1860,6 @@ class Charter extends UIState {
__event.refreshEventIcons(); __event.refreshEventIcons();
(__event.global ? rightEventsGroup : leftEventsGroup).add(__event); (__event.global ? rightEventsGroup : leftEventsGroup).add(__event);
undos.addToUndo(CEditEvent(__event, [], __event.events)); undos.addToUndo(CEditEvent(__event, [], __event.events));
updateCameraChanges();
} }
public function getBookmarkList():Array<ChartBookmark> { public function getBookmarkList():Array<ChartBookmark> {
@@ -1979,7 +1868,7 @@ class Charter extends UIState {
if (PlayState.SONG.bookmarks != null) if (PlayState.SONG.bookmarks != null)
bookmarks = PlayState.SONG.bookmarks; bookmarks = PlayState.SONG.bookmarks;
} catch (e) {} } catch (e) {}
return bookmarks; return bookmarks;
} }
@@ -1989,9 +1878,9 @@ class Charter extends UIState {
var currentBookmarks:Array<ChartBookmark> = getBookmarkList(); var currentBookmarks:Array<ChartBookmark> = getBookmarkList();
var newBookmarks:Array<ChartBookmark> = getBookmarkList(); var newBookmarks:Array<ChartBookmark> = getBookmarkList();
newBookmarks.push({time: daStep, name: name, color: color.toWebString()}); newBookmarks.push({time: daStep, name: name, color: color.toWebString()});
PlayState.SONG.bookmarks = newBookmarks; PlayState.SONG.bookmarks = newBookmarks;
updateBookmarks(); updateBookmarks();
undos.addToUndo(CEditBookmarks(currentBookmarks, newBookmarks)); undos.addToUndo(CEditBookmarks(currentBookmarks, newBookmarks));
} }
@@ -2016,7 +1905,7 @@ class Charter extends UIState {
{ {
var bars:Array<FlxSprite> = bs[0]; var bars:Array<FlxSprite> = bs[0];
var text:UIText = bs[1]; var text:UIText = bs[1];
if (bars != null) { if (bars != null) {
for (spr in bars) { for (spr in bars) {
if (spr == null) continue; if (spr == null) continue;
@@ -2070,7 +1959,7 @@ class Charter extends UIState {
0, 0,
scrollBar.height scrollBar.height
); );
var bookmarkspr = new FlxSprite(scrollBar.x - 10, yPos).makeSolid(40, 4, bookmarkcolor); var bookmarkspr = new FlxSprite(scrollBar.x - 10, yPos).makeSolid(40, 4, bookmarkcolor);
uiGroup.add(bookmarkspr); uiGroup.add(bookmarkspr);
sprites.push(bookmarkspr); sprites.push(bookmarkspr);
@@ -2122,56 +2011,26 @@ class Charter extends UIState {
if (bookmarks.length > 0) if (bookmarks.length > 0)
{ {
var bookmarkOptions:Array<UIContextMenuOption> = [];
var goToBookmark = TU.getRaw("charter.bookmarks.goTo"); var goToBookmark = TU.getRaw("charter.bookmarks.goTo");
for (b in bookmarks) for (b in bookmarks)
{ {
bookmarkOptions.push({ newChilds.push({
label: goToBookmark.format([b.name]), label: goToBookmark.format([b.name]),
onSelect: function(_) { Conductor.songPosition = Conductor.getTimeForStep(b.time); } onSelect: function(_) { Conductor.songPosition = Conductor.getTimeForStep(b.time); }
}); });
} }
newChilds.push({
label: translate("bookmarks.bookmarkList"),
childs: bookmarkOptions
});
newChilds.push(null); newChilds.push(null);
} }
newChilds.push({ newChilds.push({
label: translate("song.inst"), label: translate("song.muteInst"),
slider: { onSelect: _song_muteinst
min: 0,
max: 1,
value: 1,
onChange: _song_instvolume
},
onIconClick: _slider_mutetoggle,
icon: 7
}); });
newChilds.push({ newChilds.push({
label: translate("song.voices"), label: translate("song.muteVoices"),
slider: { onSelect: _song_mutevoices
min: 0,
max: 1,
value: 1,
onChange: _song_voicesvolume
},
onIconClick: _slider_mutetoggle,
icon: 7
});
newChilds.push({
label: translate("song.hitsounds"),
slider: {
min: 0,
max: 1,
value: 1,
onChange: _song_hitsoundvolume
},
onIconClick: _slider_mutetoggle,
icon: 7
}); });
if (songTopButton != null) songTopButton.contextMenu = newChilds; if (songTopButton != null) songTopButton.contextMenu = newChilds;
@@ -2196,10 +2055,6 @@ class Charter extends UIState {
function _view_showeventBeatSeparator(t) { function _view_showeventBeatSeparator(t) {
t.icon = (Options.charterShowBeats = !Options.charterShowBeats) ? 1 : 0; t.icon = (Options.charterShowBeats = !Options.charterShowBeats) ? 1 : 0;
} }
function _view_showeventCameraHighlights(t) {
t.icon = (Options.charterShowCameraHighlights = !Options.charterShowCameraHighlights) ? 1 : 0;
updateCameraChanges();
}
function _view_switchWaveformRainbow(t) { function _view_switchWaveformRainbow(t) {
t.icon = (Options.charterRainbowWaveforms = !Options.charterRainbowWaveforms) ? 1 : 0; t.icon = (Options.charterRainbowWaveforms = !Options.charterRainbowWaveforms) ? 1 : 0;
@@ -2225,8 +2080,8 @@ class Charter extends UIState {
inline function _snap_decreasesnap(_) changequant(-1); inline function _snap_decreasesnap(_) changequant(-1);
inline function _snap_resetsnap(_) setquant(16); inline function _snap_resetsnap(_) setquant(16);
inline function changequant(change:Int) {UIState.playEditorSound(Flags.DEFAULT_CHARTER_SNAPPINGCHANGE_SOUND); quant = quants[FlxMath.wrap(quants.indexOf(quant) + change, 0, quants.length-1)]; buildSnapsUI();}; inline function changequant(change:Int) {FlxG.sound.play(Paths.sound(Flags.DEFAULT_CHARTER_SNAPPINGCHANGE_SOUND)); quant = quants[FlxMath.wrap(quants.indexOf(quant) + change, 0, quants.length-1)]; buildSnapsUI();};
inline function setquant(newQuant:Int) {UIState.playEditorSound(Flags.DEFAULT_CHARTER_SNAPPINGCHANGE_SOUND); quant = newQuant; buildSnapsUI();} inline function setquant(newQuant:Int) {FlxG.sound.play(Paths.sound(Flags.DEFAULT_CHARTER_SNAPPINGCHANGE_SOUND)); quant = newQuant; buildSnapsUI();}
function buildSnapsUI():Array<UIContextMenuOption> { function buildSnapsUI():Array<UIContextMenuOption> {
var snapsTopButton:UITopMenuButton = topMenuSpr == null ? null : cast topMenuSpr.members[snapIndex]; var snapsTopButton:UITopMenuButton = topMenuSpr == null ? null : cast topMenuSpr.members[snapIndex];
@@ -2262,12 +2117,12 @@ class Charter extends UIState {
} }
inline function _note_addsustain(t) { inline function _note_addsustain(t) {
UIState.playEditorSound(Flags.DEFAULT_CHARTER_SUSTAINADD_SOUND); FlxG.sound.play(Paths.sound(Flags.DEFAULT_CHARTER_SUSTAINADD_SOUND));
changeNoteSustain(1); changeNoteSustain(1);
} }
inline function _note_subtractsustain(t) { inline function _note_subtractsustain(t) {
UIState.playEditorSound(Flags.DEFAULT_CHARTER_SUSTAINDELETE_SOUND); FlxG.sound.play(Paths.sound(Flags.DEFAULT_CHARTER_SUSTAINDELETE_SOUND));
changeNoteSustain(-1); changeNoteSustain(-1);
} }
@@ -2344,18 +2199,16 @@ class Charter extends UIState {
keybind: [CONTROL, SHIFT, A], keybind: [CONTROL, SHIFT, A],
onSelect: _note_selectmeasure onSelect: _note_selectmeasure
}, },
null null,
{
label: "(0) " + translate("noteTypes.default"),
keybind: [ZERO],
onSelect: (_) -> {changeNoteType(0);},
icon: this.noteType == 0 ? 1 : 0
}
]; ];
var noteTypeOptions:Array<UIContextMenuOption> = [{ var noteKeys:Array<FlxKey> = [ZERO, ONE, TWO, THREE, FOUR, FIVE, SIX, SEVEN, EIGHT, NINE];
label: "(0) " + translate("noteTypes.default"),
keybind: [ZERO],
onSelect: (_) -> {changeNoteType(0);},
icon: this.noteType == 0 ? 1 : 0
}];
final noteKeys:Array<Array<Array<FlxKey>>> = [[[ZERO], [NUMPADZERO]], [[ONE], [NUMPADONE]], [[TWO], [NUMPADTWO]], [[THREE], [NUMPADTHREE]], [[FOUR], [NUMPADFOUR]], [[FIVE], [NUMPADFIVE]],
[[SIX], [NUMPADSIX]], [[SEVEN], [NUMPADSEVEN]], [[EIGHT], [NUMPADEIGHT]], [[NINE], [NUMPADNINE]]];
for (i=>type in noteTypes) { for (i=>type in noteTypes) {
var realNoteID:Int = i+1; // Default Note not stored var realNoteID:Int = i+1; // Default Note not stored
var newChild:UIContextMenuOption = { var newChild:UIContextMenuOption = {
@@ -2364,13 +2217,9 @@ class Charter extends UIState {
onSelect: (_) -> {changeNoteType(realNoteID);}, onSelect: (_) -> {changeNoteType(realNoteID);},
icon: this.noteType == realNoteID ? 1 : 0 icon: this.noteType == realNoteID ? 1 : 0
}; };
if (realNoteID <= 9) newChild.keybinds = noteKeys[realNoteID]; if (realNoteID <= 9) newChild.keybind = [noteKeys[realNoteID]];
noteTypeOptions.push(newChild); newChilds.push(newChild);
} }
newChilds.push({
label: translate("note.noteTypesList"),
childs: noteTypeOptions
});
newChilds.push({ newChilds.push({
label: translate("note.editNoteTypesList"), label: translate("note.editNoteTypesList"),
color: 0xFF959829, icon: 4, color: 0xFF959829, icon: 4,
@@ -2378,7 +2227,6 @@ class Charter extends UIState {
onSelect: editNoteTypesList onSelect: editNoteTypesList
}); });
if (noteTopButton != null) noteTopButton.contextMenu = newChilds; if (noteTopButton != null) noteTopButton.contextMenu = newChilds;
if (topMenu != null && topMenu[noteIndex] != null) topMenu[noteIndex].childs = newChilds;
return newChilds; return newChilds;
} }
@@ -2466,12 +2314,8 @@ class Charter extends UIState {
} }
} }
public inline function playHitsound(id:Int) { public inline function hitsoundsEnabled(id:Int)
if (strumLines.members[id] != null && strumLines.members[id].hitsoundVolume > 0 && hitsoundGlobalVolume > 0) { return strumLines.members[id] != null && strumLines.members[id].hitsounds;
hitsound.volume = hitsoundGlobalVolume * strumLines.members[id].hitsoundVolume;
hitsound.replay();
}
}
public inline function __fixSelection(selection:Selection):Selection { public inline function __fixSelection(selection:Selection):Selection {
var newSelection:Selection = new Selection(); var newSelection:Selection = new Selection();
@@ -2562,7 +2406,7 @@ class Charter extends UIState {
quantSelected: quant, quantSelected: quant,
noteTypeSelected: noteType, noteTypeSelected: noteType,
strumlinesDraggable: strumLines.draggable, strumlinesDraggable: strumLines.draggable,
hitSounds: [for (strumLine in strumLines.members) strumLine.hitsoundVolume > 0], hitSounds: [for (strumLine in strumLines.members) strumLine.hitsounds],
mutedVocals: [for (strumLine in strumLines.members) !(strumLine.vocals.volume > 0)], mutedVocals: [for (strumLine in strumLines.members) !(strumLine.vocals.volume > 0)],
waveforms: [for (strumLine in strumLines.members) strumLine.selectedWaveform] waveforms: [for (strumLine in strumLines.members) strumLine.selectedWaveform]
} }
@@ -2578,7 +2422,7 @@ class Charter extends UIState {
strumLines.draggable = playtestInfo.strumlinesDraggable; strumLines.draggable = playtestInfo.strumlinesDraggable;
for (i => strumLine in strumLines.members) for (i => strumLine in strumLines.members)
strumLine.hitsoundVolume = playtestInfo.hitSounds[i] ? 1 : 0; strumLine.hitsounds = playtestInfo.hitSounds[i];
for (i => strumLine in strumLines.members) for (i => strumLine in strumLines.members)
strumLine.vocals.volume = playtestInfo.mutedVocals[i] ? 0 : 1; strumLine.vocals.volume = playtestInfo.mutedVocals[i] ? 0 : 1;
for (i => strumLine in strumLines.members) for (i => strumLine in strumLines.members)
@@ -2670,9 +2514,3 @@ typedef PlaytestInfo = {
var mutedVocals:Array<Bool>; var mutedVocals:Array<Bool>;
var waveforms:Array<Int>; var waveforms:Array<Int>;
} }
typedef CameraChange = {
var strumLineID:Int;
var step:Float;
var endStep:Float;
}
@@ -82,7 +82,7 @@ class CharterAutoSaveUI extends UISliceSprite {
icon.animation.curAnim.curFrame = 1; icon.animation.curAnim.curFrame = 1;
for (member in [this, progressBar, progressBarBack, autosavingText]) member.color = 0xFFA3EC95; for (member in [this, progressBar, progressBarBack, autosavingText]) member.color = 0xFFA3EC95;
UIState.playEditorSound(Flags.DEFAULT_EDITOR_AUTOSAVE_SOUND); FlxG.sound.play(Paths.sound(Flags.DEFAULT_EDITOR_AUTOSAVE_SOUND));
(new FlxTimer()).start(1, (_) -> {disappearAnimation();}); (new FlxTimer()).start(1, (_) -> {disappearAnimation();});
}); });
@@ -178,8 +178,6 @@ class CharterBackdrop extends FlxTypedGroup<FlxBasic> {
public var gridShader:CustomShader = new CustomShader("engine/charterGrid"); public var gridShader:CustomShader = new CustomShader("engine/charterGrid");
var __lastKeyCount:Int = 4; var __lastKeyCount:Int = 4;
public var cameraHighlight:CameraHighlight;
public function new() { public function new() {
super(); super();
@@ -189,10 +187,6 @@ class CharterBackdrop extends FlxTypedGroup<FlxBasic> {
add(gridBackDrop); add(gridBackDrop);
gridShader.hset("segments", 4); gridShader.hset("segments", 4);
cameraHighlight = new CameraHighlight(this);
cameraHighlight.makeSolid(1, 1, 0xFFFFFFFF);
add(cameraHighlight);
waveformSprite = new FlxSprite().makeSolid(1, 1, 0xFF000000); waveformSprite = new FlxSprite().makeSolid(1, 1, 0xFF000000);
waveformSprite.scale.set(160, 1); waveformSprite.scale.set(160, 1);
waveformSprite.updateHitbox(); waveformSprite.updateHitbox();
@@ -253,11 +247,10 @@ class CharterBackdrop extends FlxTypedGroup<FlxBasic> {
x = strumLine.x; x = strumLine.x;
alpha = strumLine.strumLine.visible ? 0.9 : 0.4; alpha = strumLine.strumLine.visible ? 0.9 : 0.4;
keyCount = strumLine.keyCount; keyCount = strumLine.keyCount;
cameraHighlight.color = strumLine.highlightColor;
} else alpha = 0.9; } else alpha = 0.9;
for (spr in [gridBackDrop, beatSeparator, topLimit, bottomLimit, for (spr in [gridBackDrop, beatSeparator, topLimit, bottomLimit,
topSeparator, bottomSeparator, conductorFollowerSpr, waveformSprite, cameraHighlight]) { topSeparator, bottomSeparator, conductorFollowerSpr, waveformSprite]) {
spr.x = x; if (spr != waveformSprite) spr.alpha = alpha; spr.x = x; if (spr != waveformSprite) spr.alpha = alpha;
spr.cameras = this.cameras; spr.cameras = this.cameras;
} }
@@ -279,9 +272,6 @@ class CharterBackdrop extends FlxTypedGroup<FlxBasic> {
spr.updateHitbox(); spr.updateHitbox();
} }
cameraHighlight.scale.x = (keyCount * 40)-2;
cameraHighlight.x += 1;
waveformSprite.visible = waveformSprite.shader != null; waveformSprite.visible = waveformSprite.shader != null;
if (waveformSprite.shader == null) return; if (waveformSprite.shader == null) return;
@@ -321,19 +311,16 @@ class CharterGridSeperatorBase extends FlxSprite {
private static var lastMaxMeasure:Float = -1; private static var lastMaxMeasure:Float = -1;
public static var lastConductorSprY:Float = Math.NEGATIVE_INFINITY; public static var lastConductorSprY:Float = Math.NEGATIVE_INFINITY;
public static var lastCameraZoom:Float = -1;
private static var beatStepTimes:Array<Float> = []; private static var beatStepTimes:Array<Float> = [];
private static var measureStepTimes:Array<Float> = []; private static var measureStepTimes:Array<Float> = [];
private static var timeSignatureChangeGaps:Array<Float> = []; private static var timeSignatureChangeGaps:Array<Float> = [];
private function recalculateBeats() { private function recalculateBeats() {
@:privateAccess
var currentZoom = Charter.instance.__camZoom;
var conductorSprY = Charter.instance.gridBackdrops.conductorSprY; var conductorSprY = Charter.instance.gridBackdrops.conductorSprY;
if (conductorSprY == lastConductorSprY && currentZoom == lastCameraZoom) return; //only update if song pos or camera zoom has changed if (conductorSprY == lastConductorSprY) return;
var zoomOffset = ((FlxG.height * (1/currentZoom)) * 0.5); var zoomOffset = ((FlxG.height * (1/cameras[0].zoom)) * 0.5);
minStep = (conductorSprY - zoomOffset)/40; minStep = (conductorSprY - zoomOffset)/40;
maxStep = (conductorSprY + zoomOffset)/40; maxStep = (conductorSprY + zoomOffset)/40;
@@ -372,7 +359,6 @@ class CharterGridSeperatorBase extends FlxSprite {
} }
lastConductorSprY = conductorSprY; lastConductorSprY = conductorSprY;
lastCameraZoom = currentZoom;
} }
private inline function calculateTimeSignatureGaps() { private inline function calculateTimeSignatureGaps() {
@@ -460,77 +446,6 @@ class CharterGridSeperator extends CharterGridSeperatorBase {
} }
} }
class CameraHighlight extends FlxSprite {
private var grid:CharterBackdrop;
private var _currentCameraMovementIndex:Int = 0;
public function new(grid:CharterBackdrop) {
this.grid = grid;
super();
}
override public function draw() {
if (!Options.charterShowCameraHighlights || grid.strumLine == null) return;
@:privateAccess
var minStep = CharterGridSeperatorBase.minStep;
@:privateAccess
var maxStep = CharterGridSeperatorBase.maxStep;
@:privateAccess
var strumLineID = Charter.instance.strumLines.isDragging ? Charter.instance.strumLines.__pastStrumlines.indexOf(grid.strumLine) : Charter.instance.gridBackdrops.members.indexOf(grid);
//first default camera change
if ((Charter.instance.cameraMovementChanges[0] == null || Charter.instance.cameraMovementChanges[0].step != 0) && strumLineID == 0) {
var endStep = Charter.instance.cameraMovementChanges[0] != null ? Charter.instance.cameraMovementChanges[0].step : Charter.instance.__endStep;
if (endStep >= minStep) {
setupHighlight(0, endStep); super.draw();
setupLine(endStep); super.draw();
}
}
//update index if gone backwards
while(_currentCameraMovementIndex > 0) {
if (Charter.instance.cameraMovementChanges[_currentCameraMovementIndex] == null || Charter.instance.cameraMovementChanges[_currentCameraMovementIndex].endStep >= minStep) {
_currentCameraMovementIndex--;
} else {
break;
}
}
var seenFirstVisible = false;
for (i in _currentCameraMovementIndex...Charter.instance.cameraMovementChanges.length) {
var change = Charter.instance.cameraMovementChanges[i];
if (change.endStep >= minStep) {
if (!seenFirstVisible) {
_currentCameraMovementIndex = i; //remember the index for the next frame, so we dont need to loop through everything every time
seenFirstVisible = true;
}
if (change.strumLineID == strumLineID) {
setupHighlight(change.step, change.endStep); super.draw();
setupLine(change.step); super.draw();
setupLine(change.endStep); super.draw();
}
}
if (change.endStep > maxStep) break;
}
}
private inline function setupHighlight(step:Float, endStep:Float) {
y = step * 40;
alpha = 0.15;
scale.y = (endStep -step) * 40;
updateHitbox();
}
private inline function setupLine(step:Float) {
y = (step * 40)-1;
alpha = 0.8;
scale.y = 2;
updateHitbox();
}
}
class EventBackdrop extends FlxBackdrop { class EventBackdrop extends FlxBackdrop {
public var eventBeatSeparator:CharterEventGridSeperator; public var eventBeatSeparator:CharterEventGridSeperator;
@@ -1,5 +1,6 @@
package funkin.editors.charter; package funkin.editors.charter;
import funkin.game.HealthIcon;
import flixel.math.FlxPoint; import flixel.math.FlxPoint;
import funkin.backend.chart.ChartData.ChartMetaData; import funkin.backend.chart.ChartData.ChartMetaData;
import funkin.editors.extra.PropertyButton; import funkin.editors.extra.PropertyButton;
@@ -21,8 +22,7 @@ class CharterMetaDataScreen extends UISubstateWindow {
public var displayNameTextBox:UITextBox; public var displayNameTextBox:UITextBox;
public var iconTextBox:UITextBox; public var iconTextBox:UITextBox;
public var iconSprite:HealthIcon; public var iconSprite:HealthIcon;
public var opponentModeCheckbox:UICheckbox; public var excludedGameModesList:UIAutoCompleteButtonList;
public var coopAllowedCheckbox:UICheckbox;
public var needsVoicesCheckbox:UICheckbox; public var needsVoicesCheckbox:UICheckbox;
public var colorWheel:UIColorwheel; public var colorWheel:UIColorwheel;
public var difficultiesTextBox:UITextBox; public var difficultiesTextBox:UITextBox;
@@ -78,25 +78,29 @@ class CharterMetaDataScreen extends UISubstateWindow {
add(displayNameTextBox); add(displayNameTextBox);
addLabelOn(displayNameTextBox, translate("displayName")); addLabelOn(displayNameTextBox, translate("displayName"));
add(iconSprite = new HealthIcon(metadata.icon));
iconSprite.scale.set(0.5, 0.5);
iconSprite.updateHitbox();
iconTextBox = new UITextBox(displayNameTextBox.x + 320 + 26, displayNameTextBox.y, metadata.icon, 150); iconTextBox = new UITextBox(displayNameTextBox.x + 320 + 26, displayNameTextBox.y, metadata.icon, 150);
iconTextBox.onChange = (newIcon:String) -> {updateIcon(newIcon);} iconTextBox.onChange = (newIcon:String) -> iconSprite.setIcon(newIcon);
add(iconTextBox); add(iconTextBox);
addLabelOn(iconTextBox, translate("icon")); addLabelOn(iconTextBox, translate("icon"));
updateIcon(metadata.icon); updateIcon(metadata.icon);
opponentModeCheckbox = new UICheckbox(displayNameTextBox.x, iconTextBox.y + 10 + 32 + 26, translate("opponentMode"), metadata.opponentModeAllowed); add(excludedGameModesList = new UIAutoCompleteButtonList(displayNameTextBox.x, iconTextBox.y + 62, Std.int(displayNameTextBox.bWidth), 100, "", [for (mode in funkin.menus.FreeplayState.FreeplayGameMode.get()) mode.modeID]));
add(opponentModeCheckbox); excludedGameModesList.frames = Paths.getFrames('editors/ui/inputbox');
addLabelOn(opponentModeCheckbox, translate("modesAllowed")); excludedGameModesList.cameraSpacing = 0;
addLabelOn(excludedGameModesList, "Excluded Game Modes (IDs)");
coopAllowedCheckbox = new UICheckbox(opponentModeCheckbox.x + 150 + 26, opponentModeCheckbox.y, translate("coopAllowed"), metadata.coopAllowed); for (mode in metadata.excludedGameModes)
add(coopAllowedCheckbox); excludedGameModesList.add(new UIAutoCompleteButtonList.UIAutoCompleteButton(0, 0, excludedGameModesList, excludedGameModesList.suggestItems, mode));
colorWheel = new UIColorwheel(iconTextBox.x, coopAllowedCheckbox.y, metadata.color); colorWheel = new UIColorwheel(iconTextBox.x, coopAllowedCheckbox.y, metadata.color);
add(colorWheel); add(colorWheel);
addLabelOn(colorWheel, translate("color")); addLabelOn(colorWheel, translate("color"));
difficultiesTextBox = new UITextBox(opponentModeCheckbox.x, opponentModeCheckbox.y + 6 + 32 + 26, metadata.difficulties.join(", ")); difficultiesTextBox = new UITextBox(excludedGameModesList.x, excludedGameModesList.y + excludedGameModesList.bHeight + 32, metadata.difficulties.join(", "));
add(difficultiesTextBox); add(difficultiesTextBox);
addLabelOn(difficultiesTextBox, translate("difficulties")); addLabelOn(difficultiesTextBox, translate("difficulties"));
@@ -111,9 +115,6 @@ class CharterMetaDataScreen extends UISubstateWindow {
add(customPropertiesButtonList); add(customPropertiesButtonList);
addLabelOn(customPropertiesButtonList, translate("customValues")); addLabelOn(customPropertiesButtonList, translate("customValues"));
for (checkbox in [opponentModeCheckbox, coopAllowedCheckbox])
{checkbox.y += 6; checkbox.x += 4;}
saveButton = new UIButton(windowSpr.x + windowSpr.bWidth - 20, windowSpr.y + windowSpr.bHeight - 20, TU.translate("editor.saveClose"), function() { saveButton = new UIButton(windowSpr.x + windowSpr.bWidth - 20, windowSpr.y + windowSpr.bHeight - 20, TU.translate("editor.saveClose"), function() {
saveMeta(); saveMeta();
close(); close();
@@ -161,8 +162,7 @@ class CharterMetaDataScreen extends UISubstateWindow {
meta.displayName = displayNameTextBox.label.text; meta.displayName = displayNameTextBox.label.text;
meta.icon = iconTextBox.label.text; meta.icon = iconTextBox.label.text;
meta.color = colorWheel.curColor; meta.color = colorWheel.curColor;
meta.opponentModeAllowed = opponentModeCheckbox.checked; meta.excludedGameModes = [for (button in excludedGameModesList.buttons.members) button.textBox.label.text.trim()],
meta.coopAllowed = coopAllowedCheckbox.checked;
meta.difficulties = [for (diff in difficultiesTextBox.label.text.split(",")) diff.trim()]; meta.difficulties = [for (diff in difficultiesTextBox.label.text.split(",")) diff.trim()];
meta.customValues = customVals; meta.customValues = customVals;
+2 -3
View File
@@ -161,9 +161,8 @@ class CharterNote extends UISprite implements ICharterSelectable {
} }
if (__passed != (__passed = step < Conductor.curStepFloat + (Options.songOffsetAffectEditors ? (Conductor.songOffset / Conductor.stepCrochet) : 0))) { if (__passed != (__passed = step < Conductor.curStepFloat + (Options.songOffsetAffectEditors ? (Conductor.songOffset / Conductor.stepCrochet) : 0))) {
if (__passed && FlxG.sound.music.playing) { if (__passed && FlxG.sound.music.playing && Charter.instance.hitsoundsEnabled(strumLineID))
Charter.instance.playHitsound(strumLineID); Charter.instance.hitsound.replay();
}
} }
if (strumLine != null) { if (strumLine != null) {
@@ -21,7 +21,7 @@ class CharterPreviewStrumLine extends FlxTypedGroup<FlxSprite>
for (i in 0...keyCount){ for (i in 0...keyCount){
var strum = new FlxSprite(); var strum = new FlxSprite();
strum.frames = Paths.getFrames("game/notes/default"); strum.frames = Paths.getFrames("game/notes/default");
strum.setGraphicSize(Std.int((strum.width * Flags.DEFAULT_NOTE_SCALE) * scale)); strum.setGraphicSize(Std.int((strum.width * 0.7) * scale));
strum.updateHitbox(); strum.updateHitbox();
var animPrefix = strumAnimPrefix[i % 4]; var animPrefix = strumAnimPrefix[i % 4];
@@ -33,7 +33,7 @@ class CharterPreviewStrumLine extends FlxTypedGroup<FlxSprite>
note = new FlxSprite(); note = new FlxSprite();
note.frames = Paths.getFrames("game/notes/default"); note.frames = Paths.getFrames("game/notes/default");
note.setGraphicSize(Std.int((note.width * Flags.DEFAULT_NOTE_SCALE) * scale)); note.setGraphicSize(Std.int((note.width * 0.7) * scale));
note.updateHitbox(); note.updateHitbox();
note.animation.addByPrefix('purple', 'purple0'); note.animation.addByPrefix('purple', 'purple0');
note.animation.play('purple'); note.animation.play('purple');
@@ -41,7 +41,7 @@ class CharterPreviewStrumLine extends FlxTypedGroup<FlxSprite>
add(note); add(note);
} }
var noteTime:Float = FlxG.initialHeight; var noteTime:Float = FlxG.height;
var scroll:Float = 1.0; var scroll:Float = 1.0;
public function updatePos(x:Float, y:Float, scale:Float, spacing:Float, keyCount:Int, scrollSpeed:Float){ public function updatePos(x:Float, y:Float, scale:Float, spacing:Float, keyCount:Int, scrollSpeed:Float){
@@ -53,7 +53,7 @@ class CharterPreviewStrumLine extends FlxTypedGroup<FlxSprite>
strum.x = CoolUtil.fpsLerp(strum.x, x + (Note.swagWidth * scale * spacing * i), 0.2); strum.x = CoolUtil.fpsLerp(strum.x, x + (Note.swagWidth * scale * spacing * i), 0.2);
strum.y = CoolUtil.fpsLerp(strum.y, y + (Note.swagWidth*0.5) - (Note.swagWidth * scale * 0.5), 0.2); strum.y = CoolUtil.fpsLerp(strum.y, y + (Note.swagWidth*0.5) - (Note.swagWidth * scale * 0.5), 0.2);
strum.scale.x = strum.scale.y = CoolUtil.fpsLerp(strum.scale.x, Flags.DEFAULT_NOTE_SCALE * scale, 0.2); strum.scale.x = strum.scale.y = CoolUtil.fpsLerp(strum.scale.x, 0.7 * scale, 0.2);
strum.updateHitbox(); strum.updateHitbox();
} }
@@ -61,7 +61,7 @@ class CharterPreviewStrumLine extends FlxTypedGroup<FlxSprite>
scroll = CoolUtil.fpsLerp(scroll, scrollSpeed, 0.2); scroll = CoolUtil.fpsLerp(scroll, scrollSpeed, 0.2);
noteTime -= FlxG.elapsed * scroll * 1000 * 0.45; noteTime -= FlxG.elapsed * scroll * 1000 * 0.45;
if (noteTime <= 0.0) if (noteTime <= 0.0)
noteTime = FlxG.initialHeight; noteTime = FlxG.height;
note.x = members[0].x; note.x = members[0].x;
note.y = members[0].y + noteTime; note.y = members[0].y + noteTime;
@@ -146,10 +146,11 @@ class CharterSelectionScreen extends EditorTreeMenuScreen {
var screen = parent.tree.last(); var screen = parent.tree.last();
var idx = 0; var idx = 0;
while (!(screen.members[idx] is Separator || idx >= screen.members.length)) idx++; while (!(screen.members[idx] is Separator)) idx++;
screen.insert(idx, makeChartOption(name, curSong.variant != null && curSong.variant != "" ? curSong.variant : null, curSong.name)); screen.insert(idx, makeChartOption(name, curSong.variant != null && curSong.variant != "" ? curSong.variant : null, curSong.name));
// Add to Meta // Add to Meta
var metaPath = '$songFolder/meta${curSong.variant != null && curSong.variant != "" ? "-" + curSong.variant : ""}.json'; var metaPath = '$songFolder/meta${curSong.variant != null && curSong.variant == "" ? "-" + curSong.variant : ""}.json';
CoolUtil.safeSaveFile(metaPath, Chart.makeMetaSaveable(curSong)); CoolUtil.safeSaveFile(metaPath, Chart.makeMetaSaveable(curSong));
} }
#end #end
@@ -105,7 +105,6 @@ class CharterStrumLineGroup extends FlxTypedGroup<CharterStrumline> {
draggingObj = null; draggingObj = null;
fixEvents(); fixEvents();
refreshStrumlineIDs(); refreshStrumlineIDs();
Charter.instance.updateCameraChanges();
} }
public inline function fixEvents() { public inline function fixEvents() {
@@ -1,7 +1,5 @@
package funkin.editors.charter; package funkin.editors.charter;
import funkin.editors.ui.UIContextMenu.UIContextMenuOption;
import flixel.util.FlxColor;
import flixel.group.FlxSpriteGroup; import flixel.group.FlxSpriteGroup;
import flixel.sound.FlxSound; import flixel.sound.FlxSound;
import funkin.backend.chart.ChartData.ChartStrumLine; import funkin.backend.chart.ChartData.ChartStrumLine;
@@ -12,11 +10,11 @@ import funkin.game.HealthIcon;
class CharterStrumline extends UISprite { class CharterStrumline extends UISprite {
public var strumLine:ChartStrumLine; public var strumLine:ChartStrumLine;
public var hitsounds:Bool = true;
public var draggingSprite:UISprite; public var draggingSprite:UISprite;
public var healthIcons:FlxSpriteGroup; public var healthIcons:FlxSpriteGroup;
public var button:CharterStrumlineOptions; public var button:CharterStrumlineOptions;
public var highlightColor:FlxColor;
public var draggable:Bool = false; public var draggable:Bool = false;
public var dragging:Bool = false; public var dragging:Bool = false;
@@ -24,9 +22,7 @@ class CharterStrumline extends UISprite {
public var curMenu:UIContextMenu = null; public var curMenu:UIContextMenu = null;
public var vocals:FlxSound; public var vocals:FlxSound;
public var hasVocals:Bool = false; public var voicesMuted:Bool = false;
public var vocalsVolume:Float = 1;
public var hitsoundVolume:Float = 1;
public var keyCount:Int = 4; public var keyCount:Int = 4;
public var startingID(get, null):Int; public var startingID(get, null):Int;
@@ -146,22 +142,15 @@ class CharterStrumline extends UISprite {
if (asset != null) { if (asset != null) {
vocals.reset(); vocals.reset();
vocals.loadEmbedded(asset); vocals.loadEmbedded(asset);
hasVocals = true;
} }
else { else {
vocals.destroy(); vocals.destroy();
hasVocals = false;
} }
vocals.group = FlxG.sound.defaultMusicGroup; vocals.group = FlxG.sound.defaultMusicGroup;
}
highlightColor = 0xFFFFFFFF; public function updateVoicesVolume() {
if (icons[0] != null) { vocals.volume = (voicesMuted || (Charter.instance?.voicesMuted ?? false)) ? 0 : 1;
var characterXML = Character.getXMLFromCharName(icons[0]);
if (characterXML != null && characterXML.x.exists("color")) highlightColor = FlxColor.fromString(characterXML.x.get("color"));
//make darker colors more visible for the highlight
highlightColor.brightness = Math.max(highlightColor.brightness, 0.65);
}
} }
} }
@@ -184,17 +173,18 @@ class CharterStrumlineOptions extends UITopMenuButton {
contextMenu = [ contextMenu = [
{ {
label: TU.translate("charter.strumLine.hitsounds"), label: TU.translate("charter.strumLine.hitsounds"),
slider: { onSelect: function(_) {
min: 0, strLine.hitsounds = !strLine.hitsounds;
max: 1,
value: strLine.hitsoundVolume,
onChange: function(t) {
strLine.hitsoundVolume = t.slider.value;
t.icon = t.slider.value > 0.5 ? 7 : (t.slider.value > 0 ? 8 : 9);
}
}, },
onIconClick: Charter.instance._slider_mutetoggle, icon: strLine.hitsounds ? 1 : 0
icon: 7 },
{
label: TU.translate("charter.strumLine.muteVocals"),
onSelect: function(_) {
strLine.voicesMuted = !strLine.voicesMuted;
strLine.updateVoicesVolume();
},
icon: strLine.voicesMuted ? 1 : 0
}, },
null, null,
{ {
@@ -215,44 +205,20 @@ class CharterStrumlineOptions extends UITopMenuButton {
} }
]; ];
if (strLine.hasVocals) { contextMenu.insert(0, {
contextMenu.insert(1, { label: TU.translate("charter.strumLine.noWaveform"),
label: TU.translate("charter.strumLine.vocals"), onSelect: function(_) {strLine.selectedWaveform = -1;},
slider: { icon: strLine.selectedWaveform == -1 ? 1 : 0
min: 0, });
max: 1,
value: strLine.vocalsVolume,
onChange: function(t) {
strLine.vocalsVolume = t.slider.value;
strLine.vocals.volume = Charter.instance.vocals.volume * strLine.vocalsVolume;
t.icon = t.slider.value > 0.5 ? 7 : (t.slider.value > 0 ? 8 : 9);
}
},
onIconClick: Charter.instance._slider_mutetoggle,
icon: 7
});
}
var waveformOptions:Array<UIContextMenuOption> = [
{
label: TU.translate("charter.strumLine.noWaveform"),
onSelect: function(_) {strLine.selectedWaveform = -1;},
icon: strLine.selectedWaveform == -1 ? 1 : 0
}
];
for (i => name in Charter.waveformHandler.waveformList) for (i => name in Charter.waveformHandler.waveformList)
waveformOptions.push({ contextMenu.insert(1+i, {
label: name, label: name,
onSelect: function(_) {strLine.selectedWaveform = i;}, onSelect: function(_) {strLine.selectedWaveform = i;},
icon: strLine.selectedWaveform == i ? 6 : 5 icon: strLine.selectedWaveform == i ? 6 : 5
}); });
contextMenu.insert(0, { contextMenu.insert(1+Charter.waveformHandler.waveformList.length, null);
label: TU.translate("charter.strumLine.waveforms"),
childs: waveformOptions
});
contextMenu.insert(1, null);
var cam = Charter.instance.charterCamera; var cam = Charter.instance.charterCamera;
var point = CoolUtil.worldToScreenPosition(this, cam); var point = CoolUtil.worldToScreenPosition(this, cam);
@@ -33,8 +33,6 @@ class CharterStrumlineScreen extends UISubstateWindow {
public var strumLineCam:HudCamera; public var strumLineCam:HudCamera;
public var previewStrumLine:CharterPreviewStrumLine; public var previewStrumLine:CharterPreviewStrumLine;
public var previewBorder:Array<FlxSprite> = [];
private final borderGap:Int = 5;
private var onSave:ChartStrumLine -> Void = null; private var onSave:ChartStrumLine -> Void = null;
@@ -178,30 +176,20 @@ class CharterStrumlineScreen extends UISubstateWindow {
addLabelOn(vocalsSuffixDropDown, TU.translate("charterStrumLine.vocalSuffix")); addLabelOn(vocalsSuffixDropDown, TU.translate("charterStrumLine.vocalSuffix"));
keyCountStepper = new UINumericStepper(stagePositionDropdown.x, vocalsSuffixDropDown.y, strumLine.keyCount != null ? strumLine.keyCount : 4, 1, 0, 1, 1000, 84); keyCountStepper = new UINumericStepper(stagePositionDropdown.x, vocalsSuffixDropDown.y, strumLine.keyCount != null ? strumLine.keyCount : 4, 1, 0, 1, 1000, 84);
add(keyCountStepper); // if (Flags.CHARTER_ADVANCED_SETTINGS) {
addLabelOn(keyCountStepper, TU.translate("charterStrumLine.keyCount")); add(keyCountStepper);
addLabelOn(keyCountStepper, TU.translate("charterStrumLine.keyCount"));
// }
strumLineCam = new HudCamera(); strumLineCam = new HudCamera();
strumLineCam.downscroll = Options.downscroll; strumLineCam.downscroll = Options.downscroll;
strumLineCam.bgColor = 0; strumLineCam.bgColor = 0;
strumLineCam.alpha = 0; strumLineCam.alpha = 0;
FlxG.cameras.add(strumLineCam, false); FlxG.cameras.add(strumLineCam, false);
updateStrumlineCam(FlxG.width, FlxG.height);
previewStrumLine = new CharterPreviewStrumLine(0, 0, 0, 1, 4, 0); previewStrumLine = new CharterPreviewStrumLine(0, 0, 0, 1, 4, 0);
previewStrumLine.camera = strumLineCam; previewStrumLine.camera = strumLineCam;
add(previewStrumLine); add(previewStrumLine);
FlxTween.tween(strumLineCam, {alpha: 1}, 0.25, {ease: FlxEase.cubeOut}); FlxTween.tween(strumLineCam, {alpha: 1}, 0.25, {ease: FlxEase.cubeOut});
//preview border
previewBorder.push(new FlxSprite(-borderGap, -borderGap).makeSolid(FlxG.initialWidth + (borderGap*2), borderGap, 0x88FFFFFF));
previewBorder.push(new FlxSprite(-borderGap, 0).makeSolid(borderGap, FlxG.initialHeight, 0x88FFFFFF));
previewBorder.push(new FlxSprite(FlxG.initialWidth, 0).makeSolid(borderGap, FlxG.initialHeight, 0x88FFFFFF));
previewBorder.push(new FlxSprite(-borderGap, FlxG.initialHeight).makeSolid(FlxG.initialWidth + (borderGap*2), borderGap, 0x88FFFFFF));
for (border in previewBorder) {
border.camera = strumLineCam;
add(border);
}
} }
function saveStrumline() { function saveStrumline() {
@@ -234,7 +222,7 @@ class CharterStrumlineScreen extends UISubstateWindow {
previewStrumLine.visible = visibleCheckbox.checked; previewStrumLine.visible = visibleCheckbox.checked;
var xOffset:Float = StrumLine.calculateStartingXPosFromInitialWidth(hudXStepper.value, hudScaleStepper.value, hudSpacingStepper.value, Std.int(keyCountStepper.value)); var xOffset:Float = StrumLine.calculateStartingXPos(hudXStepper.value, hudScaleStepper.value, hudSpacingStepper.value, Std.int(keyCountStepper.value));
previewStrumLine.updatePos(xOffset, hudYStepper.value, hudScaleStepper.value, hudSpacingStepper.value, Std.int(keyCountStepper.value), scrollSpeed); previewStrumLine.updatePos(xOffset, hudYStepper.value, hudScaleStepper.value, hudSpacingStepper.value, Std.int(keyCountStepper.value), scrollSpeed);
super.update(elapsed); super.update(elapsed);
@@ -245,26 +233,6 @@ class CharterStrumlineScreen extends UISubstateWindow {
FlxTween.cancelTweensOf(strumLineCam); FlxTween.cancelTweensOf(strumLineCam);
FlxG.cameras.remove(strumLineCam); FlxG.cameras.remove(strumLineCam);
} }
public override function onResize(width:Int, height:Int) {
super.onResize(width, height);
if (!UIState.resolutionAware) return;
if ((width < FlxG.initialWidth || height < FlxG.initialHeight) && !Options.bypassEditorsResize) {
width = FlxG.initialWidth; height = FlxG.initialHeight;
}
updateStrumlineCam(width, height);
}
private function updateStrumlineCam(windowWidth:Int, windowHeight:Int) {
strumLineCam.width = FlxG.initialWidth + (borderGap*2);
strumLineCam.height = FlxG.initialHeight + (borderGap*2);
strumLineCam.x = (windowWidth/2) - (strumLineCam.width/2);
strumLineCam.y = (windowHeight/2) - (strumLineCam.height/2);
strumLineCam.scroll.x = -borderGap;
strumLineCam.scroll.y = -borderGap;
}
} }
class CharacterButton extends UIButton { class CharacterButton extends UIButton {
@@ -319,4 +287,4 @@ class CharacterButton extends UIButton {
super.update(elapsed); super.update(elapsed);
} }
} }
@@ -1,5 +1,6 @@
package funkin.editors.charter; package funkin.editors.charter;
import funkin.game.HealthIcon;
import flixel.group.FlxGroup; import flixel.group.FlxGroup;
import flixel.text.FlxText.FlxTextFormat; import flixel.text.FlxText.FlxTextFormat;
import flixel.text.FlxText.FlxTextFormatMarkerPair; import flixel.text.FlxText.FlxTextFormatMarkerPair;
@@ -37,8 +38,7 @@ class SongCreationScreen extends UISubstateWindow {
public var displayNameTextBox:UITextBox; public var displayNameTextBox:UITextBox;
public var iconTextBox:UITextBox; public var iconTextBox:UITextBox;
public var iconSprite:HealthIcon; public var iconSprite:HealthIcon;
public var opponentModeCheckbox:UICheckbox; public var excludedGameModesList:UIAutoCompleteButtonList;
public var coopAllowedCheckbox:UICheckbox;
public var colorWheel:UIColorwheel; public var colorWheel:UIColorwheel;
public var difficultiesTextBox:UITextBox; public var difficultiesTextBox:UITextBox;
@@ -166,24 +166,19 @@ class SongCreationScreen extends UISubstateWindow {
updateIcon("face"); updateIcon("face");
opponentModeCheckbox = new UICheckbox(displayNameTextBox.x, iconTextBox.y + 10 + 32 + 26, translateMeta("opponentMode"), true); menuDataGroup.add(excludedGameModesList = new UIAutoCompleteButtonList(displayNameTextBox.x, iconTextBox.y + 62, Std.int(displayNameTextBox.bWidth), 100, "", [for (mode in funkin.menus.FreeplayState.FreeplayGameMode.get()) mode.modeID]));
menuDataGroup.add(opponentModeCheckbox); excludedGameModesList.frames = Paths.getFrames('editors/ui/inputbox');
addLabelOn(opponentModeCheckbox, translateMeta("modesAllowed")); excludedGameModesList.cameraSpacing = 0;
addLabelOn(excludedGameModesList, "Excluded Game Modes (IDs)");
coopAllowedCheckbox = new UICheckbox(opponentModeCheckbox.x + 150 + 26, opponentModeCheckbox.y, translateMeta("coopAllowed"), true); colorWheel = new UIColorwheel(iconTextBox.x, excludedGameModesList.y, 0xFFFFFF);
menuDataGroup.add(coopAllowedCheckbox);
colorWheel = new UIColorwheel(iconTextBox.x, coopAllowedCheckbox.y, 0xFFFFFF);
menuDataGroup.add(colorWheel); menuDataGroup.add(colorWheel);
addLabelOn(colorWheel, translateMeta("color")); addLabelOn(colorWheel, translateMeta("color"));
difficultiesTextBox = new UITextBox(opponentModeCheckbox.x, opponentModeCheckbox.y + 6 + 32 + 26, ""); difficultiesTextBox = new UITextBox(excludedGameModesList.x, excludedGameModesList.y + excludedGameModesList.bHeight + 32, "");
menuDataGroup.add(difficultiesTextBox); menuDataGroup.add(difficultiesTextBox);
addLabelOn(difficultiesTextBox, translateMeta("difficulties")); addLabelOn(difficultiesTextBox, translateMeta("difficulties"));
for (checkbox in [opponentModeCheckbox, coopAllowedCheckbox])
{checkbox.y += 6; checkbox.x += 4;}
var menuTitle:UIText; var menuTitle:UIText;
selectFormatGroup.add(menuTitle = new UIText(windowSpr.x + 20, windowSpr.y + 30 + 16, 0, translate("importSource"), 28)); selectFormatGroup.add(menuTitle = new UIText(windowSpr.x + 20, windowSpr.y + 30 + 16, 0, translate("importSource"), 28));
@@ -433,8 +428,7 @@ class SongCreationScreen extends UISubstateWindow {
displayName: displayNameTextBox.label.text, displayName: displayNameTextBox.label.text,
icon: iconTextBox.label.text, icon: iconTextBox.label.text,
color: colorWheel.curColor, color: colorWheel.curColor,
opponentModeAllowed: opponentModeCheckbox.checked, excludedGameModes: [for (button in excludedGameModesList.buttons.members) button.textBox.label.text.trim()],
coopAllowed: coopAllowedCheckbox.checked,
difficulties: [for (diff in difficultiesTextBox.label.text.split(",")) if (diff.length > 0) diff.trim()] difficulties: [for (diff in difficultiesTextBox.label.text.split(",")) if (diff.length > 0) diff.trim()]
}); });
+10 -6
View File
@@ -377,7 +377,9 @@ class StageEditor extends UIState {
// Play first anim, and make it the last frame // Play first anim, and make it the last frame
var animToPlay = char.getAnimOrder()[0]; var animToPlay = char.getAnimOrder()[0];
char.playAnim(animToPlay, true, NONE); char.playAnim(animToPlay, true, NONE);
var lastIndx = char.animation.curAnim.numFrames - 1; var lastIndx = (char.animateAtlas != null) ?
char.animateAtlas.anim.length - 1 :
char.animation.curAnim.numFrames - 1;
char.playAnim(animToPlay, true, NONE, false, lastIndx); char.playAnim(animToPlay, true, NONE, false, lastIndx);
char.stopAnimation(); char.stopAnimation();
@@ -508,7 +510,7 @@ class StageEditor extends UIState {
function _file_save(_) { function _file_save(_) {
#if sys #if sys
UIState.playEditorSound(Flags.DEFAULT_EDITOR_SAVE_SOUND); FlxG.sound.play(Paths.sound('editors/save'));
CoolUtil.safeSaveFile( CoolUtil.safeSaveFile(
'${Paths.getAssetsRoot()}/data/stages/${__stage}.xml', '${Paths.getAssetsRoot()}/data/stages/${__stage}.xml',
buildStage() buildStage()
@@ -520,7 +522,7 @@ class StageEditor extends UIState {
} }
function _file_saveas(_) { function _file_saveas(_) {
UIState.playEditorSound(Flags.DEFAULT_EDITOR_SAVE_SOUND); FlxG.sound.play(Paths.sound('editors/save'));
openSubState(new SaveSubstate(buildStage(), { openSubState(new SaveSubstate(buildStage(), {
defaultSaveFile: '${__stage}.xml' defaultSaveFile: '${__stage}.xml'
})); }));
@@ -563,7 +565,9 @@ class StageEditor extends UIState {
// Play first anim, and make it the last frame // Play first anim, and make it the last frame
var animToPlay = char.getAnimOrder()[0]; var animToPlay = char.getAnimOrder()[0];
char.playAnim(animToPlay, true, NONE); char.playAnim(animToPlay, true, NONE);
var lastIndx = char.animation.curAnim.numFrames - 1; var lastIndx = (char.animateAtlas != null) ?
char.animateAtlas.anim.length - 1 :
char.animation.curAnim.numFrames - 1;
char.playAnim(animToPlay, true, NONE, false, lastIndx); char.playAnim(animToPlay, true, NONE, false, lastIndx);
char.stopAnimation(); char.stopAnimation();
@@ -730,7 +734,7 @@ class StageEditor extends UIState {
} }
function _edit_undo(_) { function _edit_undo(_) {
UIState.playEditorSound(Flags.DEFAULT_EDITOR_UNDO_SOUND); FlxG.sound.play(Flags.DEFAULT_EDITOR_UNDO_SOUND);
var undo = undos.undo(); var undo = undos.undo();
switch(undo) { switch(undo) {
case null: case null:
@@ -756,7 +760,7 @@ class StageEditor extends UIState {
} }
function _edit_redo(_) { function _edit_redo(_) {
UIState.playEditorSound(Flags.DEFAULT_EDITOR_REDO_SOUND); FlxG.sound.play(Paths.sound(Flags.DEFAULT_EDITOR_REDO_SOUND));
var redo = undos.redo(); var redo = undos.redo();
switch(redo) { switch(redo) {
case null: case null:
@@ -0,0 +1,50 @@
package funkin.editors.ui;
typedef UIAutoCompleteButtonList = UITypedAutoCompleteButtonList<UIAutoCompleteButton>;
class UITypedAutoCompleteButtonList<T:UIAutoCompleteButton> extends UIButtonList<T> {
public var suggestItems(default, set):Array<String> = [];
private function set_suggestItems(value:Array<String>) {
buttons.forEachAlive((button) -> button.textBox.suggestItems = value);
return suggestItems = value;
}
public function new(x:Float, y:Float, width:Int, height:Int, windowName:String, ?suggestItems:Array<String>, ?buttonSize:FlxPoint, ?buttonOffset:FlxPoint, buttonSpacing:Float = 0) {
super(x, y, width, height, windowName, buttonSize == null ? FlxPoint.get(width, width * 0.15) : buttonSize, buttonOffset, buttonSpacing);
if (suggestItems != null && suggestItems.length > 0) this.suggestItems = suggestItems;
addButton.callback = () -> add(cast new UIAutoCompleteButton(0, 0, cast this, this.suggestItems));
}
}
class UIAutoCompleteButton extends UIButton {
public var textBox:UIAutoCompleteTextBox;
public var deleteButton:UIButton;
public var deleteIcon:FlxSprite;
public function new (x:Float, y:Float, parent:UIAutoCompleteButtonList, ?suggestItems:Array<String>, text:String = "", ?w:Int, ?h:Int, multiline:Bool = false) {
super(x, y, "", null, w == null ? Std.int(parent.buttonSize.x) : w, h == null ? Std.int(parent.buttonSize.y) : h);
members.push(textBox = new UIAutoCompleteTextBox(16, bHeight/2 - (32/2), text, Std.int(bWidth - 32 - 36), 32, multiline));
if (suggestItems != null && suggestItems.length > 0) textBox.suggestItems = suggestItems;
textBox.antialiasing = false;
members.push(deleteButton = new UIButton(textBox.x + textBox.bWidth + 10, textBox.y, "", () -> { parent.remove(this); destroy(); }, 32));
deleteButton.color = 0xFFFF0000;
deleteButton.autoAlpha = false;
members.push(deleteIcon = new FlxSprite(deleteButton.x + (15/2), deleteButton.y + 8).loadGraphic(Paths.image('editors/delete-button')));
deleteIcon.antialiasing = false;
}
override function update(elapsed) {
deleteButton.y = y + bHeight / 2 - deleteButton.bHeight / 2;
textBox.y = y + bHeight/2 - 16;
deleteIcon.x = deleteButton.x + (15/2); deleteIcon.y = deleteButton.y + 8;
textBox.selectable = deleteButton.selectable = selectable;
deleteButton.shouldPress = shouldPress;
super.update(elapsed);
}
}
+1 -1
View File
@@ -30,7 +30,7 @@ class UIButton extends UISliceSprite {
super.onHovered(); super.onHovered();
if (FlxG.mouse.justPressed) { if (FlxG.mouse.justPressed) {
hasBeenPressed = true; hasBeenPressed = true;
UIState.playEditorSound(Flags.DEFAULT_EDITOR_BUTTONCLICK_SOUND); FlxG.sound.play(Paths.sound(Flags.DEFAULT_EDITOR_BUTTONCLICK_SOUND));
} }
if (FlxG.mouse.justReleased && callback != null && shouldPress && hasBeenPressed) { if (FlxG.mouse.justReleased && callback != null && shouldPress && hasBeenPressed) {
callback(); callback();
+35 -229
View File
@@ -16,12 +16,6 @@ class UIContextMenu extends MusicBeatSubstate {
public var contextMenuOptions:Array<UIContextMenuOptionSpr> = []; public var contextMenuOptions:Array<UIContextMenuOptionSpr> = [];
public var separators:Array<FlxSprite> = []; public var separators:Array<FlxSprite> = [];
public var childContextMenu:UIContextMenu = null;
public var parentContextMenu:UIContextMenu = null;
private var childContextMenuOptionIndex:Int = -1;
@:allow(funkin.editors.ui.UIContextMenu)
private var lastHoveredOptionIndex:Int = -1;
var scroll:Float = 0.0; var scroll:Float = 0.0;
var flipped:Bool = false; var flipped:Bool = false;
@@ -102,10 +96,6 @@ class UIContextMenu extends MusicBeatSubstate {
for(o in separators) for(o in separators)
o.x -= bg.bWidth; o.x -= bg.bWidth;
} }
for(o in contextMenuOptions) {
o.postCreate();
}
} }
public function select(option:UIContextMenuOption) { public function select(option:UIContextMenuOption) {
@@ -115,12 +105,12 @@ class UIContextMenu extends MusicBeatSubstate {
if (callback != null) if (callback != null)
callback(this, index, option); callback(this, index, option);
if (option.closeOnSelect == null ? true : option.closeOnSelect) if (option.closeOnSelect == null ? true : option.closeOnSelect)
closeWithParents(); close();
} }
public override function update(elapsed:Float) { public override function update(elapsed:Float) {
if (__oobDeletion && FlxG.mouse.justPressed && !bg.hoveredByChild && !hoveringAnyChildren()) if (__oobDeletion && FlxG.mouse.justPressed && !bg.hoveredByChild)
closeWithParents(); close();
__oobDeletion = true; __oobDeletion = true;
@@ -131,14 +121,6 @@ class UIContextMenu extends MusicBeatSubstate {
contextCam.scroll.y = CoolUtil.fpsLerp(contextCam.scroll.y, scroll, 0.5); contextCam.scroll.y = CoolUtil.fpsLerp(contextCam.scroll.y, scroll, 0.5);
contextCam.alpha = CoolUtil.fpsLerp(contextCam.alpha, 1, 0.25); contextCam.alpha = CoolUtil.fpsLerp(contextCam.alpha, 1, 0.25);
if (parentContextMenu != null) {
if (hoveringAnyParents() && parentContextMenu.lastHoveredOptionIndex != parentContextMenu.childContextMenuOptionIndex) {
closeWithChildren();
parentContextMenu.childContextMenuOptionIndex = -1;
}
}
} }
public override function destroy() { public override function destroy() {
@@ -147,56 +129,6 @@ class UIContextMenu extends MusicBeatSubstate {
if (UIState.state.curContextMenu == this) if (UIState.state.curContextMenu == this)
UIState.state.curContextMenu = null; UIState.state.curContextMenu = null;
} }
public function openChildContextMenu(optionSpr:UIContextMenuOptionSpr) {
var index = contextMenuOptions.indexOf(optionSpr);
if (index != childContextMenuOptionIndex) {
childContextMenuOptionIndex = index;
var child = new UIContextMenu(optionSpr.option.childs, null, optionSpr.x + optionSpr.bWidth + 4, optionSpr.y - 4);
persistentDraw = true;
persistentUpdate = true;
child.parentContextMenu = this;
childContextMenu = child;
openSubState(child);
}
}
public function closeWithParents() {
close();
if (parentContextMenu != null) {
parentContextMenu.closeWithParents();
}
}
public function closeWithChildren() {
if (childContextMenu != null) {
childContextMenu.closeWithChildren();
}
close();
}
public function hoveringAnyParents() {
if (parentContextMenu != null) {
return parentContextMenu.bg.hoveredByChild || parentContextMenu.hoveringAnyParents();
}
return false;
}
public function hoveringAnyChildren() {
if (childContextMenu != null) {
return childContextMenu.bg.hoveredByChild || childContextMenu.hoveringAnyChildren();
}
return false;
}
}
typedef UIContextMenuSliderOptionData = {
var min:Float;
var max:Float;
var value:Float;
var ?onChange:UIContextMenuOption->Void;
//default = 120, ignored if sameLine = false
var ?width:Float;
//disables stepper and text if false, default = false
var ?showValues:Bool;
//if true, the slider will be on the same line as the label text, otherwise it will be on the next line below the label
var ?sameLine:Bool;
} }
typedef UIContextMenuCallback = UIContextMenu->Int->UIContextMenuOption->Void; typedef UIContextMenuCallback = UIContextMenu->Int->UIContextMenuOption->Void;
@@ -212,24 +144,13 @@ typedef UIContextMenuOption = {
var ?button:UIContextMenuOptionSpr; var ?button:UIContextMenuOptionSpr;
var ?onCreate:UIContextMenuOptionSpr->Void; var ?onCreate:UIContextMenuOptionSpr->Void;
var ?childs:Array<UIContextMenuOption>; var ?childs:Array<UIContextMenuOption>;
var ?slider:UIContextMenuSliderOptionData;
var ?onIconClick:UIContextMenuOption->Void;
}
enum abstract UIContextMenuOptionType(Int) from Int {
var DEFAULT = 0;
var SUBMENU = 1;
var SLIDER = 2;
} }
class UIContextMenuOptionSpr extends UISliceSprite { class UIContextMenuOptionSpr extends UISliceSprite {
public var label:UIText; public var label:UIText;
public var labelKeybind:UIText; public var labelKeybind:UIText;
public var icon:UIContextMenuOptionIcon; public var icon:FlxSprite;
public var option:UIContextMenuOption; public var option:UIContextMenuOption;
public var optionType:UIContextMenuOptionType = DEFAULT;
public var slider:UISlider = null;
var parent:UIContextMenu; var parent:UIContextMenu;
@@ -239,96 +160,40 @@ class UIContextMenuOptionSpr extends UISliceSprite {
this.parent = parent; this.parent = parent;
this.color = option.color; this.color = option.color;
var w:Int = label.frameWidth + 22; if (option.icon != null && option.icon > 0) {
var h:Int = label.frameHeight; icon = new FlxSprite(0, 0).loadGraphic(Paths.image('editors/ui/context-icons'), true, 20, 20);
icon.animation.add('icon', [option.icon-1], 0, true);
if (option.childs != null) optionType = SUBMENU; icon.animation.play('icon');
if (option.slider != null) optionType = SLIDER;
switch(optionType) {
case SUBMENU:
labelKeybind = new UIText(label.x + label.frameWidth + 10, 2, 0, ">");
case SLIDER:
labelKeybind = new UIText(label.x + label.frameWidth + 10, 2, 0, "");
//slider needs to be created after so that it can match the menu width (when not on the same line)
if (option.slider.sameLine != null && option.slider.sameLine) {
var sliderWidth = option.slider.width != null ? Std.int(option.slider.width) : 120;
w += 120 + slider.barWidth;
} else {
h *= 2;
}
default:
if (option.keybinds == null) {
if (option.keybind != null) {
option.keybinds = [option.keybind];
}
}
if (option.keybinds != null || option.keybindText != null) {
var text = if(option.keybindText == null) {
var textKeys:Array<String> = [];
for (o in option.keybinds[0]) {
if (Std.int(o) > 0) {
textKeys.push(o.toUIString());
}
}
textKeys.join("+");
} else {
option.keybindText;
}
labelKeybind = new UIText(label.x + label.frameWidth + 10, 2, 0, text);
labelKeybind.alpha = 0.75;
w = Std.int(labelKeybind.x + labelKeybind.frameWidth + 10);
}
} }
super(x, y, w, h, 'editors/ui/menu-item'); if (option.keybinds == null) {
if (option.keybind != null) {
option.keybinds = [option.keybind];
}
}
if (option.keybinds != null || option.keybindText != null) {
var text = if(option.keybindText == null) {
var textKeys:Array<String> = [];
for (o in option.keybinds[0]) {
if (Std.int(o) > 0) {
textKeys.push(o.toUIString());
}
}
textKeys.join("+");
} else {
option.keybindText;
}
labelKeybind = new UIText(label.x + label.frameWidth + 10, 2, 0, text);
labelKeybind.alpha = 0.75;
}
super(x, y, labelKeybind != null ? Std.int(labelKeybind.x + labelKeybind.frameWidth + 10) : (label.frameWidth + 22), label.frameHeight, 'editors/ui/menu-item');
members.push(label); members.push(label);
updateIcon(); if (icon != null)
members.push(icon);
if (labelKeybind != null) if (labelKeybind != null)
members.push(labelKeybind); members.push(labelKeybind);
}
//Called after all options are created and the context menu width/height is final
public function postCreate() {
switch(optionType) {
case SLIDER:
var sliderWidth = bWidth-50;
if (option.slider.sameLine != null && option.slider.sameLine) {
option.slider.width != null ? Std.int(option.slider.width) : 120;
}
slider = new UISlider(0, 0, sliderWidth, option.slider.value,
[{start: option.slider.min, end: option.slider.max, size: option.slider.max-option.slider.min}], false);
slider.onChange = function(v) {
option.slider.value = v;
if (option.slider.onChange != null) option.slider.onChange(option);
updateIcon(); //check if icon has changed
@:privateAccess
labelKeybind.text = '${CoolUtil.quantize(slider.__barProgress * 100, 1)}%';
};
slider.value = option.slider.value;
if (option.slider.showValues == null || !option.slider.showValues) {
slider.startText.visible = false;
slider.endText.visible = false;
slider.valueStepper.visible = false;
slider.valueStepper.selectable = false;
}
members.push(slider);
case SUBMENU:
default:
}
} }
public override function draw() { public override function draw() {
@@ -340,71 +205,12 @@ class UIContextMenuOptionSpr extends UISliceSprite {
icon.follow(this, 0, 0); icon.follow(this, 0, 0);
if (labelKeybind != null) if (labelKeybind != null)
labelKeybind.follow(this, bWidth - 10 - labelKeybind.frameWidth, 2); labelKeybind.follow(this, bWidth - 10 - labelKeybind.frameWidth, 2);
if (slider != null) {
if (option.slider.sameLine != null && option.slider.sameLine) {
slider.follow(this, bWidth - 18 - slider.barWidth - (slider.endText.visible ? slider.endText.width : 0), 5);
} else {
slider.follow(this, 20, 5 + label.frameHeight);
}
}
super.draw(); super.draw();
} }
public override function onHovered() { public override function onHovered() {
super.onHovered(); super.onHovered();
if (FlxG.mouse.justReleased)
parent.lastHoveredOptionIndex = parent.contextMenuOptions.indexOf(this); parent.select(option);
switch(optionType) {
case SUBMENU:
parent.openChildContextMenu(this);
case SLIDER:
default:
if (FlxG.mouse.justReleased)
parent.select(option);
}
}
public function updateIcon() {
var currentIcon = option.icon != null ? option.icon : 0;
if (icon == null && currentIcon > 0) {
members.push(icon = new UIContextMenuOptionIcon(option));
}
if (icon != null) {
icon.updateIconState(currentIcon);
}
}
}
class UIContextMenuOptionIcon extends UISprite {
private var option:UIContextMenuOption;
private var _lastState:Int = 0;
override public function new(option:UIContextMenuOption) {
super();
this.option = option;
loadGraphic(Paths.image('editors/ui/context-icons'), true, 20, 20);
selectable = option.onIconClick != null;
cursor = option.onIconClick != null ? CLICK : ARROW;
}
public function updateIconState(state:Int) {
if (_lastState == state) return;
_lastState = state;
visible = state > 0;
if (state > 0) {
animation.add('icon', [state-1], 0, true);
animation.play('icon');
}
}
public override function onHovered() {
super.onHovered();
if (FlxG.mouse.justReleased && option.onIconClick != null) {
option.onIconClick(option);
}
} }
} }

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