Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e8a185c404 | ||
|
|
80ca43b46e | ||
|
|
8f0583958d | ||
|
|
f82c8d7fb7 | ||
|
|
2a413071cd | ||
|
|
3fa3fbda14 | ||
|
|
cd7c9f1afc | ||
|
|
e458e868a4 | ||
|
|
6f8f43d3dc | ||
|
|
a8a5ae7a89 | ||
|
|
e0b5369eb5 | ||
|
|
d874ea0348 | ||
|
|
d80b7b95cf | ||
|
|
270ed6b9b5 | ||
|
|
39968efb19 | ||
|
|
64ea9db1c1 | ||
|
|
5957a55b96 | ||
|
|
3266e22562 | ||
|
|
a7b040152d | ||
|
|
a951e38dbb | ||
|
|
4fe3ba76e3 | ||
|
|
f44d0192af | ||
|
|
f8a06bf94c | ||
|
|
ec2a39995b | ||
|
|
3c15805c80 | ||
|
|
221d9dba1d | ||
|
|
d87ac417f7 | ||
|
|
3e084397a8 | ||
|
|
370d5ede81 | ||
|
|
d7dbe5038d | ||
|
|
6c25431c75 | ||
|
|
37eb193e53 | ||
|
|
0eeef88ac7 | ||
|
|
47a3526178 | ||
|
|
bbb16f4c5c | ||
|
|
5115067b49 | ||
|
|
4d84e65cb5 | ||
|
|
f8f9d6eb4a | ||
|
|
6d3243b256 | ||
|
|
0cfb3e52c5 |
@@ -12,6 +12,8 @@ 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:
|
||||||
@@ -35,7 +37,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
|
haxelib run lime build linux -DCOMPILE_EXPERIMENTAL
|
||||||
# - 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)
|
||||||
@@ -144,4 +146,4 @@ jobs:
|
|||||||
path: |
|
path: |
|
||||||
.haxelib/
|
.haxelib/
|
||||||
export/debug/linux/haxe/
|
export/debug/linux/haxe/
|
||||||
export/debug/linux/obj/
|
export/debug/linux/obj/
|
||||||
|
|||||||
@@ -12,6 +12,8 @@ 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:
|
||||||
@@ -32,7 +34,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
|
arch -x86_64 haxelib run lime build mac -DCOMPILE_EXPERIMENTAL
|
||||||
- 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)
|
||||||
@@ -138,4 +140,4 @@ jobs:
|
|||||||
path: |
|
path: |
|
||||||
.haxelib/
|
.haxelib/
|
||||||
export/debug/macos/haxe/
|
export/debug/macos/haxe/
|
||||||
export/debug/macos/obj/
|
export/debug/macos/obj/
|
||||||
|
|||||||
@@ -22,6 +22,8 @@ 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
|
||||||
|
|||||||
@@ -12,6 +12,8 @@ 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:
|
||||||
@@ -32,7 +34,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
|
haxelib run lime build windows -DCOMPILE_EXPERIMENTAL
|
||||||
- name: Uploading artifact (executable)
|
- name: Uploading artifact (executable)
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
@@ -134,4 +136,4 @@ jobs:
|
|||||||
path: |
|
path: |
|
||||||
.haxelib/
|
.haxelib/
|
||||||
export/debug/windows/haxe/
|
export/debug/windows/haxe/
|
||||||
export/debug/windows/obj/
|
export/debug/windows/obj/
|
||||||
|
|||||||
@@ -73,7 +73,7 @@ _**QOL = Quality of Life**_
|
|||||||
- 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 (Stage coming soon)
|
||||||
- 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 (Character editor rework soon)
|
||||||
- Features not found in other editors!
|
- Features not found in other editors!
|
||||||
|
|||||||
@@ -2,13 +2,6 @@
|
|||||||
<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>
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
<!DOCTYPE codename-engine-character>
|
<!DOCTYPE codename-engine-character>
|
||||||
<character x="100" y="275" sprite="gf" icon="gf" color="#A5004D">
|
<character x="100" y="275" color="#A5004D">
|
||||||
<anim name="cheer" anim="GF Cheer" x="0" y="0" fps="24" loop="false"/>
|
<anim name="cheer" anim="GF Cheer"/>
|
||||||
<anim name="singUP" anim="GF Up Note" x="0" y="0" fps="24" loop="false"/>
|
<anim name="singUP" anim="GF Up Note"/>
|
||||||
<anim name="singLEFT" anim="GF left note" x="0" y="0" fps="24" loop="false"/>
|
<anim name="singLEFT" anim="GF left note"/>
|
||||||
<anim name="singRIGHT" anim="GF Right Note" x="0" y="0" fps="24" loop="false"/>
|
<anim name="singRIGHT" anim="GF Right Note"/>
|
||||||
<anim name="singDOWN" anim="GF Down Note" x="0" y="0" fps="24" loop="false"/>
|
<anim name="singDOWN" anim="GF Down Note"/>
|
||||||
<anim name="danceLeft" anim="GF Dancing Beat" x="0" y="0" fps="24" loop="false" indices="0..14"/>
|
<anim name="danceLeft" anim="GF Dancing Beat" indices="0..14"/>
|
||||||
<anim name="danceRight" anim="GF Dancing Beat" x="0" y="0" fps="24" loop="false" indices="15..30"/>
|
<anim name="danceRight" anim="GF Dancing Beat" indices="15..30"/>
|
||||||
<anim name="hairBlow" anim="GF Dancing Beat Hair blowing" x="0" y="0" fps="24" loop="true" indices="0,1,2,3"/>
|
<anim name="hairBlow" anim="GF Dancing Beat Hair blowing" loop="true" indices="0..3"/>
|
||||||
<anim name="hairFall" anim="GF Dancing Beat Hair Landing" x="0" y="0" fps="24" loop="false" indices="0..11"/>
|
<anim name="hairFall" anim="GF Dancing Beat Hair Landing" indices="0..11"/>
|
||||||
<anim name="scared" anim="GF FEAR" x="0" y="0" fps="24" loop="true"/>
|
<anim name="scared" anim="GF FEAR " loop="true"/>
|
||||||
<anim name="sad" anim="gf sad" x="0" y="0" fps="24" loop="true" indices="0..12"/>
|
<anim name="sad" anim="gf sad" x="-51" y="315" loop="true" indices="0..12"/>
|
||||||
</character>
|
</character>
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
<sprite name="fgSnow" x="-600" y="680" sprite="fgSnow"/>
|
<sprite name="fgSnow" x="-600" y="680" sprite="fgSnow"/>
|
||||||
|
|
||||||
|
|
||||||
<girlfriend x="540" y="110"/>
|
<girlfriend x="440" y="110"/>
|
||||||
<dad/>
|
<dad/>
|
||||||
<boyfriend x="1030" camyoffset="-150" camxoffset="-150"/>
|
<boyfriend x="1030" camyoffset="-150" camxoffset="-150"/>
|
||||||
|
|
||||||
|
|||||||
@@ -1,28 +1,28 @@
|
|||||||
{"ATLAS": {"SPRITES":[
|
{"ATLAS":{"SPRITES":[
|
||||||
{"SPRITE" : {"name": "0000","x":1636,"y":275,"w":183,"h":115,"rotated": false}},
|
{"SPRITE":{"name":"0","x":1662,"y":282,"w":194,"h":117,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0001","x":215,"y":360,"w":84,"h":140,"rotated": false}},
|
{"SPRITE":{"name":"1","x":1790,"y":417,"w":92,"h":136,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0002","x":419,"y":358,"w":251,"h":121,"rotated": false}},
|
{"SPRITE":{"name":"2","x":1193,"y":539,"w":259,"h":123,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0003","x":1636,"y":394,"w":120,"h":65,"rotated": false}},
|
{"SPRITE":{"name":"3","x":483,"y":553,"w":125,"h":68,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0004","x":4,"y":360,"w":108,"h":126,"rotated": false}},
|
{"SPRITE":{"name":"4","x":1662,"y":417,"w":110,"h":127,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0005","x":674,"y":358,"w":102,"h":147,"rotated": false}},
|
{"SPRITE":{"name":"5","x":1886,"y":0,"w":105,"h":149,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0006","x":116,"y":360,"w":95,"h":130,"rotated": false}},
|
{"SPRITE":{"name":"6","x":1886,"y":167,"w":97,"h":130,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0007","x":2038,"y":4,"w":1,"h":4,"rotated": false}},
|
{"SPRITE":{"name":"7","x":1398,"y":0,"w":470,"h":264,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0008","x":4,"y":4,"w":411,"h":352,"rotated": false}},
|
{"SPRITE":{"name":"8","x":867,"y":0,"w":513,"h":254,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0009","x":419,"y":4,"w":398,"h":350,"rotated": false}},
|
{"SPRITE":{"name":"9","x":0,"y":372,"w":465,"h":270,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0010","x":1303,"y":275,"w":329,"h":162,"rotated": false}},
|
{"SPRITE":{"name":"10","x":1900,"y":315,"w":101,"h":118,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0011","x":303,"y":360,"w":90,"h":103,"rotated": false}},
|
{"SPRITE":{"name":"11","x":867,"y":272,"w":308,"h":367,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0012","x":1823,"y":4,"w":211,"h":236,"rotated": false}},
|
{"SPRITE":{"name":"12","x":483,"y":371,"w":338,"h":164,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0013","x":1823,"y":244,"w":208,"h":235,"rotated": false}},
|
{"SPRITE":{"name":"13","x":0,"y":0,"w":422,"h":354,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0014","x":821,"y":258,"w":478,"h":262,"rotated": false}},
|
{"SPRITE":{"name":"14","x":440,"y":0,"w":409,"h":353,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0015","x":821,"y":4,"w":521,"h":250,"rotated": false}},
|
{"SPRITE":{"name":"15","x":1900,"y":451,"w":92,"h":103,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0016","x":1346,"y":4,"w":473,"h":267,"rotated": false}}
|
{"SPRITE":{"name":"16","x":1193,"y":282,"w":218,"h":239,"rotated":false}},
|
||||||
]},
|
{"SPRITE":{"name":"17","x":1429,"y":282,"w":215,"h":237,"rotated":false}}]},
|
||||||
"meta": {
|
"meta":{
|
||||||
"app": "Adobe Animate",
|
"app":"Adobe Animate (Better TA Extension)",
|
||||||
"version": "22.0.5.191",
|
"version":"24.0.2.12",
|
||||||
"image": "spritemap1.png",
|
"image":"spritemap1.png",
|
||||||
"format": "RGBA8888",
|
"format":"RGBA8888",
|
||||||
"size": {"w":2043,"h":524},
|
"size":{"w":2031,"h":662},
|
||||||
"resolution": "1"
|
"resolution":"1"
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
Before Width: | Height: | Size: 74 KiB After Width: | Height: | Size: 134 KiB |
@@ -1,58 +1,40 @@
|
|||||||
{"ATLAS": {"SPRITES":[
|
{"ATLAS":{"SPRITES":[
|
||||||
{"SPRITE" : {"name": "0000","x":994,"y":1029,"w":187,"h":118,"rotated": false}},
|
{"SPRITE":{"name":"0","x":349,"y":867,"w":254,"h":136,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0001","x":1953,"y":524,"w":84,"h":140,"rotated": false}},
|
{"SPRITE":{"name":"1","x":1648,"y":328,"w":287,"h":363,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0002","x":471,"y":430,"w":258,"h":137,"rotated": false}},
|
{"SPRITE":{"name":"2","x":1571,"y":709,"w":185,"h":117,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0003","x":1300,"y":641,"w":122,"h":66,"rotated": false}},
|
{"SPRITE":{"name":"3","x":1686,"y":855,"w":86,"h":136,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0004","x":1825,"y":1078,"w":108,"h":126,"rotated": false}},
|
{"SPRITE":{"name":"4","x":349,"y":1021,"w":122,"h":68,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0005","x":360,"y":695,"w":103,"h":149,"rotated": false}},
|
{"SPRITE":{"name":"5","x":1774,"y":709,"w":110,"h":128,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0006","x":1945,"y":867,"w":95,"h":130,"rotated": false}},
|
{"SPRITE":{"name":"6","x":621,"y":867,"w":105,"h":148,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0007","x":2034,"y":4,"w":1,"h":4,"rotated": false}},
|
{"SPRITE":{"name":"7","x":1571,"y":844,"w":97,"h":131,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0008","x":943,"y":650,"w":309,"h":375,"rotated": false}},
|
{"SPRITE":{"name":"8","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":"9","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":"10","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":"11","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":"12","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":"13","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":"14","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":"15","x":800,"y":1,"w":543,"h":308,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0016","x":782,"y":1029,"w":208,"h":235,"rotated": false}},
|
{"SPRITE":{"name":"16","x":1363,"y":1,"w":543,"h":308,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0017","x":782,"y":910,"w":117,"h":83,"rotated": false}},
|
{"SPRITE":{"name":"17","x":1,"y":444,"w":771,"h":404,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0018","x":994,"y":1151,"w":117,"h":83,"rotated": false}},
|
{"SPRITE":{"name":"18","x":791,"y":700,"w":302,"h":369,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0019","x":1937,"y":1108,"w":103,"h":83,"rotated": false}},
|
{"SPRITE":{"name":"19","x":1111,"y":957,"w":120,"h":86,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0020","x":1115,"y":1151,"w":117,"h":83,"rotated": false}},
|
{"SPRITE":{"name":"20","x":1790,"y":855,"w":120,"h":86,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0021","x":1654,"y":714,"w":287,"h":360,"rotated": false}},
|
{"SPRITE":{"name":"21","x":1790,"y":959,"w":106,"h":86,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0022","x":471,"y":571,"w":179,"h":67,"rotated": false}},
|
{"SPRITE":{"name":"22","x":1249,"y":957,"w":120,"h":86,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0023","x":654,"y":571,"w":118,"h":75,"rotated": false}},
|
{"SPRITE":{"name":"23","x":0,"y":0,"w":781,"h":425,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0024","x":1966,"y":223,"w":55,"h":112,"rotated": false}},
|
{"SPRITE":{"name":"24","x":0,"y":867,"w":331,"h":164,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0025","x":1966,"y":4,"w":64,"h":106,"rotated": false}},
|
{"SPRITE":{"name":"25","x":799,"y":328,"w":413,"h":354,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0026","x":1185,"y":1029,"w":67,"h":70,"rotated": false}},
|
{"SPRITE":{"name":"26","x":1230,"y":328,"w":400,"h":353,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0027","x":337,"y":1182,"w":122,"h":62,"rotated": false}},
|
{"SPRITE":{"name":"27","x":1387,"y":954,"w":90,"h":103,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0028","x":1647,"y":1078,"w":174,"h":97,"rotated": false}},
|
{"SPRITE":{"name":"28","x":1111,"y":700,"w":213,"h":239,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0029","x":360,"y":870,"w":82,"h":14,"rotated": false}},
|
{"SPRITE":{"name":"29","x":1342,"y":699,"w":211,"h":237,"rotated":false}}]},
|
||||||
{"SPRITE" : {"name": "0030","x":1647,"y":1179,"w":128,"h":61,"rotated": false}},
|
"meta":{
|
||||||
{"SPRITE" : {"name": "0031","x":463,"y":1182,"w":124,"h":58,"rotated": false}},
|
"app":"Adobe Animate (Better TA Extension)",
|
||||||
{"SPRITE" : {"name": "0032","x":1966,"y":114,"w":59,"h":105,"rotated": false}},
|
"version":"24.0.2.12",
|
||||||
{"SPRITE" : {"name": "0033","x":1953,"y":360,"w":87,"h":160,"rotated": false}},
|
"image":"spritemap1.png",
|
||||||
{"SPRITE" : {"name": "0034","x":1945,"y":714,"w":92,"h":149,"rotated": false}},
|
"format":"RGBA8888",
|
||||||
{"SPRITE" : {"name": "0035","x":1426,"y":641,"w":104,"h":42,"rotated": false}},
|
"size":{"w":1965,"h":1089},
|
||||||
{"SPRITE" : {"name": "0036","x":1953,"y":692,"w":73,"h":18,"rotated": false}},
|
"resolution":"1"
|
||||||
{"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"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
Before Width: | Height: | Size: 228 KiB After Width: | Height: | Size: 453 KiB |
@@ -1,57 +1,55 @@
|
|||||||
{"ATLAS": {"SPRITES":[
|
{"ATLAS":{"SPRITES":[
|
||||||
{"SPRITE" : {"name": "0000","x":1623,"y":602,"w":287,"h":360,"rotated": false}},
|
{"SPRITE":{"name":"0","x":1129,"y":977,"w":86,"h":17,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0001","x":1310,"y":269,"w":309,"h":375,"rotated": false}},
|
{"SPRITE":{"name":"1","x":1690,"y":1012,"w":86,"h":17,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0002","x":4,"y":4,"w":420,"h":359,"rotated": false}},
|
{"SPRITE":{"name":"2","x":1656,"y":852,"w":126,"h":64,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0003","x":428,"y":4,"w":406,"h":358,"rotated": false}},
|
{"SPRITE":{"name":"3","x":1915,"y":841,"w":121,"h":77,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0004","x":4,"y":639,"w":336,"h":165,"rotated": false}},
|
{"SPRITE":{"name":"4","x":1382,"y":980,"w":131,"h":64,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0005","x":125,"y":808,"w":90,"h":103,"rotated": false}},
|
{"SPRITE":{"name":"5","x":1132,"y":283,"w":420,"h":270,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0006","x":1819,"y":4,"w":215,"h":242,"rotated": false}},
|
{"SPRITE":{"name":"6","x":1570,"y":277,"w":389,"h":273,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0007","x":1217,"y":648,"w":213,"h":240,"rotated": false}},
|
{"SPRITE":{"name":"7","x":0,"y":743,"w":397,"h":292,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0008","x":606,"y":660,"w":191,"h":120,"rotated": false}},
|
{"SPRITE":{"name":"8","x":431,"y":267,"w":354,"h":332,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0009","x":606,"y":784,"w":90,"h":151,"rotated": false}},
|
{"SPRITE":{"name":"9","x":1592,"y":568,"w":190,"h":117,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0010","x":344,"y":660,"w":258,"h":124,"rotated": false}},
|
{"SPRITE":{"name":"10","x":1444,"y":826,"w":86,"h":136,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0011","x":448,"y":859,"w":122,"h":67,"rotated": false}},
|
{"SPRITE":{"name":"11","x":723,"y":852,"w":260,"h":123,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0012","x":1914,"y":755,"w":108,"h":126,"rotated": false}},
|
{"SPRITE":{"name":"12","x":1548,"y":947,"w":124,"h":68,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0013","x":1914,"y":602,"w":103,"h":149,"rotated": false}},
|
{"SPRITE":{"name":"13","x":1001,"y":852,"w":110,"h":128,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0014","x":700,"y":784,"w":95,"h":130,"rotated": false}},
|
{"SPRITE":{"name":"14","x":1933,"y":0,"w":106,"h":148,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0015","x":2038,"y":4,"w":1,"h":4,"rotated": false}},
|
{"SPRITE":{"name":"15","x":1129,"y":828,"w":97,"h":131,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0016","x":838,"y":253,"w":468,"h":256,"rotated": false}},
|
{"SPRITE":{"name":"16","x":803,"y":283,"w":311,"h":369,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0017","x":838,"y":4,"w":510,"h":245,"rotated": false}},
|
{"SPRITE":{"name":"17","x":1592,"y":703,"w":167,"h":101,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0018","x":1352,"y":4,"w":463,"h":261,"rotated": false}},
|
{"SPRITE":{"name":"18","x":1835,"y":852,"w":57,"h":105,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0019","x":4,"y":367,"w":418,"h":268,"rotated": false}},
|
{"SPRITE":{"name":"19","x":1977,"y":270,"w":66,"h":104,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0020","x":826,"y":513,"w":387,"h":271,"rotated": false}},
|
{"SPRITE":{"name":"20","x":1910,"y":936,"w":70,"h":73,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0021","x":428,"y":366,"w":394,"h":290,"rotated": false}},
|
{"SPRITE":{"name":"21","x":1244,"y":828,"w":182,"h":69,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0022","x":1623,"y":269,"w":352,"h":329,"rotated": false}},
|
{"SPRITE":{"name":"22","x":1690,"y":934,"w":127,"h":60,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0023","x":1143,"y":788,"w":67,"h":70,"rotated": false}},
|
{"SPRITE":{"name":"23","x":418,"y":617,"w":287,"h":363,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0024","x":1033,"y":875,"w":122,"h":62,"rotated": false}},
|
{"SPRITE":{"name":"24","x":1244,"y":915,"w":120,"h":86,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0025","x":1217,"y":513,"w":64,"h":106,"rotated": false}},
|
{"SPRITE":{"name":"25","x":1777,"y":748,"w":120,"h":86,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0026","x":1979,"y":359,"w":55,"h":112,"rotated": false}},
|
{"SPRITE":{"name":"26","x":1933,"y":166,"w":106,"h":86,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0027","x":799,"y":788,"w":98,"h":118,"rotated": false}},
|
{"SPRITE":{"name":"27","x":1915,"y":737,"w":120,"h":86,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0028","x":1979,"y":250,"w":59,"h":105,"rotated": false}},
|
{"SPRITE":{"name":"28","x":1800,"y":568,"w":89,"h":162,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0029","x":1434,"y":749,"w":87,"h":160,"rotated": false}},
|
{"SPRITE":{"name":"29","x":1907,"y":568,"w":95,"h":151,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0030","x":1525,"y":749,"w":92,"h":149,"rotated": false}},
|
{"SPRITE":{"name":"30","x":1977,"y":392,"w":61,"h":107,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0031","x":219,"y":887,"w":104,"h":42,"rotated": false}},
|
{"SPRITE":{"name":"31","x":415,"y":998,"w":107,"h":45,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0032","x":527,"y":811,"w":73,"h":18,"rotated": false}},
|
{"SPRITE":{"name":"32","x":727,"y":993,"w":77,"h":22,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0033","x":527,"y":788,"w":72,"h":19,"rotated": false}},
|
{"SPRITE":{"name":"33","x":634,"y":998,"w":75,"h":23,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0034","x":527,"y":833,"w":72,"h":18,"rotated": false}},
|
{"SPRITE":{"name":"34","x":822,"y":993,"w":75,"h":22,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0035","x":1217,"y":623,"w":73,"h":20,"rotated": false}},
|
{"SPRITE":{"name":"35","x":540,"y":998,"w":76,"h":24,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0036","x":344,"y":788,"w":179,"h":67,"rotated": false}},
|
{"SPRITE":{"name":"36","x":1445,"y":0,"w":470,"h":259,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0037","x":219,"y":808,"w":118,"h":75,"rotated": false}},
|
{"SPRITE":{"name":"37","x":431,"y":0,"w":513,"h":249,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0038","x":901,"y":875,"w":128,"h":61,"rotated": false}},
|
{"SPRITE":{"name":"38","x":962,"y":0,"w":465,"h":265,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0039","x":1914,"y":885,"w":124,"h":58,"rotated": false}},
|
{"SPRITE":{"name":"39","x":723,"y":670,"w":331,"h":164,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0040","x":901,"y":788,"w":117,"h":83,"rotated": false}},
|
{"SPRITE":{"name":"40","x":0,"y":0,"w":413,"h":354,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0041","x":1022,"y":788,"w":117,"h":83,"rotated": false}},
|
{"SPRITE":{"name":"41","x":0,"y":372,"w":400,"h":353,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0042","x":341,"y":859,"w":103,"h":83,"rotated": false}},
|
{"SPRITE":{"name":"42","x":1548,"y":826,"w":90,"h":103,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0043","x":4,"y":808,"w":117,"h":83,"rotated": false}},
|
{"SPRITE":{"name":"43","x":1132,"y":571,"w":213,"h":239,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0044","x":1434,"y":648,"w":174,"h":97,"rotated": false}},
|
{"SPRITE":{"name":"44","x":1363,"y":571,"w":211,"h":237,"rotated":false}}]},
|
||||||
{"SPRITE" : {"name": "0045","x":1819,"y":250,"w":82,"h":14,"rotated": false}}
|
"meta":{
|
||||||
]},
|
"app":"Adobe Animate (Better TA Extension)",
|
||||||
"meta": {
|
"version":"24.0.2.12",
|
||||||
"app": "Adobe Animate",
|
"image":"spritemap1.png",
|
||||||
"version": "21.0.1.37179",
|
"format":"RGBA8888",
|
||||||
"image": "spritemap1.png",
|
"size":{"w":2064,"h":1065},
|
||||||
"format": "RGBA8888",
|
"resolution":"1"
|
||||||
"size": {"w":2043,"h":966},
|
|
||||||
"resolution": "1"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
Before Width: | Height: | Size: 165 KiB After Width: | Height: | Size: 265 KiB |
@@ -1,60 +1,60 @@
|
|||||||
{"ATLAS": {"SPRITES":[
|
{"ATLAS":{"SPRITES":[
|
||||||
{"SPRITE" : {"name": "0000","x":4076,"y":2,"w":9,"h":12,"rotated": false}},
|
{"SPRITE":{"name":"0","x":2834,"y":332,"w":12,"h":15,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0001","x":1957,"y":2,"w":524,"h":501,"rotated": false}},
|
{"SPRITE":{"name":"1","x":1476,"y":532,"w":527,"h":503,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0002","x":716,"y":2,"w":721,"h":621,"rotated": false}},
|
{"SPRITE":{"name":"2","x":733,"y":0,"w":725,"h":623,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0003","x":2331,"y":505,"w":139,"h":109,"rotated": false}},
|
{"SPRITE":{"name":"3","x":0,"y":659,"w":741,"h":304,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0004","x":3244,"y":725,"w":303,"h":170,"rotated": false}},
|
{"SPRITE":{"name":"4","x":2311,"y":0,"w":349,"h":540,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0005","x":1691,"y":516,"w":248,"h":277,"rotated": false}},
|
{"SPRITE":{"name":"5","x":759,"y":641,"w":583,"h":373,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0006","x":2495,"y":843,"w":173,"h":229,"rotated": false}},
|
{"SPRITE":{"name":"6","x":2021,"y":0,"w":272,"h":702,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0007","x":2,"y":642,"w":262,"h":221,"rotated": false}},
|
{"SPRITE":{"name":"7","x":1476,"y":0,"w":518,"h":514,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0008","x":2331,"y":616,"w":118,"h":117,"rotated": false}},
|
{"SPRITE":{"name":"8","x":0,"y":0,"w":715,"h":641,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0009","x":3549,"y":865,"w":261,"h":139,"rotated": false}},
|
{"SPRITE":{"name":"9","x":619,"y":1032,"w":205,"h":122,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0010","x":3209,"y":897,"w":202,"h":122,"rotated": false}},
|
{"SPRITE":{"name":"10","x":842,"y":1032,"w":205,"h":122,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0011","x":580,"y":913,"w":202,"h":122,"rotated": false}},
|
{"SPRITE":{"name":"11","x":2311,"y":558,"w":115,"h":112,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0012","x":2831,"y":304,"w":45,"h":42,"rotated": false}},
|
{"SPRITE":{"name":"12","x":2801,"y":947,"w":305,"h":172,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0013","x":1957,"y":505,"w":372,"h":311,"rotated": false}},
|
{"SPRITE":{"name":"13","x":2678,"y":0,"w":375,"h":314,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0014","x":1439,"y":516,"w":250,"h":325,"rotated": false}},
|
{"SPRITE":{"name":"14","x":2870,"y":332,"w":252,"h":328,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0015","x":716,"y":625,"w":235,"h":286,"rotated": false}},
|
{"SPRITE":{"name":"15","x":3071,"y":0,"w":239,"h":290,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0016","x":953,"y":625,"w":245,"h":249,"rotated": false}},
|
{"SPRITE":{"name":"16","x":3135,"y":678,"w":220,"h":246,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0017","x":3644,"y":373,"w":136,"h":133,"rotated": false}},
|
{"SPRITE":{"name":"17","x":3597,"y":248,"w":173,"h":231,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0018","x":2331,"y":735,"w":150,"h":91,"rotated": false}},
|
{"SPRITE":{"name":"18","x":3769,"y":0,"w":225,"h":190,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0019","x":3644,"y":508,"w":151,"h":95,"rotated": false}},
|
{"SPRITE":{"name":"19","x":1290,"y":1053,"w":131,"h":81,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0020","x":784,"y":913,"w":140,"h":90,"rotated": false}},
|
{"SPRITE":{"name":"20","x":3905,"y":814,"w":132,"h":85,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0021","x":3644,"y":605,"w":149,"h":92,"rotated": false}},
|
{"SPRITE":{"name":"21","x":1733,"y":1053,"w":122,"h":80,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0022","x":2670,"y":932,"w":144,"h":87,"rotated": false}},
|
{"SPRITE":{"name":"22","x":3905,"y":917,"w":129,"h":82,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0023","x":2670,"y":843,"w":152,"h":87,"rotated": false}},
|
{"SPRITE":{"name":"23","x":1589,"y":1053,"w":126,"h":78,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0024","x":4087,"y":2,"w":1,"h":4,"rotated": false}},
|
{"SPRITE":{"name":"24","x":1439,"y":1053,"w":132,"h":77,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0025","x":2831,"y":373,"w":411,"h":352,"rotated": false}},
|
{"SPRITE":{"name":"25","x":3778,"y":814,"w":109,"h":107,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0026","x":3244,"y":373,"w":398,"h":350,"rotated": false}},
|
{"SPRITE":{"name":"26","x":3124,"y":1123,"w":3,"h":7,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0027","x":266,"y":642,"w":329,"h":162,"rotated": false}},
|
{"SPRITE":{"name":"27","x":3145,"y":1123,"w":3,"h":7,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0028","x":597,"y":642,"w":90,"h":103,"rotated": false}},
|
{"SPRITE":{"name":"28","x":3673,"y":497,"w":260,"h":141,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0029","x":1200,"y":625,"w":211,"h":236,"rotated": false}},
|
{"SPRITE":{"name":"29","x":3788,"y":208,"w":237,"h":161,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0030","x":2831,"y":727,"w":208,"h":235,"rotated": false}},
|
{"SPRITE":{"name":"30","x":3542,"y":660,"w":218,"h":144,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0031","x":2483,"y":2,"w":738,"h":300,"rotated": false}},
|
{"SPRITE":{"name":"31","x":3124,"y":947,"w":301,"h":158,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0032","x":2483,"y":304,"w":346,"h":537,"rotated": false}},
|
{"SPRITE":{"name":"32","x":3371,"y":498,"w":284,"h":144,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0033","x":2,"y":865,"w":235,"h":158,"rotated": false}},
|
{"SPRITE":{"name":"33","x":0,"y":981,"w":295,"h":150,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0034","x":3812,"y":865,"w":216,"h":141,"rotated": false}},
|
{"SPRITE":{"name":"34","x":313,"y":981,"w":288,"h":145,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0035","x":2000,"y":818,"w":299,"h":155,"rotated": false}},
|
{"SPRITE":{"name":"35","x":3443,"y":942,"w":182,"h":212,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0036","x":1200,"y":863,"w":179,"h":208,"rotated": false}},
|
{"SPRITE":{"name":"36","x":3371,"y":255,"w":208,"h":225,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0037","x":1691,"y":818,"w":307,"h":154,"rotated": false}},
|
{"SPRITE":{"name":"37","x":3373,"y":660,"w":151,"h":264,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0038","x":3644,"y":702,"w":320,"h":161,"rotated": false}},
|
{"SPRITE":{"name":"38","x":3778,"y":656,"w":206,"h":140,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0039","x":266,"y":806,"w":312,"h":155,"rotated": false}},
|
{"SPRITE":{"name":"39","x":3557,"y":0,"w":194,"h":230,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0040","x":239,"y":963,"w":224,"h":108,"rotated": false}},
|
{"SPRITE":{"name":"40","x":2678,"y":485,"w":47,"h":44,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0041","x":3223,"y":2,"w":580,"h":369,"rotated": false}},
|
{"SPRITE":{"name":"41","x":2870,"y":678,"w":247,"h":251,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0042","x":3805,"y":2,"w":269,"h":698,"rotated": false}},
|
{"SPRITE":{"name":"42","x":2678,"y":332,"w":138,"h":135,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0043","x":1413,"y":843,"w":205,"h":222,"rotated": false}},
|
{"SPRITE":{"name":"43","x":1065,"y":1053,"w":207,"h":101,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0044","x":3041,"y":727,"w":166,"h":292,"rotated": false}},
|
{"SPRITE":{"name":"44","x":2452,"y":947,"w":331,"h":164,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0045","x":953,"y":876,"w":203,"h":137,"rotated": false}},
|
{"SPRITE":{"name":"45","x":2021,"y":720,"w":413,"h":354,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0046","x":1439,"y":2,"w":516,"h":512,"rotated": false}},
|
{"SPRITE":{"name":"46","x":2452,"y":558,"w":400,"h":353,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0047","x":2,"y":2,"w":712,"h":638,"rotated": false}},
|
{"SPRITE":{"name":"47","x":3951,"y":387,"w":90,"h":103,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0048","x":2301,"y":843,"w":192,"h":227,"rotated": false}}
|
{"SPRITE":{"name":"48","x":3140,"y":308,"w":213,"h":239,"rotated":false}},
|
||||||
]},
|
{"SPRITE":{"name":"49","x":3328,"y":0,"w":211,"h":237,"rotated":false}}]},
|
||||||
"meta": {
|
"meta":{
|
||||||
"app": "Adobe Animate",
|
"app":"Adobe Animate (Better TA Extension)",
|
||||||
"version": "21.0.1.37179",
|
"version":"24.0.2.12",
|
||||||
"image": "spritemap1.png",
|
"image":"spritemap1.png",
|
||||||
"format": "RGBA8888",
|
"format":"RGBA8888",
|
||||||
"size": {"w":4090,"h":1074},
|
"size":{"w":4061,"h":1154},
|
||||||
"resolution": "1"
|
"resolution":"1"
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
Before Width: | Height: | Size: 344 KiB After Width: | Height: | Size: 535 KiB |
|
Before Width: | Height: | Size: 804 B After Width: | Height: | Size: 1.0 KiB |
@@ -1,145 +1,241 @@
|
|||||||
{"ATLAS": {"SPRITES":[
|
{"ATLAS":{"SPRITES":[
|
||||||
{"SPRITE" : {"name": "0000","x":2847,"y":969,"w":327,"h":397,"rotated": false}},
|
{"SPRITE":{"name":"0","x":2564,"y":2,"w":23,"h":144,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0001","x":2441,"y":894,"w":110,"h":159,"rotated": false}},
|
{"SPRITE":{"name":"1","x":3024,"y":522,"w":42,"h":85,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0002","x":1709,"y":1631,"w":197,"h":185,"rotated": false}},
|
{"SPRITE":{"name":"2","x":2598,"y":1211,"w":67,"h":60,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0003","x":408,"y":1773,"w":92,"h":155,"rotated": false}},
|
{"SPRITE":{"name":"3","x":3964,"y":932,"w":93,"h":51,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0004","x":236,"y":1639,"w":274,"h":132,"rotated": false}},
|
{"SPRITE":{"name":"4","x":3691,"y":1016,"w":91,"h":43,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0005","x":3427,"y":1495,"w":133,"h":74,"rotated": false}},
|
{"SPRITE":{"name":"5","x":3877,"y":270,"w":111,"h":95,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0006","x":3270,"y":540,"w":121,"h":162,"rotated": false}},
|
{"SPRITE":{"name":"6","x":3449,"y":1124,"w":113,"h":127,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0007","x":359,"y":649,"w":518,"h":294,"rotated": false}},
|
{"SPRITE":{"name":"7","x":367,"y":1129,"w":382,"h":123,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0008","x":1957,"y":2,"w":775,"h":483,"rotated": false}},
|
{"SPRITE":{"name":"8","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":"9","x":2,"y":1122,"w":364,"h":131,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0010","x":2,"y":2,"w":1010,"h":645,"rotated": false}},
|
{"SPRITE":{"name":"10","x":2437,"y":1136,"w":31,"h":31,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0011","x":4059,"y":2,"w":20,"h":142,"rotated": false}},
|
{"SPRITE":{"name":"11","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":"12","x":1599,"y":1133,"w":350,"h":113,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0013","x":2755,"y":1508,"w":64,"h":57,"rotated": false}},
|
{"SPRITE":{"name":"13","x":2670,"y":1175,"w":142,"h":94,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0014","x":3176,"y":1171,"w":91,"h":48,"rotated": false}},
|
{"SPRITE":{"name":"14","x":3877,"y":366,"w":122,"h":82,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0015","x":3245,"y":1737,"w":88,"h":41,"rotated": false}},
|
{"SPRITE":{"name":"15","x":1162,"y":1112,"w":436,"h":151,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0016","x":3064,"y":1368,"w":109,"h":93,"rotated": false}},
|
{"SPRITE":{"name":"16","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":"17","x":1599,"y":985,"w":435,"h":147,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0018","x":1957,"y":487,"w":626,"h":405,"rotated": false}},
|
{"SPRITE":{"name":"18","x":779,"y":692,"w":440,"h":344,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0019","x":3402,"y":438,"w":631,"h":438,"rotated": false}},
|
{"SPRITE":{"name":"19","x":1550,"y":711,"w":388,"h":273,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0020","x":1170,"y":1211,"w":393,"h":287,"rotated": false}},
|
{"SPRITE":{"name":"20","x":2106,"y":2,"w":376,"h":155,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0021","x":2847,"y":540,"w":421,"h":427,"rotated": false}},
|
{"SPRITE":{"name":"21","x":2,"y":2,"w":932,"h":689,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0022","x":2734,"y":2,"w":666,"h":536,"rotated": false}},
|
{"SPRITE":{"name":"22","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":"23","x":3907,"y":1171,"w":48,"h":36,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0024","x":3657,"y":1736,"w":186,"h":175,"rotated": false}},
|
{"SPRITE":{"name":"24","x":3858,"y":1206,"w":48,"h":40,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0025","x":4035,"y":764,"w":56,"h":52,"rotated": false}},
|
{"SPRITE":{"name":"25","x":3762,"y":1093,"w":48,"h":64,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0026","x":502,"y":1876,"w":126,"h":104,"rotated": false}},
|
{"SPRITE":{"name":"26","x":3713,"y":1060,"w":48,"h":66,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0027","x":1709,"y":1818,"w":135,"h":104,"rotated": false}},
|
{"SPRITE":{"name":"27","x":3885,"y":1095,"w":48,"h":67,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0028","x":2,"y":1440,"w":232,"h":236,"rotated": false}},
|
{"SPRITE":{"name":"28","x":2106,"y":158,"w":48,"h":69,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0029","x":3938,"y":1437,"w":139,"h":109,"rotated": false}},
|
{"SPRITE":{"name":"29","x":2481,"y":498,"w":48,"h":71,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0030","x":2755,"y":1627,"w":235,"h":158,"rotated": false}},
|
{"SPRITE":{"name":"30","x":1162,"y":1037,"w":48,"h":73,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0031","x":1147,"y":1500,"w":198,"h":233,"rotated": false}},
|
{"SPRITE":{"name":"31","x":4018,"y":188,"w":48,"h":76,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0032","x":2,"y":1860,"w":118,"h":117,"rotated": false}},
|
{"SPRITE":{"name":"32","x":3455,"y":856,"w":48,"h":78,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0033","x":1565,"y":1398,"w":262,"h":221,"rotated": false}},
|
{"SPRITE":{"name":"33","x":3785,"y":1011,"w":48,"h":81,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0034","x":3845,"y":1736,"w":222,"h":145,"rotated": false}},
|
{"SPRITE":{"name":"34","x":4002,"y":1164,"w":48,"h":82,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0035","x":979,"y":1480,"w":166,"h":292,"rotated": false}},
|
{"SPRITE":{"name":"35","x":3953,"y":1083,"w":48,"h":87,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0036","x":3657,"y":1592,"w":276,"h":142,"rotated": false}},
|
{"SPRITE":{"name":"36","x":3904,"y":1004,"w":48,"h":90,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0037","x":925,"y":1774,"w":203,"h":138,"rotated": false}},
|
{"SPRITE":{"name":"37","x":4013,"y":1070,"w":48,"h":93,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0038","x":236,"y":1467,"w":304,"h":170,"rotated": false}},
|
{"SPRITE":{"name":"38","x":3964,"y":984,"w":48,"h":98,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0039","x":4081,"y":2,"w":1,"h":4,"rotated": false}},
|
{"SPRITE":{"name":"39","x":1550,"y":985,"w":48,"h":103,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0040","x":2441,"y":1055,"w":135,"h":127,"rotated": false}},
|
{"SPRITE":{"name":"40","x":3848,"y":894,"w":50,"h":109,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0041","x":2,"y":1678,"w":195,"h":180,"rotated": false}},
|
{"SPRITE":{"name":"41","x":3797,"y":894,"w":50,"h":116,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0042","x":2751,"y":1787,"w":160,"h":144,"rotated": false}},
|
{"SPRITE":{"name":"42","x":2777,"y":452,"w":50,"h":121,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0043","x":713,"y":945,"w":243,"h":261,"rotated": false}},
|
{"SPRITE":{"name":"43","x":4002,"y":585,"w":50,"h":119,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0044","x":2375,"y":1508,"w":378,"h":121,"rotated": false}},
|
{"SPRITE":{"name":"44","x":3913,"y":886,"w":50,"h":117,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0045","x":3064,"y":1495,"w":361,"h":128,"rotated": false}},
|
{"SPRITE":{"name":"45","x":3059,"y":2,"w":52,"h":129,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0046","x":713,"y":1211,"w":455,"h":267,"rotated": false}},
|
{"SPRITE":{"name":"46","x":3964,"y":886,"w":123,"h":45,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0047","x":2,"y":1112,"w":272,"h":326,"rotated": false}},
|
{"SPRITE":{"name":"47","x":1770,"y":228,"w":123,"h":43,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0048","x":3710,"y":878,"w":249,"h":557,"rotated": false}},
|
{"SPRITE":{"name":"48","x":3424,"y":486,"w":99,"h":35,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0049","x":2585,"y":540,"w":260,"h":701,"rotated": false}},
|
{"SPRITE":{"name":"49","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":"50","x":2979,"y":1141,"w":99,"h":34,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0051","x":1307,"y":611,"w":315,"h":540,"rotated": false}},
|
{"SPRITE":{"name":"51","x":2590,"y":360,"w":99,"h":36,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0052","x":2,"y":649,"w":355,"h":461,"rotated": false}},
|
{"SPRITE":{"name":"52","x":3709,"y":783,"w":35,"h":21,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0053","x":359,"y":945,"w":352,"h":373,"rotated": false}},
|
{"SPRITE":{"name":"53","x":1220,"y":711,"w":329,"h":400,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0054","x":3064,"y":1625,"w":347,"h":110,"rotated": false}},
|
{"SPRITE":{"name":"54","x":3042,"y":979,"w":112,"h":161,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0055","x":2039,"y":1248,"w":379,"h":216,"rotated": false}},
|
{"SPRITE":{"name":"55","x":2929,"y":163,"w":199,"h":188,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0056","x":2827,"y":1368,"w":235,"h":257,"rotated": false}},
|
{"SPRITE":{"name":"56","x":2175,"y":574,"w":96,"h":158,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0057","x":2100,"y":1879,"w":140,"h":92,"rotated": false}},
|
{"SPRITE":{"name":"57","x":1623,"y":570,"w":277,"h":134,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0058","x":776,"y":1886,"w":119,"h":79,"rotated": false}},
|
{"SPRITE":{"name":"58","x":1550,"y":1089,"w":38,"h":22,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0059","x":1565,"y":1249,"w":434,"h":147,"rotated": false}},
|
{"SPRITE":{"name":"59","x":3666,"y":152,"w":124,"h":165,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0060","x":276,"y":1320,"w":433,"h":145,"rotated": false}},
|
{"SPRITE":{"name":"60","x":1623,"y":272,"w":309,"h":297,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0061","x":3270,"y":878,"w":438,"h":342,"rotated": false}},
|
{"SPRITE":{"name":"61","x":3801,"y":2,"w":121,"h":91,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0062","x":3176,"y":1222,"w":385,"h":271,"rotated": false}},
|
{"SPRITE":{"name":"62","x":3281,"y":522,"w":320,"h":77,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0063","x":3563,"y":1437,"w":373,"h":153,"rotated": false}},
|
{"SPRITE":{"name":"63","x":3921,"y":755,"w":17,"h":22,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0064","x":3245,"y":1786,"w":202,"h":122,"rotated": false}},
|
{"SPRITE":{"name":"64","x":1351,"y":272,"w":162,"h":74,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0065","x":3449,"y":1786,"w":202,"h":122,"rotated": false}},
|
{"SPRITE":{"name":"65","x":3801,"y":94,"w":69,"h":50,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0066","x":3064,"y":1861,"w":150,"h":91,"rotated": false}},
|
{"SPRITE":{"name":"66","x":2273,"y":574,"w":277,"h":174,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0067","x":3938,"y":1548,"w":151,"h":95,"rotated": false}},
|
{"SPRITE":{"name":"67","x":2261,"y":1136,"w":175,"h":123,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0068","x":3845,"y":1883,"w":140,"h":90,"rotated": false}},
|
{"SPRITE":{"name":"68","x":4058,"y":932,"w":32,"h":49,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0069","x":2913,"y":1861,"w":149,"h":92,"rotated": false}},
|
{"SPRITE":{"name":"69","x":3791,"y":270,"w":66,"h":38,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0070","x":630,"y":1886,"w":144,"h":87,"rotated": false}},
|
{"SPRITE":{"name":"70","x":3079,"y":1141,"w":71,"h":40,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0071","x":3935,"y":1645,"w":152,"h":87,"rotated": false}},
|
{"SPRITE":{"name":"71","x":2690,"y":360,"w":82,"h":29,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0072","x":2441,"y":1243,"w":384,"h":263,"rotated": false}},
|
{"SPRITE":{"name":"72","x":3602,"y":516,"w":88,"h":69,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0073","x":1624,"y":611,"w":248,"h":277,"rotated": false}},
|
{"SPRITE":{"name":"73","x":4022,"y":806,"w":69,"h":27,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0074","x":1624,"y":894,"w":413,"h":353,"rotated": false}},
|
{"SPRITE":{"name":"74","x":1894,"y":228,"w":30,"h":40,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0075","x":2039,"y":894,"w":400,"h":352,"rotated": false}},
|
{"SPRITE":{"name":"75","x":3987,"y":654,"w":10,"h":13,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0076","x":1829,"y":1466,"w":330,"h":163,"rotated": false}},
|
{"SPRITE":{"name":"76","x":3896,"y":1084,"w":7,"h":7,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0077","x":3987,"y":1883,"w":90,"h":103,"rotated": false}},
|
{"SPRITE":{"name":"77","x":3834,"y":1074,"w":9,"h":9,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0078","x":2161,"y":1466,"w":212,"h":238,"rotated": false}},
|
{"SPRITE":{"name":"78","x":3885,"y":1084,"w":10,"h":10,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0079","x":768,"y":1480,"w":209,"h":236,"rotated": false}},
|
{"SPRITE":{"name":"79","x":3441,"y":736,"w":12,"h":12,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0080","x":2242,"y":1879,"w":86,"h":84,"rotated": false}},
|
{"SPRITE":{"name":"80","x":3811,"y":1128,"w":19,"h":17,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0081","x":879,"y":649,"w":126,"h":148,"rotated": false}},
|
{"SPRITE":{"name":"81","x":3971,"y":654,"w":15,"h":14,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0082","x":1908,"y":1631,"w":216,"h":168,"rotated": false}},
|
{"SPRITE":{"name":"82","x":3858,"y":1150,"w":7,"h":7,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0083","x":2575,"y":1631,"w":174,"h":192,"rotated": false}},
|
{"SPRITE":{"name":"83","x":3794,"y":452,"w":5,"h":5,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0084","x":1130,"y":1901,"w":106,"h":75,"rotated": false}},
|
{"SPRITE":{"name":"84","x":3326,"y":751,"w":32,"h":57,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0085","x":3961,"y":1367,"w":129,"h":63,"rotated": false}},
|
{"SPRITE":{"name":"85","x":2583,"y":147,"w":6,"h":7,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0086","x":1829,"y":1398,"w":158,"h":60,"rotated": false}},
|
{"SPRITE":{"name":"86","x":935,"y":617,"w":198,"h":66,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0087","x":3270,"y":704,"w":123,"h":148,"rotated": false}},
|
{"SPRITE":{"name":"87","x":426,"y":692,"w":352,"h":436,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0088","x":3961,"y":878,"w":123,"h":148,"rotated": false}},
|
{"SPRITE":{"name":"88","x":3814,"y":452,"w":156,"h":69,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0089","x":199,"y":1773,"w":207,"h":142,"rotated": false}},
|
{"SPRITE":{"name":"89","x":2829,"y":452,"w":194,"h":197,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0090","x":1238,"y":1901,"w":91,"h":53,"rotated": false}},
|
{"SPRITE":{"name":"90","x":2670,"y":733,"w":181,"h":216,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0091","x":276,"y":1112,"w":65,"h":96,"rotated": false}},
|
{"SPRITE":{"name":"91","x":3791,"y":150,"w":93,"h":119,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0092","x":276,"y":1210,"w":65,"h":96,"rotated": false}},
|
{"SPRITE":{"name":"92","x":4000,"y":372,"w":86,"h":75,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0093","x":2518,"y":1825,"w":136,"h":102,"rotated": false}},
|
{"SPRITE":{"name":"93","x":3587,"y":320,"w":113,"h":195,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0094","x":1537,"y":1857,"w":136,"h":102,"rotated": false}},
|
{"SPRITE":{"name":"94","x":2483,"y":2,"w":80,"h":151,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0095","x":3427,"y":1592,"w":228,"h":192,"rotated": false}},
|
{"SPRITE":{"name":"95","x":3493,"y":2,"w":177,"h":149,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0096","x":1541,"y":1621,"w":166,"h":234,"rotated": false}},
|
{"SPRITE":{"name":"96","x":3327,"y":183,"w":9,"h":8,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0097","x":512,"y":1703,"w":205,"h":171,"rotated": false}},
|
{"SPRITE":{"name":"97","x":3787,"y":452,"w":6,"h":6,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0098","x":2126,"y":1706,"w":205,"h":171,"rotated": false}},
|
{"SPRITE":{"name":"98","x":4002,"y":705,"w":57,"h":48,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0099","x":719,"y":1718,"w":204,"h":166,"rotated": false}},
|
{"SPRITE":{"name":"99","x":2574,"y":147,"w":8,"h":8,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0100","x":1147,"y":1735,"w":206,"h":164,"rotated": false}},
|
{"SPRITE":{"name":"100","x":3814,"y":605,"w":8,"h":12,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0101","x":1874,"y":611,"w":79,"h":185,"rotated": false}},
|
{"SPRITE":{"name":"101","x":1589,"y":1089,"w":9,"h":10,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0102","x":3176,"y":969,"w":83,"h":200,"rotated": false}},
|
{"SPRITE":{"name":"102","x":3701,"y":318,"w":85,"h":140,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0103","x":3563,"y":1222,"w":86,"h":180,"rotated": false}},
|
{"SPRITE":{"name":"103","x":2,"y":692,"w":423,"h":429,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0104","x":3961,"y":1028,"w":89,"h":186,"rotated": false}},
|
{"SPRITE":{"name":"104","x":3533,"y":152,"w":132,"h":167,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0105","x":2375,"y":1631,"w":198,"h":183,"rotated": false}},
|
{"SPRITE":{"name":"105","x":3249,"y":961,"w":66,"h":16,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0106","x":1908,"y":1801,"w":190,"h":120,"rotated": false}},
|
{"SPRITE":{"name":"106","x":3576,"y":808,"w":52,"h":43,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0107","x":2656,"y":1825,"w":86,"h":145,"rotated": false}},
|
{"SPRITE":{"name":"107","x":3858,"y":1163,"w":46,"h":42,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0108","x":1355,"y":1724,"w":180,"h":170,"rotated": false}},
|
{"SPRITE":{"name":"108","x":3834,"y":1011,"w":13,"h":62,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0109","x":3961,"y":1216,"w":111,"h":149,"rotated": false}},
|
{"SPRITE":{"name":"109","x":3654,"y":1025,"w":34,"h":29,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0110","x":4035,"y":516,"w":39,"h":98,"rotated": false}},
|
{"SPRITE":{"name":"110","x":3811,"y":1150,"w":46,"h":65,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0111","x":1307,"y":1153,"w":118,"h":47,"rotated": false}},
|
{"SPRITE":{"name":"111","x":3701,"y":459,"w":112,"h":46,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0112","x":1427,"y":1153,"w":120,"h":43,"rotated": false}},
|
{"SPRITE":{"name":"112","x":2035,"y":898,"w":226,"h":223,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0113","x":2441,"y":1184,"w":120,"h":41,"rotated": false}},
|
{"SPRITE":{"name":"113","x":3233,"y":351,"w":190,"h":170,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0114","x":3216,"y":1910,"w":95,"h":33,"rotated": false}},
|
{"SPRITE":{"name":"114","x":3654,"y":1060,"w":58,"h":55,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0115","x":3563,"y":1404,"w":95,"h":31,"rotated": false}},
|
{"SPRITE":{"name":"115","x":3885,"y":94,"w":112,"h":94,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0116","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": "0117","x":2330,"y":1906,"w":95,"h":34,"rotated": false}},
|
{"SPRITE":{"name":"117","x":1939,"y":493,"w":235,"h":239,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0118","x":2585,"y":487,"w":131,"h":47,"rotated": false}},
|
{"SPRITE":{"name":"118","x":3242,"y":1150,"w":141,"h":111,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0119","x":4059,"y":258,"w":31,"h":18,"rotated": false}},
|
{"SPRITE":{"name":"119","x":2822,"y":2,"w":236,"h":160,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0120","x":1355,"y":1896,"w":122,"h":66,"rotated": false}},
|
{"SPRITE":{"name":"120","x":2475,"y":749,"w":194,"h":236,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0121","x":2992,"y":1737,"w":251,"h":122,"rotated": false}},
|
{"SPRITE":{"name":"121","x":3455,"y":736,"w":120,"h":119,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0122","x":879,"y":799,"w":114,"h":133,"rotated": false}},
|
{"SPRITE":{"name":"122","x":2551,"y":398,"w":225,"h":189,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0123","x":1347,"y":1500,"w":192,"h":222,"rotated": false}},
|
{"SPRITE":{"name":"123","x":3923,"y":2,"w":130,"h":81,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0124","x":4035,"y":818,"w":39,"h":34,"rotated": false}},
|
{"SPRITE":{"name":"124","x":3691,"y":621,"w":132,"h":83,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0125","x":4035,"y":701,"w":50,"h":61,"rotated": false}},
|
{"SPRITE":{"name":"125","x":3531,"y":1025,"w":122,"h":80,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0126","x":1874,"y":798,"w":64,"h":78,"rotated": false}},
|
{"SPRITE":{"name":"126","x":3814,"y":522,"w":129,"h":82,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0127","x":4035,"y":438,"w":52,"h":76,"rotated": false}},
|
{"SPRITE":{"name":"127","x":3709,"y":705,"w":125,"h":77,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0128","x":958,"y":934,"w":46,"h":63,"rotated": false}},
|
{"SPRITE":{"name":"128","x":3885,"y":189,"w":132,"h":76,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0129","x":4059,"y":146,"w":30,"h":41,"rotated": false}},
|
{"SPRITE":{"name":"129","x":2035,"y":1122,"w":225,"h":142,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0130","x":4059,"y":189,"w":23,"h":35,"rotated": false}},
|
{"SPRITE":{"name":"130","x":2777,"y":187,"w":151,"h":264,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0131","x":4059,"y":226,"w":20,"h":30,"rotated": false}},
|
{"SPRITE":{"name":"131","x":2551,"y":588,"w":277,"h":144,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0132","x":4059,"y":278,"w":17,"h":22,"rotated": false}},
|
{"SPRITE":{"name":"132","x":3327,"y":197,"w":205,"h":140,"rotated":false}},
|
||||||
{"SPRITE" : {"name": "0133","x":2333,"y":1816,"w":183,"h":88,"rotated": false}}
|
{"SPRITE":{"name":"133","x":2175,"y":401,"w":305,"h":172,"rotated":false}},
|
||||||
]},
|
{"SPRITE":{"name":"134","x":2841,"y":1136,"w":137,"h":129,"rotated":false}},
|
||||||
"meta": {
|
{"SPRITE":{"name":"135","x":3129,"y":172,"w":197,"h":178,"rotated":false}},
|
||||||
"app": "Adobe Animate",
|
{"SPRITE":{"name":"136","x":2,"y":1122,"w":364,"h":131,"rotated":false}},
|
||||||
"version": "21.0.1.37179",
|
{"SPRITE":{"name":"137","x":3424,"y":338,"w":162,"h":147,"rotated":false}},
|
||||||
"image": "spritemap1.png",
|
{"SPRITE":{"name":"138","x":1933,"y":228,"w":223,"h":264,"rotated":false}},
|
||||||
"format": "RGBA8888",
|
{"SPRITE":{"name":"139","x":1351,"y":2,"w":418,"h":269,"rotated":false}},
|
||||||
"size": {"w":4093,"h":1988},
|
{"SPRITE":{"name":"140","x":1599,"y":1133,"w":350,"h":113,"rotated":false}},
|
||||||
"resolution": "1"
|
{"SPRITE":{"name":"141","x":1599,"y":985,"w":435,"h":147,"rotated":false}},
|
||||||
}
|
{"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"
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
Before Width: | Height: | Size: 642 KiB After Width: | Height: | Size: 1.2 MiB |
@@ -203,6 +203,7 @@
|
|||||||
<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>
|
||||||
@@ -223,6 +224,7 @@
|
|||||||
<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>
|
||||||
@@ -236,8 +238,9 @@
|
|||||||
<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="muteInst">Mute instrumental</str>
|
<str id="inst">Instrumental</str>
|
||||||
<str id="muteVoices">Mute voices</str>
|
<str id="voices">Voices</str>
|
||||||
|
<str id="hitsounds">Hitsounds</str>
|
||||||
</group>
|
</group>
|
||||||
|
|
||||||
<group name="BookmarkMenu" prefix="bookmarks.">
|
<group name="BookmarkMenu" prefix="bookmarks.">
|
||||||
@@ -250,6 +253,7 @@
|
|||||||
<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>
|
||||||
@@ -258,6 +262,7 @@
|
|||||||
<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>
|
||||||
@@ -308,8 +313,9 @@
|
|||||||
<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="muteVocals">Mute Vocals</str>
|
<str id="vocals">Vocals</str>
|
||||||
<str id="edit">Edit</str>
|
<str id="edit">Edit</str>
|
||||||
<str id="delete">Delete</str>
|
<str id="delete">Delete</str>
|
||||||
|
|
||||||
@@ -433,6 +439,8 @@
|
|||||||
<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.">
|
||||||
|
|||||||
@@ -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,6 +188,7 @@
|
|||||||
<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>
|
||||||
|
|||||||
@@ -194,6 +194,7 @@
|
|||||||
<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>
|
||||||
|
|||||||
@@ -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,6 +197,7 @@
|
|||||||
<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>
|
||||||
@@ -223,7 +224,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>
|
||||||
|
|||||||
@@ -203,6 +203,7 @@
|
|||||||
<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>
|
||||||
|
|||||||
@@ -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.animateAtlas.anim.addBySymbol('tank', 'TANK TALK 2', 0, false);
|
tankman.addAnim('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});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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.animateAtlas.anim.addBySymbol('p1', 'TANK TALK 3 P1 UNCUT', 0, false);
|
tankman.addAnim('p1', 'TANK TALK 3 P1 UNCUT', 0, false);
|
||||||
tankman.animateAtlas.anim.addBySymbol('p2', 'TANK TALK 3 P2 UNCUT', 0, false);
|
tankman.addAnim('p2', 'TANK TALK 3 P2 UNCUT', 0, false);
|
||||||
tankman.playAnim('p1');
|
tankman.playAnim('p1');
|
||||||
|
|
||||||
pico = new FunkinSprite(game.gf.x + game.gf.globalOffset.x + 150, game.gf.y + game.gf.globalOffset.y + 395);
|
pico = new FunkinSprite(game.gf.x + game.gf.globalOffset.x - 615, game.gf.y + game.gf.globalOffset.y - 130);
|
||||||
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.animateAtlas.anim.addBySymbol('die', 'GF Time to Die sequence', 24, false);
|
pico.addAnim('die', 'die', 24, false, null, null, 0, 0, null, true);
|
||||||
pico.animateAtlas.anim.addBySymbol('saves', 'Pico Saves them sequence', 24, false);
|
pico.addAnim('saves', 'saves', 24, false, null, null, 0, 0, null, true);
|
||||||
pico.animateAtlas.anim.addBySymbol('idle', 'Pico Dual Wield on Speaker idle', 24, true);
|
pico.addAnim('idle', 'idle', 24, true, null, null, 0, 0, null, 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) + 1, pico);
|
game.insert(game.members.indexOf(game.gf) + 2, 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,7 +59,11 @@ 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);
|
||||||
|
|
||||||
@@ -118,7 +122,7 @@ function update(elapsed) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function lipSync(char:FunkinSprite, begin:Float, end:Float) {
|
function lipSync(char:FunkinSprite, begin:Float, end:Float) {
|
||||||
char.animateAtlas.anim.curFrame = Std.int(FlxMath.remapToRange(stressCutscene.time, begin, end, 0, char.animateAtlas.anim.length-1));
|
char.anim.curAnim.curFrame = Std.int(FlxMath.remapToRange(stressCutscene.time, begin, end, 0, char.anim.curAnim.numFrames - 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
function focusOn(char, snap:Bool = false) {
|
function focusOn(char, snap:Bool = false) {
|
||||||
|
|||||||
@@ -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.animateAtlas.anim.addBySymbol('1', 'TANK TALK 1 P1', 0, false);
|
tankman.addAnim('1', 'TANK TALK 1 P1', 0, false);
|
||||||
tankman.animateAtlas.anim.addBySymbol('2', 'TANK TALK 1 P2', 0, false);
|
tankman.addAnim('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();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,19 +4,17 @@
|
|||||||
<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" />
|
<git name="openfl" url="https://github.com/CodenameCrew/cne-openfl" ref="old" />
|
||||||
<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" />
|
<git name="flixel" url="https://github.com/CodenameCrew/cne-flixel" ref="old" />
|
||||||
<git name="flixel-addons" url="https://github.com/CodenameCrew/cne-flixel-addons" />
|
<git name="flixel-addons" url="https://github.com/CodenameCrew/cne-flixel-addons" ref="old" />
|
||||||
|
|
||||||
<!-- 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="flxanimate" url="https://github.com/CodenameCrew/cne-flxanimate" />
|
<git name="hxdiscord_rpc" url="https://github.com/CodenameCrew/cne-hxdiscord_rpc" ref="old" skipDeps="true" />
|
||||||
<git name="hxdiscord_rpc" url="https://github.com/CodenameCrew/cne-hxdiscord_rpc" skipDeps="true" />
|
<lib name="funkin-modchart" 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" />
|
||||||
|
|
||||||
<!-- Documentation and other features -->
|
<!-- Documentation and other features -->
|
||||||
@@ -31,7 +29,9 @@
|
|||||||
<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" />
|
<git name="hxcpp" url="https://github.com/CodenameCrew/cne-hxcpp" ref="old" />
|
||||||
|
|
||||||
|
<git name="flixel-animate" url="https://github.com/CodenameCrew/cne-flixel-animate/" ref="old" skipDeps="true"/>
|
||||||
</if>
|
</if>
|
||||||
|
|
||||||
<!-- Hxcpp Building -->
|
<!-- Hxcpp Building -->
|
||||||
|
|||||||
@@ -74,6 +74,9 @@
|
|||||||
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" />
|
||||||
|
|
||||||
@@ -130,7 +133,7 @@
|
|||||||
<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="flxanimate" />
|
<haxelib name="flixel-animate" />
|
||||||
<haxelib name="nape-haxe4" if="NAPE_ENABLED"/>
|
<haxelib name="nape-haxe4" if="NAPE_ENABLED"/>
|
||||||
|
|
||||||
<haxelib name="hscript-improved" />
|
<haxelib name="hscript-improved" />
|
||||||
|
|||||||
@@ -1,92 +0,0 @@
|
|||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,5 +1,7 @@
|
|||||||
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;
|
||||||
@@ -7,7 +9,6 @@ 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;
|
||||||
@@ -15,6 +16,10 @@ 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)
|
||||||
{
|
{
|
||||||
@@ -43,7 +48,7 @@ enum abstract XMLAnimType(Int)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class FunkinSprite extends FlxSkewedSprite implements IBeatReceiver implements IOffsetCompatible implements IXMLEvents
|
class FunkinSprite extends FlxAnimate implements IBeatReceiver implements IOffsetCompatible implements IXMLEvents
|
||||||
{
|
{
|
||||||
public var extra:Map<String, Dynamic> = [];
|
public var extra:Map<String, Dynamic> = [];
|
||||||
|
|
||||||
@@ -56,6 +61,9 @@ class FunkinSprite extends FlxSkewedSprite implements IBeatReceiver implements I
|
|||||||
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;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -66,9 +74,7 @@ class FunkinSprite extends FlxSkewedSprite implements IBeatReceiver implements I
|
|||||||
public var beatOffset:Int = 0;
|
public var beatOffset:Int = 0;
|
||||||
public var skipNegativeBeats:Bool = false;
|
public var skipNegativeBeats:Bool = false;
|
||||||
|
|
||||||
public var animateAtlas:FlxAnimate;
|
public var animateSettings:FlxAnimateSettings = {};
|
||||||
@:noCompletion public var atlasPlayingAnim:String;
|
|
||||||
@:noCompletion public var atlasPath:String;
|
|
||||||
|
|
||||||
var _rect2:FlxRect;
|
var _rect2:FlxRect;
|
||||||
|
|
||||||
@@ -85,6 +91,7 @@ class FunkinSprite extends FlxSkewedSprite implements IBeatReceiver implements I
|
|||||||
}
|
}
|
||||||
|
|
||||||
moves = false;
|
moves = false;
|
||||||
|
applyStageMatrix = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -100,8 +107,6 @@ class FunkinSprite extends FlxSkewedSprite implements IBeatReceiver implements I
|
|||||||
@: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;
|
||||||
@@ -111,8 +116,6 @@ class FunkinSprite extends FlxSkewedSprite implements IBeatReceiver implements I
|
|||||||
|
|
||||||
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;
|
||||||
}
|
}
|
||||||
@@ -123,8 +126,6 @@ class FunkinSprite extends FlxSkewedSprite implements IBeatReceiver implements I
|
|||||||
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()) {
|
||||||
@@ -142,15 +143,7 @@ class FunkinSprite extends FlxSkewedSprite implements IBeatReceiver implements I
|
|||||||
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);
|
||||||
if (Assets.exists('$noExt/Animation.json'))
|
frames = Paths.getFrames(path, true, null, null, animateSettings);
|
||||||
{
|
|
||||||
atlasPath = noExt;
|
|
||||||
animateAtlas = new FlxAnimate(x, y, noExt);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
frames = Paths.getFrames(path, true);
|
|
||||||
}
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -180,50 +173,22 @@ class FunkinSprite extends FlxSkewedSprite implements IBeatReceiver implements I
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
// ANIMATE ATLAS DRAWING
|
public override function draw() {
|
||||||
#if REGION
|
// re-implementing the `onDraw` functionality from `FlxSprite` since `FlxAnimate` didn't have this, so we have to add it back in ourselves
|
||||||
public override function draw()
|
if (this.isAnimate && this.__drawOverrided) {
|
||||||
{
|
this.__drawOverrided = false;
|
||||||
if (animateAtlas != null)
|
this.onDraw(this);
|
||||||
{
|
this.__drawOverrided = true;
|
||||||
copyAtlasValues();
|
return;
|
||||||
animateAtlas.draw();
|
}
|
||||||
}
|
super.draw();
|
||||||
else
|
|
||||||
{
|
|
||||||
super.draw();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function copyAtlasValues()
|
// ANIMATE ATLAS DRAWING
|
||||||
{
|
#if REGION
|
||||||
@: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];
|
||||||
@@ -260,25 +225,6 @@ class FunkinSprite extends FlxSkewedSprite implements IBeatReceiver implements I
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
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)
|
||||||
@@ -293,22 +239,6 @@ class FunkinSprite extends FlxSkewedSprite implements IBeatReceiver implements I
|
|||||||
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>();
|
||||||
@@ -340,13 +270,7 @@ class FunkinSprite extends FlxSkewedSprite implements IBeatReceiver implements I
|
|||||||
Force = anim != null && anim.forced;
|
Force = anim != null && anim.forced;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (animateAtlas != null)
|
animation.play(AnimName, Force, Reversed, Frame);
|
||||||
{
|
|
||||||
@: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);
|
||||||
@@ -355,7 +279,7 @@ class FunkinSprite extends FlxSkewedSprite implements IBeatReceiver implements I
|
|||||||
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)
|
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)
|
||||||
{
|
{
|
||||||
return XMLUtil.addAnimToSprite(this, {
|
return XMLUtil.addAnimToSprite(this, {
|
||||||
name: name,
|
name: name,
|
||||||
@@ -366,22 +290,16 @@ class FunkinSprite extends FlxSkewedSprite implements IBeatReceiver implements I
|
|||||||
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, FlxSymbolAnimation>
|
public function getAnim(name:String):OneOfTwo<FlxAnimation, FlxAnimateAnimation> {
|
||||||
{
|
|
||||||
if(animateAtlas != null)
|
|
||||||
return animateAtlas.anim.getByName(name);
|
|
||||||
return animation.getByName(name);
|
return animation.getByName(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -392,40 +310,26 @@ class FunkinSprite extends FlxSkewedSprite implements IBeatReceiver implements I
|
|||||||
return FlxPoint.weak(0, 0);
|
return FlxPoint.weak(0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public inline function hasAnim(AnimName:String):Bool @:privateAccess
|
public inline function hasAnim(AnimName:String):Bool
|
||||||
return animateAtlas != null ? (animateAtlas.anim.animsMap.exists(AnimName)
|
return animation.exists(AnimName);
|
||||||
|| animateAtlas.anim.symbolDictionary.exists(AnimName)) : animation.exists(AnimName);
|
|
||||||
|
|
||||||
public inline function getAnimName() {
|
public inline function getAnimName()
|
||||||
return (animateAtlas != null) ? atlasPlayingAnim : animation.name;
|
return animation.name;
|
||||||
}
|
|
||||||
|
|
||||||
public inline function isAnimReversed():Bool {
|
public inline function isAnimReversed():Bool
|
||||||
return animateAtlas != null ? animateAtlas.anim.reversed : animation.curAnim != null ? animation.curAnim.reversed : false;
|
return animation.curAnim?.reversed ?? false;
|
||||||
}
|
|
||||||
|
|
||||||
public inline function getNameList():Array<String> {
|
public inline function getNameList():Array<String>
|
||||||
if (animateAtlas != null)
|
return animation.getNameList();
|
||||||
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 animateAtlas != null ? animateAtlas.anim.finished : (animation.curAnim != null ? animation.curAnim.finished : true);
|
return animation.curAnim?.finished ?? true;
|
||||||
}
|
|
||||||
|
|
||||||
public inline function isAnimAtEnd() {
|
public inline function isAnimAtEnd()
|
||||||
return animateAtlas != null ? animateAtlas.anim.isAtEnd : (animation.curAnim != null ? animation.curAnim.isAtEnd : false);
|
return animation.curAnim?.isAtEnd ?? false;
|
||||||
}
|
|
||||||
|
|
||||||
override function updateAnimation(elapsed:Float) {
|
override function updateAnimation(elapsed:Float) {
|
||||||
if (animEnabled)
|
if (animEnabled)
|
||||||
@@ -447,10 +351,38 @@ class FunkinSprite extends FlxSkewedSprite implements IBeatReceiver implements I
|
|||||||
return beatInterval = v;
|
return beatInterval = v;
|
||||||
}
|
}
|
||||||
|
|
||||||
@:noCompletion private inline function get_globalCurFrame() {
|
@:noCompletion
|
||||||
return animateAtlas != null ? (animateAtlas.anim.curFrame) : (animation.curAnim != null ? animation.curAnim.curFrame : 0);
|
@:deprecated("`FunkinSprite.animateAtlas` is deprecated, just use `FunkinSprite` instead")
|
||||||
}
|
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) {
|
||||||
return animateAtlas != null ? (animateAtlas.anim.curFrame = val) : (animation.curAnim != null ? animation.curAnim.curFrame = val : val);
|
if (animation.curAnim != null)
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -114,12 +114,8 @@ class MusicBeatTransition extends MusicBeatSubstate {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (transitionSprite != null) {
|
if (transitionSprite != null) {
|
||||||
if (transitionSprite.animateAtlas == null) {
|
transitionSprite.setGraphicSize(transitionCamera.width, transitionCamera.height);
|
||||||
transitionSprite.setGraphicSize(transitionCamera.width, transitionCamera.height);
|
transitionSprite.updateHitbox();
|
||||||
transitionSprite.updateHitbox();
|
|
||||||
} else {
|
|
||||||
transitionSprite.screenCenter();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,9 +5,22 @@ 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)
|
||||||
@@ -141,6 +154,16 @@ 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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -83,10 +83,11 @@ 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
|
||||||
if (FileSystem.exists('$path.zip'))
|
for (ext in Flags.ALLOWED_ZIP_EXTENSIONS) {
|
||||||
return loadLibraryFromZip('$path'.toLowerCase(), '$path.zip', force, modName);
|
if (!FileSystem.exists('$path.$ext')) continue;
|
||||||
else
|
return loadLibraryFromZip('$path'.toLowerCase(), '$path.$ext', force, modName);
|
||||||
return loadLibraryFromFolder('$path'.toLowerCase(), '$path', force, modName);
|
}
|
||||||
|
return loadLibraryFromFolder('$path'.toLowerCase(), '$path', force, modName);
|
||||||
|
|
||||||
#else
|
#else
|
||||||
return null;
|
return null;
|
||||||
@@ -96,27 +97,16 @@ 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
|
||||||
if (!FileSystem.exists(modsPath)) {
|
// Mods directory does not exist yet, create it
|
||||||
// Mods directory does not exist yet, create it
|
if (!FileSystem.exists(modsPath)) FileSystem.createDirectory(modsPath);
|
||||||
FileSystem.createDirectory(modsPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
final modsList:Array<String> = FileSystem.readDirectory(modsPath);
|
final modsList:Array<String> = FileSystem.readDirectory(modsPath);
|
||||||
|
|
||||||
if (modsList == null || modsList.length <= 0)
|
if (modsList == null || modsList.length <= 0) return mods;
|
||||||
return mods;
|
|
||||||
|
|
||||||
for (modFolder in modsList) {
|
for (modFolder in modsList) {
|
||||||
if (FileSystem.isDirectory(modsPath + modFolder)) {
|
if (FileSystem.isDirectory(modsPath + modFolder)) mods.push(modFolder);
|
||||||
mods.push(modFolder);
|
else if (Flags.ALLOWED_ZIP_EXTENSIONS.contains(Path.extension(modFolder))) mods.push(Path.withoutExtension(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;
|
||||||
@@ -128,7 +118,9 @@ class ModsFolder {
|
|||||||
#if TRANSLATIONS_SUPPORT
|
#if TRANSLATIONS_SUPPORT
|
||||||
if(skipTranslated && (l is TranslatedAssetLibrary)) continue;
|
if(skipTranslated && (l is TranslatedAssetLibrary)) continue;
|
||||||
#end
|
#end
|
||||||
if (l is ScriptedAssetLibrary || l is IModsAssetLibrary) libs.push(cast(l, IModsAssetLibrary));
|
// No need to check for it being a `ScriptedAssetLibrary`, if `ScriptedAssetLibrary` extends ModsFolderLibrary, which implements `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,6 +149,22 @@ 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
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ 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;
|
||||||
|
|
||||||
@@ -174,6 +175,9 @@ 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');
|
||||||
|
|
||||||
@@ -197,7 +201,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) {
|
public static function getFrames(key:String, assetsPath:Bool = false, ?library:String, ?ext:String = null, ?animateSettings:FlxAnimateSettings) {
|
||||||
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)
|
||||||
@@ -205,7 +209,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);
|
return tempFramesCache[key] = loadFrames(assetsPath ? key : Paths.image(key, library, true, ext), false, null, false, ext, animateSettings);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -242,7 +246,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):FlxFramesCollection {
|
static function loadFrames(path:String, Unique:Bool = false, Key:String = null, SkipAtlasCheck:Bool = false, SkipMultiCheck:Bool = false, ?Ext:String = null, ?animateSettings:FlxAnimateSettings):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;
|
||||||
|
|
||||||
@@ -263,6 +267,8 @@ 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,6 +108,8 @@ 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,11 +1,14 @@
|
|||||||
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;
|
||||||
@@ -15,15 +18,16 @@ 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 function new(basePath:String, libName:String, ?modName:String) {
|
public var PRELOAD_VIDEOS:Bool = true;
|
||||||
|
|
||||||
|
public function new(basePath:String, libName:String, ?modName:String, ?preloadVideos:Bool = true) {
|
||||||
this.libName = libName;
|
this.libName = libName;
|
||||||
|
|
||||||
this.basePath = basePath;
|
this.basePath = basePath;
|
||||||
@@ -31,21 +35,59 @@ 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) {
|
||||||
lowerCaseAssets[entry.fileName.toLowerCase()] = assets[entry.fileName.toLowerCase()] = assets[entry.fileName] = entry;
|
if (entry.fileName.length < 0 || entry.fileName.endsWith("/")) continue;
|
||||||
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)';
|
return '(ZipFolderLibrary: $libName/$modName | ${zip.entries.length} entries | Detected Video Extensions: ${_videoExtensions.join(", ")})';
|
||||||
}
|
}
|
||||||
|
|
||||||
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]));
|
||||||
@@ -68,15 +110,12 @@ 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);
|
||||||
@@ -87,8 +126,7 @@ class ZipFolderLibrary extends AssetLibrary implements IModsAssetLibrary {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_parsedAsset = _parsedAsset.toLowerCase();
|
_parsedAsset = _parsedAsset.toLowerCase();
|
||||||
if(nameMap.exists(_parsedAsset))
|
if (nameMap.exists(_parsedAsset)) _parsedAsset = nameMap.get(_parsedAsset);
|
||||||
_parsedAsset = nameMap.get(_parsedAsset);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -103,9 +141,8 @@ class ZipFolderLibrary extends AssetLibrary implements IModsAssetLibrary {
|
|||||||
return assets[_parsedAsset] != null;
|
return assets[_parsedAsset] != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function getAssetPath() {
|
private inline function getAssetPath() {
|
||||||
trace('[ZIP]$basePath/$_parsedAsset');
|
return getVideoRemap('$basePath/$_parsedAsset');
|
||||||
return '[ZIP]$basePath/$_parsedAsset';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: rewrite this to 1 function, like ModsFolderLibrary
|
// TODO: rewrite this to 1 function, like ModsFolderLibrary
|
||||||
@@ -154,14 +191,6 @@ class ZipFolderLibrary extends AssetLibrary implements IModsAssetLibrary {
|
|||||||
return content;
|
return content;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Backwards compat
|
public override function list(type:String):Array<String> { return [for(k=>e in nameMap) '$prefix$e']; }
|
||||||
|
|
||||||
@: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
|
||||||
@@ -278,9 +278,13 @@ 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' : "";
|
var songPath = saveSettings.songFolder == null ? 'songs/${chart.meta.name}' : saveSettings.songFolder, variantSuffix = variant != null && variant != "" ? '-$variant' : "", difficultySuffix = difficulty != null && difficulty != "" ? '-$difficulty' : "";
|
||||||
var metaPath = 'meta$variantSuffix.json', prettyPrint = saveSettings.prettyPrint == true ? Flags.JSON_PRETTY_PRINT : null, temp:String;
|
var metaPath = 'meta$variantSuffix.json', altMetaPath = 'meta${variantSuffix}${difficultySuffix}.json', prettyPrint = saveSettings.prettyPrint == true ? Flags.JSON_PRETTY_PRINT : null, temp:String;
|
||||||
if ((temp = Paths.assetsTree.getPath('assets/$songPath/$metaPath')) != null) {
|
if ((temp = Paths.assetsTree.getPath('assets/$songPath/$altMetaPath')) != null) { //check for difficulty specific
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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: true}
|
{name: "Multiplicative?", type: TBool, defValue: false}
|
||||||
],
|
],
|
||||||
"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,12 +106,15 @@ 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 (i in funkin.backend.assets.ModsFolder.getLoadedMods()) {
|
for (lib in funkin.backend.assets.ModsFolder.getLoadedModsLibs()) {
|
||||||
var path = Paths.script('data/global/LIB_$i');
|
var modName = lib.modName;
|
||||||
|
var path = Paths.script('data/global/LIB_$modName');
|
||||||
var script = Script.create(path);
|
var script = Script.create(path);
|
||||||
if (script is DummyScript)
|
if (script is DummyScript) continue;
|
||||||
continue;
|
script.remappedNames.set(script.fileName, '$modName:${script.fileName}');
|
||||||
script.remappedNames.set(script.fileName, '$i:${script.fileName}');
|
// so you can get the current mod's library in GloablScript :)
|
||||||
|
// 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();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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" => funkin.backend.FlxAnimate,
|
"FlxAnimate" => animate.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,
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ 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;
|
||||||
@@ -54,4 +53,4 @@ class CancellableEvent implements IFlxDestroyable {
|
|||||||
public function destroy() {
|
public function destroy() {
|
||||||
data = null;
|
data = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,9 +19,11 @@ class Flags {
|
|||||||
|
|
||||||
// -- 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;
|
public static var CURRENT_API_VERSION:Int = 2;
|
||||||
|
|
||||||
|
// -- Codename's ZipFolderLibrary Config --
|
||||||
|
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 = "";
|
||||||
public static var MOD_DESCRIPTION:String = "";
|
public static var MOD_DESCRIPTION:String = "";
|
||||||
@@ -161,6 +163,8 @@ class Flags {
|
|||||||
// 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
|
||||||
@@ -332,8 +336,9 @@ 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
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -7,12 +7,14 @@ 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;
|
||||||
@@ -57,12 +59,32 @@ 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.
|
||||||
ModsFolder.currentModFolder != null ?
|
// TODO: Write a function when the library is loaded to decompress the contents and then load the libraries :)
|
||||||
ModsFolder.modsPath + ModsFolder.currentModFolder + "/addons/" :
|
( (ModsFolder.currentModFolder != null && !isZipMod) ?
|
||||||
null
|
quick_modsPath + "/addons/" : null
|
||||||
)
|
)
|
||||||
];
|
];
|
||||||
|
|
||||||
@@ -72,12 +94,8 @@ 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)) {
|
||||||
switch(Path.extension(addon).toLowerCase()) {
|
if (Flags.ALLOWED_ZIP_EXTENSIONS.contains(Path.extension(addon))) addon = Path.withoutExtension(addon);
|
||||||
case 'zip':
|
else continue;
|
||||||
addon = Path.withoutExtension(addon);
|
|
||||||
default:
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var data:AddonInfo = {
|
var data:AddonInfo = {
|
||||||
@@ -100,9 +118,14 @@ 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) {
|
||||||
loadLib(ModsFolder.modsPath + ModsFolder.currentModFolder, ModsFolder.currentModFolder);
|
// isCneMod is a guarentee to be a zip mod because we just checked for it, so this will always load as a CompressedLibrary
|
||||||
|
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);
|
||||||
@@ -134,9 +157,15 @@ 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;
|
||||||
|
|
||||||
if (Options.devMode && Options.allowConfigWarning) {
|
// 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 && !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,8 +13,13 @@ 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}';
|
||||||
#if debug
|
#end
|
||||||
|
|
||||||
|
#if (debug || COMPILE_EXPERIMENTAL)
|
||||||
text += '\n${Flags.COMMIT_MESSAGE}';
|
text += '\n${Flags.COMMIT_MESSAGE}';
|
||||||
#end
|
#end
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -53,25 +53,6 @@ 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}';
|
||||||
@@ -81,7 +62,10 @@ class SystemInfo extends FramerateCategory {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
#if windows
|
#if windows
|
||||||
cpuName = RegistryUtil.get(HKEY_LOCAL_MACHINE, "HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0", "ProcessorNameString");
|
var process = new HiddenProcess("wmic", ["cpu", "get", "name"]);
|
||||||
|
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';
|
||||||
|
|||||||
@@ -0,0 +1,134 @@
|
|||||||
|
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
|
||||||
@@ -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"
|
"DateTools", "EReg", "Lambda", "StringBuf", "haxe.crypto", "haxe.display", "haxe.exceptions", "haxe.extern", "scripting", "animate"
|
||||||
])
|
])
|
||||||
Compiler.include(inc);
|
Compiler.include(inc);
|
||||||
|
|
||||||
@@ -69,6 +69,7 @@ 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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,7 +21,6 @@ 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;
|
||||||
@@ -34,6 +33,8 @@ 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;
|
||||||
|
|
||||||
@@ -439,11 +440,9 @@ 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)
|
if (fadeIn) FlxG.sound.music.fadeIn(4, 0, 1);
|
||||||
FlxG.sound.music.fadeIn(4, 0, 0.7);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -574,6 +573,29 @@ 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
|
||||||
@@ -856,7 +878,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]);
|
||||||
@@ -1003,6 +1025,20 @@ 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
|
||||||
@@ -1053,7 +1089,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;
|
||||||
@@ -1200,8 +1236,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";
|
||||||
@@ -1252,23 +1288,20 @@ final class CoolUtil
|
|||||||
return animsList;
|
return animsList;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function getAnimsListFromAtlas(atlas:AnimAtlas):Array<String> {
|
public static function getAnimsListFromAtlas(atlas:AnimationJson):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.S)
|
for (symbol in atlas.SD)
|
||||||
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> {
|
||||||
if (spr.animateAtlas != null) {
|
return getAnimsListFromFrames(spr.frames);
|
||||||
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
|
||||||
@@ -1421,6 +1454,7 @@ final class CoolUtil
|
|||||||
|
|
||||||
return toProperty.setValue(fromProperty.getValue());
|
return toProperty.setValue(fromProperty.getValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class PropertyInfo {
|
class PropertyInfo {
|
||||||
|
|||||||
@@ -3,200 +3,220 @@ 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 minimum value in the arguments.
|
* Returns the maximum value in the arguments.
|
||||||
* @param args Array of values
|
* @param args Array of values
|
||||||
*
|
*
|
||||||
* @return The minimum value
|
* @return The maximum value
|
||||||
**/
|
**/
|
||||||
public static function minInt(...args:Int):Int {
|
public static function maxInt(...args:Int):Int {
|
||||||
var min = args[0];
|
var max = args[0];
|
||||||
for(i in 1...args.length) {
|
for(i in 1...args.length) {
|
||||||
var arg = args[i];
|
var arg = args[i];
|
||||||
if(arg < min)
|
if(arg > max)
|
||||||
min = arg;
|
max = arg;
|
||||||
}
|
}
|
||||||
return min;
|
return max;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the maximum value in the arguments.
|
* Returns the minimum 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 {
|
||||||
* @return The maximum value
|
var min = args[0];
|
||||||
**/
|
for(i in 1...args.length) {
|
||||||
public static function max(...args:Float):Float {
|
var arg = args[i];
|
||||||
var max = args[0];
|
if(arg < min)
|
||||||
for(i in 1...args.length) {
|
min = arg;
|
||||||
var arg = args[i];
|
}
|
||||||
if(arg > max)
|
return min;
|
||||||
max = arg;
|
}
|
||||||
}
|
|
||||||
return max;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the minimum value in the arguments.
|
* Returns the maximum value in the arguments.
|
||||||
*
|
*
|
||||||
* NOTE: If you are using this in compile time, you should use `MathUtil.minSmart` instead of this for better performance.
|
* NOTE: If you are using this in compile time, you should use `MathUtil.maxSmart` instead of this for better performance.
|
||||||
*
|
*
|
||||||
* @param args Array of values
|
* @param args Array of values
|
||||||
*
|
*
|
||||||
* @return The minimum value
|
* @return The maximum value
|
||||||
**/
|
**/
|
||||||
public static function min(...args:Float):Float {
|
public static function max(...args:Float):Float {
|
||||||
var min = args[0];
|
var max = args[0];
|
||||||
for(i in 1...args.length) {
|
for(i in 1...args.length) {
|
||||||
var arg = args[i];
|
var arg = args[i];
|
||||||
if(arg < min)
|
if(arg > max)
|
||||||
min = arg;
|
max = arg;
|
||||||
}
|
}
|
||||||
return min;
|
return max;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks if a is less than b with considering a margin of error.
|
* Returns the minimum value in the arguments.
|
||||||
*
|
*
|
||||||
* @param a Float
|
* NOTE: If you are using this in compile time, you should use `MathUtil.minSmart` instead of this for better performance.
|
||||||
* @param b Float
|
*
|
||||||
* @param margin Float (Default: EPSILON)
|
* @param args Array of values
|
||||||
*
|
*
|
||||||
* @return Bool
|
* @return The minimum value
|
||||||
**/
|
**/
|
||||||
public static function lessThan(a:Float, b:Float, margin:Float = 0.0000001):Bool {
|
public static function min(...args:Float):Float {
|
||||||
return a < b - margin;
|
var min = args[0];
|
||||||
}
|
for(i in 1...args.length) {
|
||||||
|
var arg = args[i];
|
||||||
|
if(arg < min)
|
||||||
|
min = arg;
|
||||||
|
}
|
||||||
|
return min;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks if a is less than or equally b with considering a margin of error.
|
* Checks if a is less than b with considering a margin of error.
|
||||||
*
|
* * @param a Float
|
||||||
* @param a Float
|
* @param b Float
|
||||||
* @param b Float
|
* @param margin Float (Default: EPSILON)
|
||||||
* @param margin Float (Default: EPSILON)
|
* * @return Bool
|
||||||
*
|
**/
|
||||||
* @return Bool
|
public static function lessThan(a:Float, b:Float, margin:Float = 0.0000001):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 greater 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 a Float
|
* @param b Float
|
||||||
* @param b Float
|
* @param margin Float (Default: EPSILON)
|
||||||
* @param margin Float (Default: EPSILON)
|
* * @return Bool
|
||||||
*
|
**/
|
||||||
* @return Bool
|
public static function lessThanEqual(a:Float, b:Float, margin:Float = 0.0000001):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 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 a Float
|
* @param b Float
|
||||||
* @param b Float
|
* @param margin Float (Default: EPSILON)
|
||||||
* @param margin Float (Default: EPSILON)
|
* * @return Bool
|
||||||
*
|
**/
|
||||||
* @return Bool
|
public static function greaterThan(a:Float, b:Float, margin:Float = 0.0000001):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 approximately equal to b.
|
* Checks if a is greater than or equally b with considering a margin of error.
|
||||||
*
|
* * @param a Float
|
||||||
* @param a Float
|
* @param b Float
|
||||||
* @param b Float
|
* @param margin Float (Default: EPSILON)
|
||||||
* @param margin Float (Default: EPSILON)
|
* * @return Bool
|
||||||
*
|
**/
|
||||||
* @return Bool
|
public static function greaterThanEqual(a:Float, b:Float, margin:Float = 0.0000001):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 are not approximately equal to b.
|
* Checks if a is approximately equal to b.
|
||||||
*
|
* * @param a Float
|
||||||
* @param a Float
|
* @param b Float
|
||||||
* @param b Float
|
* @param margin Float (Default: EPSILON)
|
||||||
* @param margin Float (Default: EPSILON)
|
* * @return Bool
|
||||||
*
|
**/
|
||||||
* @return Bool
|
public static function equal(a:Float, b:Float, margin:Float = 0.0000001):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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Shortcut to `Math.max` but with infinite amount of arguments
|
* Checks if a are not approximately equal to b.
|
||||||
*
|
* * @param a Float
|
||||||
* Might not preserve the order of arguments, please test this.
|
* @param b Float
|
||||||
*
|
* @param margin Float (Default: EPSILON)
|
||||||
* Dont use this in hscript, it doesnt work, it only works on compile time
|
* * @return Bool
|
||||||
**/
|
**/
|
||||||
@:dox(hide) public static macro function maxSmart(..._args:Expr):Expr {
|
public static function notEqual(a:Float, b:Float, margin:Float = 0.0000001):Bool {
|
||||||
return genericMinMaxSmart(_args.toArray(), "Math.max");
|
return Math.abs(a - b) > margin;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Shortcut to `Math.min` but with infinite amount of arguments
|
* @param edge0 Float
|
||||||
*
|
* @param edge1 Float
|
||||||
* Might not preserve the order of arguments, please test this.
|
* @param x Float
|
||||||
*
|
* @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 {
|
||||||
@:dox(hide) public static macro function minSmart(..._args:Expr):Expr {
|
var t = (x - edge0) / (edge1 - edge0);
|
||||||
return genericMinMaxSmart(_args.toArray(), "Math.min");
|
var clamped = t < 0.0 ? 0.0 : (t > 1.0 ? 1.0 : t);
|
||||||
}
|
return clamped * clamped * (3.0 - 2.0 * clamped);
|
||||||
|
}
|
||||||
|
|
||||||
#if macro
|
/**
|
||||||
@:dox(hide) private static function genericMinMaxSmart(_args:Array<Expr>, funcPath:String):Expr {
|
* @param a Float
|
||||||
var args = _args.copy();
|
* @param b Float
|
||||||
if (args.length == 0) return macro 0;
|
* @param v Float
|
||||||
|
* @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 {
|
/**
|
||||||
if (lst.length == 1) {
|
* Shortcut to `Math.max` but with infinite amount of arguments
|
||||||
return macro ${lst[0]};
|
*
|
||||||
} else if (lst.length == 2) {
|
* Might not preserve the order of arguments, please test this.
|
||||||
return macro $p{func}(${lst[0]}, ${lst[1]});
|
*
|
||||||
} else {
|
* Dont use this in hscript, it doesnt work, it only works on compile time
|
||||||
var mid = Std.int(lst.length / 2);
|
**/
|
||||||
return macro $p{func}(${nested(lst.slice(0, mid))}, ${nested(lst.slice(mid, lst.length))});
|
@:dox(hide) public static macro function maxSmart(..._args:Expr):Expr {
|
||||||
}
|
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");
|
||||||
|
}
|
||||||
|
|
||||||
//var printer = new haxe.macro.Printer();
|
#if macro
|
||||||
//trace(printer.printExpr(expr));
|
@:dox(hide) private static function genericMinMaxSmart(_args:Array<Expr>, funcPath:String):Expr {
|
||||||
|
var args = _args.copy();
|
||||||
|
if (args.length == 0) return macro 0;
|
||||||
|
|
||||||
return macro $expr;
|
var func = funcPath.split(".");
|
||||||
}
|
|
||||||
#end
|
function nested(lst:Array<Expr>):Expr {
|
||||||
}
|
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
|
||||||
|
}
|
||||||
|
|||||||
@@ -34,151 +34,23 @@ 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 = isAnimateAtlas ? FakeCallCamera.instance : FakeCamera.instance;
|
var nc:FakeCamera = 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(isAnimateAtlas) {
|
if(sprite is IPrePostDraw) {
|
||||||
var cnc = FakeCallCamera.instance;
|
var postDraw = cast(sprite, IPrePostDraw);
|
||||||
var sprite = funkinSprite;
|
postDraw.preDraw();
|
||||||
var oldOnDraw = cnc.onDraw;
|
sprite.drawComplex(nc);
|
||||||
|
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 {
|
||||||
if(sprite is IPrePostDraw) {
|
sprite.drawComplex(nc);
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 => null,
|
0 => "Unknown",
|
||||||
1 => "Other",
|
1 => "Other",
|
||||||
2 => "DRAM",
|
2 => "DRAM",
|
||||||
3 => "Synchronous DRAM",
|
3 => "Synchronous DRAM",
|
||||||
@@ -152,23 +152,13 @@ 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("powershell", ["-Command", "Get-CimInstance Win32_PhysicalMemory | Select-Object -ExpandProperty SMBIOSMemoryType" ]);
|
var process = new HiddenProcess("wmic", ["memorychip", "get", "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] == null ? 'Unknown ($memoryOutput)' : memoryMap[memoryOutput];
|
if (memoryOutput != -1) return 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: (.+)/;
|
||||||
|
|||||||
@@ -1,120 +0,0 @@
|
|||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -2,157 +2,143 @@ 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
|
* ~~Half of the code is taken from haxe libraries btw~~ Reworked by ItsLJcool to actually work for zip files.
|
||||||
*/
|
*/
|
||||||
class SysZip extends Reader {
|
class SysZip {
|
||||||
var input:Input;
|
|
||||||
var fileInput:FileInput;
|
var fileInput:FileInput;
|
||||||
|
var filePath:String;
|
||||||
|
|
||||||
public var entries:List<SysZipEntry>;
|
public var entries:List<SysZipEntry> = new List();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Opens a zip from a specified path.
|
* Opens a zip from a specified path.
|
||||||
* @param path Path to the zip file.
|
* @param path Path to the zip file. (With the extension)
|
||||||
*/
|
*/
|
||||||
public static function openFromFile(path:String) {
|
public static function openFromFile(path:String) { return new SysZip(path); } // keeping for compatibility.
|
||||||
|
|
||||||
return new SysZip(File.read(path, true));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new SysZip from a specified file input.
|
* Creates a new SysZip from a specified path.
|
||||||
* @param input File input.
|
* @param path Path to the zip file. (With the extension)
|
||||||
*/
|
*/
|
||||||
public function new(input:FileInput) {
|
public function new(path:String) {
|
||||||
super(input);
|
this.filePath = path;
|
||||||
fileInput = input;
|
fileInput = File.read(path, true);
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
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) {
|
public function unzipEntry(f:SysZipEntry):Bytes {
|
||||||
var data = readEntryData(f);
|
if (f.fileSize <= 0) return Bytes.alloc(0);
|
||||||
|
|
||||||
|
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 = haxe.io.Bytes.alloc(f.fileSize);
|
var s = 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)
|
|
||||||
throw "Invalid compressed data for " + f.fileName;
|
if (!r.done || r.read != data.length || r.write != f.fileSize) throw 'Invalid compressed data for ${f.fileName} | ${f.compressedSize} -> ${f.fileSize}';
|
||||||
data = s;
|
return s;
|
||||||
return data;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override function read():List<Entry> {
|
/**
|
||||||
if (entries != null)
|
* Updates the `entries` list with the current contents of the zip file.
|
||||||
return entries;
|
* 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.
|
||||||
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) {
|
||||||
var e = readEntryHeader();
|
if (fileInput.readInt32() != 0x02014b50) break; // central dir file header signature
|
||||||
if (e == null)
|
|
||||||
break;
|
fileInput.seek(6, SeekCur); // version/flags
|
||||||
|
var compression_method = fileInput.readUInt16();
|
||||||
|
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 = cast e;
|
var zipEntry:SysZipEntry = {
|
||||||
zipEntry.seekPos = fileInput.tell();
|
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 (input != null)
|
if (fileInput != null) fileInput.close();
|
||||||
input.close();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef SysZipEntry = {
|
typedef SysZipEntry = {
|
||||||
> Entry,
|
var fileName:String;
|
||||||
|
var fileSize:Int;
|
||||||
var seekPos:Int;
|
var seekPos:Int;
|
||||||
|
var compressedSize:Int;
|
||||||
|
var compressed:Bool;
|
||||||
}
|
}
|
||||||
#end
|
#end
|
||||||
@@ -14,6 +14,7 @@ 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;
|
||||||
|
|
||||||
@@ -127,6 +128,9 @@ 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;
|
||||||
@@ -225,7 +229,8 @@ 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
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -261,7 +266,8 @@ 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;
|
||||||
@@ -273,6 +279,7 @@ 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;
|
||||||
}
|
}
|
||||||
@@ -299,15 +306,23 @@ 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 is FunkinSprite && cast(sprite, FunkinSprite).animateAtlas != null) {
|
if (sprite.frames is FlxAnimateFrames) {
|
||||||
var animateAnim = cast(sprite, FunkinSprite).animateAtlas.anim;
|
|
||||||
if(animData.anim == null)
|
if(animData.anim == null)
|
||||||
return MISSING_PROPERTY;
|
return MISSING_PROPERTY;
|
||||||
|
|
||||||
if (animData.indices != null && animData.indices.length > 0)
|
var animateAnim = cast(sprite, FunkinSprite).anim;
|
||||||
animateAnim.addBySymbolIndices(animData.name, animData.anim, animData.indices, animData.fps, animData.loop);
|
|
||||||
else
|
if (animData.label) {
|
||||||
animateAnim.addBySymbol(animData.name, animData.anim, animData.fps, animData.loop);
|
if (animData.indices != null && animData.indices.length > 0)
|
||||||
|
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)
|
||||||
@@ -463,6 +478,7 @@ 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -20,6 +20,8 @@ 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) {
|
||||||
@@ -58,6 +60,21 @@ 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,18 +2,13 @@ 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;
|
||||||
|
|
||||||
@@ -26,6 +21,7 @@ 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;
|
||||||
@@ -116,13 +112,20 @@ 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, "Looping?", animData.loop, 0, true);
|
loopedCheckbox = new UICheckbox(fpsStepper.x + 82 - 32 + 26, fpsStepper.y, translate("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));
|
||||||
@@ -204,6 +207,7 @@ 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);
|
||||||
|
|
||||||
@@ -231,18 +235,12 @@ class CharacterAnimButton extends UIButton {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var oldName:String = anim;
|
var oldName:String = anim;
|
||||||
if (parent.character.animateAtlas != null) {
|
|
||||||
var animSymbol:FlxSymbolAnimation = __getAnimationSymbol();
|
var flxAnimation:FlxAnimation = __getFlxAnimation();
|
||||||
|
flxAnimation.name = newName;
|
||||||
|
|
||||||
parent.character.animateAtlas.anim.animsMap.remove(anim);
|
parent.character.animation._animations.remove(anim);
|
||||||
parent.character.animateAtlas.anim.animsMap.set(newName, animSymbol);
|
parent.character.animation._animations.set(newName, flxAnimation);
|
||||||
} 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;
|
||||||
@@ -254,7 +252,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:{scale:Float, animBounds:Rectangle, frame:Int} = parent.displayAnimsFramesList[anim];
|
var displayFrame:DisplayAnimFrameEntry = parent.displayAnimsFramesList[anim];
|
||||||
parent.displayAnimsFramesList.remove(anim);
|
parent.displayAnimsFramesList.remove(anim);
|
||||||
parent.displayAnimsFramesList.set(newName, displayFrame);
|
parent.displayAnimsFramesList.set(newName, displayFrame);
|
||||||
|
|
||||||
@@ -276,23 +274,20 @@ class CharacterAnimButton extends UIButton {
|
|||||||
var oldAnim:String = animData.anim;
|
var oldAnim:String = animData.anim;
|
||||||
animData.anim = newAnim;
|
animData.anim = newAnim;
|
||||||
|
|
||||||
if (parent.character.animateAtlas != null)
|
var flxAnimation:FlxAnimation = __getFlxAnimation();
|
||||||
__refreshAnimation();
|
flxAnimation.prefix = newAnim;
|
||||||
else {
|
|
||||||
var flxAnimation:FlxAnimation = __getFlxAnimation();
|
|
||||||
flxAnimation.prefix = newAnim;
|
|
||||||
|
|
||||||
refreshFlxAnimationFrames(flxAnimation, animData);
|
refreshAnimation(__getFlxAnimation(), data);
|
||||||
|
|
||||||
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);
|
||||||
|
|
||||||
@@ -330,13 +325,8 @@ class CharacterAnimButton extends UIButton {
|
|||||||
var oldFPS:Float = animData.fps;
|
var oldFPS:Float = animData.fps;
|
||||||
animData.fps = newFPS;
|
animData.fps = newFPS;
|
||||||
|
|
||||||
if (parent.character.animateAtlas != null) {
|
var flxAnimation:FlxAnimation = __getFlxAnimation();
|
||||||
var animSymbol:FlxSymbolAnimation = __getAnimationSymbol();
|
flxAnimation.frameRate = newFPS;
|
||||||
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);
|
||||||
@@ -351,13 +341,8 @@ class CharacterAnimButton extends UIButton {
|
|||||||
|
|
||||||
animData.loop = newLooping;
|
animData.loop = newLooping;
|
||||||
|
|
||||||
if (parent.character.animateAtlas != null) {
|
var flxAnimation:FlxAnimation = __getFlxAnimation();
|
||||||
var animSymbol:FlxSymbolAnimation = __getAnimationSymbol();
|
flxAnimation.looped = animData.loop;
|
||||||
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);
|
||||||
@@ -367,6 +352,19 @@ 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();
|
||||||
@@ -403,58 +401,14 @@ 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) {
|
||||||
FlxG.sound.play(Paths.sound(Flags.DEFAULT_CHARACTER_GHOSTENABLE_SOUND));
|
UIState.playEditorSound(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 {
|
||||||
FlxG.sound.play(Paths.sound(Flags.DEFAULT_CHARACTER_GHOSTDISABLE_SOUND));
|
UIState.playEditorSound(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;
|
||||||
@@ -466,8 +420,8 @@ class CharacterAnimButton extends UIButton {
|
|||||||
super.draw();
|
super.draw();
|
||||||
|
|
||||||
if (!closed && parent.displayAnimsFramesList.exists(anim)) {
|
if (!closed && parent.displayAnimsFramesList.exists(anim)) {
|
||||||
var displayData:{frame:Int, scale:Float, animBounds:Rectangle} = parent.displayAnimsFramesList.get(anim);
|
var displayData:DisplayAnimFrameEntry = parent.displayAnimsFramesList.get(anim);
|
||||||
parent.displayWindowSprite.frame = parent.displayWindowSprite.frames.frames[displayData.frame];
|
parent.displayWindowSprite.frame = 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();
|
||||||
@@ -521,16 +475,26 @@ class CharacterAnimButton extends UIButton {
|
|||||||
return parent.character.animation._animations[anim];
|
return parent.character.animation._animations[anim];
|
||||||
}
|
}
|
||||||
|
|
||||||
public inline function __getAnimationSymbol():Null<FlxSymbolAnimation> @:privateAccess {
|
public inline function refreshAnimation(anim:FlxAnimation, animData:AnimData) @:privateAccess {
|
||||||
if (!parent.character.animateAtlas.anim.animsMap.exists(anim))
|
var refreshed:Bool = false;
|
||||||
XMLUtil.addAnimToSprite(parent.character, data);
|
|
||||||
return parent.character.animateAtlas.anim.animsMap[anim];
|
parent.character.animation.remove(animData.name);
|
||||||
|
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 {
|
||||||
if (parent.character.animateAtlas != null) refreshSymbolKeyFrames(__getAnimationSymbol(), data);
|
refreshAnimation(__getFlxAnimation(), data);
|
||||||
else refreshFlxAnimationFrames(__getFlxAnimation(), data);
|
|
||||||
|
|
||||||
if (valid) {
|
if (valid) {
|
||||||
parent.buildAnimDisplay(anim, data);
|
parent.buildAnimDisplay(anim, data);
|
||||||
|
|||||||
@@ -8,15 +8,24 @@ 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, {scale:Float, animBounds:Rectangle, frame:OneOfTwo<Int, String>}> = [];
|
public var displayAnimsFramesList:Map<String, DisplayAnimFrameEntry> = [];
|
||||||
|
|
||||||
public var animButtons:Map<String, CharacterAnimButton> = [];
|
public var animButtons:Map<String, CharacterAnimButton> = [];
|
||||||
public var animsList:Array<String> = [];
|
public var animsList:Array<String> = [];
|
||||||
@@ -30,7 +39,7 @@ class CharacterAnimsWindow extends UIButtonList<CharacterAnimButton> {
|
|||||||
|
|
||||||
buttonCameras.pixelPerfectRender = true;
|
buttonCameras.pixelPerfectRender = true;
|
||||||
|
|
||||||
if (Assets.exists(Paths.image('characters/${character.sprite}')) && character.animateAtlas == null)
|
if (Assets.exists(Paths.image('characters/${character.sprite}')))
|
||||||
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();
|
||||||
@@ -69,37 +78,48 @@ class CharacterAnimsWindow extends UIButtonList<CharacterAnimButton> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function buildAnimDisplay(name:String, anim:AnimData) @:privateAccess {
|
public function buildAnimDisplay(name:String, anim:AnimData) @:privateAccess {
|
||||||
if (character.animateAtlas == null) {
|
var anim:FlxAnimation = character.animation._animations[anim.name];
|
||||||
var anim:FlxAnimation = character.animation._animations[anim.name];
|
if (anim == null) return;
|
||||||
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, {frame: anim.frames.getDefault([0])[0], scale: 104/Math.max(animBounds.width, animBounds.height), animBounds: animBounds});
|
displayAnimsFramesList.set(name, {
|
||||||
} else {
|
frame: character.frames.frames[anim.frames.getDefault([0])[0]],
|
||||||
character.storeAtlasState();
|
scale: 104/Math.max(animBounds.width, animBounds.height),
|
||||||
|
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) {
|
||||||
FlxG.sound.play(Paths.sound(Flags.DEFAULT_EDITOR_DELETE_SOUND));
|
UIState.playEditorSound(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);
|
||||||
@@ -134,6 +154,7 @@ 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
|
||||||
FlxG.sound.play(Paths.sound('editors/save'));
|
UIState.playEditorSound(Flags.DEFAULT_EDITOR_SAVE_SOUND);
|
||||||
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(_) {
|
||||||
FlxG.sound.play(Paths.sound('editors/save'));
|
UIState.playEditorSound(Flags.DEFAULT_EDITOR_SAVE_SOUND);
|
||||||
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) {
|
||||||
FlxG.sound.play(Paths.sound(Flags.DEFAULT_EDITOR_UNDO_SOUND));
|
UIState.playEditorSound(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,6 +554,9 @@ 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);
|
||||||
@@ -570,7 +573,7 @@ class CharacterEditor extends UIState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function _redo(redo:CharacterEditorChange) {
|
function _redo(redo:CharacterEditorChange) {
|
||||||
FlxG.sound.play(Paths.sound(Flags.DEFAULT_EDITOR_REDO_SOUND));
|
UIState.playEditorSound(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):
|
||||||
@@ -625,6 +628,9 @@ 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);
|
||||||
@@ -936,6 +942,7 @@ 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,6 +4,8 @@ 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;
|
||||||
@@ -14,39 +16,35 @@ 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();
|
||||||
|
|
||||||
if (animateAtlas != null) {
|
var animName = animation.curAnim?.name ?? null;
|
||||||
storeAtlasState();
|
var animFrame = animation.curAnim?.curFrame ?? 0;
|
||||||
for (anim in ghosts) {
|
var animFrameTimer = animation.curAnim?._frameTimer ?? 0;
|
||||||
animateAtlas.anim.play(anim, true, false, 0);
|
|
||||||
setAnimOffset(anim);
|
|
||||||
|
|
||||||
alpha = 0.4; color = 0xFFAEAEAE;
|
for (anim in ghosts) @:privateAccess {
|
||||||
super.draw();
|
alpha = 0.4; color = 0xFFAEAEAE;
|
||||||
}
|
|
||||||
|
|
||||||
if (ghosts.length > 0) restoreAtlasState();
|
var flxanim:FlxAnimation = animation._animations.get(anim);
|
||||||
|
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;
|
||||||
@@ -54,8 +52,12 @@ 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 {
|
||||||
setAnimOffset(animateAtlas != null ? atlasPlayingAnim : animation.name);
|
animation.play(animName, true, false, animFrame);
|
||||||
|
setAnimOffset(animName);
|
||||||
|
if (animation.curAnim != null)
|
||||||
|
animation.curAnim._frameTimer = animFrameTimer;
|
||||||
|
}
|
||||||
|
|
||||||
super.draw();
|
super.draw();
|
||||||
}
|
}
|
||||||
@@ -70,22 +72,45 @@ 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 {
|
||||||
|
if (!isAnimate) return null;
|
||||||
|
|
||||||
|
var wasInvalidFrame:Bool = !colorTransform.__isDefault(false);
|
||||||
|
colorTransform.__identity();
|
||||||
|
|
||||||
|
var animName = animation.curAnim?.name ?? null;
|
||||||
|
var animFrame = animation.curAnim?.curFrame ?? 0;
|
||||||
|
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
|
// This gets annoying lmao -lunar
|
||||||
private var atlasState:AtlasState = null;
|
// it's gone now <3 -yosh
|
||||||
public function storeAtlasState():AtlasState @:privateAccess {
|
|
||||||
return atlasState = {
|
|
||||||
oldAnim: atlasPlayingAnim,
|
|
||||||
oldFrame: animateAtlas.anim.curFrame,
|
|
||||||
oldTick: animateAtlas.anim._tick,
|
|
||||||
oldPlaying: animateAtlas.anim.isPlaying,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
public function restoreAtlasState(state:AtlasState = null) @:privateAccess {
|
|
||||||
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,7 +1,6 @@
|
|||||||
|
|
||||||
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;
|
||||||
@@ -184,31 +183,15 @@ class CharacterPropertiesWindow extends UISliceSprite {
|
|||||||
character.sprite = sprite;
|
character.sprite = sprite;
|
||||||
|
|
||||||
animsWindow.displayWindowSprite.animation.reset();
|
animsWindow.displayWindowSprite.animation.reset();
|
||||||
animsWindow.displayAnimsFramesList.clear();
|
animsWindow.clearDisplayAnims();
|
||||||
if (animsWindow.displayWindowGraphic != null)
|
if (animsWindow.displayWindowGraphic != null)
|
||||||
animsWindow.displayWindowGraphic.destroy();
|
animsWindow.displayWindowGraphic.destroy();
|
||||||
|
|
||||||
if (Assets.exists('$noExt/Animation.json')) {
|
character.frames = Paths.getFrames(path, true);
|
||||||
if (character.animateAtlas == null) {
|
|
||||||
character.animation.reset();
|
|
||||||
character.animateAtlas = new FlxAnimate(character.x, character.y);
|
|
||||||
} else
|
|
||||||
character.animateAtlas.anim.stop();
|
|
||||||
|
|
||||||
character.atlasPath = noExt;
|
animsWindow.displayWindowSprite.loadGraphicFromSprite(character);
|
||||||
character.animateAtlas.loadAtlas(noExt);
|
if (Assets.exists(Paths.image('characters/${character.sprite}')))
|
||||||
} else {
|
animsWindow.displayWindowGraphic = FlxG.bitmap.add(Assets.getBitmapData(Paths.image('characters/${character.sprite}'), true, false));
|
||||||
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
|
||||||
|
|||||||
@@ -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,6 +96,7 @@ 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;
|
||||||
@@ -231,6 +232,11 @@ 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
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@@ -308,6 +314,11 @@ 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"),
|
||||||
@@ -453,7 +464,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');
|
||||||
@@ -515,7 +526,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 () {
|
||||||
FlxG.sound.play(Paths.sound(!strumLines.draggable ? Flags.DEFAULT_CHARTER_STRUMUNLOCK_SOUND : Flags.DEFAULT_CHARTER_STRUMLOCK_SOUND));
|
UIState.playEditorSound(!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;
|
||||||
@@ -685,6 +696,7 @@ 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}> {
|
||||||
@@ -740,6 +752,38 @@ 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) {
|
||||||
@@ -757,6 +801,7 @@ 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) {
|
||||||
@@ -802,7 +847,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});
|
||||||
|
|
||||||
FlxG.sound.play(Paths.sound('editors/save'));
|
UIState.playEditorSound(Flags.DEFAULT_EDITOR_SAVE_SOUND);
|
||||||
undos.save();
|
undos.save();
|
||||||
}
|
}
|
||||||
autoSaveNotif.cancelled = false;
|
autoSaveNotif.cancelled = false;
|
||||||
@@ -921,17 +966,24 @@ class Charter extends UIState {
|
|||||||
if (!(verticalChange == 0 && horizontalChange == 0)) {
|
if (!(verticalChange == 0 && horizontalChange == 0)) {
|
||||||
notesGroup.sortNotes();
|
notesGroup.sortNotes();
|
||||||
|
|
||||||
undos.addToUndo(CChangeBundle([
|
var changes:Array<CharterChange> = [];
|
||||||
CSelectionDrag(undoDrags),
|
if (isAltCopyDrag) {
|
||||||
updateEventsGroups(selection)
|
changes.push(CCreateSelection(selection.copy()));
|
||||||
]));
|
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();
|
||||||
@@ -962,7 +1014,7 @@ class Charter extends UIState {
|
|||||||
notesGroup.add(note);
|
notesGroup.add(note);
|
||||||
selection = [note];
|
selection = [note];
|
||||||
undos.addToUndo(CCreateSelection([note]));
|
undos.addToUndo(CCreateSelection([note]));
|
||||||
FlxG.sound.play(Paths.sound(Flags.DEFAULT_CHARTER_NOTEPLACE_SOUND));
|
UIState.playEditorSound(Flags.DEFAULT_CHARTER_NOTEPLACE_SOUND);
|
||||||
}
|
}
|
||||||
isSelecting = false;
|
isSelecting = false;
|
||||||
}
|
}
|
||||||
@@ -979,7 +1031,32 @@ 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) gridActionType = noteHovered ? NOTE_DRAG : INVALID_DRAG;
|
if (noteHovered) {
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1091,7 +1168,7 @@ class Charter extends UIState {
|
|||||||
if (selected == null) return selected;
|
if (selected == null) return selected;
|
||||||
|
|
||||||
if (selected is CharterNote) {
|
if (selected is CharterNote) {
|
||||||
FlxG.sound.play(Paths.sound(Flags.DEFAULT_CHARTER_NOTEDELETE_SOUND));
|
UIState.playEditorSound(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
|
||||||
@@ -1571,20 +1648,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(); FlxG.sound.play(Paths.sound('editors/save'));}
|
function _file_save_all(_) {saveEverything(); UIState.playEditorSound(Flags.DEFAULT_EDITOR_SAVE_SOUND);}
|
||||||
function _file_save(_) {saveChart(); FlxG.sound.play(Paths.sound('editors/save'));}
|
function _file_save(_) {saveChart(); UIState.playEditorSound(Flags.DEFAULT_EDITOR_SAVE_SOUND);}
|
||||||
function _file_saveas(_) {saveChartAs(); FlxG.sound.play(Paths.sound('editors/save'));}
|
function _file_saveas(_) {saveChartAs(); UIState.playEditorSound(Flags.DEFAULT_EDITOR_SAVE_SOUND);}
|
||||||
function _file_events_save(_) {saveEvents(); FlxG.sound.play(Paths.sound('editors/save'));}
|
function _file_events_save(_) {saveEvents(); UIState.playEditorSound(Flags.DEFAULT_EDITOR_SAVE_SOUND);}
|
||||||
function _file_events_saveas(_) {saveEventsAs(); FlxG.sound.play(Paths.sound('editors/save'));}
|
function _file_events_saveas(_) {saveEventsAs(); UIState.playEditorSound(Flags.DEFAULT_EDITOR_SAVE_SOUND);}
|
||||||
function _file_save_no_events(_) {saveChart(true, false); FlxG.sound.play(Paths.sound('editors/save'));}
|
function _file_save_no_events(_) {saveChart(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_saveas_no_events(_) {saveChartAs(true, false); UIState.playEditorSound(Flags.DEFAULT_EDITOR_SAVE_SOUND);}
|
||||||
function _file_meta_save(_) {saveMeta(); FlxG.sound.play(Paths.sound('editors/save'));}
|
function _file_meta_save(_) {saveMeta(); UIState.playEditorSound(Flags.DEFAULT_EDITOR_SAVE_SOUND);}
|
||||||
function _file_meta_saveas(_) {saveMetaAs(); FlxG.sound.play(Paths.sound('editors/save'));}
|
function _file_meta_saveas(_) {saveMetaAs(); UIState.playEditorSound(Flags.DEFAULT_EDITOR_SAVE_SOUND);}
|
||||||
function _file_saveas_fnflegacy(_) {saveLegacyChartAs(); FlxG.sound.play(Paths.sound('editors/save'));}
|
function _file_saveas_fnflegacy(_) {saveLegacyChartAs(); UIState.playEditorSound(Flags.DEFAULT_EDITOR_SAVE_SOUND);}
|
||||||
function _file_saveas_psych(_) {savePsychChartAs(); FlxG.sound.play(Paths.sound('editors/save'));}
|
function _file_saveas_psych(_) {savePsychChartAs(); UIState.playEditorSound(Flags.DEFAULT_EDITOR_SAVE_SOUND);}
|
||||||
|
|
||||||
function _edit_copy(_, playSFX=true) {
|
function _edit_copy(_, playSFX=true) {
|
||||||
if (playSFX) FlxG.sound.play(Paths.sound(Flags.DEFAULT_EDITOR_COPY_SOUND));
|
if (playSFX) UIState.playEditorSound(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;
|
||||||
@@ -1603,7 +1680,7 @@ class Charter extends UIState {
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
function _edit_paste(_) {
|
function _edit_paste(_) {
|
||||||
FlxG.sound.play(Paths.sound(Flags.DEFAULT_EDITOR_PASTE_SOUND));
|
UIState.playEditorSound(Flags.DEFAULT_EDITOR_PASTE_SOUND);
|
||||||
if (clipboard.length <= 0) return;
|
if (clipboard.length <= 0) return;
|
||||||
|
|
||||||
var minStep = curStep;
|
var minStep = curStep;
|
||||||
@@ -1631,7 +1708,7 @@ class Charter extends UIState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function _edit_cut(_) {
|
function _edit_cut(_) {
|
||||||
FlxG.sound.play(Paths.sound(Flags.DEFAULT_EDITOR_CUT_SOUND));
|
UIState.playEditorSound(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);
|
||||||
@@ -1639,7 +1716,7 @@ class Charter extends UIState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function _edit_delete(_) {
|
function _edit_delete(_) {
|
||||||
FlxG.sound.play(Paths.sound(Flags.DEFAULT_EDITOR_DELETE_SOUND));
|
UIState.playEditorSound(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});
|
||||||
@@ -1647,8 +1724,27 @@ 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) {
|
||||||
FlxG.sound.play(Paths.sound(Flags.DEFAULT_EDITOR_UNDO_SOUND));
|
UIState.playEditorSound(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):
|
||||||
@@ -1697,7 +1793,11 @@ 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):
|
||||||
for (change in changes) _undo(change);
|
var i = changes.length - 1;
|
||||||
|
while (i >= 0) {
|
||||||
|
_undo(changes[i]);
|
||||||
|
i--;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1709,7 +1809,7 @@ class Charter extends UIState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function _redo(redo:CharterChange) {
|
function _redo(redo:CharterChange) {
|
||||||
FlxG.sound.play(Paths.sound(Flags.DEFAULT_EDITOR_REDO_SOUND));
|
UIState.playEditorSound(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):
|
||||||
@@ -1808,14 +1908,24 @@ 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) {
|
|
||||||
FlxG.sound.music.volume = FlxG.sound.music.volume > 0 ? 0 : 1;
|
public function _slider_mutetoggle(t:UIContextMenuOption) {
|
||||||
t.icon = 1 - Std.int(Math.ceil(FlxG.sound.music.volume));
|
if (t.slider == null) return;
|
||||||
|
t.button.slider.value = t.button.slider.value > 0 ? 0 : 1;
|
||||||
}
|
}
|
||||||
function _song_mutevoices(t) {
|
|
||||||
vocals.volume = (voicesMuted = !voicesMuted) ? 0 : 1;
|
function _song_instvolume(t) {
|
||||||
for (strumLine in strumLines.members) strumLine.updateVoicesVolume();
|
FlxG.sound.music.volume = t.slider.value;
|
||||||
t.icon = voicesMuted ? 1 : 0;
|
t.icon = t.slider.value > 0.5 ? 7 : (t.slider.value > 0 ? 8 : 9);
|
||||||
|
}
|
||||||
|
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;
|
||||||
@@ -1860,6 +1970,7 @@ 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> {
|
||||||
@@ -1868,7 +1979,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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1878,9 +1989,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));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1905,7 +2016,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;
|
||||||
@@ -1959,7 +2070,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);
|
||||||
@@ -2011,26 +2122,56 @@ 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)
|
||||||
{
|
{
|
||||||
newChilds.push({
|
bookmarkOptions.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.muteInst"),
|
label: translate("song.inst"),
|
||||||
onSelect: _song_muteinst
|
slider: {
|
||||||
|
min: 0,
|
||||||
|
max: 1,
|
||||||
|
value: 1,
|
||||||
|
onChange: _song_instvolume
|
||||||
|
},
|
||||||
|
onIconClick: _slider_mutetoggle,
|
||||||
|
icon: 7
|
||||||
});
|
});
|
||||||
|
|
||||||
newChilds.push({
|
newChilds.push({
|
||||||
label: translate("song.muteVoices"),
|
label: translate("song.voices"),
|
||||||
onSelect: _song_mutevoices
|
slider: {
|
||||||
|
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;
|
||||||
@@ -2055,6 +2196,10 @@ 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;
|
||||||
|
|
||||||
@@ -2080,8 +2225,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) {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 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 setquant(newQuant:Int) {FlxG.sound.play(Paths.sound(Flags.DEFAULT_CHARTER_SNAPPINGCHANGE_SOUND)); quant = newQuant; buildSnapsUI();}
|
inline function setquant(newQuant:Int) {UIState.playEditorSound(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];
|
||||||
@@ -2117,12 +2262,12 @@ class Charter extends UIState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
inline function _note_addsustain(t) {
|
inline function _note_addsustain(t) {
|
||||||
FlxG.sound.play(Paths.sound(Flags.DEFAULT_CHARTER_SUSTAINADD_SOUND));
|
UIState.playEditorSound(Flags.DEFAULT_CHARTER_SUSTAINADD_SOUND);
|
||||||
changeNoteSustain(1);
|
changeNoteSustain(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline function _note_subtractsustain(t) {
|
inline function _note_subtractsustain(t) {
|
||||||
FlxG.sound.play(Paths.sound(Flags.DEFAULT_CHARTER_SUSTAINDELETE_SOUND));
|
UIState.playEditorSound(Flags.DEFAULT_CHARTER_SUSTAINDELETE_SOUND);
|
||||||
changeNoteSustain(-1);
|
changeNoteSustain(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2199,16 +2344,18 @@ 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 noteKeys:Array<FlxKey> = [ZERO, ONE, TWO, THREE, FOUR, FIVE, SIX, SEVEN, EIGHT, NINE];
|
var noteTypeOptions:Array<UIContextMenuOption> = [{
|
||||||
|
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 = {
|
||||||
@@ -2217,9 +2364,13 @@ 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.keybind = [noteKeys[realNoteID]];
|
if (realNoteID <= 9) newChild.keybinds = noteKeys[realNoteID];
|
||||||
newChilds.push(newChild);
|
noteTypeOptions.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,
|
||||||
@@ -2227,6 +2378,7 @@ 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2314,8 +2466,12 @@ class Charter extends UIState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public inline function hitsoundsEnabled(id:Int)
|
public inline function playHitsound(id:Int) {
|
||||||
return strumLines.members[id] != null && strumLines.members[id].hitsounds;
|
if (strumLines.members[id] != null && strumLines.members[id].hitsoundVolume > 0 && hitsoundGlobalVolume > 0) {
|
||||||
|
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();
|
||||||
@@ -2406,7 +2562,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.hitsounds],
|
hitSounds: [for (strumLine in strumLines.members) strumLine.hitsoundVolume > 0],
|
||||||
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]
|
||||||
}
|
}
|
||||||
@@ -2422,7 +2578,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.hitsounds = playtestInfo.hitSounds[i];
|
strumLine.hitsoundVolume = playtestInfo.hitSounds[i] ? 1 : 0;
|
||||||
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)
|
||||||
@@ -2514,3 +2670,9 @@ 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;
|
||||||
|
|
||||||
FlxG.sound.play(Paths.sound(Flags.DEFAULT_EDITOR_AUTOSAVE_SOUND));
|
UIState.playEditorSound(Flags.DEFAULT_EDITOR_AUTOSAVE_SOUND);
|
||||||
|
|
||||||
(new FlxTimer()).start(1, (_) -> {disappearAnimation();});
|
(new FlxTimer()).start(1, (_) -> {disappearAnimation();});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -178,6 +178,8 @@ 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();
|
||||||
|
|
||||||
@@ -187,6 +189,10 @@ 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();
|
||||||
@@ -247,10 +253,11 @@ 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]) {
|
topSeparator, bottomSeparator, conductorFollowerSpr, waveformSprite, cameraHighlight]) {
|
||||||
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;
|
||||||
}
|
}
|
||||||
@@ -272,6 +279,9 @@ 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;
|
||||||
|
|
||||||
@@ -311,16 +321,19 @@ 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) return;
|
if (conductorSprY == lastConductorSprY && currentZoom == lastCameraZoom) return; //only update if song pos or camera zoom has changed
|
||||||
|
|
||||||
var zoomOffset = ((FlxG.height * (1/cameras[0].zoom)) * 0.5);
|
var zoomOffset = ((FlxG.height * (1/currentZoom)) * 0.5);
|
||||||
|
|
||||||
minStep = (conductorSprY - zoomOffset)/40;
|
minStep = (conductorSprY - zoomOffset)/40;
|
||||||
maxStep = (conductorSprY + zoomOffset)/40;
|
maxStep = (conductorSprY + zoomOffset)/40;
|
||||||
@@ -359,6 +372,7 @@ class CharterGridSeperatorBase extends FlxSprite {
|
|||||||
}
|
}
|
||||||
|
|
||||||
lastConductorSprY = conductorSprY;
|
lastConductorSprY = conductorSprY;
|
||||||
|
lastCameraZoom = currentZoom;
|
||||||
}
|
}
|
||||||
|
|
||||||
private inline function calculateTimeSignatureGaps() {
|
private inline function calculateTimeSignatureGaps() {
|
||||||
@@ -446,6 +460,77 @@ 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;
|
||||||
|
|
||||||
|
|||||||
@@ -161,8 +161,9 @@ 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 && Charter.instance.hitsoundsEnabled(strumLineID))
|
if (__passed && FlxG.sound.music.playing) {
|
||||||
Charter.instance.hitsound.replay();
|
Charter.instance.playHitsound(strumLineID);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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 * 0.7) * scale));
|
strum.setGraphicSize(Std.int((strum.width * Flags.DEFAULT_NOTE_SCALE) * 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 * 0.7) * scale));
|
note.setGraphicSize(Std.int((note.width * Flags.DEFAULT_NOTE_SCALE) * 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.height;
|
var noteTime:Float = FlxG.initialHeight;
|
||||||
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, 0.7 * scale, 0.2);
|
strum.scale.x = strum.scale.y = CoolUtil.fpsLerp(strum.scale.x, Flags.DEFAULT_NOTE_SCALE * 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.height;
|
noteTime = FlxG.initialHeight;
|
||||||
|
|
||||||
note.x = members[0].x;
|
note.x = members[0].x;
|
||||||
note.y = members[0].y + noteTime;
|
note.y = members[0].y + noteTime;
|
||||||
|
|||||||
@@ -146,11 +146,10 @@ 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++;
|
while (!(screen.members[idx] is Separator || idx >= screen.members.length)) 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,6 +105,7 @@ 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,5 +1,7 @@
|
|||||||
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;
|
||||||
@@ -10,11 +12,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;
|
||||||
@@ -22,7 +24,9 @@ class CharterStrumline extends UISprite {
|
|||||||
public var curMenu:UIContextMenu = null;
|
public var curMenu:UIContextMenu = null;
|
||||||
|
|
||||||
public var vocals:FlxSound;
|
public var vocals:FlxSound;
|
||||||
public var voicesMuted:Bool = false;
|
public var hasVocals: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;
|
||||||
@@ -142,15 +146,22 @@ 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;
|
||||||
}
|
|
||||||
|
|
||||||
public function updateVoicesVolume() {
|
highlightColor = 0xFFFFFFFF;
|
||||||
vocals.volume = (voicesMuted || (Charter.instance?.voicesMuted ?? false)) ? 0 : 1;
|
if (icons[0] != null) {
|
||||||
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -173,18 +184,17 @@ class CharterStrumlineOptions extends UITopMenuButton {
|
|||||||
contextMenu = [
|
contextMenu = [
|
||||||
{
|
{
|
||||||
label: TU.translate("charter.strumLine.hitsounds"),
|
label: TU.translate("charter.strumLine.hitsounds"),
|
||||||
onSelect: function(_) {
|
slider: {
|
||||||
strLine.hitsounds = !strLine.hitsounds;
|
min: 0,
|
||||||
|
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);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
icon: strLine.hitsounds ? 1 : 0
|
onIconClick: Charter.instance._slider_mutetoggle,
|
||||||
},
|
icon: 7
|
||||||
{
|
|
||||||
label: TU.translate("charter.strumLine.muteVocals"),
|
|
||||||
onSelect: function(_) {
|
|
||||||
strLine.voicesMuted = !strLine.voicesMuted;
|
|
||||||
strLine.updateVoicesVolume();
|
|
||||||
},
|
|
||||||
icon: strLine.voicesMuted ? 1 : 0
|
|
||||||
},
|
},
|
||||||
null,
|
null,
|
||||||
{
|
{
|
||||||
@@ -205,20 +215,44 @@ class CharterStrumlineOptions extends UITopMenuButton {
|
|||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
contextMenu.insert(0, {
|
if (strLine.hasVocals) {
|
||||||
label: TU.translate("charter.strumLine.noWaveform"),
|
contextMenu.insert(1, {
|
||||||
onSelect: function(_) {strLine.selectedWaveform = -1;},
|
label: TU.translate("charter.strumLine.vocals"),
|
||||||
icon: strLine.selectedWaveform == -1 ? 1 : 0
|
slider: {
|
||||||
});
|
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)
|
||||||
contextMenu.insert(1+i, {
|
waveformOptions.push({
|
||||||
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(1+Charter.waveformHandler.waveformList.length, null);
|
contextMenu.insert(0, {
|
||||||
|
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,6 +33,8 @@ 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;
|
||||||
|
|
||||||
@@ -176,20 +178,30 @@ 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);
|
||||||
// if (Flags.CHARTER_ADVANCED_SETTINGS) {
|
add(keyCountStepper);
|
||||||
add(keyCountStepper);
|
addLabelOn(keyCountStepper, TU.translate("charterStrumLine.keyCount"));
|
||||||
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() {
|
||||||
@@ -222,7 +234,7 @@ class CharterStrumlineScreen extends UISubstateWindow {
|
|||||||
|
|
||||||
previewStrumLine.visible = visibleCheckbox.checked;
|
previewStrumLine.visible = visibleCheckbox.checked;
|
||||||
|
|
||||||
var xOffset:Float = StrumLine.calculateStartingXPos(hudXStepper.value, hudScaleStepper.value, hudSpacingStepper.value, Std.int(keyCountStepper.value));
|
var xOffset:Float = StrumLine.calculateStartingXPosFromInitialWidth(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);
|
||||||
@@ -233,6 +245,26 @@ 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 {
|
||||||
|
|||||||
@@ -377,9 +377,7 @@ 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.animateAtlas != null) ?
|
var lastIndx = char.animation.curAnim.numFrames - 1;
|
||||||
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();
|
||||||
|
|
||||||
@@ -510,7 +508,7 @@ class StageEditor extends UIState {
|
|||||||
|
|
||||||
function _file_save(_) {
|
function _file_save(_) {
|
||||||
#if sys
|
#if sys
|
||||||
FlxG.sound.play(Paths.sound('editors/save'));
|
UIState.playEditorSound(Flags.DEFAULT_EDITOR_SAVE_SOUND);
|
||||||
CoolUtil.safeSaveFile(
|
CoolUtil.safeSaveFile(
|
||||||
'${Paths.getAssetsRoot()}/data/stages/${__stage}.xml',
|
'${Paths.getAssetsRoot()}/data/stages/${__stage}.xml',
|
||||||
buildStage()
|
buildStage()
|
||||||
@@ -522,7 +520,7 @@ class StageEditor extends UIState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function _file_saveas(_) {
|
function _file_saveas(_) {
|
||||||
FlxG.sound.play(Paths.sound('editors/save'));
|
UIState.playEditorSound(Flags.DEFAULT_EDITOR_SAVE_SOUND);
|
||||||
openSubState(new SaveSubstate(buildStage(), {
|
openSubState(new SaveSubstate(buildStage(), {
|
||||||
defaultSaveFile: '${__stage}.xml'
|
defaultSaveFile: '${__stage}.xml'
|
||||||
}));
|
}));
|
||||||
@@ -565,9 +563,7 @@ 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.animateAtlas != null) ?
|
var lastIndx = char.animation.curAnim.numFrames - 1;
|
||||||
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();
|
||||||
|
|
||||||
@@ -734,7 +730,7 @@ class StageEditor extends UIState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function _edit_undo(_) {
|
function _edit_undo(_) {
|
||||||
FlxG.sound.play(Flags.DEFAULT_EDITOR_UNDO_SOUND);
|
UIState.playEditorSound(Flags.DEFAULT_EDITOR_UNDO_SOUND);
|
||||||
var undo = undos.undo();
|
var undo = undos.undo();
|
||||||
switch(undo) {
|
switch(undo) {
|
||||||
case null:
|
case null:
|
||||||
@@ -760,7 +756,7 @@ class StageEditor extends UIState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function _edit_redo(_) {
|
function _edit_redo(_) {
|
||||||
FlxG.sound.play(Paths.sound(Flags.DEFAULT_EDITOR_REDO_SOUND));
|
UIState.playEditorSound(Flags.DEFAULT_EDITOR_REDO_SOUND);
|
||||||
var redo = undos.redo();
|
var redo = undos.redo();
|
||||||
switch(redo) {
|
switch(redo) {
|
||||||
case null:
|
case null:
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ class UIButton extends UISliceSprite {
|
|||||||
super.onHovered();
|
super.onHovered();
|
||||||
if (FlxG.mouse.justPressed) {
|
if (FlxG.mouse.justPressed) {
|
||||||
hasBeenPressed = true;
|
hasBeenPressed = true;
|
||||||
FlxG.sound.play(Paths.sound(Flags.DEFAULT_EDITOR_BUTTONCLICK_SOUND));
|
UIState.playEditorSound(Flags.DEFAULT_EDITOR_BUTTONCLICK_SOUND);
|
||||||
}
|
}
|
||||||
if (FlxG.mouse.justReleased && callback != null && shouldPress && hasBeenPressed) {
|
if (FlxG.mouse.justReleased && callback != null && shouldPress && hasBeenPressed) {
|
||||||
callback();
|
callback();
|
||||||
|
|||||||
@@ -16,6 +16,12 @@ 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;
|
||||||
|
|
||||||
@@ -96,6 +102,10 @@ 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) {
|
||||||
@@ -105,12 +115,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)
|
||||||
close();
|
closeWithParents();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override function update(elapsed:Float) {
|
public override function update(elapsed:Float) {
|
||||||
if (__oobDeletion && FlxG.mouse.justPressed && !bg.hoveredByChild)
|
if (__oobDeletion && FlxG.mouse.justPressed && !bg.hoveredByChild && !hoveringAnyChildren())
|
||||||
close();
|
closeWithParents();
|
||||||
|
|
||||||
__oobDeletion = true;
|
__oobDeletion = true;
|
||||||
|
|
||||||
@@ -121,6 +131,14 @@ 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() {
|
||||||
@@ -129,6 +147,56 @@ 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;
|
||||||
@@ -144,13 +212,24 @@ 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:FlxSprite;
|
public var icon:UIContextMenuOptionIcon;
|
||||||
public var option:UIContextMenuOption;
|
public var option:UIContextMenuOption;
|
||||||
|
public var optionType:UIContextMenuOptionType = DEFAULT;
|
||||||
|
|
||||||
|
public var slider:UISlider = null;
|
||||||
|
|
||||||
var parent:UIContextMenu;
|
var parent:UIContextMenu;
|
||||||
|
|
||||||
@@ -160,40 +239,96 @@ class UIContextMenuOptionSpr extends UISliceSprite {
|
|||||||
this.parent = parent;
|
this.parent = parent;
|
||||||
this.color = option.color;
|
this.color = option.color;
|
||||||
|
|
||||||
if (option.icon != null && option.icon > 0) {
|
var w:Int = label.frameWidth + 22;
|
||||||
icon = new FlxSprite(0, 0).loadGraphic(Paths.image('editors/ui/context-icons'), true, 20, 20);
|
var h:Int = label.frameHeight;
|
||||||
icon.animation.add('icon', [option.icon-1], 0, true);
|
|
||||||
icon.animation.play('icon');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (option.keybinds == null) {
|
if (option.childs != null) optionType = SUBMENU;
|
||||||
if (option.keybind != null) {
|
if (option.slider != null) optionType = SLIDER;
|
||||||
option.keybinds = [option.keybind];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (option.keybinds != null || option.keybindText != null) {
|
switch(optionType) {
|
||||||
var text = if(option.keybindText == null) {
|
|
||||||
var textKeys:Array<String> = [];
|
case SUBMENU:
|
||||||
for (o in option.keybinds[0]) {
|
labelKeybind = new UIText(label.x + label.frameWidth + 10, 2, 0, ">");
|
||||||
if (Std.int(o) > 0) {
|
case SLIDER:
|
||||||
textKeys.push(o.toUIString());
|
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];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
textKeys.join("+");
|
|
||||||
} else {
|
if (option.keybinds != null || option.keybindText != null) {
|
||||||
option.keybindText;
|
var text = if(option.keybindText == null) {
|
||||||
}
|
var textKeys:Array<String> = [];
|
||||||
labelKeybind = new UIText(label.x + label.frameWidth + 10, 2, 0, text);
|
for (o in option.keybinds[0]) {
|
||||||
labelKeybind.alpha = 0.75;
|
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, labelKeybind != null ? Std.int(labelKeybind.x + labelKeybind.frameWidth + 10) : (label.frameWidth + 22), label.frameHeight, 'editors/ui/menu-item');
|
super(x, y, w, h, 'editors/ui/menu-item');
|
||||||
|
|
||||||
members.push(label);
|
members.push(label);
|
||||||
if (icon != null)
|
updateIcon();
|
||||||
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() {
|
||||||
@@ -205,12 +340,71 @@ 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.select(option);
|
parent.lastHoveredOptionIndex = parent.contextMenuOptions.indexOf(this);
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -87,7 +87,7 @@ class UIDropDown extends UISliceSprite {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function openContextMenu() {
|
public function openContextMenu() {
|
||||||
FlxG.sound.play(Paths.sound(Flags.DEFAULT_EDITOR_DROPDOWNAPPEAR_SOUND));
|
UIState.playEditorSound(Flags.DEFAULT_EDITOR_DROPDOWNAPPEAR_SOUND);
|
||||||
var screenPos = getScreenPosition(null, __lastDrawCameras[0] == null ? FlxG.camera : __lastDrawCameras[0]);
|
var screenPos = getScreenPosition(null, __lastDrawCameras[0] == null ? FlxG.camera : __lastDrawCameras[0]);
|
||||||
curMenu = UIState.state.openContextMenu([
|
curMenu = UIState.state.openContextMenu([
|
||||||
for(k=>o in items) {
|
for(k=>o in items) {
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ package funkin.editors.ui;
|
|||||||
import flixel.util.typeLimit.OneOfTwo;
|
import flixel.util.typeLimit.OneOfTwo;
|
||||||
import flixel.text.FlxText.FlxTextFormat;
|
import flixel.text.FlxText.FlxTextFormat;
|
||||||
import flixel.text.FlxText.FlxTextFormatMarkerPair;
|
import flixel.text.FlxText.FlxTextFormatMarkerPair;
|
||||||
import flxanimate.data.SpriteMapData.AnimateAtlas;
|
|
||||||
import flixel.graphics.frames.FlxFramesCollection;
|
import flixel.graphics.frames.FlxFramesCollection;
|
||||||
import haxe.Json;
|
import haxe.Json;
|
||||||
import haxe.io.Bytes;
|
import haxe.io.Bytes;
|
||||||
@@ -11,6 +10,7 @@ import haxe.io.Path;
|
|||||||
import openfl.display.BitmapData;
|
import openfl.display.BitmapData;
|
||||||
import sys.FileSystem;
|
import sys.FileSystem;
|
||||||
import sys.io.File;
|
import sys.io.File;
|
||||||
|
import animate.FlxAnimateJson;
|
||||||
|
|
||||||
using StringTools;
|
using StringTools;
|
||||||
using funkin.backend.utils.BitmapUtil;
|
using funkin.backend.utils.BitmapUtil;
|
||||||
@@ -122,7 +122,7 @@ class UIImageExplorer extends UIFileExplorer {
|
|||||||
for(file in files) {
|
for(file in files) {
|
||||||
if(SPRITEMAP_JSON_REGEX.match(file)) {
|
if(SPRITEMAP_JSON_REGEX.match(file)) {
|
||||||
var content:String = CoolUtil.removeBOM(File.getContent(Path.join([directoryPath, file])));
|
var content:String = CoolUtil.removeBOM(File.getContent(Path.join([directoryPath, file])));
|
||||||
var json:AnimateAtlas = Json.parse(content);
|
var json:SpritemapJson = Json.parse(content);
|
||||||
if(json.meta.image.toLowerCase() == fileName.toLowerCase())
|
if(json.meta.image.toLowerCase() == fileName.toLowerCase())
|
||||||
foundSpritemapJson = true;
|
foundSpritemapJson = true;
|
||||||
} else if(file == "Animation.json")
|
} else if(file == "Animation.json")
|
||||||
@@ -147,7 +147,7 @@ class UIImageExplorer extends UIFileExplorer {
|
|||||||
spritemaps.sort(Reflect.compare);
|
spritemaps.sort(Reflect.compare);
|
||||||
for(spritemap in spritemaps) {
|
for(spritemap in spritemaps) {
|
||||||
var content:String = CoolUtil.removeBOM(File.getContent(Path.join([directoryPath, spritemap])));
|
var content:String = CoolUtil.removeBOM(File.getContent(Path.join([directoryPath, spritemap])));
|
||||||
var json:AnimateAtlas = Json.parse(content);
|
var json:SpritemapJson = Json.parse(content);
|
||||||
var imageToFind:String = json.meta.image.toLowerCase();
|
var imageToFind:String = json.meta.image.toLowerCase();
|
||||||
for(file in files) {
|
for(file in files) {
|
||||||
// lowercase since windows does case insensitive stuff, so we use lowercase to match behavior on mac and linux
|
// lowercase since windows does case insensitive stuff, so we use lowercase to match behavior on mac and linux
|
||||||
|
|||||||
@@ -106,7 +106,7 @@ class UIState extends MusicBeatState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (FlxG.mouse.justPressed) {
|
if (FlxG.mouse.justPressed) {
|
||||||
FlxG.sound.play(Paths.sound(Flags.DEFAULT_EDITOR_CLICK_SOUND));
|
playEditorSound(Flags.DEFAULT_EDITOR_CLICK_SOUND);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (FlxG.mouse.justReleased)
|
if (FlxG.mouse.justReleased)
|
||||||
@@ -147,7 +147,7 @@ class UIState extends MusicBeatState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function closeCurrentContextMenu() {
|
public function closeCurrentContextMenu() {
|
||||||
FlxG.sound.play(Paths.sound(Flags.DEFAULT_EDITOR_WINDOWCLOSE_SOUND));
|
playEditorSound(Flags.DEFAULT_EDITOR_WINDOWCLOSE_SOUND);
|
||||||
if(curContextMenu != null) {
|
if(curContextMenu != null) {
|
||||||
curContextMenu.close();
|
curContextMenu.close();
|
||||||
curContextMenu = null;
|
curContextMenu = null;
|
||||||
@@ -155,7 +155,7 @@ class UIState extends MusicBeatState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function openContextMenu(options:Array<UIContextMenuOption>, ?callback:UIContextMenuCallback, ?x:Float, ?y:Float, ?w:Int) {
|
public function openContextMenu(options:Array<UIContextMenuOption>, ?callback:UIContextMenuCallback, ?x:Float, ?y:Float, ?w:Int) {
|
||||||
FlxG.sound.play(Paths.sound(Flags.DEFAULT_EDITOR_WINDOWAPPEAR_SOUND));
|
playEditorSound(Flags.DEFAULT_EDITOR_WINDOWAPPEAR_SOUND);
|
||||||
var state = FlxG.state;
|
var state = FlxG.state;
|
||||||
while(state.subState != null && !(state._requestSubStateReset && state._requestedSubState == null))
|
while(state.subState != null && !(state._requestSubStateReset && state._requestedSubState == null))
|
||||||
state = state.subState;
|
state = state.subState;
|
||||||
@@ -191,4 +191,9 @@ class UIState extends MusicBeatState {
|
|||||||
resolutionAware = true;
|
resolutionAware = true;
|
||||||
FlxG.scaleMode = uiScaleMode;
|
FlxG.scaleMode = uiScaleMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function playEditorSound(path:String) {
|
||||||
|
if (!Options.editorSFX) return;
|
||||||
|
FlxG.sound.play(Paths.sound(path));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -86,7 +86,7 @@ class UISubstateWindow extends MusicBeatSubstate {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public override function destroy() {
|
public override function destroy() {
|
||||||
FlxG.sound.play(Paths.sound(Flags.DEFAULT_EDITOR_WINDOWCLOSE_SOUND));
|
UIState.playEditorSound(Flags.DEFAULT_EDITOR_WINDOWCLOSE_SOUND);
|
||||||
super.destroy();
|
super.destroy();
|
||||||
for(e in camShaders)
|
for(e in camShaders)
|
||||||
e.removeShader(blurShader);
|
e.removeShader(blurShader);
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ class UITextBox extends UISliceSprite implements IUIFocusable {
|
|||||||
|
|
||||||
var selected = selectable && focused;
|
var selected = selectable && focused;
|
||||||
if (autoAlpha) {
|
if (autoAlpha) {
|
||||||
if(selectable) {
|
if (selectable) {
|
||||||
alpha = label.alpha = 1;
|
alpha = label.alpha = 1;
|
||||||
} else {
|
} else {
|
||||||
alpha = label.alpha = 0.4;
|
alpha = label.alpha = 0.4;
|
||||||
@@ -68,19 +68,19 @@ class UITextBox extends UISliceSprite implements IUIFocusable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var off = multiline ? 4 : ((bHeight - label.height) / 2);
|
var off = multiline ? 4 : ((bHeight - label.height) / 2);
|
||||||
label.follow(this, label.autoSize ? (bWidth-label.textField.width)/2 : 4, off);
|
label.follow(this, label.autoSize ? (bWidth - label.textField.width) / 2 : 4, off);
|
||||||
framesOffset = (selected ? 18 : (hovered ? 9 : 0));
|
framesOffset = (selected ? 18 : (hovered ? 9 : 0));
|
||||||
@:privateAccess {
|
@:privateAccess {
|
||||||
if (selected) {
|
if (selected) {
|
||||||
__wasFocused = true;
|
__wasFocused = true;
|
||||||
caretSpr.alpha = (FlxG.game.ticks % 666) >= 333 ? 1 : 0;
|
caretSpr.alpha = (FlxG.game.ticks % 666) >= 333 ? 1 : 0;
|
||||||
|
|
||||||
var curPos = switch(position) {
|
var curPos = switch (position) {
|
||||||
case 0:
|
case 0:
|
||||||
FlxPoint.get(0, 0);
|
FlxPoint.get(0, 0);
|
||||||
default:
|
default:
|
||||||
if (position >= label.text.length) {
|
if (position >= label.text.length) {
|
||||||
label.textField.__getCharBoundaries(label.text.length-1, cacheRect);
|
label.textField.__getCharBoundaries(label.text.length - 1, cacheRect);
|
||||||
FlxPoint.get(cacheRect.x + cacheRect.width, cacheRect.y);
|
FlxPoint.get(cacheRect.x + cacheRect.width, cacheRect.y);
|
||||||
} else {
|
} else {
|
||||||
label.textField.__getCharBoundaries(position, cacheRect);
|
label.textField.__getCharBoundaries(position, cacheRect);
|
||||||
@@ -100,60 +100,160 @@ class UITextBox extends UISliceSprite implements IUIFocusable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static var seperators:Array<String> = [
|
||||||
|
" ", "\n", "\t", "\r", "-", "_", "=", "+", "/", "\\", "|", ",", ".", ";", ":", "!", "?", "@", "#", "$", "%", "^", "&", "*", "(", ")", "[", "]", "{",
|
||||||
|
"}",
|
||||||
|
];
|
||||||
|
|
||||||
|
public inline static function isSeperator(char:String):Bool
|
||||||
|
return seperators.contains(char);
|
||||||
|
|
||||||
|
public inline static function findWholeWord(text:String, pos:Int, ?isDelete:Bool = false):Null<Array<Int>> {
|
||||||
|
if (text.length == 0)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
var start = pos;
|
||||||
|
var end = pos;
|
||||||
|
|
||||||
|
while (!isDelete && start > 0 && !isSeperator(text.charAt(start - 1)))
|
||||||
|
start--;
|
||||||
|
|
||||||
|
while (end < text.length && !isSeperator(text.charAt(end)))
|
||||||
|
end++;
|
||||||
|
|
||||||
|
if (end == pos && isSeperator(text.charAt(end - 1)))
|
||||||
|
start--;
|
||||||
|
|
||||||
|
return [start, end];
|
||||||
|
}
|
||||||
|
|
||||||
public function onKeyDown(e:KeyCode, modifier:KeyModifier) {
|
public function onKeyDown(e:KeyCode, modifier:KeyModifier) {
|
||||||
switch(e) {
|
switch (e) {
|
||||||
case RETURN:
|
case RETURN:
|
||||||
focused = false;
|
focused = false;
|
||||||
if (onChange != null) onChange(label.text);
|
if (onChange != null)
|
||||||
|
onChange(label.text);
|
||||||
case LEFT:
|
case LEFT:
|
||||||
|
if (modifier.ctrlKey) {
|
||||||
|
if (position == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var wordBounds = findWholeWord(label.text, position);
|
||||||
|
if (wordBounds != null) {
|
||||||
|
position = position == wordBounds[0] ? wordBounds[0] - 1 : wordBounds[0];
|
||||||
|
} else {
|
||||||
|
position = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
changeSelection(-1);
|
changeSelection(-1);
|
||||||
case RIGHT:
|
case RIGHT:
|
||||||
|
if (modifier.ctrlKey) {
|
||||||
|
if (position == label.text.length)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var wordBounds = findWholeWord(label.text, position);
|
||||||
|
if (wordBounds != null) {
|
||||||
|
position = position == wordBounds[1] ? wordBounds[1] + 1 : wordBounds[1];
|
||||||
|
} else {
|
||||||
|
position = label.text.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
changeSelection(1);
|
changeSelection(1);
|
||||||
case BACKSPACE:
|
case BACKSPACE:
|
||||||
FlxG.sound.play(Paths.sound(Flags.DEFAULT_EDITOR_TEXTREMOVE_SOUND));
|
UIState.playEditorSound(Flags.DEFAULT_EDITOR_TEXTREMOVE_SOUND);
|
||||||
|
|
||||||
|
if (modifier.ctrlKey) {
|
||||||
|
var wordBounds = findWholeWord(label.text, position);
|
||||||
|
if (wordBounds != null) {
|
||||||
|
label.text = label.text.substr(0, wordBounds[0]) + label.text.substr(wordBounds[1]);
|
||||||
|
position = wordBounds[0];
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (position > 0) {
|
if (position > 0) {
|
||||||
label.text = label.text.substr(0, position-1) + label.text.substr(position);
|
label.text = label.text.substr(0, position - 1) + label.text.substr(position);
|
||||||
changeSelection(-1);
|
changeSelection(-1);
|
||||||
}
|
}
|
||||||
|
case DELETE:
|
||||||
|
UIState.playEditorSound(Flags.DEFAULT_EDITOR_TEXTREMOVE_SOUND);
|
||||||
|
|
||||||
|
if (modifier.ctrlKey) {
|
||||||
|
var wordBounds = findWholeWord(label.text, position, true);
|
||||||
|
if (wordBounds != null) {
|
||||||
|
label.text = label.text.substr(0, wordBounds[0]) + label.text.substr(wordBounds[1]);
|
||||||
|
position = wordBounds[0];
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (position < label.text.length) {
|
||||||
|
label.text = label.text.substr(0, position) + label.text.substr(position + 1);
|
||||||
|
}
|
||||||
case HOME:
|
case HOME:
|
||||||
position = 0;
|
position = 0;
|
||||||
case END:
|
case END:
|
||||||
position = label.text.length;
|
position = label.text.length;
|
||||||
case V:
|
case V:
|
||||||
FlxG.sound.play(Paths.sound(Flags.DEFAULT_EDITOR_TEXTTYPE_SOUND));
|
UIState.playEditorSound(Flags.DEFAULT_EDITOR_PASTE_SOUND);
|
||||||
// Hey lj here, fixed copying because before we checked if the modifier was left or right ctrl
|
// Hey lj here, fixed copying because before we checked if the modifier was left or right ctrl
|
||||||
// but somehow it gave a int outside of the KeyModifier's range :sob:
|
// but somehow it gave a int outside of the KeyModifier's range :sob:
|
||||||
// apparently there is a boolean that just checks for you. yw :D
|
// apparently there is a boolean that just checks for you. yw :D
|
||||||
|
|
||||||
// if we are not holding ctrl, ignore
|
// if we are not holding ctrl, ignore
|
||||||
if (!modifier.ctrlKey) return;
|
if (!modifier.ctrlKey)
|
||||||
|
return;
|
||||||
// we pasting
|
// we pasting
|
||||||
var data:String = Clipboard.generalClipboard.getData(TEXT_FORMAT);
|
var data:String = Clipboard.generalClipboard.getData(TEXT_FORMAT);
|
||||||
if (data != null) onTextInput(data);
|
if (data != null)
|
||||||
|
onTextInput(data);
|
||||||
case C:
|
case C:
|
||||||
FlxG.sound.play(Paths.sound(Flags.DEFAULT_EDITOR_TEXTTYPE_SOUND));
|
UIState.playEditorSound(Flags.DEFAULT_EDITOR_COPY_SOUND);
|
||||||
// if we are not holding ctrl, ignore
|
// if we are not holding ctrl, ignore
|
||||||
if (!modifier.ctrlKey) return;
|
if (!modifier.ctrlKey)
|
||||||
|
return;
|
||||||
|
|
||||||
// copying
|
// copying
|
||||||
Clipboard.generalClipboard.setData(TEXT_FORMAT, label.text);
|
Clipboard.generalClipboard.setData(TEXT_FORMAT, label.text);
|
||||||
|
case X:
|
||||||
|
UIState.playEditorSound(Flags.DEFAULT_EDITOR_CUT_SOUND);
|
||||||
|
|
||||||
|
// if we are not holding ctrl, ignore
|
||||||
|
if (!modifier.ctrlKey)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// cutting
|
||||||
|
Clipboard.generalClipboard.setData(TEXT_FORMAT, label.text);
|
||||||
|
position = 0;
|
||||||
|
label.text = "";
|
||||||
default:
|
default:
|
||||||
FlxG.sound.play(Paths.sound(Flags.DEFAULT_EDITOR_TEXTTYPE_SOUND));
|
if (modifier.ctrlKey || modifier.altKey || modifier.shiftKey)
|
||||||
|
return;
|
||||||
|
|
||||||
|
UIState.playEditorSound(Flags.DEFAULT_EDITOR_TEXTTYPE_SOUND);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function changeSelection(change:Int) {
|
public function changeSelection(change:Int) {
|
||||||
position = FlxMath.wrap(position + change, 0, label.text.length);
|
position = Std.int(FlxMath.bound(position + change, 0, label.text.length));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function onKeyUp(e:KeyCode, modifier:KeyModifier) {}
|
public function onKeyUp(e:KeyCode, modifier:KeyModifier) {}
|
||||||
|
|
||||||
public function onTextInput(text:String):Void {
|
public function onTextInput(text:String):Void {
|
||||||
label.text = label.text.substr(0, position) + text + label.text.substr(position);
|
label.text = label.text.substr(0, position) + text + label.text.substr(position);
|
||||||
position += text.length;
|
position += text.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
// untested, but this should be a fix for if the text wont type
|
// untested, but this should be a fix for if the text wont type
|
||||||
public function onTextEdit(text:String, start:Int, end:Int):Void {
|
public function onTextEdit(text:String, start:Int, end:Int):Void {
|
||||||
label.text = label.text.substr(0, position) + text + label.text.substr(position);
|
label.text = label.text.substr(0, position) + text + label.text.substr(position);
|
||||||
position += text.length;
|
position += text.length;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ class UIWindow extends UISliceSprite {
|
|||||||
|
|
||||||
content = new FlxTypedGroup<FlxBasic>();
|
content = new FlxTypedGroup<FlxBasic>();
|
||||||
members.push(content);
|
members.push(content);
|
||||||
FlxG.sound.play(Paths.sound(Flags.DEFAULT_EDITOR_WINDOWAPPEAR_SOUND));
|
UIState.playEditorSound(Flags.DEFAULT_EDITOR_WINDOWAPPEAR_SOUND);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override function update(elapsed:Float) {
|
public override function update(elapsed:Float) {
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ import haxe.Exception;
|
|||||||
import haxe.io.Path;
|
import haxe.io.Path;
|
||||||
import haxe.xml.Access;
|
import haxe.xml.Access;
|
||||||
import openfl.geom.ColorTransform;
|
import openfl.geom.ColorTransform;
|
||||||
|
import animate.FlxAnimateFrames;
|
||||||
|
|
||||||
using StringTools;
|
using StringTools;
|
||||||
|
|
||||||
@@ -118,7 +119,7 @@ class Character extends FunkinSprite implements IBeatReceiver implements IOffset
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (i in variants) {
|
for (i in variants) {
|
||||||
CoolUtil.switchAnimFrames(animation.getByName('singRIGHT$i'), animation.getByName('singLEFT$i'));
|
CoolUtil.swapAnims(animation, 'singLEFT$i', 'singRIGHT$i');
|
||||||
switchOffset('singLEFT$i', 'singRIGHT$i');
|
switchOffset('singLEFT$i', 'singRIGHT$i');
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -164,7 +165,7 @@ class Character extends FunkinSprite implements IBeatReceiver implements IOffset
|
|||||||
|
|
||||||
public function tryDance() {
|
public function tryDance() {
|
||||||
var event = new CancellableEvent();
|
var event = new CancellableEvent();
|
||||||
script.call("onTryDance", [event]);
|
scripts.call("onTryDance", [event]);
|
||||||
if (event.cancelled)
|
if (event.cancelled)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -196,16 +197,18 @@ class Character extends FunkinSprite implements IBeatReceiver implements IOffset
|
|||||||
}
|
}
|
||||||
|
|
||||||
public override function measureHit(curMeasure:Int)
|
public override function measureHit(curMeasure:Int)
|
||||||
script.call("measureHit", [curMeasure]);
|
scripts.call("measureHit", [curMeasure]);
|
||||||
|
|
||||||
public override function stepHit(curStep:Int)
|
public override function stepHit(curStep:Int)
|
||||||
scripts.call("stepHit", [curStep]);
|
scripts.call("stepHit", [curStep]);
|
||||||
|
|
||||||
@:noCompletion var __reverseDrawProcedure:Bool = false;
|
@:noCompletion var __reverseDrawProcedure:Bool = false;
|
||||||
public override function getScreenBounds(?newRect:FlxRect, ?camera:FlxCamera):FlxRect {
|
public override function getScreenBounds(?newRect:FlxRect, ?camera:FlxCamera):FlxRect {
|
||||||
if (__reverseDrawProcedure) {
|
if (isFlippedOffsets()) {
|
||||||
|
flipX = !flipX;
|
||||||
scale.x *= -1;
|
scale.x *= -1;
|
||||||
var bounds:FlxRect = super.getScreenBounds(newRect, camera);
|
var bounds:FlxRect = super.getScreenBounds(newRect, camera);
|
||||||
|
flipX = !flipX;
|
||||||
scale.x *= -1;
|
scale.x *= -1;
|
||||||
return bounds;
|
return bounds;
|
||||||
}
|
}
|
||||||
@@ -251,13 +254,13 @@ class Character extends FunkinSprite implements IBeatReceiver implements IOffset
|
|||||||
public var ghostDraw:Bool = false;
|
public var ghostDraw:Bool = false;
|
||||||
public override function draw() {
|
public override function draw() {
|
||||||
var e = EventManager.get(DrawEvent).recycle();
|
var e = EventManager.get(DrawEvent).recycle();
|
||||||
script.call("draw", [e]);
|
scripts.call("draw", [e]);
|
||||||
|
|
||||||
preDraw();
|
preDraw();
|
||||||
super.draw();
|
super.draw();
|
||||||
postDraw();
|
postDraw();
|
||||||
|
|
||||||
script.call("postDraw", [e]);
|
scripts.call("postDraw", [e]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public var singAnims = ["singLEFT", "singDOWN", "singUP", "singRIGHT"];
|
public var singAnims = ["singLEFT", "singDOWN", "singUP", "singRIGHT"];
|
||||||
@@ -270,7 +273,7 @@ class Character extends FunkinSprite implements IBeatReceiver implements IOffset
|
|||||||
public function playSingAnim(direction:Int, suffix:String = "", Context:PlayAnimContext = SING, ?Force:Null<Bool> = null, Reversed:Bool = false, Frame:Int = 0)
|
public function playSingAnim(direction:Int, suffix:String = "", Context:PlayAnimContext = SING, ?Force:Null<Bool> = null, Reversed:Bool = false, Frame:Int = 0)
|
||||||
{
|
{
|
||||||
var event = EventManager.get(DirectionAnimEvent).recycle(getSingAnim(direction, suffix), direction, suffix, Context, Reversed, Frame, Force);
|
var event = EventManager.get(DirectionAnimEvent).recycle(getSingAnim(direction, suffix), direction, suffix, Context, Reversed, Frame, Force);
|
||||||
script.call("onPlaySingAnim", [event]);
|
scripts.call("onPlaySingAnim", [event]);
|
||||||
if (event.cancelled) return;
|
if (event.cancelled) return;
|
||||||
|
|
||||||
playSingAnimUnsafe(event.direction, hasAnimation(event.animName) ? event.suffix : "", event.context, event.force, event.reversed, event.frame);
|
playSingAnimUnsafe(event.direction, hasAnimation(event.animName) ? event.suffix : "", event.context, event.force, event.reversed, event.frame);
|
||||||
@@ -278,7 +281,7 @@ class Character extends FunkinSprite implements IBeatReceiver implements IOffset
|
|||||||
|
|
||||||
public function playSingAnimUnsafe(direction:Int, suffix:String = "", Context:PlayAnimContext = SING, Force:Bool = true, Reversed:Bool = false, Frame:Int = 0) {
|
public function playSingAnimUnsafe(direction:Int, suffix:String = "", Context:PlayAnimContext = SING, Force:Bool = true, Reversed:Bool = false, Frame:Int = 0) {
|
||||||
var event = EventManager.get(DirectionAnimEvent).recycle(getSingAnim(direction, suffix), direction, suffix, Context, Reversed, Frame, Force);
|
var event = EventManager.get(DirectionAnimEvent).recycle(getSingAnim(direction, suffix), direction, suffix, Context, Reversed, Frame, Force);
|
||||||
script.call("playSingAnimUnsafe", [event]);
|
scripts.call("playSingAnimUnsafe", [event]);
|
||||||
if (event.cancelled) return;
|
if (event.cancelled) return;
|
||||||
|
|
||||||
playAnim(event.animName, event.force, event.context, event.reversed, event.frame);
|
playAnim(event.animName, event.force, event.context, event.reversed, event.frame);
|
||||||
@@ -291,7 +294,7 @@ class Character extends FunkinSprite implements IBeatReceiver implements IOffset
|
|||||||
|
|
||||||
super.playAnim(event.animName, event.force, event.context, event.reverse, event.startingFrame);
|
super.playAnim(event.animName, event.force, event.context, event.reverse, event.startingFrame);
|
||||||
|
|
||||||
offset.set(globalOffset.x * (isPlayer != playerOffsets ? 1 : -1), -globalOffset.y);
|
offset.set((isPlayer != playerOffsets) ? globalOffset.x : -globalOffset.x, -globalOffset.y);
|
||||||
if (event.context == SING || event.context == MISS)
|
if (event.context == SING || event.context == MISS)
|
||||||
lastHit = Conductor.songPosition;
|
lastHit = Conductor.songPosition;
|
||||||
}
|
}
|
||||||
@@ -352,7 +355,7 @@ class Character extends FunkinSprite implements IBeatReceiver implements IOffset
|
|||||||
buildCharacter(xml);
|
buildCharacter(xml);
|
||||||
}
|
}
|
||||||
|
|
||||||
public inline function buildCharacter(xml:Access) {
|
public function buildCharacter(xml:Access) {
|
||||||
for(node in xml.elements)
|
for(node in xml.elements)
|
||||||
switch(node.name) {
|
switch(node.name) {
|
||||||
case "use-extension" | "extension" | "ext":
|
case "use-extension" | "extension" | "ext":
|
||||||
@@ -382,7 +385,22 @@ class Character extends FunkinSprite implements IBeatReceiver implements IOffset
|
|||||||
updateHitbox();
|
updateHitbox();
|
||||||
}
|
}
|
||||||
if (xml.x.exists("antialiasing")) antialiasing = (xml.x.get("antialiasing") == "true");
|
if (xml.x.exists("antialiasing")) antialiasing = (xml.x.get("antialiasing") == "true");
|
||||||
|
if (xml.x.exists("applyStageMatrix")) applyStageMatrix = (xml.x.get("applyStageMatrix") == "true");
|
||||||
if (xml.x.exists("sprite")) sprite = xml.x.get("sprite");
|
if (xml.x.exists("sprite")) sprite = xml.x.get("sprite");
|
||||||
|
if (xml.x.exists("swfMode")) animateSettings.swfMode = (xml.x.get("swfMode") == "true");
|
||||||
|
if (xml.x.exists("cacheOnLoad")) animateSettings.cacheOnLoad = (xml.x.get("cacheOnLoad") == "true");
|
||||||
|
if (xml.x.exists("filterQuality")) {
|
||||||
|
var val = xml.x.get("filterQuality");
|
||||||
|
var qualityInt = Std.parseInt(val);
|
||||||
|
if (qualityInt != null) {
|
||||||
|
animateSettings.filterQuality = cast(qualityInt, FilterQuality);
|
||||||
|
} else {
|
||||||
|
var values = ["high", "medium", "low", "rudy"];
|
||||||
|
var index = values.indexOf(val.toLowerCase());
|
||||||
|
if (index > -1)
|
||||||
|
animateSettings.filterQuality = cast(index, FilterQuality);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var hasInterval:Bool = xml.x.exists("interval");
|
var hasInterval:Bool = xml.x.exists("interval");
|
||||||
if (hasInterval) beatInterval = Std.parseInt(xml.x.get("interval"));
|
if (hasInterval) beatInterval = Std.parseInt(xml.x.get("interval"));
|
||||||
@@ -421,10 +439,10 @@ class Character extends FunkinSprite implements IBeatReceiver implements IOffset
|
|||||||
public static var characterProperties:Array<String> = [
|
public static var characterProperties:Array<String> = [
|
||||||
"x", "y", "sprite", "scale", "antialiasing",
|
"x", "y", "sprite", "scale", "antialiasing",
|
||||||
"flipX", "camx", "camy", "isPlayer", "icon",
|
"flipX", "camx", "camy", "isPlayer", "icon",
|
||||||
"color", "gameOverChar", "holdTime"
|
"color", "gameOverChar", "holdTime", "applyStageMatrix"
|
||||||
];
|
];
|
||||||
public static var characterAnimProperties:Array<String> = [
|
public static var characterAnimProperties:Array<String> = [
|
||||||
"name", "anim", "x", "y", "fps", "loop", "indices"
|
"name", "anim", "label", "x", "y", "fps", "loop", "indices"
|
||||||
];
|
];
|
||||||
|
|
||||||
public inline function buildXML(?animsOrder:Array<String>):Xml {
|
public inline function buildXML(?animsOrder:Array<String>):Xml {
|
||||||
@@ -451,6 +469,7 @@ class Character extends FunkinSprite implements IBeatReceiver implements IOffset
|
|||||||
if (!antialiasing) xml.set("antialiasing", antialiasing == true ? "true" : "false");
|
if (!antialiasing) xml.set("antialiasing", antialiasing == true ? "true" : "false");
|
||||||
|
|
||||||
if (isPlayer) xml.set("isPlayer", isPlayer == true ? "true" : "false");
|
if (isPlayer) xml.set("isPlayer", isPlayer == true ? "true" : "false");
|
||||||
|
if (isAnimate) xml.set("applyStageMatrix", applyStageMatrix ? "true" : "false");
|
||||||
|
|
||||||
var anims:Array<AnimData> = [];
|
var anims:Array<AnimData> = [];
|
||||||
if (animsOrder != null) {
|
if (animsOrder != null) {
|
||||||
@@ -476,6 +495,9 @@ class Character extends FunkinSprite implements IBeatReceiver implements IOffset
|
|||||||
if (anim.indices.length > 0)
|
if (anim.indices.length > 0)
|
||||||
animXml.set("indices", CoolUtil.formatNumberRange(anim.indices));
|
animXml.set("indices", CoolUtil.formatNumberRange(anim.indices));
|
||||||
|
|
||||||
|
if (anim.label)
|
||||||
|
animXml.set("label", "true");
|
||||||
|
|
||||||
xml.addChild(animXml);
|
xml.addChild(animXml);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -161,7 +161,6 @@ class HealthIcon extends FunkinSprite
|
|||||||
var iconSize:Int = 0;
|
var iconSize:Int = 0;
|
||||||
var iconIsPlayer = xmlValid ? xmlData.get("facing").getDefault("right").toLowerCase() == "left" : false;
|
var iconIsPlayer = xmlValid ? xmlData.get("facing").getDefault("right").toLowerCase() == "left" : false;
|
||||||
|
|
||||||
animateAtlas = null; // reset
|
|
||||||
if (this.animated)
|
if (this.animated)
|
||||||
loadSprite(Paths.image(newIconPath));
|
loadSprite(Paths.image(newIconPath));
|
||||||
else {
|
else {
|
||||||
@@ -184,8 +183,6 @@ class HealthIcon extends FunkinSprite
|
|||||||
|
|
||||||
if(!animation.onFinishEnd.has(animFinishCallback))
|
if(!animation.onFinishEnd.has(animFinishCallback))
|
||||||
animation.onFinishEnd.add(animFinishCallback);
|
animation.onFinishEnd.add(animFinishCallback);
|
||||||
if(animateAtlas != null && !animateAtlas.anim.onFinishEnd.has(animFinishCallback))
|
|
||||||
animateAtlas.anim.onFinishEnd.add(animFinishCallback);
|
|
||||||
|
|
||||||
var parsedSteps:Map<Int, String> = [];
|
var parsedSteps:Map<Int, String> = [];
|
||||||
|
|
||||||
@@ -233,10 +230,10 @@ class HealthIcon extends FunkinSprite
|
|||||||
offsetY = Std.parseFloat(node.get("offsety")).getDefault(0);
|
offsetY = Std.parseFloat(node.get("offsety")).getDefault(0);
|
||||||
|
|
||||||
addAnim(animName, node.get("anim"), Std.parseInt(node.get("fps")).getDefault(24), false, null, null, offsetX, offsetY); // don't allow looping for transitions
|
addAnim(animName, node.get("anim"), Std.parseInt(node.get("fps")).getDefault(24), false, null, null, offsetX, offsetY); // don't allow looping for transitions
|
||||||
if (animateAtlas == null && animation.exists(animName))
|
if (animation.exists(animName))
|
||||||
animation.getByName(animName).flipX = isPlayer != iconIsPlayer;
|
animation.getByName(animName).flipX = isPlayer != iconIsPlayer;
|
||||||
case "anim":
|
case "anim":
|
||||||
if (this.animated == false) {
|
if (!this.animated) {
|
||||||
Logs.trace('Icon ${char} data <anim> is not allowed when not animated', WARNING);
|
Logs.trace('Icon ${char} data <anim> is not allowed when not animated', WARNING);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -270,7 +267,7 @@ class HealthIcon extends FunkinSprite
|
|||||||
looped = node.get("loop").toLowerCase() == "true";
|
looped = node.get("loop").toLowerCase() == "true";
|
||||||
|
|
||||||
addAnim(animName, node.get("anim"), Std.parseInt(node.get("fps")).getDefault(24), looped, null, null, offsetX, offsetY);
|
addAnim(animName, node.get("anim"), Std.parseInt(node.get("fps")).getDefault(24), looped, null, null, offsetX, offsetY);
|
||||||
if (animateAtlas == null && animation.exists(animName))
|
if (animation.exists(animName))
|
||||||
animation.getByName(animName).flipX = isPlayer != iconIsPlayer;
|
animation.getByName(animName).flipX = isPlayer != iconIsPlayer;
|
||||||
case "step":
|
case "step":
|
||||||
if (!node.exists("percent")) {
|
if (!node.exists("percent")) {
|
||||||
@@ -314,18 +311,8 @@ class HealthIcon extends FunkinSprite
|
|||||||
curAnimState = data.animState;
|
curAnimState = data.animState;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (animateAtlas != null) {
|
setGraphicSize(150);
|
||||||
@:bypassAccessor
|
updateHitbox();
|
||||||
frameWidth = 150;
|
|
||||||
@:bypassAccessor
|
|
||||||
frameHeight = 150;
|
|
||||||
extraOffsets.x -= frameWidth / 2;
|
|
||||||
extraOffsets.y -= frameHeight / 2;
|
|
||||||
updateHitbox();
|
|
||||||
} else {
|
|
||||||
setGraphicSize(150);
|
|
||||||
updateHitbox();
|
|
||||||
}
|
|
||||||
|
|
||||||
defaultScale = (xmlValid && xmlData.exists("scale")) ? Std.parseFloat(xmlData.get("scale")).getDefault(scale.x) : scale.x;
|
defaultScale = (xmlValid && xmlData.exists("scale")) ? Std.parseFloat(xmlData.get("scale")).getDefault(scale.x) : scale.x;
|
||||||
scale.set(defaultScale, defaultScale);
|
scale.set(defaultScale, defaultScale);
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package funkin.game;
|
package funkin.game;
|
||||||
|
|
||||||
import flixel.math.FlxPoint;
|
import flixel.math.FlxPoint;
|
||||||
|
import flixel.math.FlxAngle;
|
||||||
import flixel.math.FlxRect;
|
import flixel.math.FlxRect;
|
||||||
import funkin.backend.chart.ChartData;
|
import funkin.backend.chart.ChartData;
|
||||||
import funkin.backend.scripting.events.note.NoteCreationEvent;
|
import funkin.backend.scripting.events.note.NoteCreationEvent;
|
||||||
@@ -125,8 +126,7 @@ class Note extends FlxSprite
|
|||||||
|
|
||||||
static var DEFAULT_FIELDS:Array<String> = ["time", "id", "type", "sLen"];
|
static var DEFAULT_FIELDS:Array<String> = ["time", "id", "type", "sLen"];
|
||||||
|
|
||||||
public function new(strumLine:StrumLine, noteData:ChartNote, sustain:Bool = false, sustainLength:Float = 0, sustainOffset:Float = 0, ?prev:Note)
|
public function new(strumLine:StrumLine, noteData:ChartNote, sustain:Bool = false, sustainLength:Float = 0, sustainOffset:Float = 0, ?prev:Note) {
|
||||||
{
|
|
||||||
super();
|
super();
|
||||||
|
|
||||||
moves = false;
|
moves = false;
|
||||||
@@ -240,57 +240,83 @@ class Note extends FlxSprite
|
|||||||
*/
|
*/
|
||||||
public var strumRelativePos:Bool = true;
|
public var strumRelativePos:Bool = true;
|
||||||
|
|
||||||
override function drawComplex(camera:FlxCamera) {
|
@:dox(hide) static var __lastAngle:Float = Math.NaN;
|
||||||
var downscrollCam = (camera is HudCamera ? ({var _:HudCamera=cast camera;_;}).downscroll : false);
|
@:dox(hide) static var __lastAngleSin:Float = 0;
|
||||||
if (updateFlipY) flipY = (isSustainNote && flipSustain) && (downscrollCam != (__strum != null && __strum.getScrollSpeed(this) < 0));
|
@:dox(hide) static var __lastAngleCos:Float = 0;
|
||||||
if (downscrollCam) {
|
@:dox(hide) static var __lastStrumW:Float = Math.NaN;
|
||||||
frameOffset.y += __notePosFrameOffset.y * 2;
|
@:dox(hide) static var __lastStrumH:Float = Math.NaN;
|
||||||
super.drawComplex(camera);
|
@:dox(hide) static var __lastStrumHalfW:Float = 0;
|
||||||
frameOffset.y -= __notePosFrameOffset.y * 2;
|
@:dox(hide) static var __lastStrumHalfH:Float = 0;
|
||||||
} else
|
|
||||||
super.drawComplex(camera);
|
|
||||||
}
|
|
||||||
|
|
||||||
static var __notePosFrameOffset:FlxPoint = new FlxPoint();
|
|
||||||
static var __posPoint:FlxPoint = new FlxPoint();
|
|
||||||
|
|
||||||
override function draw() {
|
override function draw() {
|
||||||
@:privateAccess var oldDefaultCameras = FlxCamera._defaultCameras;
|
@:privateAccess var oldDefaultCameras = FlxCamera._defaultCameras;
|
||||||
@:privateAccess if (__strumCameras != null) FlxCamera._defaultCameras = __strumCameras;
|
@:privateAccess if (__strumCameras != null) FlxCamera._defaultCameras = __strumCameras;
|
||||||
|
|
||||||
var negativeScroll = isSustainNote && nextSustain != null && lastScrollSpeed < 0;
|
var negativeScroll = isSustainNote && strumRelativePos && lastScrollSpeed < 0;
|
||||||
if (negativeScroll) offset.y *= -1;
|
if (negativeScroll) y -= height;
|
||||||
|
|
||||||
if (__strum != null && strumRelativePos) {
|
if (__strum != null && strumRelativePos) {
|
||||||
var pos = __posPoint.set(x, y);
|
final originalX = x;
|
||||||
|
final originalY = y;
|
||||||
|
|
||||||
setPosition(__strum.x, __strum.y);
|
if (__noteAngle != __lastAngle) {
|
||||||
|
__lastAngle = __noteAngle;
|
||||||
|
final result = FlxMath.fastSinCos((__noteAngle + 90) * FlxAngle.TO_RAD);
|
||||||
|
__lastAngleSin = result.sin;
|
||||||
|
__lastAngleCos = result.cos;
|
||||||
|
}
|
||||||
|
|
||||||
__notePosFrameOffset.set(pos.x / scale.x, pos.y / scale.y);
|
if (__strum.width != __lastStrumW || __strum.height != __lastStrumH) {
|
||||||
|
__lastStrumW = __strum.width;
|
||||||
frameOffset.x -= __notePosFrameOffset.x;
|
__lastStrumH = __strum.height;
|
||||||
frameOffset.y -= __notePosFrameOffset.y;
|
__lastStrumHalfW = __strum.width * 0.5;
|
||||||
|
__lastStrumHalfH = __strum.height * 0.5;
|
||||||
this.frameOffsetAngle = __noteAngle;
|
}
|
||||||
|
|
||||||
|
x = -origin.x + offset.x + (originalY * __lastAngleCos) + __strum.x + __lastStrumHalfW;
|
||||||
|
y = -origin.y + offset.y + (originalY * __lastAngleSin) + __strum.y + __lastStrumHalfH;
|
||||||
super.draw();
|
super.draw();
|
||||||
|
x = originalX;
|
||||||
this.frameOffsetAngle = 0;
|
y = originalY;
|
||||||
|
|
||||||
frameOffset.x += __notePosFrameOffset.x;
|
|
||||||
frameOffset.y += __notePosFrameOffset.y;
|
|
||||||
|
|
||||||
setPosition(pos.x, pos.y);
|
|
||||||
//pos.put();
|
|
||||||
} else {
|
} else {
|
||||||
__notePosFrameOffset.set(0, 0);
|
|
||||||
super.draw();
|
super.draw();
|
||||||
}
|
}
|
||||||
|
if (negativeScroll) y += height;
|
||||||
|
|
||||||
if (negativeScroll) offset.y *= -1;
|
|
||||||
@:privateAccess FlxCamera._defaultCameras = oldDefaultCameras;
|
@:privateAccess FlxCamera._defaultCameras = oldDefaultCameras;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var __lastDownscrollCam:Bool = false;
|
||||||
|
var __lastX:Float = 0;
|
||||||
|
|
||||||
|
@:noCompletion @:dox(hide) override function isOnScreen(?camera:FlxCamera):Bool {
|
||||||
|
var downscrollCam = (Std.isOfType(camera, HudCamera) ? cast(camera, HudCamera).downscroll : false);
|
||||||
|
|
||||||
|
if (downscrollCam == __lastDownscrollCam)
|
||||||
|
return super.isOnScreen(camera);
|
||||||
|
else
|
||||||
|
__lastX = x;
|
||||||
|
|
||||||
|
if (updateFlipY) flipY = (isSustainNote && flipSustain) && (downscrollCam != (__strum != null && __strum.getScrollSpeed(this) < 0));
|
||||||
|
if (downscrollCam && __strum != null) {
|
||||||
|
x = -x + 2 * (__strum.x - origin.x + offset.x) + __strum.width;
|
||||||
|
}
|
||||||
|
final isOnScreen = super.isOnScreen(camera);
|
||||||
|
return isOnScreen;
|
||||||
|
}
|
||||||
|
|
||||||
|
override function drawComplex(camera:FlxCamera):Void {
|
||||||
|
super.drawComplex(camera);
|
||||||
|
|
||||||
|
if (__lastDownscrollCam) {
|
||||||
|
__lastDownscrollCam = false;
|
||||||
|
x = __lastX;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function isOnScreenOriginal(?camera:FlxCamera):Bool {
|
||||||
|
return super.isOnScreen(camera);
|
||||||
|
}
|
||||||
|
|
||||||
// The * 0.5 is so that it's easier to hit them too late, instead of too early
|
// The * 0.5 is so that it's easier to hit them too late, instead of too early
|
||||||
public var earlyPressWindow:Float = 0.5;
|
public var earlyPressWindow:Float = 0.5;
|
||||||
public var latePressWindow:Float = 1;
|
public var latePressWindow:Float = 1;
|
||||||
@@ -312,17 +338,27 @@ class Note extends FlxSprite
|
|||||||
|
|
||||||
public function updateSustainClip() if (wasGoodHit && !noSustainClip) {
|
public function updateSustainClip() if (wasGoodHit && !noSustainClip) {
|
||||||
var t = CoolUtil.bound((Conductor.songPosition - strumTime) / height * 0.45 * lastScrollSpeed, 0, 1);
|
var t = CoolUtil.bound((Conductor.songPosition - strumTime) / height * 0.45 * lastScrollSpeed, 0, 1);
|
||||||
var rect = clipRect == null ? FlxRect.get() : clipRect;
|
@:bypassAccessor {
|
||||||
clipRect = rect.set(0, frameHeight * t, frameWidth, frameHeight * (1 - t));
|
if (clipRect == null) clipRect = FlxRect.get();
|
||||||
|
clipRect.set(0, frameHeight * t, frameWidth, frameHeight * (1 - t));
|
||||||
|
}
|
||||||
|
@:privateAccess {
|
||||||
|
if (frame != null && _frame != null)
|
||||||
|
_frame = frame.clipTo(clipRect, _frame);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@:noCompletion
|
@:noCompletion
|
||||||
override function set_clipRect(rect:FlxRect):FlxRect
|
override function set_clipRect(rect:FlxRect):FlxRect {
|
||||||
{
|
@:bypassAccessor clipRect = rect;
|
||||||
clipRect = rect;
|
|
||||||
|
|
||||||
if (frames != null)
|
@:privateAccess if (frame != null) {
|
||||||
frame = frames.frames[animation.frameIndex];
|
if (rect != null && _frame != null)
|
||||||
|
_frame = frame.clipTo(rect, _frame);
|
||||||
|
else if (_frame != null)
|
||||||
|
_frame = frame.copyTo(_frame);
|
||||||
|
dirty = true;
|
||||||
|
}
|
||||||
|
|
||||||
return rect;
|
return rect;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -623,6 +623,18 @@ class PlayState extends MusicBeatState
|
|||||||
curRating = event.rating;
|
curRating = event.rating;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function onRatingChange(rating:Rating) {
|
||||||
|
if (!hits.exists(rating.name))
|
||||||
|
hits.set(rating.name, 0);
|
||||||
|
|
||||||
|
if (Options.ghostTapping) {
|
||||||
|
comboBreaks = false;
|
||||||
|
for (rating in ratingManager.ratingData)
|
||||||
|
comboBreaks = comboBreaks || rating.breaksCombo;
|
||||||
|
} else
|
||||||
|
comboBreaks = true;
|
||||||
|
}
|
||||||
|
|
||||||
private inline function set_health(v:Float)
|
private inline function set_health(v:Float)
|
||||||
return health = FlxMath.bound(v, 0, maxHealth);
|
return health = FlxMath.bound(v, 0, maxHealth);
|
||||||
private inline function set_maxHealth(v:Float) {
|
private inline function set_maxHealth(v:Float) {
|
||||||
@@ -643,7 +655,7 @@ class PlayState extends MusicBeatState
|
|||||||
public inline function callOnCharacters(func:String, ?parameters:Array<Dynamic>) {
|
public inline function callOnCharacters(func:String, ?parameters:Array<Dynamic>) {
|
||||||
if(strumLines != null) strumLines.forEachAlive(function (strLine:StrumLine) {
|
if(strumLines != null) strumLines.forEachAlive(function (strLine:StrumLine) {
|
||||||
if (strLine.characters != null) for (character in strLine.characters)
|
if (strLine.characters != null) for (character in strLine.characters)
|
||||||
if (character != null) character.script.call(func, parameters);
|
if (character != null) character.scripts.call(func, parameters);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -690,6 +702,14 @@ class PlayState extends MusicBeatState
|
|||||||
detailsText = isStoryMode ? ("Story Mode: " + storyWeek.name) : "Freeplay";
|
detailsText = isStoryMode ? ("Story Mode: " + storyWeek.name) : "Freeplay";
|
||||||
|
|
||||||
for (rating in [for (i in ratingManager.ratingData) i.name]) hits.set(rating, 0); // Ensure all keys exist as to prevent null errors.
|
for (rating in [for (i in ratingManager.ratingData) i.name]) hits.set(rating, 0); // Ensure all keys exist as to prevent null errors.
|
||||||
|
if (Options.ghostTapping) {
|
||||||
|
comboBreaks = false;
|
||||||
|
for (rating in ratingManager.ratingData)
|
||||||
|
comboBreaks = comboBreaks || rating.breaksCombo;
|
||||||
|
} else
|
||||||
|
comboBreaks = true;
|
||||||
|
ratingManager.onRatingAdded.add(onRatingChange);
|
||||||
|
ratingManager.onRatingRemoved.add(onRatingChange);
|
||||||
|
|
||||||
// Checks if cutscene files exists
|
// Checks if cutscene files exists
|
||||||
var cutscenePath = Paths.script('songs/${SONG.meta.name}/cutscene');
|
var cutscenePath = Paths.script('songs/${SONG.meta.name}/cutscene');
|
||||||
@@ -1667,7 +1687,7 @@ class PlayState extends MusicBeatState
|
|||||||
if (strLine.characters != null) // Alt anim Idle
|
if (strLine.characters != null) // Alt anim Idle
|
||||||
for (character in strLine.characters) {
|
for (character in strLine.characters) {
|
||||||
if (character == null) continue;
|
if (character == null) continue;
|
||||||
character.idleSuffix = event.params[1] ? "-alt" : "";
|
character.idleSuffix = event.params[1] ? strLine.defaultAnimSuffix : "";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case "Play Animation":
|
case "Play Animation":
|
||||||
@@ -1676,6 +1696,8 @@ class PlayState extends MusicBeatState
|
|||||||
if (char != null && char.hasAnim(event.params[1])) char.playAnim(event.params[1], event.params[2], event.params[3] == "NONE" ? null : event.params[3]);
|
if (char != null && char.hasAnim(event.params[1])) char.playAnim(event.params[1], event.params[2], event.params[3] == "NONE" ? null : event.params[3]);
|
||||||
case "Unknown": // nothing
|
case "Unknown": // nothing
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gameAndCharsEvent("onPostEvent", e);
|
||||||
}
|
}
|
||||||
|
|
||||||
@:dox(hide)
|
@:dox(hide)
|
||||||
@@ -1944,9 +1966,9 @@ class PlayState extends MusicBeatState
|
|||||||
|
|
||||||
var event:NoteHitEvent;
|
var event:NoteHitEvent;
|
||||||
if (strumLine != null && !strumLine.cpu)
|
if (strumLine != null && !strumLine.cpu)
|
||||||
event = EventManager.get(NoteHitEvent).recycle(false, !note.isSustainNote, !note.isSustainNote, null, defaultDisplayRating, defaultDisplayCombo, note, strumLine.characters, true, note.noteType, note.animSuffix.getDefault(note.strumID < strumLine.members.length ? strumLine.members[note.strumID].animSuffix : strumLine.animSuffix), "game/score/", "", note.strumID, rating.score, note.isSustainNote ? null : rating.accuracy, 0.023, rating.name, Options.splashesEnabled && !note.isSustainNote && rating.splash, 0.5, true, 0.7, true, true, iconP1);
|
event = EventManager.get(NoteHitEvent).recycle(rating.breaksCombo, !note.isSustainNote, !note.isSustainNote, null, defaultDisplayRating, defaultDisplayCombo, note, strumLine.characters, true, note.noteType, note.animSuffix.getDefault(note.strumID < strumLine.members.length ? strumLine.members[note.strumID].animSuffix : strumLine.animSuffix), "game/score/", "", note.strumID, rating.score, note.isSustainNote ? null : rating.accuracy, rating.health, rating.name, Options.splashesEnabled && !note.isSustainNote && rating.splash, 0.5, true, 0.7, true, true, iconP1);
|
||||||
else
|
else
|
||||||
event = EventManager.get(NoteHitEvent).recycle(false, false, false, null, defaultDisplayRating, defaultDisplayCombo, note, strumLine.characters, false, note.noteType, note.animSuffix.getDefault(note.strumID < strumLine.members.length ? strumLine.members[note.strumID].animSuffix : strumLine.animSuffix), "game/score/", "", note.strumID, 0, null, 0, rating.name, false, 0.5, true, 0.7, true, true, iconP2);
|
event = EventManager.get(NoteHitEvent).recycle(rating.breaksCombo, false, false, null, defaultDisplayRating, defaultDisplayCombo, note, strumLine.characters, false, note.noteType, note.animSuffix.getDefault(note.strumID < strumLine.members.length ? strumLine.members[note.strumID].animSuffix : strumLine.animSuffix), "game/score/", "", note.strumID, 0, null, 0, rating.name, false, 0.5, true, 0.7, true, true, iconP2);
|
||||||
event.deleteNote = !note.isSustainNote; // work around, to allow sustain notes to be deleted
|
event.deleteNote = !note.isSustainNote; // work around, to allow sustain notes to be deleted
|
||||||
event = scripts.event(strumLine != null && !strumLine.cpu ? "onPlayerHit" : "onDadHit", event);
|
event = scripts.event(strumLine != null && !strumLine.cpu ? "onPlayerHit" : "onDadHit", event);
|
||||||
strumLine.onHit.dispatch(event);
|
strumLine.onHit.dispatch(event);
|
||||||
@@ -1962,7 +1984,11 @@ class PlayState extends MusicBeatState
|
|||||||
totalAccuracyAmount += event.accuracy;
|
totalAccuracyAmount += event.accuracy;
|
||||||
updateRating();
|
updateRating();
|
||||||
}
|
}
|
||||||
if (event.countAsCombo) combo++;
|
if (event.misses) {
|
||||||
|
combo = 0;
|
||||||
|
misses++;
|
||||||
|
} else if (event.countAsCombo)
|
||||||
|
combo++;
|
||||||
|
|
||||||
if (event.showRating || (event.showRating == null && event.player))
|
if (event.showRating || (event.showRating == null && event.player))
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -20,8 +20,6 @@ class Splash extends FunkinSprite
|
|||||||
@:privateAccess {
|
@:privateAccess {
|
||||||
spr.setPosition(source.x, source.y);
|
spr.setPosition(source.x, source.y);
|
||||||
spr.frames = source.frames;
|
spr.frames = source.frames;
|
||||||
if (source.animateAtlas != null && source.atlasPath != null)
|
|
||||||
spr.loadSprite(source.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;
|
||||||
@@ -29,8 +27,6 @@ class Splash extends FunkinSprite
|
|||||||
spr.scale.set(source.scale.x, source.scale.y);
|
spr.scale.set(source.scale.x, source.scale.y);
|
||||||
spr.scrollFactor.set(source.scrollFactor.x, source.scrollFactor.y);
|
spr.scrollFactor.set(source.scrollFactor.x, source.scrollFactor.y);
|
||||||
spr.skew.set(source.skew.x, source.skew.y);
|
spr.skew.set(source.skew.x, source.skew.y);
|
||||||
spr.transformMatrix = source.transformMatrix;
|
|
||||||
spr.matrixExposed = source.matrixExposed;
|
|
||||||
spr.zoomFactor = source.zoomFactor;
|
spr.zoomFactor = source.zoomFactor;
|
||||||
spr.animOffsets = source.animOffsets.copy();
|
spr.animOffsets = source.animOffsets.copy();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
package funkin.game;
|
package funkin.game;
|
||||||
|
|
||||||
import flixel.math.FlxPoint;
|
import flixel.math.FlxPoint;
|
||||||
|
import flixel.math.FlxAngle;
|
||||||
|
import flixel.util.typeLimit.OneOfTwo;
|
||||||
import funkin.backend.system.Conductor;
|
import funkin.backend.system.Conductor;
|
||||||
|
|
||||||
class Strum extends FlxSprite {
|
class Strum extends FlxSprite {
|
||||||
@@ -51,8 +53,27 @@ class Strum extends FlxSprite {
|
|||||||
public var updateNotesPosY:Bool = true;
|
public var updateNotesPosY:Bool = true;
|
||||||
public var extraCopyFields(default, set):Array<String> = [];
|
public var extraCopyFields(default, set):Array<String> = [];
|
||||||
|
|
||||||
private inline function set_extraCopyFields(val:Array<String>)
|
@:noCompletion public var __cachedCopyFields:Array<Array<OneOfTwo<String, Int>>> = null;
|
||||||
return extraCopyFields = val == null ? [] : val;
|
|
||||||
|
private function set_extraCopyFields(val:Array<String>) {
|
||||||
|
extraCopyFields = val == null ? [] : val;
|
||||||
|
__cachedCopyFields = null;
|
||||||
|
return extraCopyFields;
|
||||||
|
}
|
||||||
|
|
||||||
|
private inline function __initCachedCopyFields() {
|
||||||
|
if (__cachedCopyFields != null) return;
|
||||||
|
__cachedCopyFields = [for (field in extraCopyFields) CoolUtil.parsePropertyString(field)];
|
||||||
|
}
|
||||||
|
|
||||||
|
private inline function __applyCopyFields(daNote:Note) {
|
||||||
|
for (i in 0...extraCopyFields.length) {
|
||||||
|
final parsed = __cachedCopyFields[i];
|
||||||
|
final fromProp = CoolUtil.parseProperty(this, parsed);
|
||||||
|
final toProp = CoolUtil.parseProperty(daNote, parsed);
|
||||||
|
toProp.setValue(fromProp.getValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whenever the strum is pressed.
|
* Whenever the strum is pressed.
|
||||||
@@ -128,13 +149,28 @@ class Strum extends FlxSprite {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public override function draw() {
|
public override function draw() {
|
||||||
lastDrawCameras = cameras.copy();
|
if (cameras.length == 1) {
|
||||||
|
if (lastDrawCameras.length != 1 || lastDrawCameras[0] != cameras[0]) {
|
||||||
|
lastDrawCameras = [cameras[0]];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
lastDrawCameras = cameras.copy();
|
||||||
|
}
|
||||||
super.draw();
|
super.draw();
|
||||||
}
|
}
|
||||||
|
|
||||||
@:noCompletion public static inline final PIX180:Float = 565.4866776461628; // 180 * Math.PI
|
@:noCompletion public static inline final PIX180:Float = 565.4866776461628; // 180 * Math.PI
|
||||||
@:noCompletion public static final N_WIDTHDIV2:Float = Note.swagWidth / 2; // DEPRECATED
|
@:noCompletion public static final N_WIDTHDIV2:Float = Note.swagWidth / 2; // DEPRECATED
|
||||||
|
|
||||||
|
static var __lastStrumW:Float = Math.NaN;
|
||||||
|
static var __lastStrumH:Float = Math.NaN;
|
||||||
|
static var __lastStrumHalfW:Float = 0;
|
||||||
|
static var __lastStrumHalfH:Float = 0;
|
||||||
|
static var __noteOffset:FlxPoint = FlxPoint.get();
|
||||||
|
static var __lastNoteAngle:Float = Math.NaN;
|
||||||
|
static var __lastAngleCos:Float = 0;
|
||||||
|
static var __lastAngleSin:Float = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates the position of a note.
|
* Updates the position of a note.
|
||||||
* @param daNote The note
|
* @param daNote The note
|
||||||
@@ -152,8 +188,10 @@ class Strum extends FlxSprite {
|
|||||||
}
|
}
|
||||||
|
|
||||||
updateNotePos(daNote);
|
updateNotePos(daNote);
|
||||||
for (field in extraCopyFields)
|
if (extraCopyFields.length > 0) {
|
||||||
CoolUtil.cloneProperty(daNote, field, this); // TODO: make this cached to reduce the reflection calls - Neo
|
__initCachedCopyFields();
|
||||||
|
__applyCopyFields(daNote);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private inline function updateNotePos(daNote:Note) {
|
private inline function updateNotePos(daNote:Note) {
|
||||||
@@ -162,40 +200,40 @@ class Strum extends FlxSprite {
|
|||||||
|
|
||||||
if (shouldX || shouldY) {
|
if (shouldX || shouldY) {
|
||||||
if (daNote.strumRelativePos) {
|
if (daNote.strumRelativePos) {
|
||||||
if (shouldX) daNote.x = (this.width - daNote.width) * 0.5;
|
if (shouldX) daNote.x = 0;
|
||||||
if (shouldY) {
|
if (shouldY) {
|
||||||
daNote.y = (daNote.strumTime - Conductor.songPosition) * (0.45 * getScrollSpeed(daNote));
|
daNote.y = ((daNote.strumTime - Conductor.songPosition) * 0.45 * getScrollSpeed(daNote));
|
||||||
if (daNote.isSustainNote) daNote.y += height * 0.5;
|
if (daNote.isSustainNote) daNote.y += daNote.height * 0.5;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
var offset = FlxPoint.get(0, (Conductor.songPosition - daNote.strumTime) * (0.45 * getScrollSpeed(daNote)));
|
if (width != __lastStrumW || height != __lastStrumH) {
|
||||||
var realOffset = FlxPoint.get(0, 0);
|
__lastStrumW = width;
|
||||||
|
__lastStrumH = height;
|
||||||
if (daNote.isSustainNote) offset.y -= height * 0.5;
|
__lastStrumHalfW = width * 0.5;
|
||||||
|
__lastStrumHalfH = height * 0.5;
|
||||||
if (Std.int(daNote.__noteAngle % 360) != 0) {
|
|
||||||
var noteAngleCos = FlxMath.fastCos(daNote.__noteAngle / PIX180);
|
|
||||||
var noteAngleSin = FlxMath.fastSin(daNote.__noteAngle / PIX180);
|
|
||||||
|
|
||||||
var aOffset:FlxPoint = FlxPoint.get(
|
|
||||||
(daNote.origin.x / daNote.scale.x) - daNote.offset.x,
|
|
||||||
(daNote.origin.y / daNote.scale.y) - daNote.offset.y
|
|
||||||
);
|
|
||||||
realOffset.x = -aOffset.x + (noteAngleCos * (offset.x + aOffset.x)) + (noteAngleSin * (offset.y + aOffset.y));
|
|
||||||
realOffset.y = -aOffset.y + (noteAngleSin * (offset.x + aOffset.x)) + (noteAngleCos * (offset.y + aOffset.y));
|
|
||||||
|
|
||||||
aOffset.put();
|
|
||||||
} else {
|
|
||||||
realOffset.x = offset.x;
|
|
||||||
realOffset.y = offset.y;
|
|
||||||
}
|
}
|
||||||
realOffset.y *= -1;
|
|
||||||
|
|
||||||
if (shouldX) daNote.x = x + realOffset.x;
|
if (daNote.__noteAngle != __lastNoteAngle) {
|
||||||
if (shouldY) daNote.y = y + realOffset.y;
|
__lastNoteAngle = daNote.__noteAngle;
|
||||||
|
final result = FlxMath.fastSinCos((__lastNoteAngle + 90) * FlxAngle.TO_RAD);
|
||||||
|
__lastAngleCos = result.cos;
|
||||||
|
__lastAngleSin = result.sin;
|
||||||
|
}
|
||||||
|
|
||||||
offset.put();
|
final speed = getScrollSpeed(daNote);
|
||||||
realOffset.put();
|
final distance = (daNote.strumTime - Conductor.songPosition) * 0.45 * speed;
|
||||||
|
__noteOffset.set(__lastAngleCos * distance, __lastAngleSin * distance);
|
||||||
|
__noteOffset.x += -daNote.origin.x + daNote.offset.x;
|
||||||
|
__noteOffset.y += -daNote.origin.y + daNote.offset.y;
|
||||||
|
if (daNote.isSustainNote) {
|
||||||
|
final m = (daNote.height * 0.5 * (speed < 0 ? -1 : 1));
|
||||||
|
__noteOffset.x += __lastAngleCos * m;
|
||||||
|
__noteOffset.y += __lastAngleSin * m;
|
||||||
|
}
|
||||||
|
__noteOffset.x += x + __lastStrumHalfW;
|
||||||
|
__noteOffset.y += y + __lastStrumHalfH;
|
||||||
|
if (shouldX) daNote.x = __noteOffset.x;
|
||||||
|
if (shouldY) daNote.y = __noteOffset.y;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -74,6 +74,10 @@ class StrumLine extends FlxTypedGroup<Strum> {
|
|||||||
* Which animation suffix on characters that should be used when hitting notes.
|
* Which animation suffix on characters that should be used when hitting notes.
|
||||||
*/
|
*/
|
||||||
public var animSuffix(default, set):String = "";
|
public var animSuffix(default, set):String = "";
|
||||||
|
/**
|
||||||
|
* The current animation suffix the strumline should use. Note that setting this will only take effect upon the alt. animation being reset.
|
||||||
|
*/
|
||||||
|
public var defaultAnimSuffix:String = Flags.DEFAULT_ALT_ANIM_SUFFIX;
|
||||||
/**
|
/**
|
||||||
* TODO: Write documentation about this being a variable that can help when making multi key
|
* TODO: Write documentation about this being a variable that can help when making multi key
|
||||||
*/
|
*/
|
||||||
@@ -258,21 +262,28 @@ class StrumLine extends FlxTypedGroup<Strum> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
function __inputProcessJustPressed(note:Note) {
|
function __inputProcessJustPressed(note:Note) {
|
||||||
if (__justPressed[note.strumID] && !note.isSustainNote && !note.wasGoodHit && note.canBeHit) {
|
var strumID = note.strumID;
|
||||||
var cur = __notePerStrum[note.strumID];
|
if (!__justPressed[strumID] || note.isSustainNote || note.wasGoodHit || !note.canBeHit) return;
|
||||||
var songPos = __updateNote_songPos;
|
|
||||||
|
var cur = __notePerStrum[strumID];
|
||||||
var noteDist = Math.abs(note.strumTime - songPos);
|
if (cur == null) {
|
||||||
var curDist = cur != null ? Math.abs(cur.strumTime - songPos) : 999999;
|
__notePerStrum[strumID] = note;
|
||||||
|
return;
|
||||||
var notePenalty = note.avoid ? 1 : 0;
|
|
||||||
var curPenalty = (cur != null && cur.avoid) ? 1 : 0;
|
|
||||||
|
|
||||||
if (cur == null
|
|
||||||
|| notePenalty < curPenalty
|
|
||||||
|| (notePenalty == curPenalty && noteDist < curDist))
|
|
||||||
__notePerStrum[note.strumID] = note;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var songPos = __updateNote_songPos;
|
||||||
|
var noteDist = Math.abs(note.strumTime - songPos);
|
||||||
|
|
||||||
|
var noteShouldAvoid = note.avoid;
|
||||||
|
var curShouldAvoid = cur.avoid;
|
||||||
|
if (!noteShouldAvoid && curShouldAvoid) {
|
||||||
|
__notePerStrum[strumID] = note;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var curDist = Math.abs(cur.strumTime - songPos);
|
||||||
|
if (noteShouldAvoid == curShouldAvoid && noteDist < curDist)
|
||||||
|
__notePerStrum[strumID] = note;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -284,13 +295,18 @@ class StrumLine extends FlxTypedGroup<Strum> {
|
|||||||
|
|
||||||
if (cpu) return;
|
if (cpu) return;
|
||||||
|
|
||||||
if (__pressed.length != members.length) {
|
final membersLength = members.length;
|
||||||
__pressed.resize(members.length);
|
|
||||||
__justPressed.resize(members.length);
|
if (__pressed.length != membersLength) {
|
||||||
__justReleased.resize(members.length);
|
__pressed.resize(membersLength);
|
||||||
|
__justPressed.resize(membersLength);
|
||||||
|
__justReleased.resize(membersLength);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i in 0...members.length) {
|
if (__notePerStrum.length != membersLength)
|
||||||
|
__notePerStrum = cast new haxe.ds.Vector(membersLength); // [for(_ in 0...members.length) null];
|
||||||
|
|
||||||
|
for (i in 0...membersLength) {
|
||||||
__pressed[i] = members[i].__getPressed(this);
|
__pressed[i] = members[i].__getPressed(this);
|
||||||
__justPressed[i] = members[i].__getJustPressed(this);
|
__justPressed[i] = members[i].__getJustPressed(this);
|
||||||
__justReleased[i] = members[i].__getJustReleased(this);
|
__justReleased[i] = members[i].__getJustReleased(this);
|
||||||
@@ -304,18 +320,20 @@ class StrumLine extends FlxTypedGroup<Strum> {
|
|||||||
__justPressed = CoolUtil.getDefault(event.justPressed, []);
|
__justPressed = CoolUtil.getDefault(event.justPressed, []);
|
||||||
__justReleased = CoolUtil.getDefault(event.justReleased, []);
|
__justReleased = CoolUtil.getDefault(event.justReleased, []);
|
||||||
|
|
||||||
__notePerStrum = cast new haxe.ds.Vector(members.length); // [for(_ in 0...members.length) null];
|
|
||||||
|
|
||||||
if (__pressed.contains(true)) {
|
if (__pressed.contains(true)) {
|
||||||
if (__justPressed.contains(true)) {
|
if (__justPressed.contains(true)) {
|
||||||
notes.forEachAlive(__inputProcessJustPressed);
|
notes.forEachAlive(__inputProcessJustPressed);
|
||||||
|
|
||||||
if (!ghostTapping) for (k => pr in __justPressed) if (pr && __notePerStrum[k] == null)
|
for (k => pr in __justPressed)
|
||||||
PlayState.instance.noteMiss(this, null, k, ID); // FUCK YOU
|
{
|
||||||
|
var note = __notePerStrum[k];
|
||||||
|
|
||||||
for (e in __notePerStrum)
|
if (note != null) {
|
||||||
if (e != null)
|
PlayState.instance.goodNoteHit(this, note);
|
||||||
PlayState.instance.goodNoteHit(this, e);
|
__notePerStrum[k] = null;
|
||||||
|
} else if (pr && !ghostTapping)
|
||||||
|
PlayState.instance.noteMiss(this, null, k, ID);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (c in characters)
|
for (c in characters)
|
||||||
@@ -433,6 +451,9 @@ class StrumLine extends FlxTypedGroup<Strum> {
|
|||||||
public static inline function calculateStartingXPos(hudXRatio:Float, scale:Float, spacing:Float, keyCount:Int) {
|
public static inline function calculateStartingXPos(hudXRatio:Float, scale:Float, spacing:Float, keyCount:Int) {
|
||||||
return (FlxG.width * hudXRatio) - ((Note.swagWidth * scale * ((keyCount/2)-0.5) * spacing) + Note.swagWidth * 0.5 * scale);
|
return (FlxG.width * hudXRatio) - ((Note.swagWidth * scale * ((keyCount/2)-0.5) * spacing) + Note.swagWidth * 0.5 * scale);
|
||||||
}
|
}
|
||||||
|
public static inline function calculateStartingXPosFromInitialWidth(hudXRatio:Float, scale:Float, spacing:Float, keyCount:Int) {
|
||||||
|
return (FlxG.initialWidth * hudXRatio) - ((Note.swagWidth * scale * ((keyCount/2)-0.5) * spacing) + Note.swagWidth * 0.5 * scale);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* SETTERS & GETTERS
|
* SETTERS & GETTERS
|
||||||
@@ -451,11 +472,11 @@ class StrumLine extends FlxTypedGroup<Strum> {
|
|||||||
return animSuffix = str;
|
return animSuffix = str;
|
||||||
}
|
}
|
||||||
private inline function set_altAnim(b:Bool):Bool {
|
private inline function set_altAnim(b:Bool):Bool {
|
||||||
animSuffix = b ? "-alt" : "";
|
animSuffix = b ? defaultAnimSuffix : "";
|
||||||
return b;
|
return b;
|
||||||
}
|
}
|
||||||
private inline function get_altAnim():Bool {
|
private inline function get_altAnim():Bool {
|
||||||
return animSuffix == "-alt";
|
return animSuffix == defaultAnimSuffix;
|
||||||
}
|
}
|
||||||
#end
|
#end
|
||||||
}
|
}
|
||||||
@@ -103,14 +103,9 @@ class VideoCutscene extends Cutscene {
|
|||||||
FlxTween.tween(loadingBackdrop, {alpha: 1}, 0.5, {ease: FlxEase.sineInOut});
|
FlxTween.tween(loadingBackdrop, {alpha: 1}, 0.5, {ease: FlxEase.sineInOut});
|
||||||
|
|
||||||
Main.execAsync(function() {
|
Main.execAsync(function() {
|
||||||
if (localPath.startsWith("[ZIP]")) {
|
if (video.load(localPath)) new FlxTimer().start(0.001, function(_) {
|
||||||
// ZIP PATH: EXPORT
|
mutex.acquire(); onReady(); mutex.release();
|
||||||
// TODO: this but better and more ram friendly
|
});
|
||||||
localPath = './.temp/video-${curVideo++}.mp4';
|
|
||||||
File.saveBytes(localPath, Assets.getBytes(path));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (video.load(localPath)) new FlxTimer().start(0.001, function(_) { mutex.acquire(); onReady(); mutex.release(); });
|
|
||||||
else { mutex.acquire(); close(); mutex.release(); }
|
else { mutex.acquire(); close(); mutex.release(); }
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -182,6 +177,7 @@ class VideoCutscene extends Cutscene {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public inline function onReady() {
|
public inline function onReady() {
|
||||||
|
trace("VideoCutscene: Ready");
|
||||||
FlxTween.cancelTweensOf(loadingBackdrop);
|
FlxTween.cancelTweensOf(loadingBackdrop);
|
||||||
FlxTween.tween(loadingBackdrop, {alpha: 0}, 0.7, {ease: FlxEase.sineInOut, onComplete: function(_) {
|
FlxTween.tween(loadingBackdrop, {alpha: 0}, 0.7, {ease: FlxEase.sineInOut, onComplete: function(_) {
|
||||||
loadingBackdrop.destroy();
|
loadingBackdrop.destroy();
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package funkin.game.scoring;
|
|||||||
|
|
||||||
import funkin.game.scoring.*;
|
import funkin.game.scoring.*;
|
||||||
import funkin.game.scoring.HitWindowData.WindowPreset;
|
import funkin.game.scoring.HitWindowData.WindowPreset;
|
||||||
|
import flixel.util.FlxSignal;
|
||||||
|
|
||||||
import haxe.ds.StringMap;
|
import haxe.ds.StringMap;
|
||||||
|
|
||||||
@@ -10,6 +11,9 @@ import haxe.ds.StringMap;
|
|||||||
*/
|
*/
|
||||||
class RatingManager
|
class RatingManager
|
||||||
{
|
{
|
||||||
|
public var onRatingAdded:FlxTypedSignal<Rating->Void> = new FlxTypedSignal();
|
||||||
|
public var onRatingRemoved:FlxTypedSignal<Rating->Void> = new FlxTypedSignal();
|
||||||
|
|
||||||
public var hitWindows:StringMap<Float>;
|
public var hitWindows:StringMap<Float>;
|
||||||
public var ratingData:Array<Rating> = [];
|
public var ratingData:Array<Rating> = [];
|
||||||
public var lastHitWindow:Float = -1;
|
public var lastHitWindow:Float = -1;
|
||||||
@@ -50,9 +54,9 @@ class RatingManager
|
|||||||
}
|
}
|
||||||
|
|
||||||
addRating({name: "sick", window: getWindow("sick"), accuracy: 1, score: 300, splash: true});
|
addRating({name: "sick", window: getWindow("sick"), accuracy: 1, score: 300, splash: true});
|
||||||
addRating({name: "good", window: getWindow("good"), accuracy: 0.75, score: 200});
|
addRating({name: "good", window: getWindow("good"), accuracy: 0.75, score: 200, health: 0.015});
|
||||||
addRating({name: "bad", window: getWindow("bad"), accuracy: 0.45, score: 100});
|
addRating({name: "bad", window: getWindow("bad"), accuracy: 0.45, score: 100, health: 0});
|
||||||
addRating({name: "shit", window: getWindow("shit"), accuracy: 0.25, score: 50});
|
addRating({name: "shit", window: getWindow("shit"), accuracy: 0.25, score: 50, health: -0.05, breaksCombo: true});
|
||||||
}
|
}
|
||||||
|
|
||||||
public function addRating(data:Dynamic)
|
public function addRating(data:Dynamic)
|
||||||
@@ -71,7 +75,9 @@ class RatingManager
|
|||||||
window: window,
|
window: window,
|
||||||
accuracy: data.accuracy != null ? data.accuracy : 1,
|
accuracy: data.accuracy != null ? data.accuracy : 1,
|
||||||
score: data.score != null ? data.score : 0,
|
score: data.score != null ? data.score : 0,
|
||||||
|
health: data.health != null ? data.health : 0.023,
|
||||||
splash: data.splash == true,
|
splash: data.splash == true,
|
||||||
|
breaksCombo: data.breaksCombo == true,
|
||||||
hittable: data.hittable != null ? data.hittable : true
|
hittable: data.hittable != null ? data.hittable : true
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -86,13 +92,18 @@ class RatingManager
|
|||||||
ratingData.push(newRating);
|
ratingData.push(newRating);
|
||||||
|
|
||||||
ratingData.sort((a, b) -> Reflect.compare(a.window, b.window));
|
ratingData.sort((a, b) -> Reflect.compare(a.window, b.window));
|
||||||
|
onRatingAdded.dispatch(newRating);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function removeRating(name:String):Void
|
public function removeRating(name:String):Void
|
||||||
{
|
{
|
||||||
if (name == null) return;
|
if (name == null) return;
|
||||||
name = name.toLowerCase();
|
name = name.toLowerCase();
|
||||||
ratingData = ratingData.filter(r -> r.name != name);
|
var toRemove = ratingData.filter(r -> r.name == name);
|
||||||
|
for (rating in toRemove) {
|
||||||
|
ratingData.remove(rating);
|
||||||
|
onRatingRemoved.dispatch(rating);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getHitWindow(name:String):Float
|
public function getHitWindow(name:String):Float
|
||||||
@@ -126,11 +137,21 @@ final class Rating
|
|||||||
*/
|
*/
|
||||||
public var score:Int = 0;
|
public var score:Int = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Amount of health given when earning this rating.
|
||||||
|
*/
|
||||||
|
public var health:Float = 0.023;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If this rating was hit, a note splash will appear.
|
* If this rating was hit, a note splash will appear.
|
||||||
*/
|
*/
|
||||||
@:optional public var splash:Bool = false;
|
@:optional public var splash:Bool = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether the rating will break your combo or not.
|
||||||
|
*/
|
||||||
|
@:optional public var breaksCombo:Bool = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether the rating is hittable or not.
|
* Whether the rating is hittable or not.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -261,7 +261,7 @@ class FreeplayState extends MusicBeatState
|
|||||||
if (!disableAutoPlay && !songInstPlaying && (autoplayElapsed > timeUntilAutoplay)) {
|
if (!disableAutoPlay && !songInstPlaying && (autoplayElapsed > timeUntilAutoplay)) {
|
||||||
if (curPlayingInst != (curPlayingInst = Paths.inst(curSong.name, curDifficulties[curDifficulty], curSong.instSuffix))) {
|
if (curPlayingInst != (curPlayingInst = Paths.inst(curSong.name, curDifficulties[curDifficulty], curSong.instSuffix))) {
|
||||||
var streamed = false;
|
var streamed = false;
|
||||||
if (Options.streamedMusic) {
|
/*if (Options.streamedMusic) {
|
||||||
var sound = Assets.getMusic(curPlayingInst, true, false);
|
var sound = Assets.getMusic(curPlayingInst, true, false);
|
||||||
streamed = sound != null;
|
streamed = sound != null;
|
||||||
|
|
||||||
@@ -269,7 +269,7 @@ class FreeplayState extends MusicBeatState
|
|||||||
FlxG.sound.playMusic(sound, 0);
|
FlxG.sound.playMusic(sound, 0);
|
||||||
Conductor.changeBPM(curSong.bpm, curSong.beatsPerMeasure, curSong.stepsPerBeat);
|
Conductor.changeBPM(curSong.bpm, curSong.beatsPerMeasure, curSong.stepsPerBeat);
|
||||||
}
|
}
|
||||||
}
|
}*/
|
||||||
|
|
||||||
if (!streamed) {
|
if (!streamed) {
|
||||||
var huh:Void->Void = function() {
|
var huh:Void->Void = function() {
|
||||||
@@ -290,7 +290,7 @@ class FreeplayState extends MusicBeatState
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
songInstPlaying = true;
|
songInstPlaying = true;
|
||||||
if (disableAsyncLoading && !Options.streamedMusic) dontPlaySongThisFrame = true;
|
if (disableAsyncLoading/* && !Options.streamedMusic*/) dontPlaySongThisFrame = true;
|
||||||
}
|
}
|
||||||
#end
|
#end
|
||||||
|
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ class ModSwitchMenu extends MusicBeatSubstate {
|
|||||||
|
|
||||||
alphabets = new FlxTypedGroup<Alphabet>();
|
alphabets = new FlxTypedGroup<Alphabet>();
|
||||||
for(mod in mods) {
|
for(mod in mods) {
|
||||||
var a = new Alphabet(0, 0, mod == null ? TU.translate("mods.disableMods") : mod, "bold");
|
var a = new Alphabet(0, 0, mod == null ? TU.translate("mods.disableMods") : Path.withoutExtension(mod), "bold");
|
||||||
if(mod == ModsFolder.currentModFolder)
|
if(mod == ModsFolder.currentModFolder)
|
||||||
a.color = FlxColor.LIME;
|
a.color = FlxColor.LIME;
|
||||||
a.isMenuItem = true;
|
a.isMenuItem = true;
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ final class AlphabetComponent {
|
|||||||
public var cos:Float;
|
public var cos:Float;
|
||||||
public var scaleX:Float;
|
public var scaleX:Float;
|
||||||
public var scaleY:Float;
|
public var scaleY:Float;
|
||||||
|
|
||||||
public var flipX:Bool;
|
public var flipX:Bool;
|
||||||
public var flipY:Bool;
|
public var flipY:Bool;
|
||||||
|
|
||||||
@@ -281,7 +281,7 @@ class Alphabet extends FlxSprite {
|
|||||||
var anim = getLetterAnim(letter, data, __component, i);
|
var anim = getLetterAnim(letter, data, __component, i);
|
||||||
//if (cantrace)
|
//if (cantrace)
|
||||||
//trace(anim.name + " | " + __component.anim + " | " + frames.frames[anim.frames[0]]);
|
//trace(anim.name + " | " + __component.anim + " | " + frames.frames[anim.frames[0]]);
|
||||||
advance = (Math.isNaN(advance)) ? getAdvance(letter, anim, data) : advance;
|
advance = (Math.isNaN(advance) && i >= data.startIndex) ? getAdvance(letter, anim, data) : advance;
|
||||||
|
|
||||||
if (anim == null || __renderData.alpha <= 0.0)
|
if (anim == null || __renderData.alpha <= 0.0)
|
||||||
continue;
|
continue;
|
||||||
@@ -551,7 +551,7 @@ class Alphabet extends FlxSprite {
|
|||||||
angle: angle,
|
angle: angle,
|
||||||
cos: angleCos,
|
cos: angleCos,
|
||||||
sin: angleSin,
|
sin: angleSin,
|
||||||
|
|
||||||
flipX: node.get("flipX") == "true",
|
flipX: node.get("flipX") == "true",
|
||||||
flipY: node.get("flipY") == "true",
|
flipY: node.get("flipY") == "true",
|
||||||
|
|
||||||
@@ -607,7 +607,7 @@ class Alphabet extends FlxSprite {
|
|||||||
angle: angle,
|
angle: angle,
|
||||||
cos: angleCos,
|
cos: angleCos,
|
||||||
sin: angleSin,
|
sin: angleSin,
|
||||||
|
|
||||||
flipX: xFlip,
|
flipX: xFlip,
|
||||||
flipY: yFlip,
|
flipY: yFlip,
|
||||||
|
|
||||||
@@ -630,7 +630,7 @@ class Alphabet extends FlxSprite {
|
|||||||
angle: angle,
|
angle: angle,
|
||||||
cos: angleCos,
|
cos: angleCos,
|
||||||
sin: angleSin,
|
sin: angleSin,
|
||||||
|
|
||||||
flipX: xFlip,
|
flipX: xFlip,
|
||||||
flipY: yFlip,
|
flipY: yFlip,
|
||||||
|
|
||||||
@@ -664,7 +664,7 @@ class Alphabet extends FlxSprite {
|
|||||||
var xScale:Float = Std.parseFloat(node.get("scaleX")).getDefaultFloat(1.0);
|
var xScale:Float = Std.parseFloat(node.get("scaleX")).getDefaultFloat(1.0);
|
||||||
var yScale:Float = Std.parseFloat(node.get("scaleY")).getDefaultFloat(1.0);
|
var yScale:Float = Std.parseFloat(node.get("scaleY")).getDefaultFloat(1.0);
|
||||||
var advance:Float = Std.parseFloat(node.get("advance"));
|
var advance:Float = Std.parseFloat(node.get("advance"));
|
||||||
|
|
||||||
var xFlip = node.get("flipX") == "true";
|
var xFlip = node.get("flipX") == "true";
|
||||||
var yFlip = node.get("flipY") == "true";
|
var yFlip = node.get("flipY") == "true";
|
||||||
|
|
||||||
@@ -685,7 +685,7 @@ class Alphabet extends FlxSprite {
|
|||||||
angle: angle,
|
angle: angle,
|
||||||
cos: angleCos,
|
cos: angleCos,
|
||||||
sin: angleSin,
|
sin: angleSin,
|
||||||
|
|
||||||
flipX: xFlip,
|
flipX: xFlip,
|
||||||
flipY: yFlip,
|
flipY: yFlip,
|
||||||
|
|
||||||
|
|||||||
@@ -43,8 +43,8 @@ class Options
|
|||||||
public static var framerate:Int = 120;
|
public static var framerate:Int = 120;
|
||||||
public static var gpuOnlyBitmaps:Bool = #if (mac || web) false #else true #end; // causes issues on mac and web
|
public static var gpuOnlyBitmaps:Bool = #if (mac || web) false #else true #end; // causes issues on mac and web
|
||||||
public static var language = "en"; // default to english, Flags.DEFAULT_LANGUAGE should not modify this
|
public static var language = "en"; // default to english, Flags.DEFAULT_LANGUAGE should not modify this
|
||||||
public static var streamedMusic:Bool = true;
|
public static var streamedMusic:Bool = false;
|
||||||
public static var streamedVocals:Bool = true;
|
public static var streamedVocals:Bool = false;
|
||||||
public static var quality:Int = 1;
|
public static var quality:Int = 1;
|
||||||
public static var allowConfigWarning:Bool = true;
|
public static var allowConfigWarning:Bool = true;
|
||||||
#if MODCHARTING_FEATURES
|
#if MODCHARTING_FEATURES
|
||||||
@@ -84,6 +84,7 @@ class Options
|
|||||||
public static var charterMetronomeEnabled:Bool = false;
|
public static var charterMetronomeEnabled:Bool = false;
|
||||||
public static var charterShowSections:Bool = true;
|
public static var charterShowSections:Bool = true;
|
||||||
public static var charterShowBeats:Bool = true;
|
public static var charterShowBeats:Bool = true;
|
||||||
|
public static var charterShowCameraHighlights:Bool = true;
|
||||||
public static var charterEnablePlaytestScripts:Bool = true;
|
public static var charterEnablePlaytestScripts:Bool = true;
|
||||||
public static var charterRainbowWaveforms:Bool = false;
|
public static var charterRainbowWaveforms:Bool = false;
|
||||||
public static var charterLowDetailWaveforms:Bool = false;
|
public static var charterLowDetailWaveforms:Bool = false;
|
||||||
|
|||||||
@@ -202,8 +202,8 @@ class OptionsMenu extends TreeMenu {
|
|||||||
Logs.warn("A radio option requires an \"id\" for option saving.");
|
Logs.warn("A radio option requires an \"id\" for option saving.");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
var v:Dynamic = Std.parseFloat(node.att.value);
|
var f = Std.parseFloat(node.att.value);
|
||||||
options.push(new RadioButton(screen, name, desc, node.att.id, v != null ? v : node.att.value, null, FlxG.save.data, node.has.forId ? node.att.forId : null));
|
options.push(new RadioButton(screen, name, desc, node.att.id, Math.isNaN(f) ? node.att.value : f, null, FlxG.save.data, node.has.forId ? node.att.forId : null));
|
||||||
case 'slider':
|
case 'slider':
|
||||||
if (!node.has.id) {
|
if (!node.has.id) {
|
||||||
Logs.warn("A slider option requires an \"id\" for option saving.");
|
Logs.warn("A slider option requires an \"id\" for option saving.");
|
||||||
@@ -223,4 +223,4 @@ class OptionsMenu extends TreeMenu {
|
|||||||
|
|
||||||
return options;
|
return options;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import flixel.util.FlxTimer;
|
|||||||
import funkin.backend.system.Conductor;
|
import funkin.backend.system.Conductor;
|
||||||
|
|
||||||
class GameplayOptions extends TreeMenuScreen {
|
class GameplayOptions extends TreeMenuScreen {
|
||||||
var __metronome = FlxG.sound.load(Paths.sound('editors/charter/metronome'));
|
var __metronome = FlxG.sound.load(Paths.sound(Flags.DEFAULT_CHARTER_METRONOME_SOUND));
|
||||||
var offsetSetting:NumOption;
|
var offsetSetting:NumOption;
|
||||||
|
|
||||||
public function new() {
|
public function new() {
|
||||||
@@ -67,7 +67,14 @@ class AdvancedGameplayOptions extends TreeMenuScreen {
|
|||||||
public function new() {
|
public function new() {
|
||||||
super('optionsMenu.advanced', 'optionsTree.gameplay.advanced-desc', 'GameplayOptions.Advanced.');
|
super('optionsMenu.advanced', 'optionsTree.gameplay.advanced-desc', 'GameplayOptions.Advanced.');
|
||||||
|
|
||||||
add(new Checkbox(getNameID('streamedMusic'), getDescID('streamedMusic'), 'streamedMusic'));
|
// Remove locked whenever this PR from FunkinCrew is merged.
|
||||||
add(new Checkbox(getNameID('streamedVocals'), getDescID('streamedVocals'), 'streamedVocals'));
|
// https://github.com/FunkinCrew/lime/pull/57
|
||||||
|
for (checkbox in [
|
||||||
|
new Checkbox(getNameID('streamedMusic'), getDescID('streamedMusic'), 'streamedMusic'),
|
||||||
|
new Checkbox(getNameID('streamedVocals'), getDescID('streamedVocals'), 'streamedVocals')
|
||||||
|
]) {
|
||||||
|
checkbox.locked = true;
|
||||||
|
add(checkbox);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||