Compare commits
105
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e540cb454b | ||
|
|
8506619465 | ||
|
|
3469524d8c | ||
|
|
90e0e5618d | ||
|
|
7a9edf809c | ||
|
|
7719fd6a10 | ||
|
|
95b4d888f0 | ||
|
|
f5dde710e3 | ||
|
|
3220a2e360 | ||
|
|
86839ac6b3 | ||
|
|
dba8200854 | ||
|
|
a296b33c0f | ||
|
|
a3498ce32b | ||
|
|
d358724fd2 | ||
|
|
4ffd164fd2 | ||
|
|
b87c206d45 | ||
|
|
0f8354415e | ||
|
|
0251fe87bb | ||
|
|
b7c932f9a9 | ||
|
|
11b86c389c | ||
|
|
2b66d74b01 | ||
|
|
3b8859120f | ||
|
|
bacd218e0b | ||
|
|
b2049e6285 | ||
|
|
6612fa6205 | ||
|
|
5d63442626 | ||
|
|
2b77d2820c | ||
|
|
071f651d0b | ||
|
|
079fda42fb | ||
|
|
96aac150f0 | ||
|
|
fa135df33d | ||
|
|
ed8a9c6390 | ||
|
|
282fa0376d | ||
|
|
3dbb22667b | ||
|
|
9a2751733e | ||
|
|
734b13904e | ||
|
|
0803e82e58 | ||
|
|
2d6b85365b | ||
|
|
356607f53a | ||
|
|
f9402fe826 | ||
|
|
be1657884e | ||
|
|
e862d72d71 | ||
|
|
43e6aac281 | ||
|
|
157e209f31 | ||
|
|
b8fef83ef1 | ||
|
|
283929b1a2 | ||
|
|
000546e9ff | ||
|
|
7df13ec012 | ||
|
|
68a5dd2482 | ||
|
|
4f834169f3 | ||
|
|
689eda7114 | ||
|
|
9757b002bd | ||
|
|
3140ee8512 | ||
|
|
c96ee6c465 | ||
|
|
1c4c962f4d | ||
|
|
49d4708265 | ||
|
|
ffa5e66bc8 | ||
|
|
18fcacc2b5 | ||
|
|
a2ff5c112e | ||
|
|
3862995213 | ||
|
|
f7e4875097 | ||
|
|
cabdffd058 | ||
|
|
c28e056a8a | ||
|
|
3fd87c8d52 | ||
|
|
eaacc5dfc2 | ||
|
|
4573fef74d | ||
|
|
978022dc0b | ||
|
|
970d294ea1 | ||
|
|
7568cbfd99 | ||
|
|
c5686b09db | ||
|
|
ce4d1a0d61 | ||
|
|
2eac58aaa5 | ||
|
|
ce98ad0645 | ||
|
|
037f564676 | ||
|
|
5227ed3253 | ||
|
|
9e4b6f31c0 | ||
|
|
fe02ba7b4b | ||
|
|
ec63be9e77 | ||
|
|
88ea51064b | ||
|
|
647c70839d | ||
|
|
39237dd01d | ||
|
|
d3bd40baf3 | ||
|
|
7d7db50c19 | ||
|
|
8aa2023057 | ||
|
|
d979b5c33d | ||
|
|
ba50edfc99 | ||
|
|
5acabccd9a | ||
|
|
66c1cd9dde | ||
|
|
ec65cae8fc | ||
|
|
3de652c73e | ||
|
|
8303e7ecfd | ||
|
|
e17b5d6b86 | ||
|
|
0ff829e1c6 | ||
|
|
769a33f138 | ||
|
|
91abb37281 | ||
|
|
32bca0420e | ||
|
|
faa0dbb324 | ||
|
|
14c81ef26d | ||
|
|
62f4819493 | ||
|
|
8ba41990e6 | ||
|
|
6c92fcff8b | ||
|
|
6a802c2281 | ||
|
|
9c7bb8f073 | ||
|
|
6112e2f759 | ||
|
|
3939439086 |
@@ -33,4 +33,8 @@ f8b20774e3f035eeddb9211a28a391b20db74456
|
||||
|
||||
# Revert a revert (empty script)
|
||||
392416e00cbd82e1c49e82a9fafdcf2e069a654e
|
||||
159467de832a172681200c463d244a46e295c3c8
|
||||
159467de832a172681200c463d244a46e295c3c8
|
||||
|
||||
# Revert a revert (scripted cutscene path)
|
||||
d73f86d26ec2dbf031c01f588ba4be11842db09c
|
||||
fe0ab0aa454f4ae12ced9502db8a01e7bca3e04c
|
||||
+3
-2
@@ -5,9 +5,10 @@
|
||||
pages/** linguist-vendored
|
||||
|
||||
# Include HScript files as Haxe
|
||||
*.hxs linguist-language=Haxe
|
||||
*.hsc linguist-language=Haxe
|
||||
*.hscript linguist-language=Haxe
|
||||
*.hsc linguist-language=Haxe
|
||||
*.hxs linguist-language=Haxe
|
||||
*.hxp linguist-language=Haxe
|
||||
|
||||
# Include Shader files as GLSL
|
||||
*.frag linguist-language=GLSL
|
||||
|
||||
@@ -12,9 +12,9 @@ jobs:
|
||||
- name: Pulling the source
|
||||
uses: actions/checkout@v2
|
||||
- name: Setting up Haxe
|
||||
uses: krdlab/setup-haxe@v1
|
||||
uses: krdlab/setup-haxe@v2
|
||||
with:
|
||||
haxe-version: 4.2.5
|
||||
haxe-version: 4.3.7
|
||||
- name: Restore existing build cache for faster compilation
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
|
||||
@@ -12,9 +12,9 @@ jobs:
|
||||
- name: Pulling the new commit
|
||||
uses: actions/checkout@v2
|
||||
- name: Setting up Haxe
|
||||
uses: krdlab/setup-haxe@v1
|
||||
uses: krdlab/setup-haxe@v2
|
||||
with:
|
||||
haxe-version: 4.2.5
|
||||
haxe-version: 4.3.7
|
||||
- name: Restore existing build cache for faster compilation
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
|
||||
@@ -0,0 +1,197 @@
|
||||
name: Create Release Builds
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
tag_name:
|
||||
description: "Release name (e.g. v1.0.5 or v1.2-rc1)"
|
||||
required: true
|
||||
prerelease:
|
||||
description: "Is this a prerelease?"
|
||||
required: true
|
||||
type: boolean
|
||||
custom_message:
|
||||
description: "Optional pre-changelog message"
|
||||
required: false
|
||||
|
||||
jobs:
|
||||
collect-release:
|
||||
name: Release ${{ github.event.inputs.tag_name }} Builds
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Download Windows Full Build
|
||||
uses: dawidd6/action-download-artifact@v6
|
||||
with:
|
||||
workflow: windows.yml
|
||||
name: Codename Engine
|
||||
path: artifacts/windows/full_build
|
||||
allow_forks: false
|
||||
|
||||
- name: Download Windows Executable
|
||||
uses: dawidd6/action-download-artifact@v6
|
||||
with:
|
||||
workflow: windows.yml
|
||||
name: Codename Engine (Executable Only)
|
||||
path: artifacts/windows/executable
|
||||
allow_forks: false
|
||||
|
||||
- name: Download Mac OS Full Build
|
||||
uses: dawidd6/action-download-artifact@v6
|
||||
with:
|
||||
workflow: macos.yml
|
||||
name: Codename Engine
|
||||
path: artifacts/macos/full_build
|
||||
allow_forks: false
|
||||
|
||||
- name: Download Mac OS Executable
|
||||
uses: dawidd6/action-download-artifact@v6
|
||||
with:
|
||||
workflow: macos.yml
|
||||
name: Codename Engine (Executable Only)
|
||||
path: artifacts/macos/executable
|
||||
allow_forks: false
|
||||
|
||||
- name: Download Linux Full Build
|
||||
uses: dawidd6/action-download-artifact@v6
|
||||
with:
|
||||
workflow: linux.yml
|
||||
name: Codename Engine
|
||||
path: artifacts/linux/full_build
|
||||
allow_forks: false
|
||||
|
||||
- name: Download Linux Executable
|
||||
uses: dawidd6/action-download-artifact@v6
|
||||
with:
|
||||
workflow: linux.yml
|
||||
name: Codename Engine (Executable Only)
|
||||
path: artifacts/linux/executable
|
||||
allow_forks: false
|
||||
|
||||
- name: Prepare artifacts
|
||||
run: |
|
||||
mkdir -p renamed
|
||||
|
||||
# Windows
|
||||
mv artifacts/windows/executable/CodenameEngine.exe renamed/update-windows.exe
|
||||
cd artifacts/windows/full_build
|
||||
zip -r ../../../renamed/"Codename Engine-Windows.zip" *
|
||||
cd -
|
||||
|
||||
# Mac OS
|
||||
mv artifacts/macos/executable/CodenameEngine renamed/update-mac
|
||||
cd artifacts/macos/full_build
|
||||
if [ -f CodenameEngine.tar.gz ]; then
|
||||
# Keep tar.gz as-is
|
||||
cp CodenameEngine.tar.gz ../../../renamed/"Codename Engine-Mac.tar.gz"
|
||||
else
|
||||
# Zip contents at root
|
||||
zip -r ../../../renamed/"Codename Engine-Mac.zip" *
|
||||
fi
|
||||
cd -
|
||||
|
||||
# Linux
|
||||
mv artifacts/linux/executable/CodenameEngine renamed/update-linux
|
||||
cd artifacts/linux/full_build
|
||||
zip -r ../../../renamed/"Codename Engine-Linux.zip" *
|
||||
cd -
|
||||
|
||||
- name: Find Base Release
|
||||
id: get_base_release
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
echo "Looking for base release..."
|
||||
PRERELEASE="${{ github.event.inputs.prerelease }}"
|
||||
|
||||
if [[ "$PRERELEASE" == "true" ]]; then
|
||||
BASE=$(gh release list --repo ${{ github.repository }} --json tagName,isPrerelease,isDraft \
|
||||
-L 50 -q '.[] | select(.isPrerelease==false and .isDraft==false) | .tagName' | head -n 1)
|
||||
|
||||
if [ -z "$BASE" ]; then
|
||||
echo "No stable release found, resorting to prereleases."
|
||||
BASE=$(gh release list --repo ${{ github.repository }} --json tagName,isDraft \
|
||||
-L 1 -q '.[] | select(.isDraft==false) | .tagName')
|
||||
fi
|
||||
else
|
||||
BASE=$(gh release list --repo ${{ github.repository }} --json tagName,isPrerelease,isDraft \
|
||||
-L 50 -q '.[] | select(.isPrerelease==false and .isDraft==false) | .tagName' | head -n 1)
|
||||
fi
|
||||
|
||||
if [ -z "$BASE" ]; then
|
||||
echo "No older release found; please make sure to have at least one older release containing the 'update-assets.zip' file in order to generate the differences."
|
||||
exit 1
|
||||
else
|
||||
echo "Base release: $BASE"
|
||||
echo "base_release=$BASE" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
|
||||
- name: Prepare update-assets.zip
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
echo "Looking for 'update-assets.zip' from release '${{ steps.get_base_release.outputs.base_release }}'"
|
||||
ASSETS=$(gh release view "${{ steps.get_base_release.outputs.base_release }}" \
|
||||
--repo "${{ github.repository }}" \
|
||||
--json assets \
|
||||
| jq -r '.assets[].name')
|
||||
|
||||
if echo "$ASSETS" | grep -xq "update-assets.zip"; then
|
||||
mkdir -p update_assets_temp renamed
|
||||
echo "Downloading assets from release '${{ steps.get_base_release.outputs.base_release }}'"
|
||||
gh release download "${{ steps.get_base_release.outputs.base_release }}" \
|
||||
--repo ${{ github.repository }} \
|
||||
--pattern "update-assets.zip" \
|
||||
-D update_assets_temp
|
||||
|
||||
unzip -q update_assets_temp/update-assets.zip -d update_assets_temp
|
||||
cd update_assets_temp
|
||||
zip -r ../renamed/update-assets.zip . -i assets
|
||||
else
|
||||
echo "No 'update-assets.zip' file found in release '${{ steps.get_base_release.outputs.base_release }}'; please make sure to have this file in that older release in order to generate the differences."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: Prepare pre-changelog message
|
||||
id: pre_changelog_message
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
echo "Preparing a pre-changelog message..."
|
||||
|
||||
BODY="If you would like to download the full builds of the engine from this release, please ignore the files starting with 'update-' as they're needed for the engine's internal autoupdater.\n\n"
|
||||
|
||||
if [ -n "${{ github.event.inputs.custom_message }}" ]; then
|
||||
BODY="${{ github.event.inputs.custom_message }}\n${BODY}"
|
||||
fi
|
||||
|
||||
{
|
||||
echo "body<<EOF"
|
||||
echo -e "$BODY"
|
||||
echo "EOF"
|
||||
} >> $GITHUB_OUTPUT
|
||||
echo -e "Final pre-changelog message:\n\n$BODY"
|
||||
|
||||
- name: Create GitHub Release with Assets
|
||||
uses: softprops/action-gh-release@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
tag_name: ${{ github.event.inputs.tag_name }}
|
||||
name: Release ${{ github.event.inputs.tag_name }}
|
||||
draft: true
|
||||
prerelease: ${{ github.event.inputs.prerelease }}
|
||||
body: ${{ steps.build_body.outputs.body }}
|
||||
generate_release_notes: true
|
||||
files: |
|
||||
renamed/Codename Engine-Windows.zip
|
||||
renamed/Codename Engine-Mac.zip
|
||||
renamed/Codename Engine-Mac.tar.gz
|
||||
renamed/Codename Engine-Linux.zip
|
||||
renamed/update-assets.zip
|
||||
renamed/update-windows.exe
|
||||
renamed/update-mac
|
||||
renamed/update-linux
|
||||
@@ -12,9 +12,9 @@ jobs:
|
||||
- name: Pulling the new commit
|
||||
uses: actions/checkout@v2
|
||||
- name: Setting up Haxe
|
||||
uses: krdlab/setup-haxe@v1
|
||||
uses: krdlab/setup-haxe@v2
|
||||
with:
|
||||
haxe-version: 4.2.5
|
||||
haxe-version: 4.3.7
|
||||
- name: Restore existing build cache for faster compilation
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
|
||||
Vendored
+4
-1
@@ -1,12 +1,15 @@
|
||||
{
|
||||
"editor.detectIndentation": false,
|
||||
"editor.insertSpaces": false,
|
||||
"editor.tabSize": 4,
|
||||
"files.associations": {
|
||||
"*.hx": "haxe",
|
||||
"*.hscript": "haxe",
|
||||
"*.hsc": "haxe",
|
||||
"*.hxs": "haxe"
|
||||
"*.hxs": "haxe",
|
||||
"*.hxp": "haxe"
|
||||
},
|
||||
"lime.projectFile": "project.hxp",
|
||||
"lime.targetConfigurations": [
|
||||
{
|
||||
"label": "Windows (Test Build)",
|
||||
|
||||
+2
-6
@@ -26,6 +26,7 @@ This changelog lists every change that has been added since the last update (inc
|
||||
- `--fast` for quickly downloading git libraries, but requires you to reinstall it fully when updates happen
|
||||
- Alphabet now allows multiple lines in the text ([d519db0](https://github.com/CodenameCrew/CodenameEngine/commit/d519db011a14aac0ddfc052089836c6b445f7f44))
|
||||
- Allow importing mod root level modules in hscript, instead of only source/ ([7e66ee8](https://github.com/CodenameCrew/CodenameEngine/commit/7e66ee81e24204cd152de20046fa1500bb9d204b))
|
||||
- Made the substate have the possibility to open automatically transitions ([d31454c](https://github.com/CodenameCrew/CodenameEngine/commit/d31454c7ddf4cbf6a681cc8b32cd3f9480f8eacd))
|
||||
- Added a way to force animations in the `Play Animation` event ([d7b6fbe](https://github.com/CodenameCrew/CodenameEngine/commit/d7b6fbe510edeb832112ab5adc8ab19dfe97d77f))
|
||||
- Adde unused boyfriend animations ([be55696](https://github.com/CodenameCrew/CodenameEngine/commit/be55696bbefe537f06ad6550b039278ffcbcfb2f))
|
||||
- Made it display the keybind for the mod menu in main menu ([1ac2e7f](https://github.com/CodenameCrew/CodenameEngine/commit/1ac2e7f53390a9e92aa2a1fea94d147ed50d3694))
|
||||
@@ -197,9 +198,4 @@ This changelog lists every change that has been added since the last update (inc
|
||||
- Cleaned up the controls code ([c3580cf](https://github.com/CodenameCrew/CodenameEngine/commit/c3580cf1413f90386dd52763042e11b20d21ce2d), [c1123b9](https://github.com/CodenameCrew/CodenameEngine/commit/c1123b9e3c3c1887888744e0c62827231abc48be))
|
||||
- Cleaned up unused variables in TitleState ([2779ef3](https://github.com/CodenameCrew/CodenameEngine/commit/2779ef3314471558e371b3ec2f17f8d4df48943a))
|
||||
- Restructured the events folder ([77b7eeb](https://github.com/CodenameCrew/CodenameEngine/commit/77b7eebed1ea077516ff884902528c0ff3d01872))
|
||||
- Reduced the amount of data thats stored for the Github Contributors savefile ([2abc45a](https://github.com/CodenameCrew/CodenameEngine/commit/2abc45a9e416a1c5dd2bd0a5297c664e60c6f1d8))
|
||||
|
||||
|
||||
## Unsorted list
|
||||
|
||||
- @NexIsDumb Please document this i still dont understand it ([d31454c](https://github.com/CodenameCrew/CodenameEngine/commit/d31454c7ddf4cbf6a681cc8b32cd3f9480f8eacd))
|
||||
- Reduced the amount of data thats stored for the Github Contributors savefile ([2abc45a](https://github.com/CodenameCrew/CodenameEngine/commit/2abc45a9e416a1c5dd2bd0a5297c664e60c6f1d8))
|
||||
+3
-2
@@ -1,5 +1,5 @@
|
||||
# Codename Engine features
|
||||
This markdown file contains every single feature Codename has, separated into multiple categories. List may be incomplete.
|
||||
This markdown file contains most of the main features Codename has, separated into multiple categories.
|
||||
|
||||
_**QOL = Quality of Life**_
|
||||
|
||||
@@ -79,4 +79,5 @@ _**QOL = Quality of Life**_
|
||||
- Features not found in other editors!
|
||||
- Every single state & substate can be modified via HScript (`data/states/StateName.hx`)
|
||||
- **Instances launched via `lime test windows` will automatically use assets from source.**
|
||||
</details>
|
||||
- Modcharting features powered by [FunkinModchart](https://lib.haxe.org/p/funkin-modchart/).
|
||||
</details>
|
||||
|
||||
@@ -1,90 +1,104 @@
|
||||
# Friday Night Funkin' - Codename Engine (WIP)
|
||||
# Friday Night Funkin' - Codename Engine
|
||||
|
||||
## PLEASE NOTE - THIS IS STILL IN A BETA STATE
|
||||
### Mods created with beta versions of Codename may not be compatible with the release version
|
||||
Known issues in the beta:
|
||||
- Some options are missing
|
||||

|
||||
|
||||
Build instructions are below. Press TAB on the main menu to switch mods.
|
||||
Codename Engine is a cross platform [Friday Night Funkin'](https://github.com/FunkinCrew/Funkin) Engine aimed at simplifying modding focusing on softcoding, along with extensiblity and ease of use.<br>
|
||||
It is the the official successor of the previously well known [Yoshi Engine](https://github.com/CodenameCrew/YoshiCrafterEngine).
|
||||
|
||||
Also, the command `.\cne test` uses the source assets folder instead of the export one for easier development (Although you can still use `lime test windows` normally).
|
||||
The engine uses [HaxeFlixel](https://haxeflixel.com/) and it mainly features:
|
||||
- A full scripting system with an optimized fork of [Hscript](https://lib.haxe.org/p/hscript/) (its name is [Hscript Improved](https://github.com/CodenameCrew/hscript-improved))
|
||||
- Uses forks of popular libraries tailored specifically for the engine for the goal of better optimization.
|
||||
- Modding system and softcoding is as capable as source coding.
|
||||
- Focuses heavily on optimization, and encourages its users to also take on optimization practices.
|
||||
- Many modding tools without changing the core gameplay and the base to mod on.
|
||||
- Allows modularity using addons and mods that apply on top of the core mod.
|
||||
- Advanced editors which allows for possibly better experience and easiness when creating the mod.
|
||||
- Much more can be read [HERE](FEATURES.md)
|
||||
|
||||
## Codename Engine
|
||||
> [!NOTE]
|
||||
> Please keep in mind that, despite these differences, we do not consider our engine to be any better or worse than the others.
|
||||
|
||||
Codename Engine is a new Friday Night Funkin' Engine aimed at simplifying modding, along with extensiblity and ease of use.<br>
|
||||
### Before making issues or need help with something, check our website [HERE](https://codename-engine.com/) (it contains a wiki of how to mod with EXAMPLES, an api, lists of mods made with Codename Engine and more)!!!
|
||||
#### The Engine includes many new features, as seen [here](FEATURES.md)<br>
|
||||
#### Wanna see the new features added in the most recent update? Click [here](PATCHNOTES.md)<br>
|
||||
---
|
||||
|
||||
## How to download
|
||||
> [!CAUTION]
|
||||
> Want to use this project's code for different purposes or something similar? Check out the ***Usage Info*** part below first, it basically explains what you can do or not do!<br>
|
||||
> We love open source but we also love proper credits for having respect of all the people who worked hard on this project!!
|
||||
|
||||
Latest builds for the engine can be found in the [Actions](https://github.com/CodenameCrew/CodenameEngine/actions) tab.<br>
|
||||
In the future (when the engine won't be a WIP anymore) we're gonna also publish the engine on platforms like Gamebanana; stay tuned!
|
||||
> [!WARNING]
|
||||
> Before making issues or if you need help with something, check our website [HERE](https://codename-engine.com/).<br>
|
||||
> It contains a wiki of how to mod with EXAMPLES, an api, lists of mods made with Codename Engine and more!
|
||||
|
||||
If you don't have a github account please go onto https://codename-engine.com/ and click the download button for the respective operating system.
|
||||
> [!TIP]
|
||||
> Want to stay updated with this project?<br>
|
||||
> Check out our [patch notes](PATCHNOTES.md)!
|
||||
|
||||
---
|
||||
|
||||
<img width="1080" height="146" alt="immagine" src="https://github.com/user-attachments/assets/93604082-6bac-4ffc-99b0-5393b1e340a4" />
|
||||
|
||||
<br><br>
|
||||
|
||||
<img width="1280" height="720" alt="immagine" src="https://github.com/user-attachments/assets/4106f77a-40f8-4159-9f4e-b601cc79e1d0" />
|
||||
<img width="1280" height="720" alt="immagine" src="https://github.com/user-attachments/assets/2c06f5ea-3462-459b-982e-bf4eddf3d099" />
|
||||
<img width="1280" height="720" alt="immagine" src="https://github.com/user-attachments/assets/4979e256-6b99-4857-8a2a-96abd94f9c4e" />
|
||||
<img width="1280" height="720" alt="immagine" src="https://github.com/user-attachments/assets/55a5a710-55b9-4988-bdcc-0977ba1de97a" />
|
||||
<img width="1280" height="720" alt="immagine" src="https://github.com/user-attachments/assets/4676b035-bec7-445b-a303-78e66f11c479" />
|
||||
|
||||
---
|
||||
|
||||
> [!NOTE]
|
||||
> Codename Engine as for now supports **Windows x64**, **Mac OS x64** and **Linux x64**.<br>
|
||||
> More platforms will soon come, stay tuned!<br>
|
||||
> - [ ] **Web (HTML5) Support**
|
||||
> - [ ] **Mobile Support**
|
||||
|
||||
<details>
|
||||
<summary><h2>How to build</h2></summary>
|
||||
<summary><h2>How to download</h2></summary>
|
||||
|
||||
> **Open the instructions for your platform**
|
||||
<details>
|
||||
<summary>Windows</summary>
|
||||
- Stable builds of the engine can be found on our [GameBanana](https://gamebanana.com/mods/598553) or our [itch.io](https://nex-isdumb.itch.io/codename-engine) pages.
|
||||
- Latest *EXPERIMENTAL* builds of the engine can be found in the [Actions](https://github.com/CodenameCrew/CodenameEngine/actions) tab. **REQUIRES A GITHUB ACCOUNT!!**
|
||||
|
||||
##### Tested on Windows 10 21H2
|
||||
1. Install [version 4.2.5 of Haxe](https://haxe.org/download/version/4.2.5/).
|
||||
2. Download and install [`git-scm`](https://git-scm.com/download/win).
|
||||
- Leave all installation options as default.
|
||||
3. Run `update.bat` using cmd or double-clicking it, and wait for the libraries to install.
|
||||
4. Once the libraries are installed, run `haxelib run lime test windows` to compile and launch the game (may take a long time)
|
||||
- ℹ You can run `haxelib run lime setup` to make the lime command global, allowing you to execute `lime test windows` directly.
|
||||
</details>
|
||||
<details>
|
||||
<summary>Linux</summary>
|
||||
|
||||
##### Requires testing
|
||||
1. Install [version 4.2.5 of Haxe](https://haxe.org/download/version/4.2.5/).
|
||||
2. Install `g++`, if not present already.
|
||||
3. Download and install [`git-scm`](https://git-scm.com/download/linux).
|
||||
4. Open a terminal in the Codename Engine source folder, and run `update.sh`.
|
||||
5. Once the libraries are installed, run `haxelib run lime test linux` to compile and launch the game (may take a long time)
|
||||
- ℹ You can run `haxelib run lime setup` to make the lime command global, allowing you to execute `lime test linux` directly.
|
||||
</details>
|
||||
<details>
|
||||
<summary>MacOS</summary>
|
||||
|
||||
##### Requires testing
|
||||
1. Install [version 4.2.5 of Haxe](https://haxe.org/download/version/4.2.5/).
|
||||
2. Install `Xcode` to allow C++ app building.
|
||||
3. Download and install [`git-scm`](https://git-scm.com/download/mac).
|
||||
4. Open a terminal in the Codename Engine source folder, and run `update.sh`.
|
||||
5. Once the libraries are installed, run `haxelib run lime test mac` to compile and launch the game (may take a long time)
|
||||
- ℹ You can run `haxelib run lime setup` to make the lime command global, allowing you to execute `lime test mac` directly.
|
||||
</details>
|
||||
If you don't have a GitHub account to download experimental builds, you can also go onto our [official website](https://codename-engine.com/) and click the download button for the respective operating system under the **Experimental** section.
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><h2>What can you do or not do</h2></summary>
|
||||
<summary><h2>How to mod</h2></summary>
|
||||
|
||||
### You can:
|
||||
Check out our wiki [HERE](https://codename-engine.com/wiki/)
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><h2>How to setup and build</h2></summary>
|
||||
|
||||
Check out our guide [HERE](building/README.md)
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><h2>Usage Info</h2></summary>
|
||||
|
||||
### Feel free to:
|
||||
- Download and play the engine with its mods and modpacks
|
||||
- Mod and fork the engine (without using it for illicit purposes)
|
||||
- Contribute to the engine (for example through *Pull Requests*, *Issues*, etc)
|
||||
- Contribute to the engine (for example through *Pull Requests*, *Issues*, etc.)
|
||||
- Create a sub engine with Codename Engine as **TEMPLATE** with **CREDITS** (for example leaving the *credits menu submenu with the GitHub contributors* and putting the *[main devs](https://github.com/CodenameCrew)* in a *README* specifying that it's a *sub engine from Codename Engine*)
|
||||
- Release excutable mods that use Codename Engine as source (Specifing that uses Codename Engine by for example the same way written above this)
|
||||
- Release modpacks
|
||||
- Release excutable mods that use Codename Engine as source (specifing that uses Codename Engine by for example the same way written above this)
|
||||
- Release Codename Engine modpacks
|
||||
|
||||
### You can't:
|
||||
### Please do not:
|
||||
- Create a *side/new/etc* engine (or mod that doesn't use Codename Engine) using Codename Engine's code
|
||||
- Steal code from Codename Engine for another different project that is not Codename Engine related (Codename Engine mods excluded) without properly crediting
|
||||
- Release the entire Codename Engine on platforms (Mods that use Codename Engine as source are fine, if it's specified even better)
|
||||
- Release the entirety of Codename Engine on platforms (mods that use Codename Engine as source are fine)
|
||||
|
||||
#### *If you need more info or feel like asking to do something which is not listed here, ask us directly on our discord (linked on the website)!*
|
||||
#### *If you need more info or feel like asking to do something which is not listed here, ask us directly on our [discord server](https://discord.com/servers/codename-engine-860561967383445535)!*
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><h2>Credits</h2></summary>
|
||||
|
||||
- All main Credits can be seen inside the Engine and specifically [HERE](https://github.com/CodenameCrew/CodenameEngine/graphs/contributors)
|
||||
- Credits to the [FlxAnimate](https://github.com/Dot-Stuff/flxanimate) team for the Animate Atlas support
|
||||
- Credits to Smokey555 for the backup Animate Atlas to spritesheet code
|
||||
- Credits to MAJigsaw77 for [hxvlc](https://github.com/MAJigsaw77/hxvlc) (video cutscene/mp4 support) and [hxdiscord_rpc](https://github.com/MAJigsaw77/hxdiscord_rpc) (discord rpc integration)
|
||||
- Credits to [TheoDev](https://github.com/TheoDevelops) for [FunkinModchart](https://lib.haxe.org/p/funkin-modchart/). ***(library used for modcharting features)***
|
||||
- Credits to [Ninjamuffin99](https://github.com/ninjamuffin99) and the [Funkin Crew](https://github.com/FunkinCrew) for the base game Friday Night Funkin'
|
||||
</details>
|
||||
|
||||
@@ -1,61 +0,0 @@
|
||||
# Codename Engine Todo List
|
||||
|
||||
## `v1.0.0` - Initial release
|
||||
|
||||
- [x] Remove Herobrine
|
||||
- [ ] Chart Editor
|
||||
- [x] Place & Delete notes
|
||||
- [x] Ctrl+Z & Ctrl+Y
|
||||
- [x] Selection box & dragging
|
||||
- [x] Scroll bar at the right + Song info
|
||||
- [x] Fix the strumlines bar when zooming out
|
||||
- [x] Algorithm to make note placements faster & sorted out
|
||||
- [x] Play here working
|
||||
- [x] Cap zoom in & out
|
||||
- [x] Events (including Camera Movement)
|
||||
- [x] Metadata Editing
|
||||
- [ ] Custom Notetypes
|
||||
- [ ] Reorderable Strumlines
|
||||
- [ ] Step based zooming
|
||||
- [ ] Add Undo to more actions
|
||||
- [ ] New Chart Button
|
||||
- [ ] Bug fixes
|
||||
- [ ] Zooming in causing notes to disappear
|
||||
- [ ] Holds disappear too early
|
||||
- [ ] Time signature fixes
|
||||
- [ ] BPM Changes Events
|
||||
- [ ] Character Editor
|
||||
- [x] Animation Editing
|
||||
- [x] Animation Deletion/Creation
|
||||
- [x] Character Info Editing
|
||||
- [x] Character Saving
|
||||
- [x] Add Undos to Actions
|
||||
- [ ] Change Stage
|
||||
- [ ] New Character Button
|
||||
- [ ] Port Videos to a more stable video lib
|
||||
- [ ] Optimization to Editors
|
||||
- [ ] Fix Ratings Lag
|
||||
- [x] Re-export gf-christmas, gf-car and gf-tankmen with padding
|
||||
- [x] Re-add shader camera stuff
|
||||
- [x] Make update.bat use libs.xml instead of hmm.json
|
||||
- [ ] New Switch Mod menu
|
||||
- [x] Port shader camera stuff over to new flixel fork
|
||||
- [ ] Add note offset
|
||||
- [x] Dialogue
|
||||
- [ ] Finish Base Game port
|
||||
- [x] Add credits
|
||||
- [x] Verbose mode (`--verbose`)
|
||||
- [ ] Tooltips
|
||||
- [ ] Fix bugs
|
||||
|
||||
## `v1.1.0`
|
||||
- [ ] Charter Waveforms (maybe in v1.1.0, don't wanna slow shit down)
|
||||
- [ ] Custom classes
|
||||
- [ ] Proper super overrides (FlxText_HSX doesn't allow overrides for update because of this)
|
||||
- [ ] Custom Class extending Custom Classes
|
||||
- [ ] Statics on Custom Classes
|
||||
- [ ] Fix Bugs
|
||||
- [ ] Full 3D support via stages files
|
||||
- [ ] Multithread sprites and assets loading (for faster load times) ?
|
||||
- [ ] Stage Editor
|
||||
- [ ] Optimize flxanimate isOnScreen
|
||||
@@ -47,10 +47,18 @@
|
||||
<anim char="8">character-eight</anim>
|
||||
<anim char="9">character-nine</anim>
|
||||
|
||||
<composite char="ã">
|
||||
<component anim="character-a0" x="0" y="0"/>
|
||||
<component anim="diacritic-tilde-fill" x="11" y="73" outline="diacritic-tilde-outline" outlineX="-1" hasOutline="true"/>
|
||||
</composite>
|
||||
<composite char="ẽ">
|
||||
<component anim="character-e0" x="0" y="0"/>
|
||||
<component anim="diacritic-tilde-fill" x="3" y="73" outline="diacritic-tilde-outline" outlineX="-1" hasOutline="true"/>
|
||||
</composite>
|
||||
<composite char="õ">
|
||||
<component anim="character-o0" x="0" y="0"/>
|
||||
<component anim="diacritic-tilde-fill" x="8" y="73" outline="diacritic-tilde-outline" outlineX="-1" hasOutline="true"/>
|
||||
</composite>
|
||||
<composite char="ñ">
|
||||
<component anim="character-n0" x="0" y="0"/>
|
||||
<component anim="diacritic-tilde-fill" x="3" y="73" outline="diacritic-tilde-outline" outlineX="-1" hasOutline="true"/>
|
||||
@@ -75,6 +83,22 @@
|
||||
<component anim="character-u0" x="0" y="0"/>
|
||||
<component anim="diacritic-acute-fill" x="15" y="60" outline="diacritic-acute-outline" outlineX="-1" hasOutline="true"/>
|
||||
</composite>
|
||||
<composite char="â">
|
||||
<component anim="character-a0" x="0" y="0"/>
|
||||
<component anim="diacritic-circumflex-fill" x="13" y="70" outline="diacritic-circumflex-outline" outlineX="-1" hasOutline="true"/>
|
||||
</composite>
|
||||
<composite char="ê">
|
||||
<component anim="character-e0" x="0" y="0"/>
|
||||
<component anim="diacritic-circumflex-fill" x="6" y="70" outline="diacritic-circumflex-outline" outlineX="-1" hasOutline="true"/>
|
||||
</composite>
|
||||
<composite char="ô">
|
||||
<component anim="character-o0" x="0" y="0"/>
|
||||
<component anim="diacritic-circumflex-fill" x="11" y="70" outline="diacritic-circumflex-outline" outlineX="-1" hasOutline="true"/>
|
||||
</composite>
|
||||
<composite char="à">
|
||||
<component anim="character-a0" x="0" y="0"/>
|
||||
<component anim="diacritic-acute-fill" x="16" y="70" outline="diacritic-acute-outline" outlineX="1" hasOutline="true" flipX="true"/>
|
||||
</composite>
|
||||
<composite char="ą">
|
||||
<component anim="character-a0" x="0" y="0"/>
|
||||
<component anim="diacritic-ogonek-fill" x="34" y="-12" outline="diacritic-ogonek-outline" outlineX="2" outlineY="-2" hasOutline="true"/>
|
||||
@@ -83,6 +107,10 @@
|
||||
<component anim="character-e0" x="0" y="0"/>
|
||||
<component anim="diacritic-ogonek-fill" x="23" y="-14" outline="diacritic-ogonek-outline" outlineX="2" outlineY="-2" hasOutline="true"/>
|
||||
</composite>
|
||||
<composite char="ç">
|
||||
<component anim="character-c0" x="0" y="0"/>
|
||||
<component anim="diacritic-cadilla-fill" x="20" y="-15" outline="diacritic-cadilla-outline" outlineX="3" outlineY="-1" hasOutline="true"/>
|
||||
</composite>
|
||||
<composite char="ć">
|
||||
<component anim="character-c0" x="0" y="0"/>
|
||||
<component anim="diacritic-acute-fill" x="18" y="73" outline="diacritic-acute-outline" outlineX="-1" hasOutline="true"/>
|
||||
|
||||
@@ -8,7 +8,7 @@ function onDiscordPresenceUpdate(e) {
|
||||
var data = e.presence;
|
||||
|
||||
if(data.button1Label == null)
|
||||
data.button1Label = "meow"; // "Codename Engine Discord"
|
||||
data.button1Label = "Codename Engine Discord";
|
||||
if(data.button1Url == null)
|
||||
data.button1Url = "https://discord.gg/2NTCdsQvx4";
|
||||
}
|
||||
@@ -33,8 +33,8 @@ function onEditorTreeLoaded(name:String) {
|
||||
DiscordUtil.changePresenceSince("Choosing a Character", null);
|
||||
case "Chart Editor":
|
||||
DiscordUtil.changePresenceSince("Choosing a Chart", null);
|
||||
//case "Stage Editor": // secret for now
|
||||
// DiscordUtil.changePresenceSince("Choosing a Stage", null);
|
||||
case "Stage Editor": // secret for now
|
||||
DiscordUtil.changePresenceSince("Choosing a Stage", null);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,7 +44,7 @@ function onEditorLoaded(name:String, editingThing:String) {
|
||||
DiscordUtil.changePresenceSince("Editing a Character", editingThing);
|
||||
case "Chart Editor":
|
||||
DiscordUtil.changePresenceSince("Editing a Chart", editingThing);
|
||||
//case "Stage Editor":
|
||||
// DiscordUtil.changePresenceSince("Editing a Stage", editingThing);
|
||||
case "Stage Editor":
|
||||
DiscordUtil.changePresenceSince("Editing a Stage", editingThing);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,5 +16,5 @@ version="version based on the English config.ini version"
|
||||
|
||||
4. Translate the texts in the copied xml files. The {0} and {1}, and so on are placeholders are used for variables, and should be left as is.
|
||||
|
||||
5. Make a pull request with your changes.
|
||||
5. **If you wanna help us with the language(s) you added in the engine**: Make a pull request with your changes.
|
||||
Make sure the pull request is labeled as `[LANG] Add <language name>` or `[LANG] Update <language name>` or `[LANG] Fix typo in <language name>`, generally anything is allowed but it has to contain the language name.
|
||||
|
||||
@@ -45,12 +45,15 @@
|
||||
<group name="CharterSelection" prefix="charterSelection.">
|
||||
<str id="desc">Select a song to modify the charts from.</str>
|
||||
<str id="acceptSong">Press ACCEPT to choose a difficulty to edit.</str>
|
||||
<str id="acceptVariation">Press ACCEPT to choose a song variation to edit.</str>
|
||||
<str id="acceptDifficulty">Press ACCEPT to edit the chart for the selected difficulty.</str>
|
||||
<str id="selectDifficulty">Select a difficulty to continue.</str>
|
||||
<str id="newDifficulty">New Difficulty</str>
|
||||
<str id="newDifficultyDesc">Press ACCEPT to create a new chart difficulty.</str>
|
||||
<str id="newSong">New Song</str>
|
||||
<str id="newSongDesc">Press ACCEPT to create a new song.</str>
|
||||
<str id="newVariation">New Variation</str>
|
||||
<str id="newVariationDesc">Press ACCEPT to create a new song variation.</str>
|
||||
</group>
|
||||
|
||||
<group name="ChartCreationScreen" prefix="chartCreation.">
|
||||
@@ -104,6 +107,7 @@
|
||||
|
||||
<str id="songData">Song Data</str>
|
||||
<str id="songName">Song Name</str>
|
||||
<str id="variation">Song Variation</str>
|
||||
<str id="bpm">BPM</str>
|
||||
<str id="timeSignature">Time Signature</str>
|
||||
<str id="menusData">Menus Data (Freeplay/Story)</str>
|
||||
@@ -484,6 +488,7 @@
|
||||
<str id="newGlyph">New Glyph</str>
|
||||
<str id="editGlyph">Edit Glyph</str>
|
||||
<str id="deleteGlyph">Delete Glyph</str>
|
||||
<str id="deleteCurGlyph">Delete Current Glyph</str>
|
||||
</group>
|
||||
|
||||
<str id="topBar.offset">Offsets</str>
|
||||
|
||||
@@ -0,0 +1,686 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<language>
|
||||
<group name="General Editor Translations" prefix="editor.">
|
||||
<str id="autosavingIn">Guardando automáticamente em {0} segundos{1}</str>
|
||||
<str id="autosavingCanceledSuffix">(Cancelado)!</str>
|
||||
|
||||
<str id="ok">Ok</str>
|
||||
<str id="cancel">Cancelar</str>
|
||||
<str id="save">Guardar</str>
|
||||
<str id="saveClose">Guardar e Fechar</str>
|
||||
<str id="close">Fechar</str>
|
||||
<str id="notNow">Agora Não</str>
|
||||
<str id="yes">Sim</str>
|
||||
</group>
|
||||
|
||||
<group name="UIImageExplorer" prefix="uiImageExplorer.">
|
||||
<str id="symbol">Simbolo</str>
|
||||
<str id="animation">Animação</str>
|
||||
<str id="atlas">Atlas</str>
|
||||
<str id="spritemap">Mapa de Sprites</str>
|
||||
|
||||
<str id="directory">Diretório ({0}/)</str>
|
||||
<str id="found">{0} {1} Encontrado</str>
|
||||
<str id="foundplural">{0} {1} Encontrado</str>
|
||||
<str id="notFound">#{0}s NÃO Encontrado#</str>
|
||||
<str id="foundAtlas">{0} Mapa de Sprites Encontrado</str>
|
||||
<str id="foundAtlasplural">{0} Mapas de Sprites Encontrados</str>
|
||||
|
||||
<str id="fileAlreadyExists">Os seguintes ficheiros já existem: \n\n{0}\n\nIMPORTANTE: SUBSTITUIR NÃO PODE SER DESFEITO!</str>
|
||||
<str id="override">Substituir Ficheiros</str>
|
||||
<str id="useExisting">Usar Existentes</str>
|
||||
</group>
|
||||
|
||||
<group name="EditorPicker" prefix="editor.">
|
||||
<str id="alphabet.name">Editor de Alfabetos</str>
|
||||
<str id="chart.name">Editor de Mapas</str>
|
||||
<str id="character.name">Editor de Personagens</str>
|
||||
<str id="stage.name">Editor de Cenários</str>
|
||||
<str id="uiDebug.name">Interface de Depuração</str>
|
||||
<str id="wiki.name">Wiki</str>
|
||||
<str id="debugOptions.name">Opções de Depuração</str>
|
||||
</group>
|
||||
|
||||
<group name="ChartEditor">
|
||||
<group name="CharterSelection" prefix="charterSelection.">
|
||||
<str id="desc">Selecione uma canção para modificar os seus mapas.</str>
|
||||
<str id="acceptSong">Carregue em ACEITAR para escolher uma dificuldade para editar.</str>
|
||||
<str id="acceptVariation">Carregue em ACEITAR para escolher uma variação para editar.</str>
|
||||
<str id="acceptDifficulty">Carregue em ACEITAR para editar o mapa para a dificuldade selecionada.</str>
|
||||
<str id="selectDifficulty">Selecione uma dificuldade para continuar.</str>
|
||||
<str id="newDifficulty">Nova Dificuldade</str>
|
||||
<str id="newDifficultyDesc">Carregue em ACEITAR para criar uma dificuldade nova.</str>
|
||||
<str id="newSong">Nova Canção</str>
|
||||
<str id="newSongDesc">Carregue em ACEITAR para criar uma canção nova.</str>
|
||||
<str id="newVariation">Nova Variação</str>
|
||||
<str id="newSongDesc">Carregue em ACEITAR para criar uma variação nova.</str>
|
||||
</group>
|
||||
|
||||
<group name="ChartCreationScreen" prefix="chartCreation.">
|
||||
<str id="title">A Criar um Mapa Novo</str>
|
||||
<str id="info">Info. do Mapa</str>
|
||||
<str id="diffName">Nome da Dificuldade</str>
|
||||
<str id="stage">Cenário</str>
|
||||
<str id="scrollSpeed">Velocidade das Notas</str>
|
||||
|
||||
<str id="strumLineList">Pistas $* Pelo menos 1 Pista Necessária$</str>
|
||||
<str id="strumLine.format">Pistas - #{0}</str>
|
||||
|
||||
<group name="Warnings" prefix="warnings.">
|
||||
<str id="song-exists-title">Criação de Canção: Erro!</str>
|
||||
<str id="song-exists-body">A canção que está a tentar criar já existe, se a quiser substituir apague a canção primeiro!</str>
|
||||
<str id="chart-exists-title">Criação de Mapa: Erro!</str>
|
||||
<str id="chart-exists-body">O mapa que está a tentar criar já existe, se o quiser substituir apague o mapa primeiro!</str>
|
||||
</group>
|
||||
</group>
|
||||
|
||||
<group name="ChartDataScreen" prefix="chartDataScreen.">
|
||||
<str id="title">Propriedades do Mapa</str>
|
||||
<str id="editChartData">Editar Dados do Mapa</str>
|
||||
<str id="stage">Cenário</str>
|
||||
<str id="scrollSpeed">Velocidade das Notas</str>
|
||||
</group>
|
||||
|
||||
<group name="SongPosInfo" prefix="songPosInfo.">
|
||||
<str id="step">Passo: {0}</str>
|
||||
<str id="beat">Batida: {0}</str>
|
||||
<str id="measure">Medida: {0}</str>
|
||||
<str id="bpm">BPM: {0}</str>
|
||||
<str id="timeSignature">Compasso: {0}/{1}</str>
|
||||
</group>
|
||||
|
||||
<group name="CharterEventScreen" prefix="charterEventScreen.">
|
||||
<str id="title-creating">Criar Grupo de Eventos</str>
|
||||
<str id="title-editing">Editar Grupo de Eventos</str>
|
||||
|
||||
<str id="noEvent">Sem Eventos</str>
|
||||
|
||||
<str id="strumLine.format">Pista #{0} ({1})</str>
|
||||
</group>
|
||||
|
||||
<group name="CharterEventTypeSelection" prefix="charterEventTypeSelection.">
|
||||
<str id="title">Escolha um tipo de evento...</str>
|
||||
</group>
|
||||
|
||||
<group name="CharterMetaDataScreen" prefix="charterMetaDataScreen.">
|
||||
<str id="title">Editar Metadados</str>
|
||||
|
||||
<str id="songData">Dados da Canção</str>
|
||||
<str id="songName">Nome da Canção</str>
|
||||
<str id="variation">Variação da Canção</str>
|
||||
<str id="bpm">BPM</str>
|
||||
<str id="timeSignature">Compasso</str>
|
||||
<str id="menusData">Dados dos Menus (Jogo Livre/História)</str>
|
||||
<str id="displayName">Nome Exibido</str>
|
||||
<str id="icon">Ícone</str>
|
||||
<str id="modesAllowed">Modos Permitidos</str>
|
||||
<str id="color">Cor</str>
|
||||
<str id="difficulties">Dificuldades</str>
|
||||
<str id="customValues">Valores Especiais (Avançado)</str>
|
||||
<str id="needsVoices">Necessita Vozes</str>
|
||||
|
||||
<str id="opponentMode">Modo Oponente</str>
|
||||
<str id="coopAllowed">Modo Cooperativo</str>
|
||||
</group>
|
||||
|
||||
<group name="CharterNoteTypesList" prefix="charterNoteTypesList.">
|
||||
<str id="title">Editor da Lista de Tipos de Nota</str>
|
||||
|
||||
<str id="editNoteTypes">Editar Tipos de Nota</str>
|
||||
<str id="editType">Tipo de Nota {0}</str>
|
||||
</group>
|
||||
|
||||
<group name="CharterStrumlineScreen" prefix="charterStrumlineScreen.">
|
||||
<str id="win-title-creating">A Criar a pista {0}</str>
|
||||
<str id="win-title-editing">A Editar as propriedades da pista {0}</str>
|
||||
|
||||
<str id="title-creating">Criar Nova Pista</str>
|
||||
<str id="title-editing">Editar Propriedades da Pista</str>
|
||||
</group>
|
||||
|
||||
<group name="SongCreationScreen" prefix="songCreationScreen.">
|
||||
<str id="win-title">A Criar Nova Canção</str>
|
||||
<str id="win-title-importing">A Importar Canção</str>
|
||||
<str id="title">Info. da Canção</str>
|
||||
|
||||
<str id="instAudio">Ficheiro do Instrumental $* Obrigatório*$</str>
|
||||
<str id="voicesAudio">Ficheiro das Vozes</str>
|
||||
|
||||
<str id="importFrom">Importar de...</str>
|
||||
<str id="importSource">Fonte de Importação:</str>
|
||||
<str id="legacyOrPsych">Psych/Legacy FNF</str>
|
||||
<str id="vslice">V-Slice</str>
|
||||
<str id="vsliceProject">Projeto V-Slice (.fnfc)</str>
|
||||
<str id="importChartFormat">Formato de Mapa</str>
|
||||
<str id="importAudios">Adicionar Audios</str>
|
||||
<str id="songFileName">Nome da canção $* Obrigatório$</str>
|
||||
<str id="songDataFile">Ficheiro Dados/Mapa $* Obrigatório$</str>
|
||||
<str id="songMetaFile">Ficheiro dos Metadados $* Obrigatório$</str>
|
||||
|
||||
<str id="back">Atrás</str>
|
||||
<str id="next">Seguinte</str>
|
||||
</group>
|
||||
|
||||
<group name="StrumlineOptions" prefix="charterStrumLine.">
|
||||
<str id="characters">Personagens</str>
|
||||
<str id="newChar">Nova Personagem</str>
|
||||
<str id="type">Tipo</str>
|
||||
<str id="scrollSpeed">Velocidade das Notas</str>
|
||||
<str id="stagePos">Posição no Cenário</str>
|
||||
<str id="scale">Tamanho</str>
|
||||
<str id="spacing">Espaço</str>
|
||||
<str id="hudPos">Posição HUD (X [Rácio 0-1],Y)</str>
|
||||
<str id="visible">Visível?</str>
|
||||
<str id="useChartScrollSpeed">Usa velocidade global?</str>
|
||||
<str id="vocalSuffix">Sufixo Vocal</str>
|
||||
<str id="keyCount">Número de Teclas</str>
|
||||
</group>
|
||||
|
||||
<group name="ChartEditor" prefix="charter.">
|
||||
<!-- Charter.hx -->
|
||||
<group name="TopBar">
|
||||
<str id="topBar.file">Ficheiro</str>
|
||||
<group name="FileMenu" prefix="file.">
|
||||
<str id="new">Novo</str>
|
||||
<str id="save">Guardar</str>
|
||||
<str id="saveAs">Guardar Como...</str>
|
||||
<str id="saveGlobalEvents">Guardar Eventos Globais</str>
|
||||
<str id="saveGlobalEventsAs">Guardar Eventos Globais Como...</str>
|
||||
<str id="saveNoLocalEvents">Guardar Mapa sem Eventos Locais</str>
|
||||
<str id="saveNoLocalEventsAs">Guardar Mapa sem Eventos Locais Como...</str>
|
||||
<str id="saveMeta">Guardar Metadados</str>
|
||||
<str id="saveMetaAs">Guardar Metadados Como...</str>
|
||||
<str id="exportFnfLegacy">Exportar Para FNF Legacy...</str>
|
||||
<str id="exportPsych">Exportar Para Psych Engine...</str>
|
||||
<str id="exit">Sair</str>
|
||||
</group>
|
||||
|
||||
<str id="topBar.edit">Editar</str>
|
||||
<group name="EditMenu" prefix="edit.">
|
||||
<str id="undo">Desfazer</str>
|
||||
<str id="redo">Refazer</str>
|
||||
<str id="copy">Copiar</str>
|
||||
<str id="paste">Colar</str>
|
||||
<str id="cut">Cortar</str>
|
||||
<str id="delete">Apagar</str>
|
||||
</group>
|
||||
|
||||
<str id="topBar.chart">Mapa</str>
|
||||
<group name="ChartMenu" prefix="chart.">
|
||||
<str id="playtest">Testar</str>
|
||||
<str id="playtestHere">Testar aqui</str>
|
||||
<str id="playtestOpponent">Testar como oponente</str>
|
||||
<str id="playtestOpponentHere">Testar como oponente aqui</str>
|
||||
<str id="enableScripts">Ativar scripts durante teste</str>
|
||||
<str id="editChartData">Editar dados do mapa</str>
|
||||
<str id="editMetadata">Editar info. dos metadados</str>
|
||||
</group>
|
||||
|
||||
<str id="topBar.view">Vista</str>
|
||||
<group name="ViewMenu" prefix="view.">
|
||||
<str id="zoomIn">Ampliar</str>
|
||||
<str id="zoomOut">Diminuir</str>
|
||||
<str id="resetZoom">Zoom Padrão</str>
|
||||
<str id="showSectionsSeparator">Mostrar Separador de Secções</str>
|
||||
<str id="showBeatsSeparator">Mostrar Separador de Batidas</str>
|
||||
<str id="rainbowWaveforms">Ondas Arcoíris</str>
|
||||
<str id="lowDetailWaveforms">Ondas de Baixo Detalhe</str>
|
||||
<str id="scrollLeft">Deslocar à Esquerda</str>
|
||||
<str id="scrollRight">Deslocar à Direita</str>
|
||||
<str id="scrollReset">Repor Deslocamento</str>
|
||||
</group>
|
||||
|
||||
<str id="topBar.song">Canção</str>
|
||||
<group name="SongMenu" prefix="song.">
|
||||
<str id="goStart">Voltar ao início</str>
|
||||
<str id="goEnd">Avançar até o fim</str>
|
||||
<str id="addOpponentCamera">Adicionar camera no Oponente</str>
|
||||
<str id="addPlayerCamera">Adicionar camera no Jogador</str>
|
||||
<str id="muteInst">Silenciar instrumental</str>
|
||||
<str id="muteVoices">Silenciar vozes</str>
|
||||
</group>
|
||||
|
||||
<group name="BookmarkMenu" prefix="bookmarks.">
|
||||
<str id="addBookmarkHere">Adicionar Marcador Aqui</str>
|
||||
<str id="editBookmarkList">Editar Lista de Marcadores</str>
|
||||
<str id="goTo">Ir para "{0}"</str>
|
||||
<str id="createBookmarkTitle">A Criar Marcador Novo...</str>
|
||||
<str id="createBookmarkName">Nome do Marcador:</str>
|
||||
<str id="createBookmarkColor">Cor do Marcador:</str>
|
||||
<str id="editBookmarkListTitle">Lista de Marcadores</str>
|
||||
<str id="editBookmarksTitle">Editar Marcador</str>
|
||||
<str id="newBookmarkName">Novo Marcador</str>
|
||||
</group>
|
||||
|
||||
<str id="topBar.note">Notas</str>
|
||||
<group name="NoteMenu" prefix="note.">
|
||||
<str id="addSustainLength">Alargar Nota</str>
|
||||
<str id="subtractSustainLength">Encurtar Nota</str>
|
||||
<str id="selectAll">Selecionar tudo</str>
|
||||
<str id="selectMeasure">Selecionar medida</str>
|
||||
<str id="editNoteTypesList">Editar Lista de Tipos de Nota</str>
|
||||
</group>
|
||||
<str id="topBar.snap">Ajustes</str>
|
||||
<group name="SnapMenu" prefix="snap.">
|
||||
<str id="increaseSnap">↑ Ajuste de Casa</str>
|
||||
<str id="resetSnap">Repor Ajuste de Casa</str>
|
||||
<str id="decreaseSnap">↓ Ajuste de Casa</str>
|
||||
|
||||
<str id="snap">Ajuste de Casa {0}x</str>
|
||||
</group>
|
||||
|
||||
<str id="topBar.playback">Reprodução</str>
|
||||
<group name="PlaybackMenu" prefix="playback.">
|
||||
<str id="play">Tocar/Pausar</str>
|
||||
<str id="speedRaise">↑ Velocidade {0}%</str>
|
||||
<str id="speedReset">Repor Velocidade</str>
|
||||
<str id="speedLower">↓ Velocidade {0}%</str>
|
||||
<str id="sectionBack">Voltar uma secção</str>
|
||||
<str id="sectionForward">Avançar uma secção</str>
|
||||
<str id="sectionStart">Voltar ao ínicio da secção</str>
|
||||
<str id="backStep">Voltar um passo</str>
|
||||
<str id="forwardStep">Avançar um passo</str>
|
||||
<str id="metronome">Metrónomo</str>
|
||||
<str id="visualMetronome">Metrónomo visual</str>
|
||||
</group>
|
||||
</group>
|
||||
|
||||
<group name="NoteTypes" prefix="noteTypes.">
|
||||
<str id="default">Nota Normal</str>
|
||||
</group>
|
||||
|
||||
<group name="EventTypes" prefix="events.">
|
||||
<!-- You can add your custom event types here! -->
|
||||
<!-- Just need to do some conversion from the raw name to the id -->
|
||||
<!-- Example: HScript Call -> hscriptCall -->
|
||||
<!-- Example: Change Character -> changeCharacter -->
|
||||
<str id="hscriptCall">Chamar HScript</str>
|
||||
<str id="cameraMovement">Mover Câmara</str>
|
||||
<str id="cameraPosition">Posição da Câmara</str>
|
||||
<str id="addCameraZoom">Adicionar Zoom</str>
|
||||
<str id="cameraModuloChange">Mudar Pulso da Câmara</str>
|
||||
<str id="cameraFlash">Flash da Câmara</str>
|
||||
<str id="bpmChange">Mudar BPM</str>
|
||||
<str id="continuousBpmChange">Mudança contínua de BPM</str>
|
||||
<str id="timeSignatureChange">Mudar Compasso</str>
|
||||
<str id="scrollSpeedChange">Mudança de Velocidade das Notas</str>
|
||||
<str id="altAnimationToggle">Animações Alternativas</str>
|
||||
<str id="playAnimation">Reproduzir Animação</str>
|
||||
</group>
|
||||
|
||||
<group name="StrumlineOptions" prefix="strumLine.">
|
||||
<str id="button-name">Opções ↓</str>
|
||||
|
||||
<str id="hitsounds">Som ao Bater</str>
|
||||
<str id="muteVocals">Silenciar Voz</str>
|
||||
<str id="edit">Editar</str>
|
||||
<str id="delete">Apagar</str>
|
||||
|
||||
<str id="noWaveform">Sem onda</str>
|
||||
</group>
|
||||
|
||||
<str id="createNew">Criar Nova</str>
|
||||
<str id="lock-unlock">Trancar/\nDestrancar</str>
|
||||
|
||||
<str id="info.localEvents">Eventos Locais\n(Apenas Esta Dificuldade)</str>
|
||||
<str id="info.globalEvents">Eventos Globais\n(Todas as Dificuldades)</str>
|
||||
<str id="eventType-local">Evento Local</str>
|
||||
<str id="eventType-global">Evento Global</str>
|
||||
|
||||
<!-- CharterEventAdd.hx -->
|
||||
<str id="addEvent">Adicionar Evento</str>
|
||||
<str id="editEvent">Editar Evento</str>
|
||||
<str id="deleteEvent">Apagar Evento</str>
|
||||
|
||||
<group name="Notifications" prefix="popup.">
|
||||
<str id="savedChartAt">Mapa Guardado em {0}!</str>
|
||||
</group>
|
||||
</group>
|
||||
</group>
|
||||
|
||||
<group name="CharacterEditor">
|
||||
<group name="CharacterSelection" prefix="characterSelection.">
|
||||
<str id="acceptFolder">Carregue em ACEITAR para editar esta pasta.</str>
|
||||
<str id="acceptCharacter">Carregue em ACEITAR para editar esta personagem.</str>
|
||||
<str id="newCharacter">Nova Personagem</str>
|
||||
<str id="newCharacterDesc">Carregue em ACEITAR para criar uma personagem nova.</str>
|
||||
<str id="desc">Selecione uma personagem para editar</str>
|
||||
<str id="desc-folder">Selecione uma personagem para editar em {0}</str>
|
||||
</group>
|
||||
|
||||
<group name="CharacterInfoScreen" prefix="characterInfoScreen.">
|
||||
<str id="win-title">A Editar Personagem</str>
|
||||
<str id="title">Editar Info. da Personagem</str>
|
||||
<str id="icon">Ícone</str>
|
||||
<str id="iconColor">Cor do Ícone</str>
|
||||
<str id="singDuration">Duração de Canto</str>
|
||||
<str id="useSingDuration">Usar Duração de Canto?</str>
|
||||
<str id="customValues">Valores Especiais (Avançado)</str>
|
||||
</group>
|
||||
|
||||
<group name="CharacterEditor" prefix="characterEditor.">
|
||||
<group name="TopBar">
|
||||
<str id="topBar.file">Ficheiro</str>
|
||||
<group name="FileMenu" prefix="file.">
|
||||
<str id="new">Novo</str>
|
||||
<str id="save">Guardar</str>
|
||||
<str id="saveAs">Guardar Como...</str>
|
||||
<str id="exit">Sair</str>
|
||||
</group>
|
||||
|
||||
<str id="topBar.edit">Editar</str>
|
||||
<group name="EditMenu" prefix="edit.">
|
||||
<str id="copyOffset">Copiar Posição</str>
|
||||
<str id="pasteOffset">Colar Posição</str>
|
||||
<str id="undo">Desfazer</str>
|
||||
<str id="redo">Refazer</str>
|
||||
<str id="editInfo">Editar informação</str>
|
||||
<str id="editSprite">Editar imagem fonte</str>
|
||||
</group>
|
||||
|
||||
<str id="topBar.offset">Posição</str>
|
||||
<group name="OffsetsMenu" prefix="offset.">
|
||||
<str id="moveLeft">Mover Para a Esquerda</str>
|
||||
<str id="moveUp">Mover Para Cima</str>
|
||||
<str id="moveDown">Mover Para Baixo</str>
|
||||
<str id="moveRight">Mover Para a Direita</str>
|
||||
<str id="moveExtraLeft">Mover Mais Para a Esquerda</str>
|
||||
<str id="moveExtraUp">Mover Mais Para Cima</str>
|
||||
<str id="moveExtraDown">Mover Mais Para Baixo</str>
|
||||
<str id="moveExtraRight">Mover Mais Para a Direita</str>
|
||||
<str id="dragOffsetsMouse">Arrastar Posição Com o Rato?</str>
|
||||
<str id="clearOffsets">Limpar Posições</str>
|
||||
</group>
|
||||
|
||||
<str id="topBar.stage">Cenário</str>
|
||||
<group name="StageMenu" prefix="stage.">
|
||||
<str id="useStage">Usar "{0}"</str>
|
||||
<str id="useNone">Não Usar Cenário</str>
|
||||
</group>
|
||||
|
||||
<str id="topBar.view">Vista</str>
|
||||
<group name="ViewMenu" prefix="view.">
|
||||
<str id="zoomIn">Ampliar</str>
|
||||
<str id="zoomOut">Diminuir</str>
|
||||
<str id="resetZoom">Zoom Padrão</str>
|
||||
<str id="charHitbox">"Hitbox" da Personagem?</str>
|
||||
<str id="charCam">Câmara da Personagem?</str>
|
||||
<str id="axis">Eixo XY?</str>
|
||||
</group>
|
||||
|
||||
<str id="topBar.animation">Animação</str>
|
||||
<group name="AnimationMenu" prefix="animation.">
|
||||
<str id="playAnim">Reproduzir Animação</str>
|
||||
<str id="stopAnim">Parar Animação</str>
|
||||
<str id="changeAnimUp">Mudar Animação ↑</str>
|
||||
<str id="changeAnimDown">Mudar Animação ↓</str>
|
||||
<str id="playAnimOnOffset">Reproduzir Animação Reposicionada?</str>
|
||||
</group>
|
||||
|
||||
<group name="CharacterPropertiesWindow" prefix="characterProperties.">
|
||||
<str id="position">Posição (X, Y)</str>
|
||||
<str id="scale">Tamanho</str>
|
||||
<str id="editInfo">Editar Info.</str>
|
||||
<str id="editSprite">Editar Imagem</str>
|
||||
<str id="camPosition">Posição da Câmara (X, Y)</str>
|
||||
<str id="charFlipped">Espelhado?</str>
|
||||
<str id="antialiased">Suavizado?</str>
|
||||
<str id="testCharAs">Testar Como...</str>
|
||||
<str id="charDesign">Desenhada Como...</str>
|
||||
</group>
|
||||
|
||||
<group name="CharacterAnimButton" prefix="characterAnim.">
|
||||
<str id="defaultAnimName">Nova Animação</str>
|
||||
<str id="name">Nome</str>
|
||||
<str id="anim">Animação</str>
|
||||
<str id="position">Posição (X, Y)</str>
|
||||
<str id="fps">FPS</str>
|
||||
<str id="indices">Índices (Frames)</str>
|
||||
</group>
|
||||
|
||||
<group name="CharacterSpriteScreen" prefix="characterSpriteScreen.">
|
||||
<str id="win-title">Editar imagem da personagem</str>
|
||||
<str id="charImageFile">Imagem da personagem $* Obrigatório$</str>
|
||||
</group>
|
||||
</group>
|
||||
</group>
|
||||
|
||||
<group name="CharacterCreationScreen" prefix="characterCreationScreen.">
|
||||
<str id="win-title">A Criar uma Personagem Nova</str>
|
||||
<str id="charName">Nome da Personagem $* Required$</str>
|
||||
<str id="charImgName">Imagem $* Obrigatória$</str>
|
||||
|
||||
<group name="Warnings" prefix="warnings.">
|
||||
<str id="char-exists-title">Criação da Personagem: Erro!</str>
|
||||
<str id="char-exists-body">A personagem que está a tentar criar já existe, se quiser substituir apague a personagem primeiro!</str>
|
||||
</group>
|
||||
</group>
|
||||
</group>
|
||||
|
||||
<group name="AlphabetEditor" prefix="editor.alphabet.">
|
||||
<group name="AlphabetSelection" prefix="selection.">
|
||||
<str id="acceptTypeface">Carregue em ACEITAR para editar este tipo de letra.</str>
|
||||
<str id="newTypeface">Novo Tipo de Letra</str>
|
||||
<str id="newTypefaceDesc">Carregue em ACEITAR para criar um tipo de letra novo.</str>
|
||||
<str id="desc">Selecione um tipo de letra para editar</str>
|
||||
|
||||
<group name="Warnings" prefix="warnings.">
|
||||
<str id="notImplemented-title">Novo Tipo de Letra: Função Não Implementada!</str>
|
||||
<str id="notImplemented-body">Esta função ainda não foi implementada. Por favor espere por mais atualizações até ser implementada.\n\n\n- Codename Crew (Equipa Codename)</str>
|
||||
</group>
|
||||
</group>
|
||||
|
||||
<group name="AlphabetEditor">
|
||||
<group name="TopBar">
|
||||
<str id="topBar.file">Ficheiro</str>
|
||||
<group name="FileMenu" prefix="file.">
|
||||
<str id="new">Novo</str>
|
||||
<str id="save">Guardar</str>
|
||||
<str id="saveAs">Guardar Como...</str>
|
||||
<str id="exit">Sair</str>
|
||||
</group>
|
||||
|
||||
<str id="topBar.edit">Editar</str>
|
||||
<group name="EditMenu" prefix="edit.">
|
||||
<str id="undo">Desfazer</str>
|
||||
<str id="redo">Refazer</str>
|
||||
</group>
|
||||
|
||||
<str id="topBar.glyph">Glifo</str>
|
||||
<group name="GlyphMenu" prefix="glyph.">
|
||||
<str id="newGlyph">Novo Glifo</str>
|
||||
<str id="editGlyph">Editar Glifo</str>
|
||||
<str id="deleteGlyph">Apagar Glifo</str>
|
||||
<str id="deleteCurGlyph">Apagar Glifo Atual</str>
|
||||
</group>
|
||||
|
||||
<str id="topBar.offset">Posição</str>
|
||||
<group name="OffsetsMenu" prefix="offset.">
|
||||
<str id="moveLeft">Mover Para a Esquerda</str>
|
||||
<str id="moveUp">Mover Para Cima</str>
|
||||
<str id="moveDown">Mover Para Baixo</str>
|
||||
<str id="moveRight">Mover Para a Direita</str>
|
||||
<str id="moveExtraLeft">Mover Mais Para a Esquerda</str>
|
||||
<str id="moveExtraUp">Mover Mais Para Cima</str>
|
||||
<str id="moveExtraDown">Mover Mais Para Baixo</str>
|
||||
<str id="moveExtraRight">Mover Mais Para a Direita</str>
|
||||
<str id="clearOffsets">Limpar Posições</str>
|
||||
</group>
|
||||
|
||||
<str id="topBar.view">Vista</str>
|
||||
<group name="ViewMenu" prefix="view.">
|
||||
<str id="zoomIn">Ampliar</str>
|
||||
<str id="zoomOut">Diminuir</str>
|
||||
<str id="resetZoom">Zoom Padrão</str>
|
||||
</group>
|
||||
</group>
|
||||
</group>
|
||||
</group>
|
||||
|
||||
<group name="StageEditor">
|
||||
<group name="StageSelection" prefix="stageSelection.">
|
||||
<str id="desc">Selecione um cenário para editar. Cenários HSCRIPT PURO não são suportadas.</str>
|
||||
<str id="acceptStage">Carregue em ACEITAR para editar este cenário.</str>
|
||||
<str id="newStage">Novo Cenário</str>
|
||||
<str id="acceptNewStage">Carregue em ACEITAR para criar um cenário novo.</str>
|
||||
</group>
|
||||
|
||||
<group name="StageEditor" prefix="stageEditor.">
|
||||
<group name="TopBar">
|
||||
<str id="topBar.file">Ficheiro</str>
|
||||
<group name="FileMenu" prefix="file.">
|
||||
<str id="save">Guardar</str>
|
||||
<str id="saveAs">Guardar Como...</str>
|
||||
<str id="exit">Sair</str>
|
||||
</group>
|
||||
|
||||
<str id="topBar.edit">Editar</str>
|
||||
<group name="EditMenu" prefix="edit.">
|
||||
<str id="undo">Desfazer</str>
|
||||
<str id="redo">Refazer</str>
|
||||
<str id="editStageInfo">Editar Info. do Cenário</str>
|
||||
</group>
|
||||
|
||||
<str id="topBar.select">Seleção</str>
|
||||
<group name="SelectionMenu" prefix="select.">
|
||||
<str id="all">Selecionar Tudo</str>
|
||||
<str id="deselect">Desselecionar</str>
|
||||
<str id="inverse">Inverter Seleção</str>
|
||||
</group>
|
||||
|
||||
<str id="topBar.view">Vista</str>
|
||||
<group name="ViewMenu" prefix="view.">
|
||||
<str id="zoomIn">Ampliar</str>
|
||||
<str id="zoomOut">Diminuir</str>
|
||||
<str id="zoomReset">Zoom Padrão</str>
|
||||
<str id="focusDad">Focar no Oponente</str>
|
||||
<str id="focusGF">Focar em GF</str>
|
||||
<str id="focusBF">Focar em BF</str>
|
||||
</group>
|
||||
|
||||
<str id="topBar.editor">Editor</str>
|
||||
<group name="EditorMenu" prefix="editor.">
|
||||
<str id="showCharacters">Mostrar Personagens</str>
|
||||
</group>
|
||||
|
||||
<group name="StageSpriteScreen" prefix="stageSpriteScreen.">
|
||||
<str id="win-title">Editar imagem do cenário </str>
|
||||
<str id="stageImageFile">Imagem do Cenário $* Obrigatória$</str>
|
||||
</group>
|
||||
</group>
|
||||
</group>
|
||||
|
||||
<group name="StageCreationScreen" prefix="stageCreationScreen.">
|
||||
<str id="win-title">A Criar um Cenário Novo</str>
|
||||
<str id="title">Info. do Cenário</str>
|
||||
<str id="stageName">Nome do Cenário</str>
|
||||
<str id="stagePath">Caminho do Cenário</str>
|
||||
|
||||
<group name="Warnings" prefix="warnings.">
|
||||
<str id="stage-exists-title">Criação de Cenário: Erro!</str>
|
||||
<str id="stage-exists-body">O cenário que está a tentar criar já existe, se quiser substituir apague o cenário primeiro!</str>
|
||||
</group>
|
||||
</group>
|
||||
|
||||
<group name="StageInfoScreen" prefix="stageInfoScreen">
|
||||
<str id="win-title">A Editar Info. do Cenário: "{0}"</str>
|
||||
<str id="title">Info. do Cenário</str>
|
||||
<str id="stageName">Nome do Cenário</str>
|
||||
<str id="spritePath">Caminho do Sprite\n(Requer Recarregamento)</str>
|
||||
<str id="startCamPos">Posição inicial da Câmara (X, Y)</str>
|
||||
<str id="zoom">Zoom</str>
|
||||
<str id="customAttributes">Atributos Especiais</str>
|
||||
</group>
|
||||
|
||||
<group name="StageElementEditScreen" prefix="stageElementEditScreen.">
|
||||
<str id="win-character-title">A Editar Personagem: "{0}"</str>
|
||||
<str id="win-sprite-title">A Editar Sprite: "{0}"</str>
|
||||
<str id="win-title">A Editar XML <{0} /></str>
|
||||
|
||||
<str id="character-title">Dados da Personagem</str>
|
||||
<str id="sprite-title">Dados do Sprite</str>
|
||||
<str id="title">Dados do XML</str>
|
||||
|
||||
<str id="elementName">Nome do Elemento</str>
|
||||
<str id="nameID">Nome Identificador</str>
|
||||
<str id="imageFile">Imagem (WIP: precisa recarregar)\nEm (${stage.spritesParentFolder})</str>
|
||||
<str id="scroll">Scroll {0}</str> <!-- it's "scroll" here because "deslocamento" is too big -->
|
||||
<str id="scale">Tamanho {0}</str>
|
||||
<str id="camera">Câmara {0}</str>
|
||||
<str id="spacing">Espaçamento (X, Y)</str>
|
||||
<str id="skew">Incline {0}</str>
|
||||
<str id="alpha">Opacidade</str>
|
||||
<str id="angle">Angulo</str>
|
||||
<str id="zoomFactor">Fator de Zoom</str> <!-- same as for scroll, "fator de ampliação" took too much space -->
|
||||
<str id="positionName">Nome de Posição</str>
|
||||
<str id="flipX">Espelhar X</str>
|
||||
<str id="antialiasing">"Antialiasing"</str>
|
||||
<str id="highMemory">Alta Memória</str>
|
||||
<str id="lowMemory">Baixa Memória</str>
|
||||
<str id="attributes">Atributos</str>
|
||||
<str id="transformPreview">Pré-visualização:</str>
|
||||
<str id="animations">Animações</str>
|
||||
|
||||
<str id="animType">Tipo de Animação</str>
|
||||
<group name="AnimTypeDropdown" prefix="animType.">
|
||||
<str id="none">NENHUM</str>
|
||||
<str id="beat">EM BATIDA</str>
|
||||
<str id="loop">REPETIR</str>
|
||||
</group>
|
||||
<str id="tipCustomProperties">Dica: Para aceder a mais dados,\nSegure em Shift quando Editar</str>
|
||||
</group>
|
||||
|
||||
<group name="StageXMLEditScreen" prefix="stageXMLEditScreen.">
|
||||
<str id="win-title">A Editar XML de {0}</str>
|
||||
<str id="title">Dados do XML</str>
|
||||
<str id="attributes">Atributos</str>
|
||||
</group>
|
||||
|
||||
<str id="stageCharacters.requiredPosition">Esta posição é necessária em cenários!</str>
|
||||
<str id="stageCharacters.noDeleteGirlfriend">Não pode apagar a Girlfriend</str>
|
||||
|
||||
<group name="StageElement" prefix="stageElement.">
|
||||
<str id="scale">Tamanho: {0}, {1}</str>
|
||||
<str id="scroll">Deslocamento: {0}, {1}</str>
|
||||
</group>
|
||||
|
||||
<group name="StageSprites" prefix="stageSprites.">
|
||||
<str id="win-title">Sprites do Cenário</str>
|
||||
<str id="sprite">Sprite</str>
|
||||
<str id="box">Caixa</str>
|
||||
<str id="character">Personagem</str>
|
||||
<str id="warnings.not-implemented">Criar caixas ainda não foi implementado!</str>
|
||||
</group>
|
||||
</group>
|
||||
|
||||
<group name="PlayTesting" prefix="playtesting.">
|
||||
<str id="chartPlaytesting" notrim="true"> (Teste de mapa)</str>
|
||||
<str id="exitGame">Sair do Jogo</str>
|
||||
<str id="exitToMenu">Sair Para Menu</str>
|
||||
<str id="saveAndExitGame">Guardar e Sair do Jogo</str>
|
||||
<str id="saveAndExitToMenu">Guardar e Sair Para Menu</str>
|
||||
<str id="cancel">Cancelar</str>
|
||||
|
||||
<str id="warningTitle">MUDANÇAS NÃO GUARDADAS!</str>
|
||||
<str id="warningDesc">Quaisquer mudanças serão *perdidas* se não as guardar. (Não serão recuperáveis)\n\n\nGostaria de Cancelar?</str>
|
||||
</group>
|
||||
|
||||
<group name="SaveWarning" prefix="saveWarning.">
|
||||
<str id="warningTitle">Mudanças não guardadas!</str>
|
||||
<str id="warningDesc">Quaisquer mudanças serão perdidas se não as guardar. (Não serão recuperáveis)\n\n\nGostaria de Cancelar?</str>
|
||||
|
||||
<str id="exitGame">Sair do Jogo</str>
|
||||
<str id="exitToMenu">Sair Para Menu</str>
|
||||
<str id="saveAndExitGame">Guardar e Sair do Jogo</str>
|
||||
<str id="saveAndExitToMenu">Guardar e Sair Para Menu</str>
|
||||
<str id="cancel">Cancelar</str>
|
||||
</group>
|
||||
|
||||
<group name="ModConfigWarning" prefix="modConfigWarning.">
|
||||
<str id="warningTitle">Configuração da pasta do mod em falta!</str>
|
||||
<str id="warningDesc">Está a faltar um ficheiro de configurações ao seu mod!\n\nGostaria de criar um automaticamente?\n\n(PS: Se este mod não for seu, por favor desative o Modo de desenvolvedor para fazer esta notificação parar de aparecer.)</str>
|
||||
|
||||
<str id="createdTitle">Config. de mod criada!</str>
|
||||
<str id="createdDesc">As configurações do seu mod foram criadas em {0}!</str>
|
||||
</group>
|
||||
</language>
|
||||
@@ -0,0 +1,104 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<language>
|
||||
<group name="PlayState">
|
||||
<str id="game.score">Pontos:{0}</str>
|
||||
<str id="game.misses">Erros:{0}</str>
|
||||
<str id="game.comboBreaks">Quebras de Combo:{0}</str>
|
||||
<str id="game.accuracy">Precisão:{0} - {1}</str>
|
||||
<str id="game.combo">Combo:{0}</str>
|
||||
|
||||
<str id="game.rating.[N/A]">[N/A]</str>
|
||||
<str id="game.rating.F">F</str>
|
||||
<str id="game.rating.E">E</str>
|
||||
<str id="game.rating.D">D</str>
|
||||
<str id="game.rating.C">C</str>
|
||||
<str id="game.rating.B">B</str>
|
||||
<str id="game.rating.A">A</str>
|
||||
<str id="game.rating.S">S</str>
|
||||
<str id="game.rating.S++">S++</str>
|
||||
</group>
|
||||
|
||||
<group name="StoryMenu">
|
||||
<str id="story.score">PONTUAÇÃO DA SEMANA:{0}</str>
|
||||
<str id="story.tracks">FAIXAS</str>
|
||||
</group>
|
||||
|
||||
<group name="Freeplay">
|
||||
<str id="freeplay.score">RECORDE PESSOAL:{0}</str>
|
||||
<str id="freeplay.solo">Solo</str>
|
||||
<str id="freeplay.opponentMode">Modo Oponente</str>
|
||||
<str id="freeplay.coopMode">Modo Co-Op</str>
|
||||
<str id="freeplay.coopModeSwitched">Modo Co-Op (Trocado)</str>
|
||||
</group>
|
||||
|
||||
<group name="Pause">
|
||||
<group name="PauseOptions">
|
||||
<str id="pause.resume">Continuar</str>
|
||||
<str id="pause.restartSong">Recomeçar Canção</str>
|
||||
<str id="pause.changeControls">Mudar Controlos</str>
|
||||
<str id="pause.changeOptions">Opções</str>
|
||||
<str id="pause.exitToMenu">Sair para menu</str>
|
||||
<str id="pause.exitToCharter">Sair para editor</str>
|
||||
<str id="pause.resumeCutscene">Resumir Cena</str>
|
||||
<str id="pause.skipCutscene">Saltar Cena</str>
|
||||
<str id="pause.restartCutscene">Recomeçar Cena</str>
|
||||
</group>
|
||||
|
||||
<str id="pause.deathCounter">Tomates azuis: {0}</str>
|
||||
<str id="pause.coopMode">MODO CO-OP</str>
|
||||
<str id="pause.opponentMode">MODO OPONENTE </str>
|
||||
</group>
|
||||
|
||||
<group name="Credits">
|
||||
<group name="CreditsCodename">
|
||||
<str id="credits.mainDev" notrim="true"> *- Membro público dos Desenvolvedores!*</str>
|
||||
<str id="credits.totalContributions">Contribuições Totais: ~{0}~ / *{1}* (~{2}%~) - Selecione para abrir a sua conta GitHub</str>
|
||||
<str id="credits.downloadingList">A Descarregar Lista...</str>
|
||||
<str id="credits.allContributors">Todos os contribuidores! Carregue em REINICIAR para atualizar a lista (Uma vez a cada 2 minutos).</str>
|
||||
</group>
|
||||
<group name="CreditsMain">
|
||||
<str id="credits.name">Créditos</str>
|
||||
<str id="credits.madePossible">As pessoas que fizeram isto possível!</str>
|
||||
<str id="credits.selectCodename">Selecione isto para ver todos os contribuidores de Codename Engine!</str>
|
||||
<str id="credits.selectBase">Selecione isto para abrir a página itch.io do jogo original para doar!</str>
|
||||
</group>
|
||||
</group>
|
||||
|
||||
<group name="Mods">
|
||||
<str id="mods.disableMods">Desativar Mods</str>
|
||||
</group>
|
||||
|
||||
<group name="MainMenu">
|
||||
<str id="mainMenu.commit">Commit: {0} ({1})</str>
|
||||
<str id="mainMenu.openMods">[{0}] Abrir menu de mods</str>
|
||||
</group>
|
||||
|
||||
<group name="Updater">
|
||||
<group name="UpdateAvailable">
|
||||
<str id="updateAvailable.title">NOVA ATUALIZAÇÃO</str>
|
||||
<str id="updateAvailable.install">INSTALAR</str>
|
||||
<str id="updateAvailable.skip">SALTAR</str>
|
||||
</group>
|
||||
<group name="UpdateScreen">
|
||||
<str id="updateScreen.general-1">A Preparar a instalação...</str>
|
||||
<str id="updateScreen.part-1">A Criar a pasta de instalação e a limpar ficheiros antigos...</str>
|
||||
|
||||
<str id="updateScreen.general-2">A Transferir ficheiros...</str>
|
||||
<str id="updateScreen.part-2">A Transferir ficheiro {0}</str>
|
||||
|
||||
<str id="updateScreen.general-3">A transferir executável novo...</str>
|
||||
<str id="updateScreen.part-3">A Transferir {0}</str>
|
||||
|
||||
<str id="updateScreen.general-4">A instalar ficheiros novos...</str>
|
||||
<str id="updateScreen.part-4">A Instalar {0}</str>
|
||||
</group>
|
||||
</group>
|
||||
|
||||
<group name="Difficulties">
|
||||
<str id="diff.easy">Fácil</str>
|
||||
<str id="diff.normal">Normal</str>
|
||||
<str id="diff.hard">Difícil</str>
|
||||
<str id="diff.erect">Ereto</str>
|
||||
<str id="diff.nightmare">Pesadelo</str>
|
||||
</group>
|
||||
</language>
|
||||
@@ -0,0 +1,207 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<language>
|
||||
<str id="optionsMenu.desc-missing">Sem descrição</str>
|
||||
|
||||
<group name="OptionsMenu">
|
||||
<str id="optionsMenu.advanced">Avançado</str>
|
||||
<str id="optionsMenu.header.title">Opções</str>
|
||||
<str id="optionsMenu.header.desc">Selecione uma categoria para continuar.</str>
|
||||
|
||||
<str id="optionsTree.controls-name">Controlos</str>
|
||||
<str id="optionsTree.controls-desc">Mude os Controlos para Jogador 1 e Jogador 2!</str>
|
||||
|
||||
<str id="optionsTree.gameplay-name">Jogo</str>
|
||||
<str id="optionsTree.gameplay-desc">Mude as opções como "Downscroll", Velocidade das notas, Indecência...</str>
|
||||
<str id="optionsTree.gameplay.advanced-desc">Mude as opções mais avançadas como Transmissão de áudio...</str>
|
||||
|
||||
<str id="optionsTree.appearance-name">Aparência</str>
|
||||
<str id="optionsTree.appearance-desc">Mude as opções de aparência como Luzes intermitentes...</str>
|
||||
<str id="optionsTree.appearance.advanced-desc">Mude as opções mais avançadas como Sprites apenas em VRAM, "Antialiasing", "Shaders"</str>
|
||||
|
||||
<str id="optionsTree.language-name">Idioma</str>
|
||||
<str id="optionsTree.language-desc">Mude o idioma que o jogo usa.</str>
|
||||
|
||||
<str id="optionsTree.miscellaneous-name">Outras</str>
|
||||
<str id="optionsTree.miscellaneous-desc">Use este menu para apagar dados ou definições.</str>
|
||||
|
||||
<str id="optionsTree.debug-name">Opções de Depuração</str>
|
||||
<str id="optionsTree.debug-desc">Opções de Depuração para o Modo de Desenvolvedor.</str>
|
||||
</group>
|
||||
|
||||
<group name="KeybindOptions" prefix="KeybindsOptions.">
|
||||
<str id="left">Esquerda</str>
|
||||
<str id="down">Baixo</str>
|
||||
<str id="up">Cima</str>
|
||||
<str id="right">Direita</str>
|
||||
|
||||
<str id="category.notes">Notas</str>
|
||||
|
||||
<str id="category.ui">Interface</str>
|
||||
<group name="ui" prefix="ui.">
|
||||
<str id="accept">Aceitar</str>
|
||||
<str id="back">Cancelar</str>
|
||||
<str id="reset">Reiniciar</str>
|
||||
<str id="pause">Pausa</str>
|
||||
<str id="changeMode">Mudar Modo</str>
|
||||
</group>
|
||||
|
||||
<str id="category.engine">Codename Engine</str>
|
||||
<group name="engine" prefix="engine.">
|
||||
<str id="switchMod">Trocar Mod</str>
|
||||
</group>
|
||||
|
||||
<str id="category.volume">Volume</str>
|
||||
<str id="volume.up">Subir</str>
|
||||
<str id="volume.down">Baixar</str>
|
||||
<str id="volume.mute">Silenciar</str>
|
||||
|
||||
<str id="category.developer">Desenvolvedor</str>
|
||||
<group name="developer" prefix="developer.">
|
||||
<str id="devMenus">Menus Dev.</str>
|
||||
<str id="openConsole">Consola</str>
|
||||
<str id="reloadState">Recarregar</str>
|
||||
</group>
|
||||
</group>
|
||||
|
||||
<group name="AppearanceOptions" prefix="AppearanceOptions.">
|
||||
<str id="framerate-name">FPS</str>
|
||||
<str id="framerate-desc">Quadros Por Segundo, se quiser. Explica-se a sí próprio, certo?</str>
|
||||
|
||||
<str id="flashingMenu-name">Luzes Intermitentes</str>
|
||||
<str id="flashingMenu-desc">Se desmarcado, irá desativar as luzes intermitentes quando seleciona algo no Menu Principal, e outras serão abrandadas.</str>
|
||||
|
||||
<str id="colorHealthBar-name">Barra de Vida Colorida</str>
|
||||
<str id="colorHealthBar-desc">Se desmarcado, o jogo irá usar a barra vermelha/verde de versões FNF pré-semana 7.</str>
|
||||
|
||||
<str id="week6PixelPerfect-name">Efeito "Pixel Perfect"</str>
|
||||
<str id="week6PixelPerfect-desc">se marcado, a Semana 6 ou outros cenários "pixel" terão um efeito "pixel perfect", alinhando todos os pixeis ao ecrã.</str>
|
||||
|
||||
<group name="AppearanceOptionsAdvanced" prefix="Advanced.">
|
||||
<str id="quality-name">Qualidade</str>
|
||||
<str id="quality-desc">Modos de qualidade para escolher, "BAIXA" = Desativa todos os efeitos visuais pesados para um jogo mais suave, "ALTA" = Ativa todos os efeitos visuais, ao custo do desempenho, "CUSTOMIZADA" = Permite opções especiais, disponíveis em "Advançado".</str>
|
||||
<str id="quality-low">BAIXA</str>
|
||||
<str id="quality-high">ALTA</str>
|
||||
<str id="quality-custom">CUSTOMIZADA</str>
|
||||
|
||||
<str id="antialiasing-name">"Antialiasing"</str>
|
||||
<str id="antialiasing-desc">Se desmarcado, irá remover "antialiasing" a todos os sprites. Poderá aumentar o desempenho ao custo de sprites menos suaves.</str>
|
||||
|
||||
<str id="lowMemoryMode-name">Memória baixa</str>
|
||||
<str id="lowMemoryMode-desc">Se marcado, irá remover certos elementos de fundo para reduzir o uso de memória.</str>
|
||||
|
||||
<str id="gameplayShaders-name">"Shaders"</str>
|
||||
<str id="gameplayShaders-desc">If desmarcado, "Shaders" (efeitos visuais como a Aberração cromática de "Thorns") não serão carregadas; poderá ser útil em dispositivos fracos.</str>
|
||||
|
||||
<str id="gpuOnlyBitmaps-name">Sprites só em VRAM</str>
|
||||
<str id="gpuOnlyBitmaps-desc">Se marcado, irá apenas guardar os bitmaps na GPU, libertando IMENSA memória (EXPERIMENTAL). Desmarcar isto irá consumir muita memória, especialmente em sprites maiores. Se não tiver a certeza, deixe isto marcado.</str>
|
||||
</group>
|
||||
</group>
|
||||
|
||||
<group name="GameplayOptions" prefix="GameplayOptions.">
|
||||
<str id="downscroll-name">"Downscroll"</str>
|
||||
<str id="downscroll-desc">Se marcado, notas irão de cima para baixo em vez de baixo para cima, como se estivessem a cair.</str>
|
||||
|
||||
<str id="ghostTapping-name">Toques Fantasma</str>
|
||||
<str id="ghostTapping-desc">Se desmarcado, bater em teclas que não tem uma nota conta como erro.</str>
|
||||
|
||||
<str id="naughtyness-name">Indecência</str>
|
||||
<str id="naughtyness-desc">Se desmarcado, irá censurar as cenas da Semana 7, ou mais.</str>
|
||||
|
||||
<str id="camZoomOnBeat-name">Zoom na Batida</str>
|
||||
<str id="camZoomOnBeat-desc">Se desmarcado. irá parar a câmara de ampliar a cada 4 batidas.</str>
|
||||
|
||||
<str id="autoPause-name">Auto Pausa</str>
|
||||
<str id="autoPause-desc">Se marcado, mudar de janela pausará o jogo.</str>
|
||||
|
||||
<str id="volumeMusic-name">Volume da Música</str>
|
||||
<str id="volumeMusic-desc">Muda apenas o volume da música em vez de tudo.</str>
|
||||
|
||||
<str id="volumeSFX-name">Volume dos SFX</str>
|
||||
<str id="volumeSFX-desc">Muda apenas o volume dos efeitos sonoros em vez de tudo.</str>
|
||||
|
||||
<str id="songOffset-name">Atraso da Música</str>
|
||||
<str id="songOffset-desc">Muda a posição da música relativamente às notas.</str>
|
||||
|
||||
<group name="GameplayOptionsAdvanced" prefix="Advanced.">
|
||||
<str id="windowSize-name">Tamanho da Janela</str>
|
||||
<str id="windowSize-desc">...</str>
|
||||
|
||||
<str id="streamedMusic-name">Transmissão de Música</str>
|
||||
<str id="streamedMusic-desc">Se marcado, músicas serão transmitidas enquanto tocam, libertando IMENSA memória com o custo de maior uso de CPU se mais sons estiverem a ser transmitidos ao mesmo tempo (EXPERIMENTAL). Desmarcar isto irá consumir muita memória, especialmente em músicas maiores. Se não tiver a certeza, deixe marcado.</str>
|
||||
|
||||
<str id="streamedVocals-name">Transmissão de Vozes</str>
|
||||
<str id="streamedVocals-desc">Se marcado, vozes também serão transmitidas enquanto tocam se "Transmissão de Música" estiver ativada. Irá impactar o desempenho se a canção usar muitas vozes (EXPERIMENTAL). Se não tiver a certeza, deixe marcado.</str>
|
||||
</group>
|
||||
</group>
|
||||
|
||||
<group name="LanguageOptions" prefix="LanguageOptions.">
|
||||
<str id="language-name">Idioma</str>
|
||||
<str id="language-desc">Idioma por {0} (Versão: {1})</str>
|
||||
</group>
|
||||
|
||||
<group name="MiscOptions" prefix="MiscOptions.">
|
||||
<str id="forceCrash-name">Forçar "Crash"</str>
|
||||
<str id="forceCrash-desc">Selecione esta opção para forçar o jogo a encravar e travar.</str>
|
||||
|
||||
<str id="betaUpdates-name">Atualizações "Nightly"</str>
|
||||
<str id="betaUpdates-desc">Se marcado, também irá incluir versões "nightly" (a versão mais recente disponível no repositório de GitHub) na verificação de atualizações.</str>
|
||||
|
||||
<str id="checkForUpdates-name">Verificar Atualizações</str>
|
||||
<str id="checkForUpdates-desc">Selecione esta opção para verificar se existem atualizações novas.</str>
|
||||
<str id="checkForUpdates-noUpdateFound">Nenhuma atualização encontrada.</str>
|
||||
|
||||
<str id="devMode-name">Modo Desenvolvedor</str>
|
||||
<str id="devMode-desc">Se marcado, irá poder aceder funções de desenvolvedor como certas teclas, editores, opções de desenvolvedor, recarregamento de estados, consola e mais.</str>
|
||||
|
||||
<str id="allowConfigWarning-name">Aviso de Modpacks</str>
|
||||
<str id="allowConfigWarning-desc">Se marcado, um aviso no início do jogo aparecerá se houver problemas com o modpack, como configurações em falta, versões incompatíveis e mais.</str>
|
||||
|
||||
<str id="resetSaveData-name">Apagar Dados</str>
|
||||
<str id="resetSaveData-desc">Selecione esta opção para apagar todos os dados. Isto irá remover todos os seus recordes.</str>
|
||||
</group>
|
||||
|
||||
<group name="DebugOptions" prefix="DebugOptions.">
|
||||
<str id="title">Opções de Depuração</str>
|
||||
<str id="desc">Use este menu para ativar ou desativar opções de depuração.</str>
|
||||
|
||||
<str id="showConsole-name">Mostrar Consola</str>
|
||||
<str id="showConsole-desc">Selecione isto para mostrar a consola, que contém registos acerca do jogo.</str>
|
||||
|
||||
<str id="editorsResizable-name">Editores Adaptáveis</str>
|
||||
<str id="editorsResizable-desc">Se marcado, irá permitir que os editores utilizem resoluções acima da base 1280x720 de FNF (permitindo mais detalhe e espaço...)</str>
|
||||
|
||||
<str id="bypassEditorsResize-name">Sem Tamanho Mínimo</str>
|
||||
<str id="bypassEditorsResize-desc">Desativa o limite de resolução minimo dos editores (Requer que "Editores Adaptáveis" esteja marcado).</str>
|
||||
|
||||
<str id="editorSFX-name">Sons de Editor</str>
|
||||
<str id="editorSFX-desc">Se marcado, tocará efeitos sonoros nos editores (ex: ao carregar em caixas...)</str>
|
||||
|
||||
<str id="editorCharterPrettyPrint-name">Mapas Legíveis</str>
|
||||
<str id="editorCharterPrettyPrint-desc">Se marcado, os ficheiros guardados no editor de mapas serão formatados para serem fácilmente legíveis.</str>
|
||||
|
||||
<str id="editorCharacterPrettyPrint-name">Personagens Legíveis</str>
|
||||
<str id="editorCharacterPrettyPrint-desc">Se marcado, os ficheiros guardados no editor de personagens serão formatados para serem fácilmente legíveis.</str>
|
||||
|
||||
<str id="editorStagePrettyPrint-name">Cenários Legíveis</str>
|
||||
<str id="editorStagePrettyPrint-desc">Se marcado, os ficheiros guardados no editor de cenários serão formatados para serem fácilmente legíveis.</str>
|
||||
|
||||
<str id="intensiveBlur-name">Desfoque Intensivo</str>
|
||||
<str id="intensiveBlur-desc">Se marcado, irá usar um desfoque mais intensivo. Parece melhor, mas poderá ser mais lento.</str>
|
||||
|
||||
<str id="charterAutoSaves-name">Gravação Automática</str>
|
||||
<str id="charterAutoSaves-desc">Se marcado, irá guardar ficheiros de editor automáticamente, com as definições listadas abaixo.</str>
|
||||
|
||||
<str id="charterAutoSaveTime-name">Tempo de Gravação</str>
|
||||
<str id="charterAutoSaveTime-desc">Isto controla com que frequência o editor gravará o ficheiro (em segundos...)</str>
|
||||
|
||||
<str id="charterAutoSaveWarningTime-name">Tempo de Aviso</str>
|
||||
<str id="charterAutoSaveWarningTime-desc">Isto controla com que antecedência o editor irá avisá-lo antes de guardar (em segundos..., 0 para desativar)</str>
|
||||
|
||||
<str id="charterAutoSavesSeparateFolder-name">Pasta de Gravações</str>
|
||||
<str id="charterAutoSavesSeparateFolder-desc">Se marcado, irá guardar os ficheiros numa pasta separada com a data em vez de substituir o ficheiro atual. (song/autosaves/)</str>
|
||||
|
||||
<str id="songOffsetAffectEditors-name">Atraso no Mapeador</str>
|
||||
<str id="songOffsetAffectEditors-desc">Se marcado, irá ativar o Atraso da Música no Editor de Mapas, também.</str>
|
||||
</group>
|
||||
|
||||
</language>
|
||||
@@ -0,0 +1,3 @@
|
||||
name="Português"
|
||||
credits="Bitto1070"
|
||||
version="1.0.0"
|
||||
@@ -1,19 +1,15 @@
|
||||
import flixel.FlxSprite;
|
||||
|
||||
var tankmanRun:Array<TankmenBG> = [];
|
||||
var grpTankmanRun:FlxTypedGroup<FlxSprite> = [];
|
||||
|
||||
var spawnTimes = []; // [[time, direction]]
|
||||
var tankmanPool = [];
|
||||
|
||||
function recycleTankman() {
|
||||
if(tankmanPool.length == 0) {
|
||||
return new TankmenBG();
|
||||
} else {
|
||||
return tankmanPool.shift(); // can be pop but it causes it to be less random
|
||||
}
|
||||
var tankmanGroup:TankmenGroup = {
|
||||
run: [],
|
||||
pool: [],
|
||||
group: new FlxTypedGroup<FlxSprite>()
|
||||
}
|
||||
|
||||
function recycleTankman()
|
||||
return tankmanGroup.pool.length == 0 ? new TankmenBG(tankmanGroup) : tankmanGroup.pool.shift(); // can be pop but it causes it to be less random
|
||||
|
||||
function getTankman(data:Array<Float>) {
|
||||
var tankman:TankmenBG = recycleTankman();
|
||||
tankman.strumTime = data[0];
|
||||
@@ -22,9 +18,8 @@ function getTankman(data:Array<Float>) {
|
||||
}
|
||||
|
||||
function postCreate() {
|
||||
grpTankmanRun = new FlxTypedGroup();
|
||||
insert(members.indexOf(gf) - 1, grpTankmanRun);
|
||||
if(inCutscene) grpTankmanRun.visible = false;
|
||||
insert(members.indexOf(gf) - 1, tankmanGroup.group);
|
||||
if (inCutscene) tankmanGroup.group.visible = false;
|
||||
|
||||
/*var tempTankman:TankmenBG = recycleTankman();
|
||||
tempTankman.strumTime = 10;
|
||||
@@ -42,9 +37,8 @@ function postCreate() {
|
||||
//spawnTimes.reverse(); // no need to reverse it since the notes are already reversed
|
||||
}
|
||||
|
||||
function onStartCountdown() {
|
||||
if(PlayState.instance.seenCutscene) grpTankmanRun.visible = true;
|
||||
}
|
||||
function onStartCountdown()
|
||||
if (PlayState.instance.seenCutscene) tankmanGroup.group.visible = true;
|
||||
|
||||
function spawnTankmen() {
|
||||
var time = Conductor.songPosition;
|
||||
@@ -54,50 +48,46 @@ function spawnTankmen() {
|
||||
|
||||
//trace("Spawning Tankman", tankmen.sprite.offset, tankmen.goingRight);
|
||||
|
||||
tankmanRun.push(tankmen);
|
||||
grpTankmanRun.add(tankmen.sprite);
|
||||
tankmanGroup.run.push(tankmen);
|
||||
tankmanGroup.group.add(tankmen.sprite);
|
||||
}
|
||||
}
|
||||
|
||||
function update(elapsed) {
|
||||
spawnTankmen();
|
||||
|
||||
var length = tankmanRun.length;
|
||||
for(i in 0...length) {
|
||||
var length = tankmanGroup.run.length;
|
||||
for (i in 0...length) {
|
||||
var reverseIndex = length - i - 1;
|
||||
var tankmen = tankmanRun[reverseIndex];
|
||||
var tankmen = tankmanGroup.run[reverseIndex];
|
||||
tankmen.update(elapsed);
|
||||
}
|
||||
}
|
||||
|
||||
class TankmenBG {
|
||||
public var sprite:FlxSprite;
|
||||
|
||||
var strumTime = 0;
|
||||
var goingRight = false;
|
||||
var tankSpeed = 0.7;
|
||||
|
||||
var endingOffset = null;
|
||||
var sprite = null;
|
||||
|
||||
var endingOffset:Float;
|
||||
var killed = false;
|
||||
var grp:TankmenGroup; // The reference to the current pool
|
||||
|
||||
function new() {
|
||||
this.sprite = new FlxSprite();
|
||||
var sprite = this.sprite;
|
||||
function new(grp:TankmenGroup) {
|
||||
this.grp = grp;
|
||||
|
||||
sprite = new FlxSprite();
|
||||
sprite.frames = Paths.getSparrowAtlas('stages/tank/tankmanKilled1');
|
||||
sprite.antialiasing = true;
|
||||
sprite.animation.addByPrefix('run', 'tankman running', 24, true);
|
||||
|
||||
sprite.animation.play('run');
|
||||
|
||||
sprite.updateHitbox();
|
||||
|
||||
sprite.setGraphicSize(Std.int(sprite.width * 0.8));
|
||||
sprite.updateHitbox();
|
||||
}
|
||||
|
||||
function resetShit(x, y, isGoingRight) {
|
||||
var sprite = this.sprite;
|
||||
function resetShit(x:Float, y:Float, isGoingRight:Bool) {
|
||||
sprite.revive();
|
||||
sprite.setPosition(x, y);
|
||||
sprite.offset.set(0, 0);
|
||||
@@ -114,7 +104,6 @@ class TankmenBG {
|
||||
}
|
||||
|
||||
function update(elapsed) {
|
||||
var sprite = this.sprite;
|
||||
sprite.visible = !(sprite.x >= FlxG.width * 1.5 || sprite.x <= FlxG.width * -0.5);
|
||||
|
||||
if (sprite.animation.curAnim.name == 'run')
|
||||
@@ -124,8 +113,7 @@ class TankmenBG {
|
||||
if (goingRight) {
|
||||
endDirection = (FlxG.width * 0.02) - endingOffset;
|
||||
sprite.x = (endDirection + (Conductor.songPosition - strumTime) * tankSpeed);
|
||||
}
|
||||
else sprite.x = (endDirection - (Conductor.songPosition - strumTime) * tankSpeed);
|
||||
} else sprite.x = (endDirection - (Conductor.songPosition - strumTime) * tankSpeed);
|
||||
}
|
||||
|
||||
if (Conductor.songPosition > strumTime)
|
||||
@@ -133,10 +121,10 @@ class TankmenBG {
|
||||
sprite.animation.play('shot');
|
||||
sprite.animation.finishCallback = function(_) {
|
||||
killed = true;
|
||||
grpTankmanRun.remove(sprite, true);
|
||||
grp.group.remove(sprite, true);
|
||||
sprite.kill();
|
||||
tankmanPool.push(this);
|
||||
tankmanRun.remove(this);
|
||||
grp.pool.push(this);
|
||||
grp.run.remove(this);
|
||||
}
|
||||
|
||||
if (goingRight)
|
||||
@@ -146,4 +134,4 @@ class TankmenBG {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
Here's the full guide on how to setup and compile Codename Engine!<br>
|
||||
|
||||
> **Open the instructions for your platform**
|
||||
<details>
|
||||
<summary>Windows</summary>
|
||||
|
||||
1. Install [version 4.3.7 of Haxe](https://haxe.org/download/version/4.3.7/).
|
||||
2. Download and install [`git-scm`](https://git-scm.com/download/win).
|
||||
- Leave all installation options as default.
|
||||
3. Run `setup-windows.bat` using cmd or double-clicking it and wait for the libraries to install.
|
||||
4. Once the libraries are installed, run `haxelib run lime test windows` to compile and launch the game (may take a long time)
|
||||
- ℹ You can run `haxelib run lime setup` to make the lime command global, allowing you to execute `lime test windows` directly.
|
||||
</details>
|
||||
<details>
|
||||
<summary>Linux</summary>
|
||||
|
||||
1. Install [version 4.3.7 of Haxe](https://haxe.org/download/version/4.3.7/).
|
||||
2. Install `libvlc` if not present already.
|
||||
- ℹ On certain Arch based distros installing `vlc-plugins-all` might solve if `libvlc` alone doesn't work.
|
||||
3. Install `g++`, if not present already.
|
||||
4. Download and install [`git-scm`](https://git-scm.com/download/linux) if not present already.
|
||||
5. Run `setup-unix.sh` using the terminal or double-clicking it and wait for the libraries to install.
|
||||
6. Once the libraries are installed, run `haxelib run lime test linux` to compile and launch the game (may take a long time)
|
||||
- ℹ You can run `haxelib run lime setup` to make the lime command global, allowing you to execute `lime test linux` directly.
|
||||
</details>
|
||||
<details>
|
||||
<summary>MacOS</summary>
|
||||
|
||||
1. Install [version 4.3.7 of Haxe](https://haxe.org/download/version/4.3.7/).
|
||||
2. Install `Xcode` to allow C++ app building.
|
||||
3. Download and install [`git-scm`](https://git-scm.com/download/mac).
|
||||
4. Run `setup-unix.sh` using the terminal and wait for the libraries to install.
|
||||
5. Once the libraries are installed, run `haxelib run lime test mac` to compile and launch the game (may take a long time)
|
||||
- ℹ You can run `haxelib run lime setup` to make the lime command global, allowing you to execute `lime test mac` directly.
|
||||
</details>
|
||||
|
||||
> [!TIP]
|
||||
> You can also run `./cne-windows.bat -help` or `./cne-unix.sh -help` (depending on your platform) to check out more useful commands!<br>
|
||||
> For example `./cne-windows test` or `./cne-unix.sh test` builds the game and uses the source assets folder instead of the export one for easier development (although you can still use `lime test` normally).
|
||||
> - If you're running the terminal from the project's main folder, use instead `./building/cne-windows.bat -COMMAND HERE` or `./building/cne-unix.sh -COMMAND HERE` depending on your platform.
|
||||
@@ -1 +1,3 @@
|
||||
#!/usr/bin/env sh
|
||||
cd "$(dirname "$0")/.."
|
||||
haxe -cp commandline -D analyzer-optimize --run Main $@
|
||||
@@ -1 +1,2 @@
|
||||
cd /d "%~dp0.."
|
||||
@haxe -cp commandline -D analyzer-optimize --run Main %*
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
<!-- OpenFL & Lime (Required for Flixel) -->
|
||||
<git name="openfl" url="https://github.com/CodenameCrew/cne-openfl" />
|
||||
<lib name="lime" version="8.1.2" />
|
||||
<lib name="lime" version="8.2.0" />
|
||||
<!-- <git name="lime" url="https://github.com/CodenameCrew/cne-lime" /> disabled for now until fixed -->
|
||||
|
||||
<!-- Flixel -->
|
||||
@@ -16,7 +16,7 @@
|
||||
<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" skipDeps="true" />
|
||||
<git name="funkin-modchart" url="https://github.com/CodenameCrew/FunkinModchart" skipDeps="true" />
|
||||
<git name="funkin-modchart" url="https://github.com/TheoDevelops/FunkinModchart" ref="f30676579d8de7ccac7d12e13b664e8b2c42c6bf" skipDeps="true" />
|
||||
<lib name="hxvlc" version="1.9.3" skipDeps="true" />
|
||||
|
||||
<!-- Documentation and other features -->
|
||||
@@ -1,2 +1,3 @@
|
||||
#!/bin/sh
|
||||
#!/usr/bin/env sh
|
||||
cd "$(dirname "$0")/.."
|
||||
haxe -cp commandline -D analyzer-optimize --run Main setup
|
||||
@@ -1 +1,2 @@
|
||||
cd /d "%~dp0.."
|
||||
@haxe -cp commandline -D analyzer-optimize --run Main setup
|
||||
+2
-1
@@ -16,7 +16,7 @@ class Main {
|
||||
dDoc: [
|
||||
"Usage: setup",
|
||||
"",
|
||||
"This command runs through all libraries in libs.xml, and install them.",
|
||||
"This command runs through all libraries in building/libs.xml, and install them.",
|
||||
"If they're already installed, they will be updated.",
|
||||
"",
|
||||
"--all : Reinstall all libraries.",
|
||||
@@ -173,6 +173,7 @@ class Main {
|
||||
Sys.println("Codename Engine Command Line utility");
|
||||
Sys.println('Available commands (${commands.length}):\n');
|
||||
for(line in commands) {
|
||||
if(line.names.contains(null)) line.names.remove(null);
|
||||
Sys.println('${line.names.join(", ")} - ${line.doc}');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,7 +55,7 @@ class Setup {
|
||||
FileSystem.createDirectory('.haxelib');
|
||||
}
|
||||
|
||||
var libFile = "./libs.xml";
|
||||
var libFile = "./building/libs.xml";
|
||||
if(args.existsOption("lib")) {
|
||||
libFile = args.getOption("lib");
|
||||
if(libFile == null) {
|
||||
@@ -252,32 +252,32 @@ class Setup {
|
||||
|
||||
// check for outdated haxe
|
||||
final curHaxeVer = [for(v in haxeVer.split(".")) Std.parseInt(v)];
|
||||
final minumumVersion = [4, 2, 5];
|
||||
final minumumVersion = [4, 3, 7];
|
||||
for(i in 0...minumumVersion.length) {
|
||||
if (curHaxeVer[i] > minumumVersion[i]) break;
|
||||
if (curHaxeVer[i] < minumumVersion[i]) {
|
||||
prettyPrint([
|
||||
"!! WARNING !!",
|
||||
"Your current Haxe version is outdated.",
|
||||
'You\'re using ${haxeVer}, whilst the required version is 4.2.5 or newer.',
|
||||
'You\'re using ${haxeVer}, whilst the required version is 4.3.7 or newer.',
|
||||
'The engine may not compile with your current version of Haxe.',
|
||||
'We recommend upgrading to 4.2.5 or newer'
|
||||
'We recommend upgrading to 4.3.7 or newer'
|
||||
].join("\n"));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// vswhere.exe its used to find any visual studio related installations on the system, including full visual studio ide installations, visual studio build tools installations, and other related components - Nex
|
||||
if (CHECK_VSTUDIO && Compiler.getBuildTarget().toLowerCase() == "windows" && new Process('"C:/Program Files (x86)/Microsoft Visual Studio/Installer/vswhere.exe" -property catalog_productDisplayVersion').exitCode(true) == 1) {
|
||||
// vswhere.exe is used to find any visual studio related installations on the system, including full visual studio ide installations, visual studio build tools installations, and other related components - Nex
|
||||
if (CHECK_VSTUDIO && Compiler.getBuildTarget().toLowerCase() == "windows" && new Process('"C:/Program Files (x86)/Microsoft Visual Studio/Installer/vswhere.exe" -latest -products * -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -requires Microsoft.VisualStudio.Component.Windows10SDK.19041 -property installationPath').exitCode(true) != 0) {
|
||||
prettyPrint("Installing Microsoft Visual Studio Community (Dependency)");
|
||||
|
||||
// thanks to @crowplexus for these two lines! - Nex
|
||||
command("curl -# -O https://download.visualstudio.microsoft.com/download/pr/3105fcfe-e771-41d6-9a1c-fc971e7d03a7/8eb13958dc429a6e6f7e0d6704d43a55f18d02a253608351b6bf6723ffdaf24e/vs_Community.exe");
|
||||
command("vs_Community.exe --add Microsoft.VisualStudio.Component.VC.Tools.x86.x64 --add Microsoft.VisualStudio.Component.Windows10SDK.19041 -p");
|
||||
|
||||
FileSystem.deleteFile("vs_Community.exe");
|
||||
prettyPrint('If it didn\'t say it before: Because of this component if you want to compile you have to restart the device.');
|
||||
|
||||
prettyPrint("Because of this component, if you want to compile, you need to restart the device.");
|
||||
Sys.print("Do you wish to do it now [y/n]? ");
|
||||
if(Sys.stdin().readLine().toLowerCase() == "y") command("shutdown /r /t 0 /f");
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
title="Friday Night Funkin' - Codename Engine" main="funkin.backend.system.Main"
|
||||
file="CodenameEngine" packageName="com.yoshman29.codenameengine"
|
||||
package="com.yoshman29.codenameengine"
|
||||
version="1.0.1-rc2" company="Yoshman29" />
|
||||
version="1.0.1" company="Yoshman29" />
|
||||
|
||||
<!--
|
||||
CHANGE THE SAVE PATH & NAME FOR YOUR MOD HERE!
|
||||
@@ -166,14 +166,12 @@
|
||||
|
||||
<!-- OpenAL config -->
|
||||
<section if="desktop">
|
||||
<assets path="alsoft.txt" rename="plugins/alsoft.ini" type="text" if="windows"/>
|
||||
<assets path="alsoft.txt" rename="plugins/alsoft.conf" type="text" unless="windows"/>
|
||||
<assets path="building/alsoft.txt" rename="plugins/alsoft.ini" type="text" if="windows"/>
|
||||
<assets path="building/alsoft.txt" rename="plugins/alsoft.conf" type="text" unless="windows"/>
|
||||
</section>
|
||||
|
||||
<!-- ______________________________ Haxedefines _____________________________ -->
|
||||
|
||||
<haxeflag name="--macro" value="funkin.backend.system.macros.BuildInfo.printBuildInfo()" />
|
||||
|
||||
<haxedef name="FLX_NO_FOCUS_LOST_SCREEN" />
|
||||
|
||||
<!--Disable the Flixel core debugger. Automatically gets set whenever you compile in release mode!-->
|
||||
@@ -227,9 +225,9 @@
|
||||
<setenv name="HAXEPATH" value="./"/>
|
||||
|
||||
<haxedef name="HXCPP_M32" if="32bit" />
|
||||
<haxedef name="HXCPP_CHECK_POINTER" if="release" />
|
||||
<haxedef name="HXCPP_STACK_LINE" if="release" />
|
||||
<haxedef name="HXCPP_DEBUG_LINK" if="debug" />
|
||||
<haxedef name="HXCPP_CHECK_POINTER" />
|
||||
<haxedef name="HXCPP_STACK_LINE" />
|
||||
<haxedef name="HXCPP_CATCH_SEGV" />
|
||||
|
||||
<haxedef name="hscriptPos" /> <!-- for logging -->
|
||||
+494
@@ -0,0 +1,494 @@
|
||||
// funkin source classes cannot be imported here
|
||||
import haxe.io.Path;
|
||||
import hxp.*;
|
||||
import lime.tools.*;
|
||||
import sys.FileSystem;
|
||||
import sys.io.Process;
|
||||
|
||||
using StringTools;
|
||||
|
||||
class Project extends HXProject
|
||||
{
|
||||
static final TITLE:String = "Friday Night Funkin' - Codename Engine";
|
||||
static final EXECUTABLE:String = "CodenameEngine";
|
||||
static final VERSION:String = "1.0.1";
|
||||
static final COMPANY:String = "Yoshman29";
|
||||
static final PACKAGE:String = "com.codenamecrew.codenameengine";
|
||||
static final MAIN_CLASS:String = "funkin.backend.system.MainApplication";
|
||||
|
||||
static final PRELOADER:String = "flixel.system.FlxPreloader";
|
||||
static final SOURCE_FOLDERS:Array<String> = ["source"];
|
||||
|
||||
// Compile Flags
|
||||
static final EMBED_ASSETS:CompileFlag = CompileFlag.get("EMBED_ASSETS");
|
||||
static final PRELOAD_ALL:CompileFlag = CompileFlag.get("PRELOAD_ALL");
|
||||
static final STRIPPED_COMPILE:CompileFlag = CompileFlag.get("STRIPPED_COMPILE");
|
||||
static final UPDATE_CHECKING:CompileFlag = CompileFlag.get("UPDATE_CHECKING");
|
||||
static final DISCORD_RPC:CompileFlag = CompileFlag.get("DISCORD_RPC");
|
||||
static final MODCHARTING_FEATURES:CompileFlag = CompileFlag.get("MODCHARTING_FEATURES");
|
||||
static final GITHUB_API:CompileFlag = CompileFlag.get("GITHUB_API");
|
||||
static final COMPILE_ALL_CLASSES:CompileFlag = CompileFlag.get("COMPILE_ALL_CLASSES");
|
||||
static final CUSTOM_CLASSES:CompileFlag = CompileFlag.get("CUSTOM_CLASSES");
|
||||
static final ALLOW_MULTITHREADING:CompileFlag = CompileFlag.get("ALLOW_MULTITHREADING");
|
||||
static final MOD_SUPPORT:CompileFlag = CompileFlag.get("MOD_SUPPORT");
|
||||
static final TRANSLATIONS_SUPPORT:CompileFlag = CompileFlag.get("TRANSLATIONS_SUPPORT");
|
||||
static final GLOBAL_SCRIPT:CompileFlag = CompileFlag.get("GLOBAL_SCRIPT");
|
||||
static final SOFTCODED_STATES:CompileFlag = CompileFlag.get("SOFTCODED_STATES");
|
||||
static final NDLLS_SUPPORTED:CompileFlag = CompileFlag.get("NDLLS_SUPPORTED");
|
||||
static final USE_ADAPTED_ASSETS:CompileFlag = CompileFlag.get("USE_ADAPTED_ASSETS");
|
||||
static final THREE_D_SUPPORT:CompileFlag = CompileFlag.get("THREE_D_SUPPORT");
|
||||
static final NAPE_ENABLED:CompileFlag = CompileFlag.get("NAPE_ENABLED");
|
||||
static final VIDEO_CUTSCENES:CompileFlag = CompileFlag.get("VIDEO_CUTSCENES");
|
||||
static final SHOW_BUILD_ON_FPS:CompileFlag = CompileFlag.get("SHOW_BUILD_ON_FPS");
|
||||
static final DARK_MODE_WINDOW:CompileFlag = CompileFlag.get("DARK_MODE_WINDOW");
|
||||
|
||||
public function new():Void
|
||||
{
|
||||
super();
|
||||
|
||||
CompileFlag.project = this;
|
||||
|
||||
haxe.Log.trace = (v:Dynamic, ?info:haxe.PosInfos) ->
|
||||
{
|
||||
if (!isDisplay())
|
||||
Sys.println(v);
|
||||
};
|
||||
|
||||
doWelcomeHeader();
|
||||
trace("Configuring project...");
|
||||
trace("");
|
||||
configureApp();
|
||||
configureCompileFlags();
|
||||
configureAssets();
|
||||
configureLibs();
|
||||
configureIcons();
|
||||
trace("");
|
||||
trace("Configured project");
|
||||
trace("Starting build...");
|
||||
trace("");
|
||||
}
|
||||
|
||||
function getHaxeVersion():String {
|
||||
var process = new Process("haxe", ["-version"]);
|
||||
var version:String = "";
|
||||
|
||||
try {
|
||||
version = process.stdout.readAll().toString().trim();
|
||||
} catch (e) {}
|
||||
|
||||
process.close();
|
||||
return version;
|
||||
}
|
||||
|
||||
function doWelcomeHeader() {
|
||||
var haxeVersion = getHaxeVersion().trim();
|
||||
var sleepChangeVersion = false;
|
||||
|
||||
var width = 60; // total banner width
|
||||
|
||||
inline function centerText(text:String, width:Int):String {
|
||||
var innerWidth = width - 2;
|
||||
var padding = Std.int(Math.max(0, Std.int((innerWidth - text.length) / 2)));
|
||||
var left = StringTools.lpad("", " ", padding);
|
||||
var right = StringTools.lpad("", " ", innerWidth - text.length - padding);
|
||||
return "=" + left + text + right + "=";
|
||||
}
|
||||
|
||||
inline function infoLine(label:String, value:String):String {
|
||||
var innerWidth = width - 2;
|
||||
if (label.length == 0) {
|
||||
// no label: center the value
|
||||
var padding = Std.int(Math.max(0, (innerWidth - value.length) / 2));
|
||||
var left = StringTools.lpad("", " ", padding);
|
||||
var right = StringTools.lpad("", " ", innerWidth - value.length - padding);
|
||||
return "=" + left + value + right + "=";
|
||||
} else {
|
||||
var colonPos = Std.int(innerWidth / 2);
|
||||
var labelPart = StringTools.lpad(label, " ", Std.int(Math.max(0, colonPos - 2)));
|
||||
var valuePart = value;
|
||||
var remainingSpace = Std.int(Math.max(0, innerWidth - (labelPart.length + 3 + valuePart.length)));
|
||||
var rightPad = StringTools.lpad("", " ", remainingSpace);
|
||||
return "=" + labelPart + " : " + valuePart + rightPad + "=";
|
||||
}
|
||||
}
|
||||
|
||||
var unicode = #if (target.unicode) true #else false #end;
|
||||
|
||||
trace('');
|
||||
trace(StringTools.lpad("", "=", width));
|
||||
trace(centerText(TITLE, width));
|
||||
trace(StringTools.lpad("", "=", width));
|
||||
trace(infoLine("Engine Version", 'v${VERSION}'));
|
||||
trace(infoLine("Haxe Version", 'v${haxeVersion}'));
|
||||
trace(StringTools.lpad("", "=", width));
|
||||
|
||||
try {
|
||||
var lastBuiltWith:Null<String> = null;
|
||||
var compiling = isDebug() ? "debug" : "release";
|
||||
var target = isWeb() ? "html5" : (isIOS() ? "ios" : (isAndroid() ? "android" : (isWindows() ? "windows" : (isMac() ? "macos" : (isLinux() ? "linux" : "")))));
|
||||
|
||||
if (target == "") throw "Unknown target";
|
||||
|
||||
var exportPath = Sys.getCwd() + "/export/" + compiling + "/" + target + "/obj/Options.txt";
|
||||
var options = sys.io.File.getContent(exportPath);
|
||||
|
||||
for (option in options.split("\n")) {
|
||||
if (option.startsWith("haxe=")) {
|
||||
lastBuiltWith = option.substr(5).trim();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (lastBuiltWith != null && lastBuiltWith.length > 0 && lastBuiltWith != haxeVersion) {
|
||||
trace(infoLine("", unicode ? "⚠️ Haxe version mismatch!" : "[WARNING] Haxe version mismatch!"));
|
||||
trace(infoLine("Last Built With", lastBuiltWith));
|
||||
trace(infoLine("Current Version", haxeVersion));
|
||||
trace(StringTools.lpad("", "=", width));
|
||||
trace(infoLine("", "!!! Make sure to DELETE your EXPORT folders !!!"));
|
||||
trace(StringTools.lpad("", "=", width));
|
||||
sleepChangeVersion = true;
|
||||
}
|
||||
} catch (e) {}
|
||||
|
||||
var targetPlatform = isWeb() ? "Web (HTML5)" : (isIOS() ? "iOS" : (isAndroid() ? "Android" : (isWindows() ? "Windows" : (isMac() ? "Mac" : (isLinux() ? "Linux" : "Unknown")))));
|
||||
|
||||
if (isHashLink())
|
||||
targetPlatform = "Hashlink (" + targetPlatform + ")";
|
||||
|
||||
trace(infoLine("Target Platform", targetPlatform));
|
||||
trace(infoLine("Build Type", isDebug() ? "Debug" : "Release"));
|
||||
trace(infoLine("Build Date", Date.now().toString()));
|
||||
trace(StringTools.lpad("", "=", width));
|
||||
trace('');
|
||||
|
||||
if (sleepChangeVersion)
|
||||
Sys.sleep(5);
|
||||
}
|
||||
|
||||
function configureApp():Void
|
||||
{
|
||||
trace("Configuring game...");
|
||||
meta.title = TITLE;
|
||||
meta.version = VERSION;
|
||||
meta.company = COMPANY;
|
||||
meta.packageName = PACKAGE;
|
||||
|
||||
app.main = MAIN_CLASS;
|
||||
app.file = EXECUTABLE;
|
||||
app.preloader = PRELOADER;
|
||||
|
||||
var buildDir = 'export/${isDebug() ? 'debug' : 'release'}/';
|
||||
trace('Output directory: $buildDir');
|
||||
app.path = buildDir;
|
||||
|
||||
sources = SOURCE_FOLDERS;
|
||||
templatePaths.push(Path.combine(Haxelib.getPath(new Haxelib(#if lime "lime" #else "hxp" #end)), #if lime "templates" #else "" #end));
|
||||
|
||||
window.hardware = true;
|
||||
window.vsync = false;
|
||||
window.allowHighDPI = true;
|
||||
|
||||
if (isWeb())
|
||||
window.resizable = true;
|
||||
|
||||
if (isDesktop())
|
||||
{
|
||||
window.orientation = Orientation.LANDSCAPE;
|
||||
window.fullscreen = false;
|
||||
window.resizable = true;
|
||||
window.vsync = false;
|
||||
} else if (isMobile())
|
||||
{
|
||||
window.orientation = Orientation.LANDSCAPE;
|
||||
window.fullscreen = true;
|
||||
window.resizable = false;
|
||||
window.borderless = true;
|
||||
window.width = 0;
|
||||
window.height = 0;
|
||||
}
|
||||
}
|
||||
|
||||
function configureCompileFlags()
|
||||
{
|
||||
trace("Configuring compile flags...");
|
||||
|
||||
setDefine("disable-version-check");
|
||||
setHaxedef("disable-version-check");
|
||||
setHaxedef("no-deprecation-warnings");
|
||||
|
||||
// DO NOT REMOVE!! ALLOWS ME TO DO REGIONS LIKE IN C# AND KEEP CODE ORGANIZED. REMOVING IT WOULD BREAK THE ENGINE
|
||||
setHaxedef("REGION");
|
||||
|
||||
setHaxedef("SAVE_PATH", EXECUTABLE);
|
||||
setHaxedef("SAVE_NAME", "save-default");
|
||||
setHaxedef("SAVE_OPTIONS_PATH", EXECUTABLE);
|
||||
setHaxedef("SAVE_OPTIONS_NAME", "options");
|
||||
|
||||
PRELOAD_ALL.integrate(!isWeb());
|
||||
EMBED_ASSETS.integrate(false);
|
||||
|
||||
UPDATE_CHECKING.integrate(!isWeb() && !isHashLink());
|
||||
DISCORD_RPC.integrate(isCPP() && isDesktop());
|
||||
STRIPPED_COMPILE.integrate(false); //should be isRelease() if you want to use it
|
||||
MODCHARTING_FEATURES.integrate(STRIPPED_COMPILE.isDisabled());
|
||||
GITHUB_API.integrate(!isWeb() && !isHashLink());
|
||||
COMPILE_ALL_CLASSES.integrate(STRIPPED_COMPILE.isDisabled());
|
||||
CUSTOM_CLASSES.integrate(STRIPPED_COMPILE.isDisabled());
|
||||
ALLOW_MULTITHREADING.integrate(!isWeb());
|
||||
MOD_SUPPORT.integrate(!isWeb());
|
||||
TRANSLATIONS_SUPPORT.integrate(true);
|
||||
GLOBAL_SCRIPT.integrate(true);
|
||||
SOFTCODED_STATES.integrate(true);
|
||||
NDLLS_SUPPORTED.integrate(!isWeb() && !isHashLink());
|
||||
USE_ADAPTED_ASSETS.integrate(!isWeb());
|
||||
THREE_D_SUPPORT.integrate(STRIPPED_COMPILE.isDisabled());
|
||||
NAPE_ENABLED.integrate(STRIPPED_COMPILE.isDisabled());
|
||||
VIDEO_CUTSCENES.integrate(isCPP() && (isDesktop() || isMobile()));
|
||||
SHOW_BUILD_ON_FPS.integrate(true);
|
||||
DARK_MODE_WINDOW.integrate(true);
|
||||
|
||||
setDefine("FLX_NO_GENERIC"); // Disable a optimization, to allow reflection to use more functions
|
||||
|
||||
if (DISCORD_RPC.isEnabled())
|
||||
setHaxedef("DISCORD_DISABLE_IO_THREAD");
|
||||
|
||||
if (MODCHARTING_FEATURES.isEnabled())
|
||||
{
|
||||
setHaxedef("FM_ENGINE", "CODENAME");
|
||||
setHaxedef("FM_ENGINE_VERSION", "1.0");
|
||||
addMacroFlag("modchart.backend.macros.Macro.includeFiles()");
|
||||
}
|
||||
|
||||
if (COMPILE_ALL_CLASSES.isEnabled())
|
||||
{
|
||||
addHaxeFlag("-dce no");
|
||||
addMacroFlag("funkin.backend.system.macros.Macros.addAdditionalClasses()");
|
||||
}
|
||||
|
||||
addMacroFlag("funkin.backend.system.macros.Macros.initMacros()");
|
||||
|
||||
if (isDebug())
|
||||
setHaxedef("HXCPP_DEBUG_LINK");
|
||||
|
||||
environment.set("HAXEPATH", "./");
|
||||
|
||||
setHaxedef("HXCPP_CHECK_POINTER");
|
||||
setHaxedef("HXCPP_STACK_LINE");
|
||||
setHaxedef("HXCPP_CATCH_SEGV");
|
||||
setHaxedef("hscriptPos");
|
||||
setHaxedef("EXPERIMENTAL_FLXGRAPHIC_DESTROY_FIX");
|
||||
setHaxedef("FLX_NO_FOCUS_LOST_SCREEN");
|
||||
|
||||
if (isRelease())
|
||||
{
|
||||
setHaxedef("FLX_NO_DEBUG");
|
||||
setHaxedef("analyzer-optimize");
|
||||
}
|
||||
setHaxedef("openfl_dpi_aware");
|
||||
}
|
||||
|
||||
function configureAssets()
|
||||
{
|
||||
trace("Configuring assets...");
|
||||
|
||||
var shouldPreload = PRELOAD_ALL.isEnabled();
|
||||
var shouldEmbed = EMBED_ASSETS.isEnabled();
|
||||
|
||||
includeAssetLibrary("default", shouldEmbed, shouldPreload);
|
||||
addAssetPath("assets", shouldEmbed);
|
||||
addAsset("art/readme.txt", "do NOT readme.txt", false);
|
||||
|
||||
if (isDesktop())
|
||||
addAsset("building/alsoft.txt", 'plugins/alsoft.${isWindows() ? "ini" : "conf"}', false);
|
||||
}
|
||||
|
||||
function configureLibs()
|
||||
{
|
||||
trace("Configuring libraries...");
|
||||
|
||||
includeHaxelib("flixel");
|
||||
includeHaxelib("flixel-addons");
|
||||
includeHaxelib("format");
|
||||
includeHaxelib("flxanimate");
|
||||
includeHaxelib("hscript-improved");
|
||||
includeHaxelib("markdown");
|
||||
|
||||
if (VIDEO_CUTSCENES.isEnabled())
|
||||
includeHaxelib("hxvlc");
|
||||
if (THREE_D_SUPPORT.isEnabled())
|
||||
includeHaxelib("away3d");
|
||||
if (NAPE_ENABLED.isEnabled())
|
||||
includeHaxelib("nape-haxe4");
|
||||
if (DISCORD_RPC.isEnabled())
|
||||
includeHaxelib("hxdiscord_rpc");
|
||||
if (MODCHARTING_FEATURES.isEnabled())
|
||||
includeHaxelib("funkin-modchart");
|
||||
if (isDebug())
|
||||
includeHaxelib("hxcpp-debug-server");
|
||||
}
|
||||
|
||||
function configureIcons()
|
||||
{
|
||||
trace("Configuring app icons...");
|
||||
// TODO: ADD MOBILE ICONS
|
||||
for (size in [16, 32, 64])
|
||||
addIcon('art/icon${size}.png', size);
|
||||
addIcon("art/icons/iconOG.png");
|
||||
}
|
||||
|
||||
function includeHaxelib(name:String, version:String = ""):Void
|
||||
{
|
||||
haxelibs.push(new Haxelib(name, version));
|
||||
}
|
||||
|
||||
function addAsset(path:String, ?rename:String, embed:Bool = false):Void
|
||||
{
|
||||
var asset = new Asset(path, rename, null, embed, true);
|
||||
asset.library = "default";
|
||||
assets.push(asset);
|
||||
}
|
||||
|
||||
public function addAssetPath(path:String, ?rename:String, embed:Bool = false):Void
|
||||
{
|
||||
if (path == "") return;
|
||||
|
||||
var targetPath = Path.addTrailingSlash(rename ?? path);
|
||||
|
||||
if (!FileSystem.exists(path))
|
||||
trace('[ERROR] Path "${path}" was not found');
|
||||
else if (!FileSystem.isDirectory(path))
|
||||
trace('[ERROR] Path "${path}" needs to be a directory.');
|
||||
|
||||
for (file in FileSystem.readDirectory(path))
|
||||
{
|
||||
if (FileSystem.isDirectory('${path}/${file}'))
|
||||
addAssetPath('${path}/${file}', '${targetPath}${file}', embed);
|
||||
else
|
||||
addAsset('${path}/${file}', '${targetPath}${file}', embed);
|
||||
}
|
||||
}
|
||||
|
||||
function includeAssetLibrary(name:String, embed:Bool = false, preload:Bool = false):Void
|
||||
{
|
||||
this.libraries.push(new Library('', name, null, embed, preload, false, ""));
|
||||
}
|
||||
|
||||
inline function addIcon(icon:String, ?size:Int):Void
|
||||
icons.push(new Icon(icon, size));
|
||||
|
||||
inline function addHaxeFlag(value:String):Void
|
||||
haxeflags.push(value);
|
||||
|
||||
inline function addMacroFlag(value:String):Void
|
||||
addHaxeFlag('--macro ${value}');
|
||||
|
||||
inline function isDebug():Bool
|
||||
return debug;
|
||||
|
||||
inline function isRelease():Bool
|
||||
return !isDebug();
|
||||
|
||||
inline function isDisplay():Bool
|
||||
return command == "display";
|
||||
|
||||
inline function isWeb():Bool
|
||||
return platformType == PlatformType.WEB;
|
||||
|
||||
inline function isMobile():Bool
|
||||
return platformType == PlatformType.MOBILE;
|
||||
|
||||
inline function isDesktop():Bool
|
||||
return platformType == PlatformType.DESKTOP;
|
||||
|
||||
inline function isWindows():Bool
|
||||
return target == Platform.WINDOWS;
|
||||
|
||||
inline function isMac():Bool
|
||||
return target == Platform.MAC;
|
||||
|
||||
inline function isLinux():Bool
|
||||
return target == Platform.LINUX;
|
||||
|
||||
inline function isAndroid():Bool
|
||||
return target == Platform.ANDROID;
|
||||
|
||||
inline function isIOS():Bool
|
||||
return target == Platform.IOS;
|
||||
|
||||
inline function isHashLink():Bool
|
||||
return targetFlags.exists("hl");
|
||||
|
||||
inline function isCPP():Bool
|
||||
return defines.exists("cpp");
|
||||
|
||||
public inline function getHaxedef(name:String):Null<Dynamic>
|
||||
return haxedefs.get(name);
|
||||
|
||||
public inline function setHaxedef(name:String, ?value:String):Void
|
||||
haxedefs.set(name, value ?? "");
|
||||
|
||||
public inline function unsetHaxedef(name:String):Void
|
||||
haxedefs.remove(name);
|
||||
|
||||
public inline function getDefine(name:String):Null<Dynamic>
|
||||
return defines.get(name);
|
||||
|
||||
public inline function setDefine(name:String, ?value:String):Void
|
||||
defines.set(name, value ?? "");
|
||||
|
||||
public inline function unsetDefine(name:String):Void
|
||||
defines.remove(name);
|
||||
}
|
||||
|
||||
class CompileFlag {
|
||||
public static final INVERSION:String = "NO_";
|
||||
public static var project:Project;
|
||||
|
||||
public static function get(name:String):CompileFlag {
|
||||
return new CompileFlag(name);
|
||||
}
|
||||
|
||||
var name:String;
|
||||
public function new(name:String) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public function enable(stopPropagation:Bool = false):Void
|
||||
{
|
||||
project.setHaxedef(name);
|
||||
project.setDefine(name);
|
||||
if (!stopPropagation)
|
||||
getInverse().disable(true);
|
||||
}
|
||||
|
||||
public function disable(stopPropagation:Bool = false):Void
|
||||
{
|
||||
project.unsetHaxedef(name);
|
||||
project.unsetDefine(name);
|
||||
if (!stopPropagation)
|
||||
getInverse().enable(true);
|
||||
}
|
||||
|
||||
public function integrate(defaultEnabled:Bool = false):Void {
|
||||
var inverse = getInverse();
|
||||
|
||||
if (isEnabled()) inverse.disable(true); // Makes sure the inverse is disabled if it wasn't already
|
||||
else if (inverse.isEnabled()) disable(true); // If the inverse is enabled, disable this
|
||||
else (defaultEnabled ? enable : disable)(true); // Set to the default state otherwise
|
||||
}
|
||||
|
||||
public function isEnabled():Bool {
|
||||
return project.haxedefs.exists(name) || project.defines.exists(name);
|
||||
}
|
||||
|
||||
public function isDisabled():Bool {
|
||||
return getInverse().isEnabled() || !isEnabled();
|
||||
}
|
||||
|
||||
function getInverse():CompileFlag {
|
||||
var inversionName = name;
|
||||
if (!inversionName.startsWith(INVERSION))
|
||||
inversionName = INVERSION + inversionName;
|
||||
return new CompileFlag(inversionName);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
{ }:
|
||||
let
|
||||
pkgs = import (builtins.fetchTarball {
|
||||
url = "https://github.com/NixOS/nixpkgs/archive/c407032be28ca2236f45c49cfb2b8b3885294f7f.tar.gz";
|
||||
}) { };
|
||||
|
||||
libs =
|
||||
with pkgs;
|
||||
[
|
||||
SDL2
|
||||
pkg-config
|
||||
openal
|
||||
alsa-lib
|
||||
libvlc
|
||||
libpulseaudio
|
||||
libGL
|
||||
]
|
||||
++ (with xorg; [
|
||||
libX11
|
||||
libXext
|
||||
libXinerama
|
||||
libXi
|
||||
libXrandr
|
||||
]);
|
||||
in
|
||||
pkgs.mkShell {
|
||||
name = "CodenameEngine";
|
||||
|
||||
packages = with pkgs; [
|
||||
haxe
|
||||
neko
|
||||
libsForQt5.qttools
|
||||
];
|
||||
|
||||
buildInputs = libs;
|
||||
|
||||
LD_LIBRARY_PATH = pkgs.lib.makeLibraryPath libs;
|
||||
|
||||
shellHook = ''
|
||||
source update.sh
|
||||
'';
|
||||
}
|
||||
@@ -126,7 +126,7 @@ class FunkinSprite extends FlxSkewedSprite implements IBeatReceiver implements I
|
||||
// hate how it looks like but hey at least its optimized and fast - Nex
|
||||
if (!debugMode && isAnimFinished()) {
|
||||
var name = getAnimName() + '-loop';
|
||||
if (hasAnimation(name))
|
||||
if (hasAnim(name))
|
||||
playAnim(name, null, lastAnimContext);
|
||||
}
|
||||
}
|
||||
@@ -307,7 +307,7 @@ class FunkinSprite extends FlxSkewedSprite implements IBeatReceiver implements I
|
||||
|
||||
public function playAnim(AnimName:String, ?Force:Null<Bool>, Context:PlayAnimContext = NONE, Reversed:Bool = false, Frame:Int = 0):Void
|
||||
{
|
||||
if (AnimName == null)
|
||||
if (AnimName == null || (!hasAnim(AnimName) && !debugMode))
|
||||
return;
|
||||
|
||||
if (Force == null) {
|
||||
@@ -318,16 +318,10 @@ class FunkinSprite extends FlxSkewedSprite implements IBeatReceiver implements I
|
||||
if (animateAtlas != null)
|
||||
{
|
||||
@:privateAccess
|
||||
// if (!animateAtlas.anim.animsMap.exists(AnimName) && !animateAtlas.anim.symbolDictionary.exists(AnimName)) return;
|
||||
animateAtlas.anim.play(AnimName, Force, Reversed, Frame);
|
||||
atlasPlayingAnim = AnimName;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!animation.exists(AnimName) && !debugMode)
|
||||
return;
|
||||
animation.play(AnimName, Force, Reversed, Frame);
|
||||
}
|
||||
else animation.play(AnimName, Force, Reversed, Frame);
|
||||
|
||||
var daOffset = getAnimOffset(AnimName);
|
||||
frameOffset.set(daOffset.x, daOffset.y);
|
||||
@@ -414,9 +408,9 @@ class FunkinSprite extends FlxSkewedSprite implements IBeatReceiver implements I
|
||||
}
|
||||
|
||||
// Backwards compat (the names used to be all different and it sucked, please lets use the same format in the future) - Nex
|
||||
public inline function hasAnimation(AnimName:String) return hasAnim(AnimName);
|
||||
public inline function removeAnimation(name:String) return removeAnim(name);
|
||||
public inline function stopAnimation() return stopAnim();
|
||||
@:dox(hide) public inline function hasAnimation(AnimName:String) return hasAnim(AnimName);
|
||||
@:dox(hide) public inline function removeAnimation(name:String) return removeAnim(name);
|
||||
@:dox(hide) public inline function stopAnimation() return stopAnim();
|
||||
#end
|
||||
|
||||
// Getter / Setters
|
||||
|
||||
@@ -2,11 +2,14 @@ package funkin.backend;
|
||||
|
||||
import flixel.text.FlxText;
|
||||
import flixel.util.FlxColor;
|
||||
import funkin.backend.system.Flags;
|
||||
|
||||
class FunkinText extends FlxText {
|
||||
public function new(X:Float = 0, Y:Float = 0, FieldWidth:Float = 0, ?Text:String, Size:Int = 16, Border:Bool = true) {
|
||||
public function new(X:Float = 0, Y:Float = 0, FieldWidth:Float = 0, ?Text:String, ?Size:Int, Border:Bool = true) {
|
||||
if (Size == null) Size = Flags.DEFAULT_FONT_SIZE;
|
||||
|
||||
super(X, Y, FieldWidth, Text, Size);
|
||||
setFormat(Paths.font("vcr.ttf"), Size, FlxColor.WHITE);
|
||||
setFormat(Paths.font(Flags.DEFAULT_FONT), Size, FlxColor.WHITE);
|
||||
if (Border) {
|
||||
borderStyle = OUTLINE;
|
||||
borderSize = 1;
|
||||
|
||||
@@ -275,6 +275,12 @@ class MusicBeatState extends FlxState implements IBeatCancellableReceiver
|
||||
if (!e.cancelled)
|
||||
super.openSubState(e.substate is FlxSubState ? cast e.substate : subState);
|
||||
}
|
||||
|
||||
public override function closeSubState() {
|
||||
var e = event("onCloseSubState", EventManager.get(StateEvent).recycle(subState));
|
||||
if (!e.cancelled)
|
||||
super.closeSubState();
|
||||
}
|
||||
|
||||
public override function onResize(w:Int, h:Int) {
|
||||
super.onResize(w, h);
|
||||
|
||||
@@ -128,11 +128,11 @@ class Paths
|
||||
return scriptPath;
|
||||
}
|
||||
|
||||
static public function chart(song:String, ?difficulty:String):String
|
||||
static public function chart(song:String, ?difficulty:String, ?variant:String):String
|
||||
{
|
||||
difficulty = (difficulty != null ? difficulty : Flags.DEFAULT_DIFFICULTY);
|
||||
|
||||
return getPath('songs/$song/charts/$difficulty.json', null);
|
||||
return getPath('songs/$song/charts/${variant != null ? variant + "/" : ""}$difficulty.json', null);
|
||||
}
|
||||
|
||||
public static function character(character:String):String {
|
||||
|
||||
@@ -71,8 +71,9 @@ class Chart {
|
||||
return LEGACY;
|
||||
}
|
||||
|
||||
public static function loadEventsJson(songName:String) {
|
||||
var path = Paths.file('songs/${songName}/events.json');
|
||||
public static function loadEventsJson(songName:String, ?variant:String) {
|
||||
var variantSuffix = variant != null && variant != "" ? '-$variant' : "";
|
||||
var path = Paths.file('songs/${songName}/events$variantSuffix.json');
|
||||
var data:Array<ChartEvent> = null;
|
||||
if (Assets.exists(path)) {
|
||||
try {
|
||||
@@ -83,77 +84,91 @@ class Chart {
|
||||
return data;
|
||||
}
|
||||
|
||||
public static function loadChartMeta(songName:String, difficulty:String = '', fromMods:Bool = true, includeMetaDifficulties:Bool = true):ChartMetaData {
|
||||
var metaPath = Paths.file('songs/${songName}/meta.json');
|
||||
var metaDiffPath = Paths.file('songs/${songName}/meta-${difficulty}.json');
|
||||
|
||||
var data:ChartMetaData = null, fromDifficulty = false;
|
||||
var fromMods:Bool = fromMods;
|
||||
for (path in [metaDiffPath, metaPath]) if (Assets.exists(path)) {
|
||||
fromMods = Paths.assetsTree.existsSpecific(path, "TEXT", MODS);
|
||||
try {
|
||||
var tempData = Json.parse(Assets.getText(path));
|
||||
tempData.color = CoolUtil.getColorFromDynamic(tempData.color).getDefault(Flags.DEFAULT_COLOR);
|
||||
data = tempData;
|
||||
} catch(e) Logs.trace('Failed to load song metadata for ${songName} ($path): ${Std.string(e)}', ERROR);
|
||||
if (data != null) {
|
||||
fromDifficulty = path == metaDiffPath;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (data == null) {
|
||||
data = {
|
||||
name: songName,
|
||||
bpm: Flags.DEFAULT_BPM
|
||||
};
|
||||
}
|
||||
else {
|
||||
data.name = songName;
|
||||
data.setFieldDefault("bpm", Flags.DEFAULT_BPM);
|
||||
}
|
||||
|
||||
inline public static function defaultChartMetaFields(data:ChartMetaData):ChartMetaData {
|
||||
data.setFieldDefault("displayName", data.name);
|
||||
|
||||
data.setFieldDefault("bpm", Flags.DEFAULT_BPM);
|
||||
data.setFieldDefault("beatsPerMeasure", Flags.DEFAULT_BEATS_PER_MEASURE);
|
||||
data.setFieldDefault("stepsPerBeat", Flags.DEFAULT_STEPS_PER_BEAT);
|
||||
data.setFieldDefault("icon", Flags.DEFAULT_HEALTH_ICON);
|
||||
data.setFieldDefault("difficulties", []);
|
||||
data.setFieldDefault("coopAllowed", Flags.DEFAULT_COOP_ALLOWED);
|
||||
data.setFieldDefault("opponentModeAllowed", Flags.DEFAULT_OPPONENT_MODE_ALLOWED);
|
||||
data.setFieldDefault("instSuffix", "");
|
||||
data.setFieldDefault("vocalsSuffix", "");
|
||||
data.setFieldDefault("needsVoices", true);
|
||||
data.setFieldDefault("difficulties", []);
|
||||
data.setFieldDefault("variants", []);
|
||||
data.setFieldDefault("metas", []);
|
||||
|
||||
if (data.difficulties.length <= 0) {
|
||||
data.difficulties = [for(f in Paths.getFolderContent('songs/${songName}/charts/', false, fromMods ? MODS : SOURCE)) if (Path.extension(f.toUpperCase()) == "JSON") Path.withoutExtension(f)];
|
||||
var tempDiffs = [];
|
||||
if (data.difficulties.length == 3) {
|
||||
for(d in data.difficulties) {
|
||||
switch(d.toLowerCase()) {
|
||||
case "easy": tempDiffs.insert(0, d);
|
||||
case "normal": tempDiffs.insert(1, d);
|
||||
case "hard": tempDiffs.insert(2, d);
|
||||
}
|
||||
}
|
||||
data.difficulties = tempDiffs;
|
||||
return data;
|
||||
}
|
||||
|
||||
public static function loadChartMeta(songName:String, ?variant:String, ?difficulty:String, fromMods:Bool = true, includeMetaVariations = true):ChartMetaData {
|
||||
var folder = 'songs/$songName', isVariant = false, data:ChartMetaData = null;
|
||||
var defaultPaths = [Paths.file('$folder/meta-$difficulty.json'), Paths.file('$folder/meta.json')], variantPaths = [];
|
||||
if (difficulty != null) defaultPaths.unshift(Paths.file('$folder/meta-$difficulty.json'));
|
||||
|
||||
if (variant != null && variant != '') {
|
||||
variantPaths.push(Paths.file('$folder/meta-$variant.json'));
|
||||
if (difficulty != null) variantPaths.unshift(Paths.file('$folder/meta-$variant-$difficulty.json'));
|
||||
}
|
||||
|
||||
for (path in variantPaths.concat(defaultPaths)) if (Assets.exists(path)) {
|
||||
fromMods = Paths.assetsTree.existsSpecific(path, "TEXT", MODS);
|
||||
try {
|
||||
var tempData = Json.parse(Assets.getText(path));
|
||||
tempData.color = CoolUtil.getColorFromDynamic(tempData.color).getDefault(Flags.DEFAULT_COLOR);
|
||||
data = tempData;
|
||||
} catch(e) Logs.trace('Failed to load song metadata for $songName ($path): ${Std.string(e)}', ERROR);
|
||||
|
||||
if (data != null) {
|
||||
isVariant = variantPaths.contains(path);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (includeMetaDifficulties && !fromDifficulty) {
|
||||
data.metas = [];
|
||||
for (difficulty in data.difficulties) {
|
||||
if (!data.metas.exists(difficulty) && Assets.exists(Paths.file('songs/${songName}/meta-${difficulty}.json')))
|
||||
data.metas.set(difficulty, loadChartMeta(songName, difficulty, fromMods, false));
|
||||
if (data != null) data.name = songName;
|
||||
else data = {
|
||||
name: songName,
|
||||
color: Flags.DEFAULT_COLOR
|
||||
};
|
||||
|
||||
if (isVariant) data.variant = variant;
|
||||
else data.variant = null;
|
||||
|
||||
defaultChartMetaFields(data);
|
||||
|
||||
if (data.difficulties.length <= 0) {
|
||||
var path = 'songs/$songName/charts/';
|
||||
if (isVariant) path += '$variant/';
|
||||
|
||||
data.difficulties = [for(f in Paths.getFolderContent(path, false, fromMods ? MODS : SOURCE)) if (Path.extension(f.toUpperCase()) == "JSON") Path.withoutExtension(f)];
|
||||
if (data.difficulties.length == 3) {
|
||||
var tempDiffs = [];
|
||||
for (d in data.difficulties) switch(d.toLowerCase()) {
|
||||
case "easy": tempDiffs.insert(0, d);
|
||||
case "normal": tempDiffs.insert(1, d);
|
||||
case "hard": tempDiffs.insert(2, d);
|
||||
}
|
||||
if (tempDiffs.length == 3) data.difficulties = tempDiffs;
|
||||
}
|
||||
}
|
||||
|
||||
data.metas = [];
|
||||
if (includeMetaVariations && data.variants.length > 0) for (variant in data.variants) {
|
||||
if (!data.metas.exists(variant) && Assets.exists(Paths.file('songs/$songName/meta-$variant.json'))) {
|
||||
var meta = loadChartMeta(songName, variant, fromMods);
|
||||
if (meta.variant != null) data.metas.set(variant, meta);
|
||||
}
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
public static function parse(songName:String, ?difficulty:String):ChartData {
|
||||
public static function parse(songName:String, ?difficulty:String, ?variant:String):ChartData {
|
||||
if (difficulty == null) difficulty = Flags.DEFAULT_DIFFICULTY;
|
||||
|
||||
var chartPath = Paths.chart(songName, difficulty);
|
||||
var chartPath = Paths.chart(songName, difficulty, variant);
|
||||
var base:ChartData = {
|
||||
strumLines: [],
|
||||
noteTypes: [],
|
||||
@@ -167,15 +182,15 @@ class Chart {
|
||||
fromMods: Paths.assetsTree.existsSpecific(chartPath, "TEXT", MODS)
|
||||
};
|
||||
|
||||
var valid:Bool = true;
|
||||
var valid:Bool = true, namePrint = '$songName $difficulty' + ((variant != null && variant != '') ? ' ($variant)' : '');
|
||||
if (!Assets.exists(chartPath)) {
|
||||
Logs.error('Chart for song ${songName} ($difficulty) at "$chartPath" was not found.');
|
||||
Logs.error('Chart for song $namePrint at "$chartPath" was not found.');
|
||||
valid = false;
|
||||
}
|
||||
var data:Dynamic = null;
|
||||
if (valid) {
|
||||
try data = Json.parse(Assets.getText(chartPath))
|
||||
catch(e) Logs.trace('Could not parse chart for song ${songName} ($difficulty): ${Std.string(e)}', ERROR, RED);
|
||||
catch(e) Logs.trace('Could not parse chart for song $namePrint: ${Std.string(e)}', ERROR, RED);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -207,13 +222,12 @@ class Chart {
|
||||
}
|
||||
#end
|
||||
|
||||
var loadedMeta = loadChartMeta(songName, difficulty, base.fromMods);
|
||||
var loadedMeta = loadChartMeta(songName, variant, difficulty, base.fromMods, false);
|
||||
if (base.meta == null) base.meta = loadedMeta;
|
||||
else {
|
||||
for (field in Reflect.fields(base.meta)) {
|
||||
var f = Reflect.field(base.meta, field);
|
||||
if (f != null)
|
||||
Reflect.setField(loadedMeta, field, f);
|
||||
if (f != null) Reflect.setField(loadedMeta, field, f);
|
||||
}
|
||||
base.meta = loadedMeta;
|
||||
}
|
||||
@@ -222,9 +236,8 @@ class Chart {
|
||||
* events.json LOADING
|
||||
*/
|
||||
#if REGION
|
||||
var extraEvents:Array<ChartEvent> = loadEventsJson(songName);
|
||||
if (extraEvents != null)
|
||||
base.events = base.events.concat(extraEvents);
|
||||
var extraEvents:Array<ChartEvent> = loadEventsJson(songName, variant);
|
||||
if (extraEvents != null) base.events = base.events.concat(extraEvents);
|
||||
#end
|
||||
|
||||
/**
|
||||
@@ -252,61 +265,59 @@ class Chart {
|
||||
|
||||
/**
|
||||
* Saves the chart to the specific song folder path.
|
||||
* @param songFolderPath Path to the song folder (ex: `mods/your mod/songs/song/`)
|
||||
* @param chart Chart to save
|
||||
* @param difficulty Name of the difficulty
|
||||
* @param saveSettings
|
||||
* @param chart Chart to save.
|
||||
* @param difficulty Name of the difficulty (Optional).
|
||||
* @param variant Name of the Variant (Optional).
|
||||
* @param saveSettings (Optional).
|
||||
* @return Filtered chart used for saving.
|
||||
*/
|
||||
public static function save(songFolderPath:String, chart:ChartData, ?difficulty:String, ?saveSettings:ChartSaveSettings):ChartData {
|
||||
public static function save(chart:ChartData, ?difficulty:String, ?variant:String, ?saveSettings:ChartSaveSettings):ChartData {
|
||||
if (difficulty == null) difficulty = Flags.DEFAULT_DIFFICULTY;
|
||||
if (saveSettings == null) saveSettings = {};
|
||||
|
||||
if (saveSettings.saveMetaInChart == null) saveSettings.saveMetaInChart = true;
|
||||
if (saveSettings.saveLocalEvents == null) saveSettings.saveLocalEvents = true;
|
||||
if (saveSettings.saveGlobalEvents == null) saveSettings.saveGlobalEvents = false;
|
||||
|
||||
var filteredChart = filterChartForSaving(chart, saveSettings.saveMetaInChart, saveSettings.saveLocalEvents, saveSettings.saveGlobalEvents);
|
||||
var meta = filteredChart.meta;
|
||||
var filteredChart = filterChartForSaving(chart, saveSettings.saveMetaInChart, saveSettings.saveLocalEvents, saveSettings.saveGlobalEvents && saveSettings.seperateGlobalEvents != true);
|
||||
|
||||
#if sys
|
||||
var saveFolder:String = saveSettings.folder == null ? "charts" : saveSettings.folder;
|
||||
var songPath = saveSettings.songFolder == null ? 'songs/${chart.meta.name}' : saveSettings.songFolder, variantSuffix = variant != null && variant != "" ? '-$variant' : "";
|
||||
var metaPath = 'meta$variantSuffix.json', prettyPrint = saveSettings.prettyPrint == true ? Flags.JSON_PRETTY_PRINT : null, temp:String;
|
||||
if ((temp = Paths.assetsTree.getPath('assets/$songPath/$metaPath')) != null) {
|
||||
songPath = temp.substr(0, temp.length - metaPath.length - 1);
|
||||
metaPath = temp;
|
||||
}
|
||||
else if (saveSettings.songFolder == null)
|
||||
metaPath = (songPath = '${Paths.getAssetsRoot()}/$songPath') + '/$metaPath';
|
||||
|
||||
if (!FileSystem.exists('${songFolderPath}/$saveFolder/'))
|
||||
FileSystem.createDirectory('${songFolderPath}/$saveFolder/');
|
||||
var chartFolder = saveSettings.folder == null ? ((variant == null || variant == '') ? 'charts' : 'charts/$variant') : saveSettings.folder;
|
||||
var chartPath = '$songPath/$chartFolder/${difficulty.trim()}.json';
|
||||
|
||||
var chartPath = '${songFolderPath}/$saveFolder/${difficulty.trim()}.json';
|
||||
var metaPath = '${songFolderPath}/meta.json';
|
||||
if (saveSettings.saveChart == null || saveSettings.saveChart == true)
|
||||
CoolUtil.safeSaveFile(chartPath, Json.stringify(filteredChart, null, prettyPrint));
|
||||
|
||||
CoolUtil.safeSaveFile(chartPath, Json.stringify(filteredChart, null, saveSettings.prettyPrint == true ? Flags.JSON_PRETTY_PRINT : null));
|
||||
if (saveSettings.overrideExistingMeta || !FileSystem.exists(metaPath))
|
||||
CoolUtil.safeSaveFile(metaPath, Json.stringify(filterMetaForSaving(chart.meta), null, prettyPrint));
|
||||
|
||||
if (meta != null && (saveSettings.overrideExistingMeta || !FileSystem.exists(metaPath)))
|
||||
CoolUtil.safeSaveFile(metaPath, makeMetaSaveable(meta));
|
||||
if (saveSettings.seperateGlobalEvents == true) {
|
||||
var eventsPath = '$songPath/events$variantSuffix.json', events = filterEventsForSaving(chart.events, false, true);
|
||||
|
||||
if (events.length != 0) CoolUtil.safeSaveFile(eventsPath, Json.stringify({events: events}, null, prettyPrint));
|
||||
}
|
||||
#end
|
||||
|
||||
return filteredChart;
|
||||
}
|
||||
|
||||
public static function filterChartForSaving(chart:ChartData, ?saveMetaInChart:Bool, ?saveLocalEvents:Bool, ?saveGlobalEvents:Bool):ChartData {
|
||||
public static function filterChartForSaving(chart:ChartData, saveMetaInChart = true, ?saveLocalEvents:Bool, ?saveGlobalEvents:Bool):ChartData {
|
||||
var meta = chart.meta, events = chart.events;
|
||||
chart.meta = null;
|
||||
chart.events = null;
|
||||
|
||||
var data = Reflect.copy(chart); // make a copy of the chart to leave the OG intact
|
||||
if (saveMetaInChart != true) {
|
||||
data.meta = null;
|
||||
} else {
|
||||
data.meta = Reflect.copy(chart.meta); // also make a copy of the metadata to leave the OG intact.
|
||||
if (data.meta != null && Reflect.hasField(data.meta, "parsedColor")) Reflect.deleteField(data.meta, "parsedColor");
|
||||
}
|
||||
|
||||
// in this part abt the events, i gotta account that these booleans can be null - Nex
|
||||
if (saveLocalEvents != true && saveGlobalEvents != true) data.events = null;
|
||||
else {
|
||||
data.events = [];
|
||||
for (event in chart.events) if ((saveLocalEvents == true && event.global != true) || (saveGlobalEvents == true && event.global == true)) {
|
||||
var copy = Reflect.copy(event);
|
||||
if (saveLocalEvents == true ? event.global != true : event.global == true) Reflect.deleteField(copy, "global"); // should NOT delete the field when saving with the local events and the event should have been global - Nex
|
||||
data.events.push(copy);
|
||||
}
|
||||
if (data.events.length == 0) data.events = null;
|
||||
}
|
||||
chart.meta = meta;
|
||||
chart.events = events;
|
||||
|
||||
data.meta = saveMetaInChart ? filterMetaForSaving(meta) : null;
|
||||
data.events = filterEventsForSaving(events, saveLocalEvents, saveGlobalEvents);
|
||||
data.fromMods = null;
|
||||
|
||||
var sortedData:Dynamic = {};
|
||||
@@ -318,19 +329,47 @@ class Chart {
|
||||
return sortedData;
|
||||
}
|
||||
|
||||
public static inline function makeMetaSaveable(meta:ChartMetaData, prettyPrint:Bool = true):String {
|
||||
public static function filterEventsForSaving(events:Array<ChartEvent>, saveLocalEvents = true, saveGlobalEvents = false):Array<ChartEvent> {
|
||||
var data = [];
|
||||
if (!saveLocalEvents && !saveGlobalEvents) return data;
|
||||
|
||||
for (event in events) if ((saveLocalEvents && event.global != true) || (saveGlobalEvents && event.global == true)) {
|
||||
var copy = Reflect.copy(event);
|
||||
if (saveLocalEvents ? event.global != true : event.global == true) Reflect.deleteField(copy, "global"); // should NOT delete the field when saving with the local events and the event should have been global - Nex
|
||||
data.push(copy);
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
public static inline function makeMetaSaveable(meta:ChartMetaData, prettyPrint:Bool = true):String
|
||||
return Json.stringify(filterMetaForSaving(meta), null, prettyPrint ? Flags.JSON_PRETTY_PRINT : null);
|
||||
|
||||
public static inline function filterMetaForSaving(meta:ChartMetaData):ChartMetaData {
|
||||
var data:Dynamic = Reflect.copy(meta);
|
||||
if (data.color != null) data.color = FlxColor.fromInt(data.color).toWebString(); // dont even ask me - Nex
|
||||
if (data.color != null) data.color = FlxColor.fromInt(data.color).toWebString(); // dont even ask me - Nex
|
||||
Reflect.deleteField(data, "name");
|
||||
Reflect.deleteField(data, 'parsedColor');
|
||||
Reflect.deleteField(data, 'metas');
|
||||
return Json.stringify(data, null, prettyPrint ? Flags.JSON_PRETTY_PRINT : null);
|
||||
Reflect.deleteField(data, "variant");
|
||||
if (data.instSuffix != null && data.instSuffix == "") Reflect.deleteField(data, "instSuffix");
|
||||
if (data.vocalsSuffix != null && data.vocalsSuffix == "") Reflect.deleteField(data, "vocalsSuffix");
|
||||
if (data.variants != null && data.variants.length == 0) Reflect.deleteField(data, "variants");
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
typedef ChartSaveSettings = {
|
||||
var ?overrideExistingMeta:Bool;
|
||||
var ?prettyPrint:Bool;
|
||||
|
||||
var ?saveMetaInChart:Bool;
|
||||
var ?saveLocalEvents:Bool;
|
||||
var ?saveGlobalEvents:Bool;
|
||||
var ?prettyPrint:Bool;
|
||||
|
||||
var ?saveChart:Bool;
|
||||
var ?overrideExistingMeta:Bool;
|
||||
var ?seperateGlobalEvents:Bool;
|
||||
|
||||
var ?folder:String;
|
||||
var ?songFolder:String;
|
||||
}
|
||||
|
||||
@@ -18,16 +18,23 @@ typedef ChartData = {
|
||||
|
||||
typedef ChartMetaData = {
|
||||
public var name:String;
|
||||
public var ?bpm:Float;
|
||||
public var ?variant:String;
|
||||
public var ?displayName:String;
|
||||
|
||||
public var ?bpm:Float;
|
||||
public var ?beatsPerMeasure:Float;
|
||||
public var ?stepsPerBeat:Int;
|
||||
|
||||
public var ?difficulties:Array<String>;
|
||||
public var ?variants:Array<String>;
|
||||
public var ?customValues:Dynamic;
|
||||
|
||||
public var ?icon:String;
|
||||
public var ?color:FlxColor;
|
||||
public var ?difficulties:Array<String>;
|
||||
|
||||
public var ?coopAllowed:Bool;
|
||||
public var ?opponentModeAllowed:Bool;
|
||||
public var ?customValues:Dynamic;
|
||||
|
||||
public var ?metas:Map<String, ChartMetaData>;
|
||||
public var ?instSuffix:String;
|
||||
public var ?vocalsSuffix:String;
|
||||
|
||||
@@ -164,8 +164,10 @@ class EventsData {
|
||||
|
||||
if (fileTxt.trim() == "") continue;
|
||||
|
||||
eventsList.push(eventName);
|
||||
eventsParams.set(eventName, []);
|
||||
if (!eventsList.contains(eventName)) {
|
||||
eventsList.push(eventName);
|
||||
eventsParams.set(eventName, []);
|
||||
}
|
||||
|
||||
try {
|
||||
var data:EventInfoFile = cast Json.parse(fileTxt);
|
||||
|
||||
@@ -26,12 +26,12 @@ class VSliceParser {
|
||||
stage: Flags.DEFAULT_STAGE,
|
||||
codenameChart: true
|
||||
};
|
||||
parseChart(Reflect.field(chartData.notes, diff), metaData, chartData.events, base);
|
||||
parseChart(Reflect.field(chartData.notes, diff), metaData, chartData.events, base, resultMeta);
|
||||
resultCharts.push({diffName: diff, chart: base});
|
||||
}
|
||||
}
|
||||
|
||||
public static function parseChart(data:Dynamic, metaData:Dynamic, events:Dynamic, result:ChartData) {
|
||||
public static function parseChart(data:Dynamic, metaData:Dynamic, events:Dynamic, result:ChartData, resultMeta:ChartMetaData) {
|
||||
// vslice chart parsing
|
||||
var data:Array<SwagNote> = data;
|
||||
var metadata:SwagMetadata = metaData;
|
||||
@@ -45,14 +45,14 @@ class VSliceParser {
|
||||
type: 0,
|
||||
position: (p2isGF = metadata.playData.characters.opponent.startsWith("gf")) ? "girlfriend" : "dad",
|
||||
notes: [],
|
||||
vocalsSuffix: "-Opponent"
|
||||
vocalsSuffix: '-${metadata.playData.characters.opponent}${resultMeta.vocalsSuffix != null ? resultMeta.vocalsSuffix : ""}'
|
||||
});
|
||||
result.strumLines.push({
|
||||
characters: [metadata.playData.characters.player],
|
||||
type: 1,
|
||||
position: "boyfriend",
|
||||
notes: [],
|
||||
vocalsSuffix: "-Player"
|
||||
vocalsSuffix: '-${metadata.playData.characters.player}${resultMeta.vocalsSuffix != null ? resultMeta.vocalsSuffix : ""}'
|
||||
});
|
||||
var gfName = metadata.playData.characters.girlfriend;
|
||||
if (!p2isGF && gfName != "none") {
|
||||
@@ -108,7 +108,7 @@ class VSliceParser {
|
||||
{
|
||||
case "FocusCamera":
|
||||
var isPosOnly = false;
|
||||
var arr:Array<Dynamic> = [switch(values.char) {
|
||||
var arr:Array<Dynamic> = [switch(values is Int ? values : values.char) {
|
||||
// more cases here in the future if they add em? (i hope not) - Nex
|
||||
case 0: 1;
|
||||
case 1: 0;
|
||||
@@ -177,16 +177,12 @@ class VSliceParser {
|
||||
var songID:String = songID == null ? songName.toLowerCase().replace(" ", "-") : songID;
|
||||
var firstTimeChange:SwagTimeChange = data.timeChanges[0];
|
||||
|
||||
result.name = songID;
|
||||
result.bpm = firstTimeChange.bpm.getDefault(Flags.DEFAULT_BPM);
|
||||
result.beatsPerMeasure = firstTimeChange.n.getDefault(Flags.DEFAULT_BEATS_PER_MEASURE);
|
||||
result.stepsPerBeat = firstTimeChange.d.getDefault(Flags.DEFAULT_STEPS_PER_BEAT);
|
||||
result.displayName = songName;
|
||||
result.icon = Flags.DEFAULT_HEALTH_ICON;
|
||||
result.color = 0xFFFFFF;
|
||||
result.opponentModeAllowed = true;
|
||||
result.coopAllowed = true;
|
||||
result.difficulties = data.playData.difficulties.concat(data.playData.songVariations.getDefault([]));
|
||||
result.difficulties = data.playData.difficulties.copy();
|
||||
if (data.playData.songVariations != null) result.variants = data.playData.songVariations.copy();
|
||||
|
||||
if (result.customValues == null) result.customValues = {};
|
||||
result.customValues.artist = data.artist;
|
||||
|
||||
@@ -106,20 +106,8 @@ class GlobalScript {
|
||||
});
|
||||
}
|
||||
|
||||
public static function event<T:CancellableEvent>(name:String, event:T):T {
|
||||
if (scripts != null)
|
||||
scripts.event(name, event);
|
||||
return event;
|
||||
}
|
||||
|
||||
public static function call(name:String, ?args:Array<Dynamic>) {
|
||||
if (scripts != null)
|
||||
scripts.call(name, args);
|
||||
}
|
||||
|
||||
public static function onModSwitch(newMod:String) {
|
||||
call("destroy");
|
||||
scripts = FlxDestroyUtil.destroy(scripts);
|
||||
destroy();
|
||||
scripts = new ScriptPack("GlobalScript");
|
||||
for (i in funkin.backend.assets.ModsFolder.getLoadedMods()) {
|
||||
var path = Paths.script('data/global/LIB_$i');
|
||||
@@ -132,12 +120,24 @@ class GlobalScript {
|
||||
}
|
||||
}
|
||||
|
||||
public static function beatHit(curBeat:Int) {
|
||||
call("beatHit", [curBeat]);
|
||||
public static inline function event<T:CancellableEvent>(name:String, event:T):T {
|
||||
if (scripts != null)
|
||||
scripts.event(name, event);
|
||||
return event;
|
||||
}
|
||||
|
||||
public static function stepHit(curStep:Int) {
|
||||
public static inline function call(name:String, ?args:Array<Dynamic>)
|
||||
if (scripts != null) scripts.call(name, args);
|
||||
|
||||
public static inline function beatHit(curBeat:Int)
|
||||
call("beatHit", [curBeat]);
|
||||
|
||||
public static inline function stepHit(curStep:Int)
|
||||
call("stepHit", [curStep]);
|
||||
|
||||
public static inline function destroy() if (scripts != null) {
|
||||
call("destroy");
|
||||
scripts = FlxDestroyUtil.destroy(scripts);
|
||||
}
|
||||
}
|
||||
#end
|
||||
@@ -34,6 +34,7 @@ class HScript extends Script {
|
||||
__importedPaths = [path];
|
||||
|
||||
interp.errorHandler = _errorHandler;
|
||||
interp.warnHandler = _warnHandler;
|
||||
interp.importFailedCallback = importFailedCallback;
|
||||
interp.staticVariables = Script.staticVariables;
|
||||
interp.allowStaticVariables = interp.allowPublicVariables = true;
|
||||
@@ -63,7 +64,7 @@ class HScript extends Script {
|
||||
return this;
|
||||
}
|
||||
|
||||
private function importFailedCallback(cl:Array<String>):Bool {
|
||||
private function importFailedCallback(cl:Array<String>, ?asName:String):Bool {
|
||||
if(_importFailedCallback(cl, "source/") || _importFailedCallback(cl, "")) {
|
||||
return true;
|
||||
}
|
||||
@@ -117,6 +118,24 @@ class HScript extends Script {
|
||||
], ERROR);
|
||||
}
|
||||
|
||||
private function _warnHandler(error:Error) {
|
||||
var fileName = error.origin;
|
||||
var oldfn = '$fileName:${error.line}: ';
|
||||
if(remappedNames.exists(fileName))
|
||||
fileName = remappedNames.get(fileName);
|
||||
var fn = '$fileName:${error.line}: ';
|
||||
var err = error.toString();
|
||||
while(err.startsWith(oldfn) || err.startsWith(fn)) {
|
||||
if (err.startsWith(oldfn)) err = err.substr(oldfn.length);
|
||||
if (err.startsWith(fn)) err = err.substr(fn.length);
|
||||
}
|
||||
|
||||
Logs.traceColored([
|
||||
Logs.logText(fn, GREEN),
|
||||
Logs.logText(err, YELLOW)
|
||||
], WARNING);
|
||||
}
|
||||
|
||||
public override function setParent(parent:Dynamic) {
|
||||
interp.scriptObject = parent;
|
||||
}
|
||||
|
||||
@@ -28,6 +28,11 @@ class Script extends FlxBasic implements IFlxDestroyable {
|
||||
"Reflect" => Reflect,
|
||||
"StringTools" => StringTools,
|
||||
"Json" => haxe.Json,
|
||||
"Xml" => Xml,
|
||||
"Type" => Type,
|
||||
"Date" => Date,
|
||||
"Lambda" => Lambda,
|
||||
#if sys "Sys" => Sys, #end
|
||||
|
||||
// OpenFL & Lime related stuff
|
||||
"Assets" => openfl.utils.Assets,
|
||||
@@ -89,6 +94,7 @@ class Script extends FlxBasic implements IFlxDestroyable {
|
||||
"FlxAnimate" => funkin.backend.FlxAnimate,
|
||||
"FunkinSprite" => funkin.backend.FunkinSprite,
|
||||
"Alphabet" => funkin.menus.ui.Alphabet,
|
||||
"Flags" => funkin.backend.system.Flags,
|
||||
|
||||
"CoolUtil" => funkin.backend.utils.CoolUtil,
|
||||
"IniUtil" => funkin.backend.utils.IniUtil,
|
||||
@@ -395,4 +401,4 @@ class Script extends FlxBasic implements IFlxDestroyable {
|
||||
* Called when the script is loaded.
|
||||
*/
|
||||
public function onLoad() {}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,10 @@ final class FreeplaySongSelectEvent extends CancellableEvent {
|
||||
* Difficulty name
|
||||
*/
|
||||
public var difficulty:String;
|
||||
/**
|
||||
* Variation Name
|
||||
*/
|
||||
public var variant:String;
|
||||
/**
|
||||
* Whenever opponent mode is enabled or not.
|
||||
*/
|
||||
|
||||
@@ -127,6 +127,9 @@ class Flags {
|
||||
|
||||
public static var DEFAULT_NOTE_MS_LIMIT:Float = 1500;
|
||||
public static var DEFAULT_NOTE_SCALE:Float = 0.7;
|
||||
#if MODCHARTING_FEATURES
|
||||
public static var DEFAULT_MODCHART_HOLD_SUBDIVISIONS:Int = 4;
|
||||
#end
|
||||
|
||||
@:also(funkin.game.Character.FALLBACK_DEAD_CHARACTER)
|
||||
public static var DEFAULT_GAMEOVER_CHARACTER:String = "bf-dead";
|
||||
@@ -145,6 +148,10 @@ class Flags {
|
||||
public static var DEFAULT_HUD_ZOOM_MULT:Float = 0.03;
|
||||
public static var DEFAULT_CAM_ZOOM_LERP:Float = 0.05;
|
||||
public static var DEFAULT_HUD_ZOOM_LERP:Float = 0.05;
|
||||
|
||||
// Font configuration
|
||||
public static var DEFAULT_FONT:String = "vcr.ttf";
|
||||
public static var DEFAULT_FONT_SIZE:Int = 16;
|
||||
|
||||
// to translate these you need to convert them into ids
|
||||
// Resume -> pause.resume
|
||||
@@ -166,6 +173,7 @@ class Flags {
|
||||
public static var DEFAULT_HEALTH:Null<Float> = null;//DEFAULT_MAX_HEALTH / 2.0;
|
||||
public static var DEFAULT_ICONBOP:Bool = true;
|
||||
public static var BOP_ICON_SCALE:Float = 1.2;
|
||||
public static var ICON_DEFAULT_SCALE:Float = 1;
|
||||
public static var ICON_OFFSET:Float = 26;
|
||||
public static var ICON_LERP:Float = 0.33;
|
||||
|
||||
@@ -269,6 +277,8 @@ class Flags {
|
||||
@:bypass public static var customFlags:Map<String, String> = [];
|
||||
|
||||
public static function loadFromData(flags:Map<String, String>, data:String) {
|
||||
WINDOW_TITLE_USE_MOD_NAME = false;
|
||||
|
||||
if (!(data.length > 0)) return;
|
||||
var res = IniUtil.parseString(data);
|
||||
|
||||
@@ -286,7 +296,7 @@ class Flags {
|
||||
}
|
||||
}
|
||||
|
||||
if (!flags.exists("WINDOW_TITLE_USE_MOD_NAME")) WINDOW_TITLE_USE_MOD_NAME = !flags.exists('TITLE');
|
||||
if (!flags.exists("WINDOW_TITLE_USE_MOD_NAME")) WINDOW_TITLE_USE_MOD_NAME = !flags.exists('TITLE') && flags.exists('MOD_NAME');
|
||||
else WINDOW_TITLE_USE_MOD_NAME = parseBool(flags.get("WINDOW_TITLE_USE_MOD_NAME"));
|
||||
|
||||
flags.remove("WINDOW_TITLE_USE_MOD_NAME");
|
||||
@@ -305,6 +315,8 @@ class Flags {
|
||||
for(name=>value in flags)
|
||||
if(!parse(name, value))
|
||||
customFlags.set(name, value);
|
||||
|
||||
Options.modchartingHoldSubdivisions = DEFAULT_MODCHART_HOLD_SUBDIVISIONS;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
package funkin.backend.system;
|
||||
|
||||
import lime.app.Application;
|
||||
import funkin.backend.system.Main;
|
||||
|
||||
class MainApplication extends Application {
|
||||
public function new() {
|
||||
super();
|
||||
|
||||
#if openfl
|
||||
openfl.Lib.current.stage.addChild(new Main());
|
||||
#end
|
||||
}
|
||||
}
|
||||
@@ -66,12 +66,12 @@ class MainState extends FlxState {
|
||||
)
|
||||
];
|
||||
|
||||
for(path in addonPaths) {
|
||||
for (path in addonPaths) {
|
||||
if (path == null) continue;
|
||||
if (!isDirectory(path)) continue;
|
||||
|
||||
for(addon in FileSystem.readDirectory(path)) {
|
||||
if(!FileSystem.isDirectory(path + addon)) {
|
||||
for (addon in FileSystem.readDirectory(path)) {
|
||||
if (!FileSystem.isDirectory(path + addon)) {
|
||||
switch(Path.extension(addon).toLowerCase()) {
|
||||
case 'zip':
|
||||
addon = Path.withoutExtension(addon);
|
||||
@@ -90,7 +90,14 @@ class MainState extends FlxState {
|
||||
else _noPriorityAddons.insert(0, data);
|
||||
}
|
||||
}
|
||||
#end
|
||||
|
||||
#if GLOBAL_SCRIPT
|
||||
funkin.backend.scripting.GlobalScript.destroy();
|
||||
#end
|
||||
funkin.backend.scripting.Script.staticVariables.clear();
|
||||
|
||||
#if MOD_SUPPORT
|
||||
for (addon in _lowPriorityAddons)
|
||||
loadLib(addon.path, ltrim(addon.name, "[LOW]"));
|
||||
|
||||
@@ -143,4 +150,4 @@ class MainState extends FlxState {
|
||||
|
||||
FlxG.switchState(cast Type.createInstance(startState, []));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,68 +0,0 @@
|
||||
package funkin.backend.system.macros;
|
||||
|
||||
using StringTools;
|
||||
|
||||
#if macro
|
||||
class BuildInfo {
|
||||
public static function printBuildInfo() {
|
||||
if(haxe.macro.Context.defined("display") || haxe.macro.Context.defined("display-details")) return;
|
||||
var haxeVersion = haxe.macro.Context.definedValue("haxe").trim();
|
||||
var sleepChangeVersion = false;
|
||||
|
||||
Sys.println('[ BUILD INFO ]');
|
||||
Sys.println('Haxe Version: ${haxeVersion}');
|
||||
try {
|
||||
var lastBuiltWith:Null<String> = null;
|
||||
var compiling = #if final "release" #elseif debug "debug" #else "release" #end;
|
||||
var target = #if hl "hl"
|
||||
#elseif html5 "html5"
|
||||
#elseif ios "ios"
|
||||
#elseif android "android"
|
||||
#elseif windows "windows"
|
||||
#elseif (mac || macos) "macos"
|
||||
#elseif linux "linux"
|
||||
#else ""
|
||||
#end;
|
||||
if(target == "") throw "Unknown target";
|
||||
var exportPath = Sys.getCwd() + "/export/" + compiling + "/" + target + "/";
|
||||
exportPath += "obj/Options.txt";
|
||||
|
||||
var options = sys.io.File.getContent(exportPath);
|
||||
for(option in options.split("\n")) {
|
||||
if(option.startsWith("haxe=")) {
|
||||
lastBuiltWith = option.substr(5).trim();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(lastBuiltWith != null && lastBuiltWith.length > 0 && lastBuiltWith != haxeVersion) {
|
||||
Sys.println('Last Built With Haxe: ${lastBuiltWith} [!!!! MAKE SURE IF YOU SWITCHED VERSIONS YOU DELETE EXPORT FOLDERS !!!!]');
|
||||
sleepChangeVersion = true;
|
||||
}
|
||||
} catch(e) {}
|
||||
var targetPlatform = #if html5 "Web (HTML5)"
|
||||
#elseif ios "iOS"
|
||||
#elseif android "Android"
|
||||
#elseif windows "Windows"
|
||||
#elseif (mac || macos) "Mac"
|
||||
#elseif linux "Linux"
|
||||
#else "Unknown"
|
||||
#end;
|
||||
|
||||
if(haxe.macro.Context.defined("hl")) {
|
||||
targetPlatform = "Hashlink (" + targetPlatform + ")";
|
||||
}
|
||||
Sys.println('Target Platform: ' + targetPlatform);
|
||||
Sys.println('Build Date: ${Date.now().toString()}');
|
||||
Sys.println('');
|
||||
|
||||
if(sleepChangeVersion) {
|
||||
Sys.println('!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!');
|
||||
Sys.println('!!!! MAKE SURE IF YOU SWITCHED VERSIONS YOU DELETE EXPORT FOLDERS !!!!');
|
||||
Sys.println('!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!');
|
||||
Sys.println('');
|
||||
Sys.sleep(5);
|
||||
}
|
||||
}
|
||||
}
|
||||
#end
|
||||
@@ -43,7 +43,6 @@ class FunkinSaveMacro {
|
||||
* SAVE FUNCTION
|
||||
*/
|
||||
var saveFuncBlocks:Array<Expr> = [for(f in fieldNames) macro $i{saveFieldName}.data.$f = $i{f}];
|
||||
|
||||
saveFuncBlocks.push(macro $i{saveFieldName}.flush());
|
||||
|
||||
fields.push({
|
||||
@@ -59,6 +58,8 @@ class FunkinSaveMacro {
|
||||
access: [APublic, AStatic]
|
||||
});
|
||||
|
||||
var loadFuncBlocks:Array<Expr> = [for(f in fieldNames) macro if ($i{saveFieldName}.data.$f != null) $i{f} = $i{saveFieldName}.data.$f];
|
||||
|
||||
/**
|
||||
* LOAD FUNCTION
|
||||
*/
|
||||
@@ -69,10 +70,7 @@ class FunkinSaveMacro {
|
||||
args: [],
|
||||
expr: {
|
||||
pos: Context.currentPos(),
|
||||
expr: EBlock([for(f in fieldNames)
|
||||
macro if ($i{saveFieldName}.data.$f != null)
|
||||
$i{f} = $i{saveFieldName}.data.$f
|
||||
])
|
||||
expr: EBlock(loadFuncBlocks)
|
||||
}
|
||||
}),
|
||||
access: [APublic, AStatic]
|
||||
|
||||
@@ -63,7 +63,7 @@ class UpdateUtil {
|
||||
}
|
||||
|
||||
static function __checkForUpdates():UpdateCheckCallback {
|
||||
var curTag = 'v${Flags.VERSION}', error = false;
|
||||
var curTag = 'v' + (Flags.VERSION == null ? Application.current.meta.get('version') : Flags.VERSION), error = false;
|
||||
var newUpdates = __doReleaseFiltering(GitHub.getReleases(Flags.REPO_OWNER, Flags.REPO_NAME, (e) -> {
|
||||
error = true;
|
||||
}), curTag);
|
||||
|
||||
@@ -3,31 +3,15 @@ package funkin.backend.utils;
|
||||
#if cpp
|
||||
import cpp.Float64;
|
||||
#end
|
||||
import flxanimate.data.AnimationData.AnimAtlas;
|
||||
import flixel.graphics.FlxGraphic;
|
||||
import openfl.display.BitmapData;
|
||||
import flixel.graphics.frames.FlxAtlasFrames;
|
||||
import flixel.graphics.frames.FlxFramesCollection;
|
||||
#if sys
|
||||
import sys.FileSystem;
|
||||
#end
|
||||
import flixel.text.FlxText;
|
||||
import funkin.backend.utils.XMLUtil.TextFormat;
|
||||
import flixel.util.typeLimit.OneOfTwo;
|
||||
import flixel.util.typeLimit.OneOfThree;
|
||||
import flixel.tweens.FlxTween;
|
||||
import flixel.system.frontEnds.SoundFrontEnd;
|
||||
import flixel.sound.FlxSound;
|
||||
import funkin.backend.system.Conductor;
|
||||
import flixel.sound.FlxSoundGroup;
|
||||
import haxe.Json;
|
||||
import haxe.io.Path;
|
||||
import haxe.io.Bytes;
|
||||
import haxe.xml.Access;
|
||||
import flixel.input.keyboard.FlxKey;
|
||||
import lime.utils.Assets;
|
||||
import flixel.animation.FlxAnimation;
|
||||
import flixel.graphics.FlxGraphic;
|
||||
import flixel.graphics.frames.FlxAtlasFrames;
|
||||
import flixel.graphics.frames.FlxFramesCollection;
|
||||
import flixel.input.keyboard.FlxKey;
|
||||
import flixel.math.FlxPoint;
|
||||
import flixel.sound.FlxSound;
|
||||
import flixel.sound.FlxSoundGroup;
|
||||
import flixel.system.frontEnds.SoundFrontEnd;
|
||||
@@ -35,19 +19,21 @@ import flixel.text.FlxText;
|
||||
import flixel.tweens.FlxTween;
|
||||
import flixel.util.FlxAxes;
|
||||
import flixel.util.FlxColor;
|
||||
import flixel.util.typeLimit.OneOfThree;
|
||||
import flixel.util.typeLimit.OneOfTwo;
|
||||
import flxanimate.data.AnimationData.AnimAtlas;
|
||||
import funkin.backend.system.Conductor;
|
||||
import funkin.backend.utils.XMLUtil.TextFormat;
|
||||
import haxe.CallStack;
|
||||
import haxe.Constraints.IMap;
|
||||
import haxe.EnumTools.EnumValueTools;
|
||||
import haxe.Json;
|
||||
import haxe.io.Bytes;
|
||||
import haxe.io.Path;
|
||||
import haxe.xml.Access;
|
||||
import lime.utils.Assets;
|
||||
import openfl.display.BitmapData;
|
||||
import openfl.geom.ColorTransform;
|
||||
import flixel.math.FlxPoint;
|
||||
import haxe.Constraints.IMap;
|
||||
import haxe.EnumTools.EnumValueTools;
|
||||
|
||||
using StringTools;
|
||||
|
||||
|
||||
@@ -38,6 +38,6 @@ class FlxInterpolateColor {
|
||||
alpha = (color.alphaFloat - alpha) * ratio + alpha;
|
||||
}
|
||||
|
||||
public inline function fpsLerpTo(color:FlxColor, ratio:Float)
|
||||
lerpTo(color, ratio * 60 * FlxG.elapsed);
|
||||
public inline function fpsLerpTo(color:FlxColor, ratio:Float, ?delta:Float)
|
||||
lerpTo(color, CoolUtil.getFPSRatio(ratio, delta));
|
||||
}
|
||||
@@ -185,6 +185,16 @@ final class Windows {
|
||||
')
|
||||
public static function setWindowTitleColor(title:String, color:Array<Int>) {}
|
||||
|
||||
@:functionCode('
|
||||
HWND window = GetConsoleWindow();
|
||||
HICON smallIcon = (HICON) LoadImage(NULL, path, IMAGE_ICON, 16, 16, LR_LOADFROMFILE);
|
||||
HICON icon = (HICON) LoadImage(NULL, path, IMAGE_ICON, 0, 0, LR_LOADFROMFILE | LR_DEFAULTSIZE);
|
||||
SendMessage(window, WM_SETICON, ICON_SMALL, (LPARAM)smallIcon);
|
||||
SendMessage(window, WM_SETICON, ICON_BIG, (LPARAM)icon);
|
||||
')
|
||||
public static function setWindowIcon(path:String) {}
|
||||
|
||||
|
||||
@:functionCode('
|
||||
// https://stackoverflow.com/questions/15543571/allocconsole-not-displaying-cout
|
||||
|
||||
|
||||
@@ -26,6 +26,7 @@ typedef WeekCharacter = {
|
||||
|
||||
typedef WeekSong = {
|
||||
var name:String;
|
||||
var hide:Bool;
|
||||
var ?hide:Bool;
|
||||
var ?variation:String;
|
||||
var ?displayName:String;
|
||||
}
|
||||
@@ -22,10 +22,11 @@ API_VERSION=1
|
||||
DOWNLOAD_LINK="YOUR MOD PAGE LINK HERE"
|
||||
|
||||
# Not supported yet
|
||||
;MOD_ICON64="path/to/icon64.png"
|
||||
;MOD_ICON32="path/to/icon32.png"
|
||||
;MOD_ICON16="path/to/icon16.png"
|
||||
ICON="path/to/icon.png"
|
||||
;MOD_ICON64="path/to/icon64"
|
||||
;MOD_ICON32="path/to/icon32"
|
||||
;MOD_ICON16="path/to/icon16"
|
||||
# The path starts in "your-mod/images/", do not add image extension.
|
||||
ICON="path/to/icon"
|
||||
|
||||
[Flags] # This section doesn\'t apply any prefix.
|
||||
DISABLE_WARNING_SCREEN=true
|
||||
@@ -84,4 +85,4 @@ LOGO_TEXT=""
|
||||
], false);
|
||||
openSubState(substate);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,6 +43,11 @@ class AlphabetEditor extends UIState {
|
||||
public var queueReorder:Bool = false;
|
||||
public var componentList:UIButtonList<ComponentButton>;
|
||||
|
||||
public var glyphCreateWindow:UISliceSprite;
|
||||
public var glyphChar:UITextBox;
|
||||
public var confirmGlyph:UIButton;
|
||||
public var deleteGlyph:UIButton;
|
||||
|
||||
public var infoWindow:GlyphInfoWindow;
|
||||
public var curSelectedComponent:AlphabetComponent = null;
|
||||
public var curSelectedData:AlphabetLetterData = null;
|
||||
@@ -83,13 +88,18 @@ class AlphabetEditor extends UIState {
|
||||
{
|
||||
label: translate("topBar.edit"),
|
||||
childs: [
|
||||
{
|
||||
// TODO: add redo and undo
|
||||
/*{
|
||||
label: translate("edit.undo"),
|
||||
// TODO: add undo
|
||||
onSelect: null
|
||||
},
|
||||
{
|
||||
label: translate("edit.redo"),
|
||||
// TODO: add redo
|
||||
onSelect: null
|
||||
},*/
|
||||
{
|
||||
label: translate("glyph.deleteCurGlyph"),
|
||||
|
||||
},
|
||||
{
|
||||
label: "Edit Main Data", // TODO: add translations
|
||||
@@ -97,23 +107,6 @@ class AlphabetEditor extends UIState {
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
label: translate("topBar.glyph"),
|
||||
childs: [
|
||||
{
|
||||
label: translate("glyph.newGlyph"),
|
||||
//onSelect: _glyph_new
|
||||
},
|
||||
{
|
||||
label: translate("glyph.editGlyph"),
|
||||
//onSelect: _glyph_edit
|
||||
},
|
||||
{
|
||||
label: translate("glyph.deleteGlyph"),
|
||||
//onSelect: _glyph_delete
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
label: translate("topBar.view"),
|
||||
childs: [
|
||||
@@ -188,6 +181,67 @@ class AlphabetEditor extends UIState {
|
||||
brokenWarning.color = 0xFFFF6969;
|
||||
add(brokenWarning);
|
||||
|
||||
glyphCreateWindow = new UISliceSprite(FlxG.width - 15, topMenuSpr.bHeight + 15, 200, 150, "editors/ui/context-bg");
|
||||
glyphCreateWindow.x -= glyphCreateWindow.bWidth;
|
||||
uiGroup.add(glyphCreateWindow);
|
||||
|
||||
glyphChar = new UITextBox(glyphCreateWindow.x + 15, glyphCreateWindow.y + 15, "", glyphCreateWindow.bWidth - 30);
|
||||
glyphCreateWindow.members.push(glyphChar);
|
||||
|
||||
confirmGlyph = new UIButton(glyphChar.x, glyphChar.y + glyphChar.bHeight + 15, translate("glyph.newGlyph"), function() {
|
||||
if (deleteGlyph.selectable) {
|
||||
curLetter = tape.manualLetters.indexOf(lastChar) + charsForDefault.length;
|
||||
changeLetter(0);
|
||||
} else {
|
||||
tape.manualLetters.push(lastChar);
|
||||
tape.text = "";
|
||||
for (def in charsForDefault)
|
||||
tape.text += def[Std.int(Math.floor(defaultTmr) % def.length)] + " ";
|
||||
tape.text += tape.manualLetters.join(" ");
|
||||
|
||||
for (i in 0...tape.fastGetData(lastChar).components.length) {
|
||||
var anim = bigLetter.text + i;
|
||||
bigLetter.animation.remove(anim);
|
||||
tape.animation.remove(anim);
|
||||
}
|
||||
|
||||
tape.letterData.set(lastChar, {
|
||||
isDefault: false,
|
||||
advance: Math.NaN,
|
||||
advanceEmpty: true,
|
||||
components: [],
|
||||
startIndex: 0
|
||||
});
|
||||
|
||||
curLetter = tape.manualLetters.length - 1 + charsForDefault.length;
|
||||
changeLetter(0);
|
||||
}
|
||||
}, glyphChar.bWidth);
|
||||
confirmGlyph.selectable = false;
|
||||
glyphCreateWindow.members.push(confirmGlyph);
|
||||
|
||||
deleteGlyph = new UIButton(glyphChar.x, confirmGlyph.y + confirmGlyph.bHeight + 5, translate("glyph.deleteGlyph"), function() {
|
||||
final charIdx = tape.manualLetters.indexOf(lastChar);
|
||||
|
||||
tape.manualLetters.splice(charIdx, 1);
|
||||
tape.text = "";
|
||||
for (def in charsForDefault)
|
||||
tape.text += def[Std.int(Math.floor(defaultTmr) % def.length)] + " ";
|
||||
tape.text += tape.manualLetters.join(" ");
|
||||
|
||||
for (i in 0...tape.fastGetData(lastChar).components.length) {
|
||||
var anim = bigLetter.text + i;
|
||||
bigLetter.animation.remove(anim);
|
||||
tape.animation.remove(anim);
|
||||
}
|
||||
tape.letterData.remove(lastChar);
|
||||
|
||||
changeLetter((curLetter >= charIdx + charsForDefault.length) ? -1 : 0);
|
||||
}, glyphChar.bWidth);
|
||||
deleteGlyph.color = FlxColor.RED;
|
||||
deleteGlyph.selectable = false;
|
||||
glyphCreateWindow.members.push(deleteGlyph);
|
||||
|
||||
infoWindow = new GlyphInfoWindow();
|
||||
uiGroup.add(infoWindow);
|
||||
|
||||
@@ -208,7 +262,7 @@ class AlphabetEditor extends UIState {
|
||||
|
||||
scaleX: 1,
|
||||
scaleY: 1,
|
||||
|
||||
|
||||
flipX: false,
|
||||
flipY: false,
|
||||
|
||||
@@ -247,8 +301,29 @@ class AlphabetEditor extends UIState {
|
||||
}
|
||||
}
|
||||
|
||||
var lastChar:String = "";
|
||||
public override function update(elapsed:Float) {
|
||||
super.update(elapsed);
|
||||
|
||||
if (glyphChar.label.text != lastChar) {
|
||||
if (glyphChar.label.text == "") {
|
||||
lastChar = "";
|
||||
confirmGlyph.selectable = false;
|
||||
deleteGlyph.selectable = false;
|
||||
confirmGlyph.field.text = translate("glyph.newGlyph");
|
||||
} else {
|
||||
glyphChar.label.text = lastChar = switch (tape.forceCase) {
|
||||
case UPPER: glyphChar.label.text.charAt(glyphChar.label.text.length - 1).toUpperCase();
|
||||
case LOWER: glyphChar.label.text.charAt(glyphChar.label.text.length - 1).toLowerCase();
|
||||
case NONE: glyphChar.label.text.charAt(glyphChar.label.text.length - 1);
|
||||
};
|
||||
|
||||
confirmGlyph.selectable = true;
|
||||
deleteGlyph.selectable = tape.manualLetters.contains(lastChar);
|
||||
confirmGlyph.field.text = translate(deleteGlyph.selectable ? "glyph.editGlyph" : "glyph.newGlyph");
|
||||
}
|
||||
}
|
||||
|
||||
if (queueReorder) {
|
||||
queueReorder = false;
|
||||
var outlines = [];
|
||||
@@ -344,6 +419,7 @@ class AlphabetEditor extends UIState {
|
||||
curLetter = CoolUtil.positiveModuloInt(curLetter + inc, tape.manualLetters.length + charsForDefault.length);
|
||||
targetX = FlxG.width * 0.5 - tape.defaultAdvance * (0.5 + curLetter * 2);
|
||||
bigLetter.text = (curLetter < charsForDefault.length) ? charsForDefault[curLetter][0] : tape.manualLetters[curLetter - charsForDefault.length];
|
||||
glyphChar.label.text = bigLetter.text;
|
||||
bigLetter.updateHitbox();
|
||||
bigLetter.screenCenter();
|
||||
|
||||
@@ -396,11 +472,17 @@ class AlphabetEditor extends UIState {
|
||||
changeLetter(1);
|
||||
}
|
||||
|
||||
function buildAlphabet() {
|
||||
var tempPrettyPrint = true;
|
||||
var xmlThingYea:String = "<!DOCTYPE codename-engine-alphabet-font>\n" + Printer.print(tape.buildXML(), tempPrettyPrint);
|
||||
return tempPrettyPrint ? xmlThingYea : xmlThingYea.replace("\n", "");
|
||||
}
|
||||
|
||||
function _file_save(_) {
|
||||
#if sys
|
||||
CoolUtil.safeSaveFile(
|
||||
'${Paths.getAssetsRoot()}/data/alphabet/${__typeface}.xml',
|
||||
""//alphabet.buildXML()
|
||||
buildAlphabet()
|
||||
);
|
||||
#else
|
||||
_file_saveas(_);
|
||||
@@ -408,7 +490,7 @@ class AlphabetEditor extends UIState {
|
||||
}
|
||||
|
||||
function _file_saveas(_) {
|
||||
openSubState(new SaveSubstate(""/*alphabet.buildXML()*/, {
|
||||
openSubState(new SaveSubstate(buildAlphabet(), {
|
||||
defaultSaveFile: '${__typeface}.xml'
|
||||
}));
|
||||
}
|
||||
|
||||
@@ -43,14 +43,11 @@ class AlphabetIconOption extends TextOption {
|
||||
var spritesheet = null;
|
||||
for (node in xml.elements()) {
|
||||
if (node.nodeName == "spritesheet") {
|
||||
spritesheet = node.firstChild().nodeValue;
|
||||
spritesheet = node.firstChild().nodeValue.trim();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
var useColorOffsets = xml.get("useColorOffsets").getDefault("false") == "true";
|
||||
|
||||
|
||||
// todo fix crash if invalid spritesheet;
|
||||
|
||||
iconSpr = new FlxSprite();
|
||||
@@ -64,7 +61,7 @@ class AlphabetIconOption extends TextOption {
|
||||
}
|
||||
}
|
||||
iconSpr.frame = frameToUse;
|
||||
if (useColorOffsets) {
|
||||
if (xml.get("colorMode") == "offsets") {
|
||||
iconSpr.colorTransform.color = -1;
|
||||
}
|
||||
iconSpr.setPosition(90 - iconSpr.width - 20, (__text.height - iconSpr.height) / 2);
|
||||
|
||||
@@ -10,7 +10,7 @@ class GlyphInfoWindow extends UIWindow {
|
||||
public var scaleYBox:UINumericStepper;
|
||||
public var angleBox:UINumericStepper;
|
||||
public var colorModeDrop:UIDropDown;
|
||||
|
||||
|
||||
public var flipXBox:UICheckbox;
|
||||
public var flipYBox:UICheckbox;
|
||||
|
||||
@@ -60,7 +60,7 @@ class GlyphInfoWindow extends UIWindow {
|
||||
|
||||
xBox = new UINumericStepper(prefixBox.x, prefixBox.y + prefixBox.bHeight + itemMargin + labelOffset, 0, 1, 2, null, null, 80);
|
||||
xBox.onChange = valueSet.bind(xBox, function(val) { // kinda dumb but blame cne ui
|
||||
compon.x = val;
|
||||
compon.x = -val;
|
||||
});
|
||||
members.push(xBox);
|
||||
|
||||
@@ -121,7 +121,7 @@ class GlyphInfoWindow extends UIWindow {
|
||||
members.push(colorModeDrop);
|
||||
addLabelOn(colorModeDrop, "Color Mode");
|
||||
|
||||
outlineCheck = new UICheckbox(colorModeDrop.x + colorModeDrop.bWidth + itemMargin * 2, colorModeDrop.y + 4, "Use Outline?");
|
||||
outlineCheck = new UICheckbox(colorModeDrop.x + colorModeDrop.bWidth + itemMargin * 2, colorModeDrop.y + 10, "Use Outline?");
|
||||
outlineCheck.onChecked = function(val) {
|
||||
targetPercent = val ? 1 : 0;
|
||||
|
||||
@@ -147,7 +147,7 @@ class GlyphInfoWindow extends UIWindow {
|
||||
angle: compon.angle,
|
||||
cos: compon.cos,
|
||||
sin: compon.sin,
|
||||
|
||||
|
||||
flipX: compon.flipX,
|
||||
flipY: compon.flipY,
|
||||
|
||||
@@ -156,15 +156,17 @@ class GlyphInfoWindow extends UIWindow {
|
||||
};
|
||||
|
||||
data.components.insert(AlphabetEditor.instance.outlineIdx, newOutline);
|
||||
++AlphabetEditor.instance.outlineIdx;
|
||||
++data.startIndex;
|
||||
} else {
|
||||
compon.outIndex = null;
|
||||
data.components.splice(AlphabetEditor.instance.outlineIdx - 1, 1);
|
||||
--AlphabetEditor.instance.outlineIdx;
|
||||
--data.startIndex;
|
||||
}
|
||||
}
|
||||
members.push(outlineCheck);
|
||||
|
||||
|
||||
flipXBox = new UICheckbox(outlineCheck.x, outlineCheck.y - outlineCheck.height - 8, "Flip X?");
|
||||
flipXBox.onChecked = function(check:Bool) {
|
||||
compon.flipX = check;
|
||||
@@ -254,7 +256,7 @@ class GlyphInfoWindow extends UIWindow {
|
||||
}
|
||||
|
||||
prefixBox.label.text = com.anim;
|
||||
xBox.value = com.x;
|
||||
xBox.value = -com.x;
|
||||
yBox.value = com.y;
|
||||
scaleXBox.value = com.scaleX;
|
||||
scaleYBox.value = com.scaleY;
|
||||
@@ -276,12 +278,12 @@ class GlyphInfoWindow extends UIWindow {
|
||||
outlineYBox.value = out.y;
|
||||
targetPercent = 1;
|
||||
}
|
||||
|
||||
for (item in members) {
|
||||
if (item is UISprite)
|
||||
cast(item, UISprite).selectable = true;
|
||||
}
|
||||
colorModeDrop.dropButton.selectable = true;
|
||||
|
||||
for (item in [prefixBox, scaleXBox, scaleYBox, angleBox, flipXBox, flipYBox])
|
||||
item.selectable = true;
|
||||
for (item in [xBox, yBox, colorModeDrop, outlineCheck, outlineBox, outlineXBox, outlineYBox])
|
||||
item.selectable = !data.isDefault;
|
||||
colorModeDrop.dropButton.selectable = colorModeDrop.selectable;
|
||||
}
|
||||
|
||||
function valueSet(item:UINumericStepper, func:Dynamic, text:String) {
|
||||
|
||||
@@ -258,6 +258,10 @@ class CharacterAnimButton extends UIButton {
|
||||
parent.displayAnimsFramesList.remove(anim);
|
||||
parent.displayAnimsFramesList.set(newName, displayFrame);
|
||||
|
||||
var animButton = parent.animButtons.get(this.anim);
|
||||
parent.animButtons.remove(this.anim);
|
||||
parent.animButtons.set(newName, animButton);
|
||||
|
||||
this.anim = newName;
|
||||
nameTextBox.label.text = newName;
|
||||
updateText();
|
||||
|
||||
@@ -28,6 +28,7 @@ import flixel.util.FlxColor;
|
||||
class Charter extends UIState {
|
||||
public static var __song:String;
|
||||
static var __diff:String;
|
||||
static var __variant:String;
|
||||
static var __reload:Bool;
|
||||
|
||||
var chart(get, never):ChartData;
|
||||
@@ -43,6 +44,7 @@ class Charter extends UIState {
|
||||
return FlxG.state is Charter ? cast FlxG.state : null;
|
||||
|
||||
public var charterBG:FunkinSprite;
|
||||
public var charterBookmarksGroup:FlxTypedGroup<FlxSprite> = new FlxTypedGroup<FlxSprite>();
|
||||
public var uiGroup:FlxTypedGroup<FlxSprite> = new FlxTypedGroup<FlxSprite>();
|
||||
|
||||
public var topMenu:Array<UIContextMenuOption>;
|
||||
@@ -114,11 +116,12 @@ class Charter extends UIState {
|
||||
private var SONGPOSINFO_BPM = TU.getRaw("songPosInfo.bpm");
|
||||
private var SONGPOSINFO_TIMESIGNATURE = TU.getRaw("songPosInfo.timeSignature");
|
||||
|
||||
public function new(song:String, diff:String, reload:Bool = true) {
|
||||
public function new(song:String, diff:String, variant:String, reload:Bool = true) {
|
||||
super();
|
||||
if (song != null) {
|
||||
__song = song;
|
||||
__diff = diff;
|
||||
__variant = variant;
|
||||
__reload = reload;
|
||||
}
|
||||
}
|
||||
@@ -460,7 +463,7 @@ class Charter extends UIState {
|
||||
noteHoverer = new CharterNoteHoverer();
|
||||
noteDeleteAnims = new CharterDeleteAnim();
|
||||
|
||||
selectionBox.cameras = notesGroup.cameras = gridBackdrops.cameras =
|
||||
charterBookmarksGroup.cameras = selectionBox.cameras = notesGroup.cameras = gridBackdrops.cameras =
|
||||
noteHoverer.cameras = noteDeleteAnims.cameras = [charterCamera];
|
||||
|
||||
topMenuSpr = new UITopMenu(topMenu);
|
||||
@@ -549,6 +552,7 @@ class Charter extends UIState {
|
||||
add(noteDeleteAnims);
|
||||
add(notesGroup);
|
||||
add(selectionBox);
|
||||
add(charterBookmarksGroup);
|
||||
add(strumlineInfoBG);
|
||||
add(strumlineLockButton);
|
||||
add(strumlineAddButton);
|
||||
@@ -570,6 +574,8 @@ class Charter extends UIState {
|
||||
if (Options.editorsResizable)
|
||||
UIState.setResolutionAware();
|
||||
|
||||
updateBookmarks(); //recalling it to fix resolutions
|
||||
|
||||
// ! IF YOU EVER WANNA VIEW IN THE FUTURE, JUST USE A FLXSPRITE :D -lunar
|
||||
/*var dataDisplay:FlxSprite = new FlxSprite().loadGraphic(waveformHandler.waveDatas.get("Voices.ogg"));
|
||||
dataDisplay.scrollFactor.set(1, 0);
|
||||
@@ -578,7 +584,7 @@ class Charter extends UIState {
|
||||
dataDisplay.screenCenter(Y);
|
||||
dataDisplay.cameras = [charterCamera]; dataDisplay.x = -dataDisplay.width; add(dataDisplay);*/
|
||||
|
||||
DiscordUtil.call("onEditorLoaded", ["Chart Editor", __song + " (" + __diff + ")"]);
|
||||
DiscordUtil.call("onEditorLoaded", ["Chart Editor", __song + " (" + __diff + ")" + (__variant != null && __variant != "" ? " (" + __variant + ")" : "")]);
|
||||
}
|
||||
|
||||
override function destroy() {
|
||||
@@ -595,9 +601,10 @@ class Charter extends UIState {
|
||||
public function loadSong() {
|
||||
if (__reload) {
|
||||
EventsData.reloadEvents();
|
||||
PlayState.loadSong(__song, __diff, false, false);
|
||||
PlayState.loadSong(__song, __diff, __variant, false, false);
|
||||
__resetStatics();
|
||||
}
|
||||
|
||||
Conductor.setupSong(PlayState.SONG);
|
||||
noteTypes = PlayState.SONG.noteTypes;
|
||||
|
||||
@@ -612,14 +619,14 @@ class Charter extends UIState {
|
||||
|
||||
gridBackdrops.createGrids(PlayState.SONG.strumLines.length);
|
||||
|
||||
for(strL in PlayState.SONG.strumLines)
|
||||
var noteCount:Int = 0;
|
||||
for (strL in PlayState.SONG.strumLines) {
|
||||
createStrumline(strumLines.members.length, strL, false, false);
|
||||
noteCount += strL.notes.length;
|
||||
}
|
||||
|
||||
// create notes
|
||||
notesGroup.autoSort = false;
|
||||
var noteCount:Int = 0;
|
||||
for (strL in PlayState.SONG.strumLines)
|
||||
noteCount += strL.notes.length;
|
||||
notesGroup.preallocate(noteCount);
|
||||
|
||||
var notesCreated:Int = 0;
|
||||
@@ -683,10 +690,10 @@ class Charter extends UIState {
|
||||
var wavesToGenerate:Array<{name:String, sound:FlxSound}> = [];
|
||||
|
||||
if (FlxG.sound.music.loaded)
|
||||
wavesToGenerate.push({name: "Inst.ogg", sound: FlxG.sound.music});
|
||||
wavesToGenerate.push({name: 'Inst${PlayState.SONG.meta.instSuffix}.ogg', sound: FlxG.sound.music});
|
||||
|
||||
if (vocals.loaded)
|
||||
wavesToGenerate.push({name: "Voices.ogg", sound: vocals});
|
||||
wavesToGenerate.push({name: 'Voices${PlayState.SONG.meta.vocalsSuffix}.ogg', sound: vocals});
|
||||
|
||||
for (strumLine in strumLines)
|
||||
if (strumLine.vocals != null && strumLine.strumLine.vocalsSuffix != null && strumLine.strumLine.vocalsSuffix != "" && strumLine.vocals.loaded)
|
||||
@@ -788,12 +795,13 @@ class Charter extends UIState {
|
||||
autoSaveTimer = Options.charterAutoSaveTime;
|
||||
if (!autoSaveNotif.cancelled) {
|
||||
buildChart();
|
||||
var songPath:String = '${Paths.getAssetsRoot()}/songs/${__song.toLowerCase()}';
|
||||
|
||||
if (Options.charterAutoSavesSeparateFolder)
|
||||
Chart.save(songPath, PlayState.SONG, __autoSaveLocation, {saveMetaInChart: true, saveLocalEvents: true, saveGlobalEvents: true, folder: "autosaves", prettyPrint: Options.editorCharterPrettyPrint});
|
||||
else // These two chart saves are particular, to avoid any kind of loss, stuff like meta, global and local events will be save all together - Nex
|
||||
Chart.save(songPath, PlayState.SONG, __diff.toLowerCase(), {saveMetaInChart: true, saveLocalEvents: true, saveGlobalEvents: true, prettyPrint: Options.editorCharterPrettyPrint});
|
||||
Chart.save(PlayState.SONG, __diff.toLowerCase(), __autoSaveLocation, {saveMetaInChart: true, saveLocalEvents: true, seperateGlobalEvents: true, folder: 'autosaves', prettyPrint: Options.editorCharterPrettyPrint});
|
||||
else
|
||||
Chart.save(PlayState.SONG, __diff.toLowerCase(), __variant, {saveMetaInChart: true, saveLocalEvents: true, seperateGlobalEvents: true, prettyPrint: Options.editorCharterPrettyPrint});
|
||||
|
||||
FlxG.sound.play(Paths.sound('editors/save'));
|
||||
undos.save();
|
||||
}
|
||||
autoSaveNotif.cancelled = false;
|
||||
@@ -1206,7 +1214,9 @@ class Charter extends UIState {
|
||||
|
||||
var strL = strumLines.members[strumLineID].strumLine;
|
||||
strumLines.members[strumLineID].destroy();
|
||||
strumLines.members.remove(strumLines.members[strumLineID]);
|
||||
strumLines.members[strumLineID] = strumLines.members[strumLines.members.length - 1];
|
||||
strumLines.members.pop();
|
||||
@:privateAccess strumLines.length--;
|
||||
strumLines.refreshStrumlineIDs();
|
||||
strumLines.snapStrums();
|
||||
|
||||
@@ -1476,8 +1486,8 @@ class Charter extends UIState {
|
||||
|
||||
public static function saveChart(shouldBuild:Bool = true, withEvents:Bool = true) {
|
||||
#if sys
|
||||
FlxG.sound.play(Paths.sound('editors/save'));
|
||||
saveTo('${Paths.getAssetsRoot()}/songs/${__song.toLowerCase()}', !withEvents, shouldBuild);
|
||||
if (shouldBuild && instance != null) instance.buildChart();
|
||||
Chart.save(PlayState.SONG, __diff.toLowerCase(), __variant, {saveMetaInChart: false, saveLocalEvents: withEvents, prettyPrint: Options.editorCharterPrettyPrint});
|
||||
if (undos != null) undos.save();
|
||||
#else
|
||||
saveChartAs(shouldBuild, withEvents);
|
||||
@@ -1493,13 +1503,9 @@ class Charter extends UIState {
|
||||
|
||||
public static function saveEvents(shouldBuild:Bool = true) {
|
||||
#if sys
|
||||
FlxG.sound.play(Paths.sound('editors/save'));
|
||||
if (shouldBuild && instance != null) instance.buildChart();
|
||||
var data = {events: Chart.filterChartForSaving(PlayState.SONG, false, false, true).events};
|
||||
|
||||
var path = '${Paths.getAssetsRoot()}/songs/${__song.toLowerCase()}/events.json';
|
||||
if (data.events != null && data.events.length > 0) CoolUtil.safeSaveFile(path, Json.stringify(data, null, Options.editorCharterPrettyPrint ? Flags.JSON_PRETTY_PRINT : null));
|
||||
else if (FileSystem.exists(path)) FileSystem.deleteFile(path); // Instead of replacing with a useless empty file, deletes the file directly - Nex
|
||||
Chart.save(PlayState.SONG, __diff.toLowerCase(), __variant, {saveChart: false, seperateGlobalEvents: true, prettyPrint: Options.editorCharterPrettyPrint});
|
||||
if (undos != null) undos.save();
|
||||
#else
|
||||
saveEventsAs(shouldBuild);
|
||||
#end
|
||||
@@ -1507,7 +1513,7 @@ class Charter extends UIState {
|
||||
|
||||
public static function saveEventsAs(shouldBuild:Bool = true) {
|
||||
if (shouldBuild && instance != null) instance.buildChart();
|
||||
var data = {events: Chart.filterChartForSaving(PlayState.SONG, false, false, true).events};
|
||||
var data = {events: Chart.filterEventsForSaving(PlayState.SONG.events, false, true)};
|
||||
|
||||
saveAs(data, null, Options.editorCharterPrettyPrint ? Flags.JSON_PRETTY_PRINT : null, {
|
||||
defaultSaveFile: 'events.json'
|
||||
@@ -1516,12 +1522,8 @@ class Charter extends UIState {
|
||||
|
||||
public static function saveMeta(shouldBuild:Bool = true) {
|
||||
#if sys
|
||||
FlxG.sound.play(Paths.sound('editors/save'));
|
||||
if (shouldBuild && instance != null) instance.buildChart();
|
||||
CoolUtil.safeSaveFile(
|
||||
'${Paths.getAssetsRoot()}/songs/${__song.toLowerCase()}/meta.json',
|
||||
Json.stringify(PlayState.SONG.meta == null ? {} : Chart.filterChartForSaving(PlayState.SONG, true, false, false).meta, null, Flags.JSON_PRETTY_PRINT)
|
||||
);
|
||||
Chart.save(PlayState.SONG, __diff.toLowerCase(), __variant, {saveChart: false, overrideExistingMeta: true, prettyPrint: true});
|
||||
#else
|
||||
saveMetaAs(shouldBuild);
|
||||
#end
|
||||
@@ -1545,9 +1547,7 @@ class Charter extends UIState {
|
||||
}, null, shouldBuild);
|
||||
}
|
||||
|
||||
public static function saveAs(data:Dynamic, ?replacer:(key:Dynamic, value:Dynamic) -> Dynamic, ?space:String, ?options:SaveSubstate.SaveSubstateData, ?saveOptions:Map<String, Bool>, shouldBuild:Bool = true) {
|
||||
FlxG.sound.play(Paths.sound('editors/save'));
|
||||
if (shouldBuild && instance != null) instance.buildChart();
|
||||
public static function saveAs(data:Dynamic, ?replacer:(key:Dynamic, value:Dynamic) -> Dynamic, ?space:String, ?options:SaveSubstate.SaveSubstateData, ?saveOptions:Map<String, Bool>, shouldBuild:Bool = true) { if (shouldBuild && instance != null) instance.buildChart();
|
||||
var cur = FlxG.state;
|
||||
while(true) {
|
||||
if (instance != null || cur.subState == null) return cur.openSubState(new SaveSubstate(Json.stringify(data, replacer, space), options, saveOptions));
|
||||
@@ -1558,7 +1558,7 @@ class Charter extends UIState {
|
||||
#if sys
|
||||
public static function saveTo(path:String, separateEvents:Bool = false, shouldBuild:Bool = true) {
|
||||
if (shouldBuild && instance != null) instance.buildChart();
|
||||
Chart.save(path, PlayState.SONG, __diff.toLowerCase(), {saveMetaInChart: false, saveLocalEvents: !separateEvents, prettyPrint: Options.editorCharterPrettyPrint});
|
||||
Chart.save(PlayState.SONG, __diff.toLowerCase(), __variant, {saveMetaInChart: false, saveLocalEvents: !separateEvents, songFolder: path, prettyPrint: Options.editorCharterPrettyPrint});
|
||||
}
|
||||
#end
|
||||
#end
|
||||
@@ -1570,17 +1570,17 @@ class Charter extends UIState {
|
||||
else {undos = null; FlxG.switchState(new CharterSelection()); Charter.instance.__clearStatics();}
|
||||
}
|
||||
|
||||
function _file_save_all(_) saveEverything();
|
||||
function _file_save(_) saveChart();
|
||||
function _file_saveas(_) saveChartAs();
|
||||
function _file_events_save(_) saveEvents();
|
||||
function _file_events_saveas(_) saveEventsAs();
|
||||
function _file_save_no_events(_) saveChart(true, false);
|
||||
function _file_saveas_no_events(_) saveChartAs(true, false);
|
||||
function _file_meta_save(_) saveMeta();
|
||||
function _file_meta_saveas(_) saveMetaAs();
|
||||
function _file_saveas_fnflegacy(_) saveLegacyChartAs();
|
||||
function _file_saveas_psych(_) savePsychChartAs();
|
||||
function _file_save_all(_) {saveEverything(); FlxG.sound.play(Paths.sound('editors/save'));}
|
||||
function _file_save(_) {saveChart(); FlxG.sound.play(Paths.sound('editors/save'));}
|
||||
function _file_saveas(_) {saveChartAs(); FlxG.sound.play(Paths.sound('editors/save'));}
|
||||
function _file_events_save(_) {saveEvents(); FlxG.sound.play(Paths.sound('editors/save'));}
|
||||
function _file_events_saveas(_) {saveEventsAs(); FlxG.sound.play(Paths.sound('editors/save'));}
|
||||
function _file_save_no_events(_) {saveChart(true, false); FlxG.sound.play(Paths.sound('editors/save'));}
|
||||
function _file_saveas_no_events(_) {saveChartAs(true, false); FlxG.sound.play(Paths.sound('editors/save'));}
|
||||
function _file_meta_save(_) {saveMeta(); FlxG.sound.play(Paths.sound('editors/save'));}
|
||||
function _file_meta_saveas(_) {saveMetaAs(); FlxG.sound.play(Paths.sound('editors/save'));}
|
||||
function _file_saveas_fnflegacy(_) {saveLegacyChartAs(); FlxG.sound.play(Paths.sound('editors/save'));}
|
||||
function _file_saveas_psych(_) {savePsychChartAs(); FlxG.sound.play(Paths.sound('editors/save'));}
|
||||
|
||||
function _edit_copy(_, playSFX=true) {
|
||||
if (playSFX) FlxG.sound.play(Paths.sound(Flags.DEFAULT_EDITOR_COPY_SOUND));
|
||||
@@ -1845,6 +1845,22 @@ class Charter extends UIState {
|
||||
Conductor.songPosition = FlxG.sound.music.length;
|
||||
}
|
||||
|
||||
function _opponent_camera_add(_) addEventAtCurrentStep("Camera Movement", [0], !FlxG.keys.pressed.ALT, !FlxG.keys.pressed.SHIFT);
|
||||
function _player_camera_add(_) addEventAtCurrentStep("Camera Movement", [1], !FlxG.keys.pressed.ALT, !FlxG.keys.pressed.SHIFT);
|
||||
|
||||
function addEventAtCurrentStep(name:String, params:Array<Dynamic>, shouldGlobal:Bool = true, shouldQuant:Bool = false) {
|
||||
var step:Float = (shouldQuant ? quantStep(curStepFloat) : curStepFloat);
|
||||
var __event:CharterEvent = new CharterEvent(step, [{
|
||||
name: name,
|
||||
params: params,
|
||||
time: Conductor.getTimeForStep(step)
|
||||
}], shouldGlobal);
|
||||
|
||||
__event.refreshEventIcons();
|
||||
(__event.global ? rightEventsGroup : leftEventsGroup).add(__event);
|
||||
undos.addToUndo(CEditEvent(__event, [], __event.events));
|
||||
}
|
||||
|
||||
public function getBookmarkList():Array<ChartBookmark> {
|
||||
var bookmarks:Array<ChartBookmark> = [];
|
||||
try {
|
||||
@@ -1855,34 +1871,6 @@ class Charter extends UIState {
|
||||
return bookmarks;
|
||||
}
|
||||
|
||||
function _opponent_camera_add(_) {
|
||||
var __event:CharterEvent = null;
|
||||
|
||||
__event = new CharterEvent(curStepFloat, [{
|
||||
name: "Camera Movement",
|
||||
params:[0],
|
||||
time: Conductor.getTimeForStep(curStepFloat)
|
||||
}], true);
|
||||
__event.refreshEventIcons();
|
||||
__event.global = true;
|
||||
rightEventsGroup.add(__event);
|
||||
undos.addToUndo(CEditEvent(__event, [], __event.events));
|
||||
|
||||
}
|
||||
function _player_camera_add(_) {
|
||||
var __event:CharterEvent = null;
|
||||
|
||||
__event = new CharterEvent(curStepFloat, [{
|
||||
name: "Camera Movement",
|
||||
params:[1],
|
||||
time: Conductor.getTimeForStep(curStepFloat)
|
||||
}], true);
|
||||
__event.refreshEventIcons();
|
||||
rightEventsGroup.add(__event);
|
||||
undos.addToUndo(CEditEvent(__event, [], __event.events));
|
||||
|
||||
}
|
||||
|
||||
function _bookmarks_add(_) {
|
||||
var addBookmarkAt = function(name:String, color:FlxColor, daStep:Float)
|
||||
{
|
||||
@@ -1904,6 +1892,7 @@ class Charter extends UIState {
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
function _bookmarks_edit_list(_)
|
||||
FlxG.state.openSubState(new CharterBookmarkList()); //idk why its FlxG.state but it looks so off lmfao
|
||||
|
||||
@@ -1919,12 +1908,12 @@ class Charter extends UIState {
|
||||
if (bars != null) {
|
||||
for (spr in bars) {
|
||||
if (spr == null) continue;
|
||||
remove(spr);
|
||||
charterBookmarksGroup.remove(spr);
|
||||
spr.kill();
|
||||
}
|
||||
}
|
||||
if (text != null) {
|
||||
remove(text);
|
||||
charterBookmarksGroup.remove(text);
|
||||
text.kill();
|
||||
}
|
||||
}
|
||||
@@ -1945,15 +1934,13 @@ class Charter extends UIState {
|
||||
{
|
||||
var bookmarkspr = new FlxSprite(str.x, (b.time * 40)).makeSolid(str.keyCount * 40, 4, bookmarkcolor);
|
||||
bookmarkspr.updateHitbox();
|
||||
bookmarkspr.camera = charterCamera;
|
||||
add(bookmarkspr);
|
||||
charterBookmarksGroup.add(bookmarkspr);
|
||||
sprites.push(bookmarkspr);
|
||||
}
|
||||
|
||||
var bookmarkText = new UIText(strumLines.members[0].x + 4, 0, 400, b.name, 15, bookmarkcolor, true);
|
||||
bookmarkText.y = sprites[0].y - (bookmarkText.height + 2);
|
||||
bookmarkText.camera = charterCamera;
|
||||
add(bookmarkText);
|
||||
charterBookmarksGroup.add(bookmarkText);
|
||||
|
||||
if (luminance < 0.5)
|
||||
bookmarkText.borderColor = 0x88FFFFFF;
|
||||
@@ -1997,12 +1984,12 @@ class Charter extends UIState {
|
||||
null,
|
||||
{
|
||||
label: translate("song.addOpponentCamera"),
|
||||
keybind: [O],
|
||||
keybinds: [[O], [O, SHIFT], [O, ALT]],
|
||||
onSelect: _opponent_camera_add
|
||||
},
|
||||
{
|
||||
label: translate("song.addPlayerCamera"),
|
||||
keybind: [P],
|
||||
keybinds: [[P], [P, SHIFT], [P, ALT]],
|
||||
onSelect: _player_camera_add
|
||||
},
|
||||
null,
|
||||
@@ -2525,4 +2512,4 @@ typedef PlaytestInfo = {
|
||||
var hitSounds:Array<Bool>;
|
||||
var mutedVocals:Array<Bool>;
|
||||
var waveforms:Array<Int>;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -150,20 +150,21 @@ class CharterMetaDataScreen extends UISubstateWindow {
|
||||
Reflect.setProperty(customVals, vals.propertyText.label.text, vals.valueText.label.text);
|
||||
}
|
||||
|
||||
PlayState.SONG.meta = {
|
||||
name: songNameTextBox.label.text,
|
||||
bpm: bpmStepper.value,
|
||||
needsVoices: needsVoicesCheckbox.checked,
|
||||
beatsPerMeasure: Std.int(beatsPerMeasureStepper.value),
|
||||
stepsPerBeat: Std.int(16 / denominatorStepper.value),
|
||||
displayName: displayNameTextBox.label.text,
|
||||
icon: iconTextBox.label.text,
|
||||
color: colorWheel.curColor,
|
||||
opponentModeAllowed: opponentModeCheckbox.checked,
|
||||
coopAllowed: coopAllowedCheckbox.checked,
|
||||
difficulties: [for (diff in difficultiesTextBox.label.text.split(",")) diff.trim()],
|
||||
customValues: customVals,
|
||||
};
|
||||
var meta = PlayState.SONG.meta;
|
||||
if (meta == null) meta = {name: songNameTextBox.label.text};
|
||||
else meta.name = songNameTextBox.label.text;
|
||||
|
||||
meta.bpm = bpmStepper.value;
|
||||
meta.needsVoices = needsVoicesCheckbox.checked;
|
||||
meta.beatsPerMeasure = Std.int(beatsPerMeasureStepper.value);
|
||||
meta.stepsPerBeat = Std.int(16 / denominatorStepper.value);
|
||||
meta.displayName = displayNameTextBox.label.text;
|
||||
meta.icon = iconTextBox.label.text;
|
||||
meta.color = colorWheel.curColor;
|
||||
meta.opponentModeAllowed = opponentModeCheckbox.checked;
|
||||
meta.coopAllowed = coopAllowedCheckbox.checked;
|
||||
meta.difficulties = [for (diff in difficultiesTextBox.label.text.split(",")) diff.trim()];
|
||||
meta.customValues = customVals;
|
||||
|
||||
Charter.instance.updateBPMEvents();
|
||||
Charter.instance.vocals.muted = !needsVoicesCheckbox.checked;
|
||||
|
||||
@@ -25,55 +25,72 @@ class CharterSelectionScreen extends EditorTreeMenuScreen {
|
||||
public var songList:Array<String> = [];
|
||||
public var curSong:ChartMetaData;
|
||||
|
||||
inline public function makeChartOption(d:String, name:String):TextOption {
|
||||
return new TextOption(d, getID('acceptDifficulty'), () -> FlxG.switchState(new Charter(name, d)));
|
||||
inline public function makeChartOption(d:String, v:String, name:String):TextOption {
|
||||
return new TextOption(d, getID('acceptDifficulty'), () -> FlxG.switchState(new Charter(name, d, v)));
|
||||
}
|
||||
|
||||
inline public function makeVariationOption(s:ChartMetaData):TextOption {
|
||||
return new TextOption(s.variant, getID('acceptVariation'), " >", () -> openSongOption(s, false));
|
||||
}
|
||||
|
||||
public function openSongOption(s:ChartMetaData, first = true) {
|
||||
curSong = s;
|
||||
|
||||
var isVariant = s.variant != null && s.variant != '';
|
||||
var screen = new EditorTreeMenuScreen((first || !isVariant) ? (s.name + (isVariant ? ' (${s.variant})' : '')) : s.variant, getID('selectDifficulty'));
|
||||
|
||||
for (d in s.difficulties) if (d != '') screen.add(makeChartOption(d, isVariant ? s.variant : null, s.name));
|
||||
screen.add(new Separator());
|
||||
for (v in s.variants) if (s.metas.get(v) != null) screen.add(makeVariationOption(s.metas.get(v)));
|
||||
|
||||
#if sys
|
||||
screen.insert(0, new NewOption(getID('newDifficulty'), getID('newDifficultyDesc'), () -> {
|
||||
parent.openSubState(new ChartCreationScreen(saveChart));
|
||||
}));
|
||||
|
||||
if (!first) screen.curSelected = 1;
|
||||
else {
|
||||
cast(screen.members[0], NewOption).itemHeight = 120;
|
||||
screen.insert(1, new NewOption(getID('newVariation'), getID('newVariationDesc'), () -> {
|
||||
parent.openSubState(new VariationCreationScreen(s, saveSong));
|
||||
}));
|
||||
screen.curSelected = 2;
|
||||
}
|
||||
#end
|
||||
|
||||
parent.addMenu(screen);
|
||||
}
|
||||
|
||||
public function makeSongOption(s:ChartMetaData):IconOption {
|
||||
songList.push(s.name.toLowerCase());
|
||||
|
||||
var opt = new IconOption(s.name, getID('acceptSong'), s.icon, () -> {
|
||||
curSong = s;
|
||||
|
||||
var screen = new EditorTreeMenuScreen(s.name, getID('selectDifficulty'), [
|
||||
for (d in s.difficulties) if (d != '') makeChartOption(d, s.name)
|
||||
]);
|
||||
|
||||
#if sys
|
||||
screen.insert(0, new NewOption(getID('newDifficulty'), getID('newDifficultyDesc'), () -> {
|
||||
parent.openSubState(new ChartCreationScreen(saveChart));
|
||||
}));
|
||||
screen.curSelected = 1;
|
||||
#end
|
||||
|
||||
parent.addMenu(screen);
|
||||
});
|
||||
opt.suffix = ' >';
|
||||
var opt = new IconOption(s.name, getID('acceptSong'), s.icon, () -> openSongOption(s, true));
|
||||
opt.suffix = " >";
|
||||
opt.editorFlashColor = s.color.getDefault(FlxColor.WHITE);
|
||||
|
||||
return opt;
|
||||
}
|
||||
|
||||
public function new() {
|
||||
super('editor.chart.name', 'charterSelection.desc', 'charterSelection.', 'newSong', 'newSongDesc', () -> {
|
||||
super('editor.chart.name', 'charterSelection.desc', 'charterSelection.', 'newSong', 'newSongDesc', #if sys () -> {
|
||||
parent.openSubState(new SongCreationScreen(saveSong));
|
||||
});
|
||||
} #end);
|
||||
freeplayList = FreeplaySonglist.get(false);
|
||||
|
||||
for (i => s in freeplayList.songs) add(makeSongOption(s));
|
||||
}
|
||||
|
||||
#if sys
|
||||
public function saveSong(creation:SongCreationData, ?callback:String -> SongCreationData -> Void) {
|
||||
var songAlreadyExists:Bool = songList.contains(creation.meta.name.toLowerCase());
|
||||
if (songAlreadyExists) {
|
||||
public function saveSong(creation:SongCreationData, ?callback:String -> Void) {
|
||||
var variant = creation.meta.variant != null && creation.meta.variant != "" ? creation.meta.variant : null;
|
||||
if (variant != null && curSong != null ? curSong.metas.exists(variant) : songList.contains(creation.meta.name.toLowerCase())) {
|
||||
parent.openSubState(new UIWarningSubstate(TU.translate("chartCreation.warnings.song-exists-title"), TU.translate("chartCreation.warnings.song-exists-body"), [
|
||||
{label: TU.translate("editor.ok"), color: 0xFFFF0000, onClick: (t) -> {}},
|
||||
]));
|
||||
return;
|
||||
}
|
||||
|
||||
var songFolder:String = '${Paths.getAssetsRoot()}/songs/${creation.meta.name}';
|
||||
var songFolder:String = '${Paths.getAssetsRoot()}/songs/${variant != null && curSong != null ? curSong.name : creation.meta.name}';
|
||||
|
||||
#if sys
|
||||
// Make Directories
|
||||
@@ -82,24 +99,37 @@ class CharterSelectionScreen extends EditorTreeMenuScreen {
|
||||
sys.FileSystem.createDirectory('$songFolder/charts');
|
||||
|
||||
// Save Files
|
||||
CoolUtil.safeSaveFile('$songFolder/meta.json', Chart.makeMetaSaveable(creation.meta));
|
||||
if (creation.instBytes != null) sys.io.File.saveBytes('$songFolder/song/Inst.${Flags.SOUND_EXT}', creation.instBytes);
|
||||
if (creation.voicesBytes != null) sys.io.File.saveBytes('$songFolder/song/Voices.${Flags.SOUND_EXT}', creation.voicesBytes);
|
||||
var instSuffix = creation.meta.instSuffix != null ? creation.meta.instSuffix : '', vocalsSuffix = creation.meta.vocalsSuffix != null ? creation.meta.vocalsSuffix : '';
|
||||
CoolUtil.safeSaveFile('$songFolder/meta${variant != null ? "-" + variant : ""}.json', Json.stringify(Chart.filterMetaForSaving(creation.meta), null, Flags.JSON_PRETTY_PRINT));
|
||||
if (creation.instBytes != null) sys.io.File.saveBytes('$songFolder/song/Inst$instSuffix.${Flags.SOUND_EXT}', creation.instBytes);
|
||||
if (creation.voicesBytes != null) sys.io.File.saveBytes('$songFolder/song/Voices$vocalsSuffix.${Flags.SOUND_EXT}', creation.voicesBytes);
|
||||
|
||||
if (creation.playerVocals != null) sys.io.File.saveBytes('$songFolder/song/Voices-Player.${Flags.SOUND_EXT}', creation.playerVocals);
|
||||
if (creation.oppVocals != null) sys.io.File.saveBytes('$songFolder/song/Voices-Opponent.${Flags.SOUND_EXT}', creation.oppVocals);
|
||||
if (creation.playerVocals != null) sys.io.File.saveBytes('$songFolder/song/Voices-Player$vocalsSuffix.${Flags.SOUND_EXT}', creation.playerVocals);
|
||||
if (creation.oppVocals != null) sys.io.File.saveBytes('$songFolder/song/Voices-Opponent$vocalsSuffix.${Flags.SOUND_EXT}', creation.oppVocals);
|
||||
#end
|
||||
|
||||
if (callback != null) callback(songFolder, creation);
|
||||
if (callback != null) callback(songFolder);
|
||||
|
||||
// Add to List
|
||||
freeplayList.songs.insert(0, creation.meta);
|
||||
insert(1, makeSongOption(creation.meta));
|
||||
if (variant != null && curSong != null) {
|
||||
if (curSong.variants == null) curSong.variants = [];
|
||||
if (!curSong.variants.contains(variant)) curSong.variants.push(variant);
|
||||
|
||||
curSong.metas.set(variant, creation.meta);
|
||||
|
||||
parent.tree.last().add(makeVariationOption(creation.meta));
|
||||
|
||||
var metaPath = '$songFolder/meta${curSong.variant != null && curSong.variant == "" ? "-" + curSong.variant : ""}.json';
|
||||
CoolUtil.safeSaveFile(metaPath, Chart.makeMetaSaveable(curSong));
|
||||
}
|
||||
else {
|
||||
freeplayList.songs.insert(0, creation.meta);
|
||||
insert(1, makeSongOption(creation.meta));
|
||||
}
|
||||
}
|
||||
|
||||
public function saveChart(name:String, data:ChartData) {
|
||||
var difficultyAlreadyExists:Bool = curSong.difficulties.contains(name);
|
||||
if (difficultyAlreadyExists) {
|
||||
if (curSong.difficulties.contains(name)) {
|
||||
parent.openSubState(new UIWarningSubstate(TU.translate("chartCreation.warnings.chart-exists-title"), TU.translate("chartCreation.warnings.chart-exists-body"), [
|
||||
{label: TU.translate("editor.ok"), color: 0xFFFF0000, onClick: (t) -> {}},
|
||||
]));
|
||||
@@ -113,14 +143,15 @@ class CharterSelectionScreen extends EditorTreeMenuScreen {
|
||||
|
||||
// Add to List
|
||||
curSong.difficulties.push(name);
|
||||
parent.tree.last().insert(parent.tree.last().length - 1, makeChartOption(name, curSong.name));
|
||||
|
||||
var screen = parent.tree.last();
|
||||
var idx = 0;
|
||||
while (!(screen.members[idx] is Separator)) idx++;
|
||||
screen.insert(idx, makeChartOption(name, curSong.variant != null && curSong.variant != "" ? curSong.variant : null, curSong.name));
|
||||
|
||||
// Add to Meta
|
||||
var meta = Json.parse(sys.io.File.getContent('$songFolder/meta.json'));
|
||||
if (meta.difficulties != null && !meta.difficulties.contains(name)) {
|
||||
meta.difficulties.push(name);
|
||||
CoolUtil.safeSaveFile('$songFolder/meta.json', Chart.makeMetaSaveable(meta));
|
||||
}
|
||||
var metaPath = '$songFolder/meta${curSong.variant != null && curSong.variant == "" ? "-" + curSong.variant : ""}.json';
|
||||
CoolUtil.safeSaveFile(metaPath, Chart.makeMetaSaveable(curSong));
|
||||
}
|
||||
#end
|
||||
}
|
||||
@@ -127,7 +127,7 @@ class CharterStrumline extends UISprite {
|
||||
var maxRow = Math.floor((icons.length-1) / 4) + 1;
|
||||
for (i=>icon in icons) {
|
||||
var healthIcon = new HealthIcon(Character.getIconFromCharName(icon));
|
||||
healthIcon.scale.x = healthIcon.scale.y = Math.max((0.6 - (icons.length / 20)), 0.35);
|
||||
healthIcon.scale.x = healthIcon.scale.y = Math.max((0.6 - (icons.length / 20)), 0.35) * (150 / Math.max(healthIcon.frameWidth, healthIcon.frameHeight));
|
||||
healthIcon.updateHitbox();
|
||||
healthIcon.x = FlxMath.lerp(0, Math.min(icons.length * 20, 120), (maxCol-1 != 0 ? (i % 4) / (maxCol-1) : 0));
|
||||
healthIcon.y = (draggable ? 14 : 7) + FlxMath.lerp(0, Math.min(maxRow * 15, 60), (maxRow-1 != 0 ? Math.floor(i / 4) / (maxRow-1) : 0));
|
||||
|
||||
@@ -3,6 +3,7 @@ package funkin.editors.charter;
|
||||
import flixel.group.FlxGroup;
|
||||
import flixel.text.FlxText.FlxTextFormat;
|
||||
import flixel.text.FlxText.FlxTextFormatMarkerPair;
|
||||
import funkin.backend.chart.Chart;
|
||||
import funkin.backend.chart.ChartData;
|
||||
import funkin.backend.chart.FNFLegacyParser.SwagSong;
|
||||
import funkin.backend.chart.PsychParser;
|
||||
@@ -23,7 +24,7 @@ typedef SongCreationData = {
|
||||
}
|
||||
|
||||
class SongCreationScreen extends UISubstateWindow {
|
||||
private var onSave:Null<SongCreationData> -> Null<String -> SongCreationData -> Void> -> Void = null;
|
||||
private var onSave:Null<SongCreationData> -> Null<String -> Void> -> Void = null;
|
||||
|
||||
public var songNameTextBox:UITextBox;
|
||||
public var bpmStepper:UINumericStepper;
|
||||
@@ -72,7 +73,7 @@ class SongCreationScreen extends UISubstateWindow {
|
||||
|
||||
public var curPage:Int = 0;
|
||||
|
||||
public function new(?onSave:SongCreationData -> Null<String -> SongCreationData -> Void> -> Void) {
|
||||
public function new(?onSave:SongCreationData -> Null<String -> Void> -> Void) {
|
||||
super();
|
||||
if (onSave != null) this.onSave = onSave;
|
||||
}
|
||||
@@ -245,7 +246,7 @@ class SongCreationScreen extends UISubstateWindow {
|
||||
var pages = isImporting ? importPages : pages;
|
||||
if (curPage == pages.length-1) {
|
||||
saveSongInfo();
|
||||
close();
|
||||
if (subState == null) close();
|
||||
} else {
|
||||
curPage++;
|
||||
refreshPages();
|
||||
@@ -296,7 +297,7 @@ class SongCreationScreen extends UISubstateWindow {
|
||||
|
||||
if (curPage == 1) {
|
||||
importInstExplorer.selectable = importVoicesExplorer.selectable = !project;
|
||||
saveButton.selectable = project ? true : (importInstExplorer.file != null);
|
||||
saveButton.selectable = #if TEST_BUILD true #else project ? true : (importInstExplorer.file != null) #end;
|
||||
} else if (curPage == 2) {
|
||||
importIdTextBox.selectable = !project;
|
||||
importChartFile.fileType = project ? "fnfc" : "json";
|
||||
@@ -356,6 +357,13 @@ class SongCreationScreen extends UISubstateWindow {
|
||||
iconSprite.scrollFactor.set(1, 1);
|
||||
}
|
||||
|
||||
// for variations
|
||||
function formatMeta(meta:ChartMetaData):ChartMetaData
|
||||
return Chart.defaultChartMetaFields(meta);
|
||||
|
||||
function getChartSavePath(meta:ChartMetaData, diff:String):String
|
||||
return 'charts/${meta.variant != null && meta.variant != "" ? meta.variant + "/" : ""}$diff.json';
|
||||
|
||||
function saveSongInfo() {
|
||||
if (isImporting)
|
||||
{
|
||||
@@ -379,34 +387,36 @@ class SongCreationScreen extends UISubstateWindow {
|
||||
saveFromVSlice(files, songId);
|
||||
default /*"Psych/Legacy FNF"*/:
|
||||
var songId = importIdTextBox.label.text;
|
||||
var oldChart:SwagSong = Json.parse(cast importChartFile.file);
|
||||
var oldChart:SwagSong = Chart.cleanSongData(Json.parse(cast importChartFile.file));
|
||||
var base:ChartData = {
|
||||
strumLines: [],
|
||||
noteTypes: [],
|
||||
events: [],
|
||||
meta: {name: null},
|
||||
meta: {name: songId},
|
||||
scrollSpeed: Flags.DEFAULT_SCROLL_SPEED,
|
||||
stage: Flags.DEFAULT_STAGE,
|
||||
codenameChart: true
|
||||
};
|
||||
PsychParser.parse(oldChart, base);
|
||||
var meta = formatMeta({
|
||||
name: songId,
|
||||
difficulties: ['normal'],
|
||||
bpm: oldChart.bpm,
|
||||
beatsPerMeasure: oldChart.beatsPerMeasure,
|
||||
stepsPerBeat: oldChart.stepsPerBeat,
|
||||
displayName: oldChart.song
|
||||
});
|
||||
if (onSave != null) onSave({
|
||||
meta: {
|
||||
name: songId,
|
||||
difficulties: [songId],
|
||||
bpm: oldChart.bpm,
|
||||
beatsPerMeasure: oldChart.beatsPerMeasure,
|
||||
stepsPerBeat: oldChart.stepsPerBeat,
|
||||
displayName: oldChart.song
|
||||
},
|
||||
meta: meta,
|
||||
instBytes: importInstExplorer.file,
|
||||
voicesBytes: importVoicesExplorer.file,
|
||||
}, (songFolder:String, creation:SongCreationData) -> {
|
||||
}, (songFolder:String) -> {
|
||||
#if sys
|
||||
CoolUtil.safeSaveFile('$songFolder/charts/${songId}.json', Json.stringify(base, Flags.JSON_PRETTY_PRINT));
|
||||
CoolUtil.safeSaveFile('$songFolder/${getChartSavePath(meta, "normal")}', Json.stringify(base, Flags.JSON_PRETTY_PRINT));
|
||||
#end
|
||||
});
|
||||
} catch (e:haxe.Exception) {
|
||||
trace(e.stack, e.message);
|
||||
openSubState(new UIWarningSubstate("Importing Song/Charts: Error!", e.details(), [
|
||||
{label: "Ok", color: 0xFFFF0000, onClick: function(t) {}}
|
||||
]));
|
||||
@@ -415,7 +425,7 @@ class SongCreationScreen extends UISubstateWindow {
|
||||
for (stepper in [bpmStepper, beatsPerMeasureStepper, denominatorStepper])
|
||||
@:privateAccess stepper.__onChange(stepper.label.text);
|
||||
|
||||
var meta:ChartMetaData = {
|
||||
var meta:ChartMetaData = formatMeta({
|
||||
name: songNameTextBox.label.text,
|
||||
bpm: bpmStepper.value,
|
||||
beatsPerMeasure: Std.int(beatsPerMeasureStepper.value),
|
||||
@@ -425,8 +435,8 @@ class SongCreationScreen extends UISubstateWindow {
|
||||
color: colorWheel.curColor,
|
||||
opponentModeAllowed: opponentModeCheckbox.checked,
|
||||
coopAllowed: coopAllowedCheckbox.checked,
|
||||
difficulties: [for (diff in difficultiesTextBox.label.text.split(",")) diff.trim()],
|
||||
};
|
||||
difficulties: [for (diff in difficultiesTextBox.label.text.split(",")) diff.trim()]
|
||||
});
|
||||
|
||||
if (onSave != null) onSave({
|
||||
meta: meta,
|
||||
@@ -442,19 +452,23 @@ class SongCreationScreen extends UISubstateWindow {
|
||||
var vslicechart:NewSwagSong = Json.parse(files.get('${songId}-chart.json'));
|
||||
var playData = vslicemeta.playData;
|
||||
|
||||
var meta:ChartMetaData = {name: songId};
|
||||
var diffCharts:Array<ChartDataWithInfo> = [];
|
||||
var meta:ChartMetaData = formatMeta({name: songId, needsVoices: files.get('Voices.${Flags.SOUND_EXT}') != null});
|
||||
var diffCharts:Array<ChartDataWithInfo> = [], events:Array<ChartEvent> = null;
|
||||
VSliceParser.parse(vslicemeta, vslicechart, meta, diffCharts, songId);
|
||||
|
||||
if (diffCharts.length != 0) events = diffCharts[0].chart.events;
|
||||
for (diff in diffCharts) diff.chart.events = [];
|
||||
|
||||
if (onSave != null) onSave({
|
||||
meta: meta,
|
||||
instBytes: files.get('Inst.${Flags.SOUND_EXT}'),
|
||||
voicesBytes: files.get('Voices.${Flags.SOUND_EXT}'), //it may exist
|
||||
playerVocals: files.get('Voices-${playData.characters.playerVocals != null ? playData.characters.playerVocals[0] : playData.characters.player}.${Flags.SOUND_EXT}'),
|
||||
oppVocals: files.get('Voices-${playData.characters.opponentVocals != null ? playData.characters.opponentVocals[0] : playData.characters.opponent}.${Flags.SOUND_EXT}'),
|
||||
}, (songFolder:String, creation:SongCreationData) -> {
|
||||
}, (songFolder:String) -> {
|
||||
#if sys
|
||||
for (diff in diffCharts) CoolUtil.safeSaveFile('$songFolder/charts/${diff.diffName}.json', Json.stringify(diff.chart, Flags.JSON_PRETTY_PRINT));
|
||||
for (diff in diffCharts) CoolUtil.safeSaveFile('$songFolder/${getChartSavePath(meta, diff.diffName)}', Json.stringify(diff.chart, Flags.JSON_PRETTY_PRINT));
|
||||
if (events != null) CoolUtil.safeSaveFile('$songFolder/events${meta.variant != null && meta.variant != "" ? "-" + meta.variant : ""}.json', Json.stringify({events: events}, Flags.JSON_PRETTY_PRINT));
|
||||
#end
|
||||
});
|
||||
}
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
package funkin.editors.charter;
|
||||
|
||||
import flixel.text.FlxText.FlxTextFormat;
|
||||
import flixel.text.FlxText.FlxTextFormatMarkerPair;
|
||||
import funkin.backend.chart.ChartData;
|
||||
import funkin.editors.charter.SongCreationScreen;
|
||||
|
||||
class VariationCreationScreen extends SongCreationScreen {
|
||||
public var parentMeta:ChartMetaData;
|
||||
|
||||
public function new(parent:ChartMetaData, ?onSave:SongCreationData -> Null<String -> Void> -> Void) {
|
||||
super(onSave);
|
||||
this.parentMeta = parent;
|
||||
}
|
||||
|
||||
override function create() {
|
||||
super.create();
|
||||
|
||||
songNameTextBox.label.text = translateMeta("variation");
|
||||
cast(songNameTextBox.members[songNameTextBox.members.length - 1], UIText).text = translateMeta("variation");
|
||||
|
||||
cast(importIdTextBox.members[importIdTextBox.members.length - 1], UIText).applyMarkup(
|
||||
translateMeta("variation"),
|
||||
[new FlxTextFormatMarkerPair(new FlxTextFormat(0xFFAD1212), "$")]
|
||||
);
|
||||
|
||||
bpmStepper.value = parentMeta.bpm;
|
||||
beatsPerMeasureStepper.value = parentMeta.beatsPerMeasure;
|
||||
denominatorStepper.value = Std.int(16 / parentMeta.stepsPerBeat);
|
||||
displayNameTextBox.label.text = parentMeta.displayName;
|
||||
iconTextBox.label.text = parentMeta.icon;
|
||||
opponentModeCheckbox.checked = parentMeta.opponentModeAllowed;
|
||||
coopAllowedCheckbox.checked = parentMeta.coopAllowed;
|
||||
colorWheel.setColor(parentMeta.color);
|
||||
difficultiesTextBox.label.text = parentMeta.difficulties.join(', ');
|
||||
}
|
||||
|
||||
override function formatMeta(meta:ChartMetaData):ChartMetaData {
|
||||
meta.variant = meta.name;
|
||||
meta.vocalsSuffix = meta.instSuffix = '-${meta.variant}';
|
||||
meta.name = parentMeta.name;
|
||||
meta.icon = parentMeta.icon;
|
||||
meta.color = parentMeta.color;
|
||||
return super.formatMeta(meta);
|
||||
}
|
||||
}
|
||||
@@ -40,11 +40,11 @@ class StageCreationScreen extends UISubstateWindow {
|
||||
var stageInfo:UIText;
|
||||
add(stageInfo = new UIText(windowSpr.x + 20, windowSpr.y + 30 + 16, 0, translate("title"), 28));
|
||||
|
||||
add(stageNameTextBox = new UITextBox(stageInfo.x, stageInfo.y + stageInfo.height + 36, translate("stage-name")));
|
||||
addLabelOn(stageNameTextBox, translate("stage-name"));
|
||||
add(stageNameTextBox = new UITextBox(stageInfo.x, stageInfo.y + stageInfo.height + 36, translate("stageName")));
|
||||
addLabelOn(stageNameTextBox, translate("stageName"));
|
||||
|
||||
add(stagePathTextBox = new UITextBox(stageNameTextBox.x + 320 + 26, stageNameTextBox.y, translate("stage-path")));
|
||||
addLabelOn(stagePathTextBox, translate("stage-path"));
|
||||
add(stagePathTextBox = new UITextBox(stageNameTextBox.x + 320 + 26, stageNameTextBox.y, translate("stagePath")));
|
||||
addLabelOn(stagePathTextBox, translate("stagePath"));
|
||||
|
||||
add(saveButton = new UIButton(windowSpr.x + windowSpr.bWidth - 20 - 125, windowSpr.y + windowSpr.bHeight - 16 - 32, TU.translate("editor.saveClose"), function() {
|
||||
saveStageInfo();
|
||||
|
||||
@@ -359,10 +359,10 @@ class StageEditor extends UIState {
|
||||
var parent = new Access(node.x.parent);
|
||||
|
||||
var charName = switch(node.name) {
|
||||
case "dad" | "opponent": "dad";
|
||||
case "gf" | "girlfriend": "gf";
|
||||
case "bf" | "boyfriend" | "player": "bf";
|
||||
default: (charPos.flipX) ? "bf" : "dad";
|
||||
case "dad" | "opponent": Flags.DEFAULT_OPPONENT;
|
||||
case "gf" | "girlfriend": Flags.DEFAULT_GIRLFRIEND;
|
||||
case "bf" | "boyfriend" | "player": Flags.DEFAULT_CHARACTER;
|
||||
default: (charPos.flipX) ? Flags.DEFAULT_CHARACTER : Flags.DEFAULT_OPPONENT;
|
||||
}
|
||||
|
||||
var char = new Character(0,0, charName, charPos.flipX, true);
|
||||
|
||||
@@ -31,7 +31,6 @@ class UIColorwheel extends UISliceSprite {
|
||||
hue = curColor.hue; saturation = curColor.saturation; brightness = curColor.brightness;
|
||||
|
||||
colorPickerShader = new CustomShader("engine/colorPicker");
|
||||
colorPickerShader.hset("hue", hue);
|
||||
|
||||
colorPicker = new FlxSprite(x + 12.5, (y + 125/2) - (100/2)).makeGraphic(100, 100, FlxColor.TRANSPARENT);
|
||||
colorPicker.drawRoundRect(0, 0, 100, 100, 10, 10, FlxColor.WHITE);
|
||||
@@ -91,6 +90,11 @@ class UIColorwheel extends UISliceSprite {
|
||||
updateWheel(false);
|
||||
}
|
||||
|
||||
public function setColor(color:FlxColor) {
|
||||
hue = curColor.hue; saturation = curColor.saturation; brightness = curColor.brightness;
|
||||
updateWheel(false);
|
||||
}
|
||||
|
||||
inline function updateColorPickerSelector()
|
||||
colorPickerSelector.selector.setPosition(colorPicker.x + (colorPicker.width *saturation) - 8, colorPicker.y + (colorPicker.height + (colorPicker.height * -brightness))- 8);
|
||||
|
||||
|
||||
@@ -121,8 +121,10 @@ class Character extends FunkinSprite implements IBeatReceiver implements IOffset
|
||||
@:noCompletion var isDanceLeftDanceRight:Bool = false;
|
||||
|
||||
override function update(elapsed:Float) {
|
||||
super.update(elapsed);
|
||||
scripts.call("update", [elapsed]);
|
||||
|
||||
super.update(elapsed);
|
||||
|
||||
if (stunned) {
|
||||
__stunnedTime += elapsed;
|
||||
if (__stunnedTime > Flags.STUNNED_TIME)
|
||||
@@ -133,6 +135,8 @@ class Character extends FunkinSprite implements IBeatReceiver implements IOffset
|
||||
tryDance();
|
||||
|
||||
__lockAnimThisFrame = false;
|
||||
|
||||
scripts.call("postUpdate", [elapsed]);
|
||||
}
|
||||
|
||||
private var danced:Bool = false;
|
||||
|
||||
@@ -55,7 +55,7 @@ class HealthIcon extends FunkinSprite
|
||||
*
|
||||
* This is what scale the icon should return to when its bump animation is finished
|
||||
*/
|
||||
public var defaultScale:Float = 1;
|
||||
public var defaultScale:Float = Flags.ICON_DEFAULT_SCALE;
|
||||
|
||||
/**
|
||||
* Whenever or not the icon is animated or not
|
||||
@@ -178,9 +178,6 @@ class HealthIcon extends FunkinSprite
|
||||
|
||||
loadGraphic(iconAsset, true, Std.int(Math.min(iconSize, assetW)), Std.int(Math.min(iconSize, assetH)));
|
||||
|
||||
setGraphicSize(150);
|
||||
updateHitbox();
|
||||
|
||||
animation.add(char, [for(i in 0...iconAmt) i], 0, false, isPlayer != iconIsPlayer);
|
||||
animation.play(char);
|
||||
}
|
||||
@@ -235,9 +232,7 @@ class HealthIcon extends FunkinSprite
|
||||
else if (node.exists("offsety"))
|
||||
offsetY = Std.parseFloat(node.get("offsety")).getDefault(0);
|
||||
|
||||
addOffset(animName, offsetX, offsetY);
|
||||
|
||||
addAnim(animName, node.get("anim"), Std.parseInt(node.get("fps")).getDefault(24), false); // 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))
|
||||
animation.getByName(animName).flipX = isPlayer != iconIsPlayer;
|
||||
case "anim":
|
||||
@@ -268,15 +263,13 @@ class HealthIcon extends FunkinSprite
|
||||
else if (node.exists("offsety"))
|
||||
offsetY = Std.parseFloat(node.get("offsety")).getDefault(0);
|
||||
|
||||
addOffset(animName, offsetX, offsetY);
|
||||
|
||||
var looped:Bool = false;
|
||||
if (node.exists("looped"))
|
||||
looped = node.get("looped").toLowerCase() == "true";
|
||||
else if (node.exists("loop"))
|
||||
looped = node.get("loop").toLowerCase() == "true";
|
||||
|
||||
addAnim(animName, node.get("anim"), Std.parseInt(node.get("fps")).getDefault(24), looped);
|
||||
addAnim(animName, node.get("anim"), Std.parseInt(node.get("fps")).getDefault(24), looped, null, null, offsetX, offsetY);
|
||||
if (animateAtlas == null && animation.exists(animName))
|
||||
animation.getByName(animName).flipX = isPlayer != iconIsPlayer;
|
||||
case "step":
|
||||
@@ -460,4 +453,4 @@ enum abstract TrackerAlignment(Int) {
|
||||
* Mathematically: `tracker.x + tracker.width`
|
||||
*/
|
||||
var RIGHT = 2;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,6 +53,13 @@ class Note extends FlxSprite
|
||||
*/
|
||||
public var nextSustain:Note;
|
||||
|
||||
/**
|
||||
* The parent of the sustain.
|
||||
*
|
||||
* If this note is not sustain, this will be null.
|
||||
*/
|
||||
public var sustainParent:Null<Note>;
|
||||
|
||||
/**
|
||||
* Name of the splash.
|
||||
*/
|
||||
@@ -125,6 +132,10 @@ class Note extends FlxSprite
|
||||
for(field in Reflect.fields(noteData)) if(!DEFAULT_FIELDS.contains(field))
|
||||
this.extra.set(field, Reflect.field(noteData, field));
|
||||
|
||||
// work around to set the `sustainParent`
|
||||
if (isSustainNote)
|
||||
sustainParent = prevNote.isSustainNote ? prevNote.sustainParent : prevNote;
|
||||
|
||||
x += 50;
|
||||
// MAKE SURE ITS DEFINITELY OFF SCREEN?
|
||||
y -= 2000;
|
||||
|
||||
@@ -61,10 +61,18 @@ class PlayState extends MusicBeatState
|
||||
* The remaining songs in the Story Mode playlist.
|
||||
*/
|
||||
public static var storyPlaylist:Array<String> = [];
|
||||
/**
|
||||
* The remaining variations to play with the Story Mode
|
||||
*/
|
||||
public static var storyVariations:Array<String> = [];
|
||||
/**
|
||||
* The selected difficulty name.
|
||||
*/
|
||||
public static var difficulty:String = Flags.DEFAULT_DIFFICULTY;
|
||||
/**
|
||||
* The selected variation name. (It can be null)
|
||||
*/
|
||||
public static var variation:Null<String>;
|
||||
/**
|
||||
* Whenever the week is coming from the mods folder or not.
|
||||
*/
|
||||
@@ -657,7 +665,7 @@ class PlayState extends MusicBeatState
|
||||
persistentDraw = true;
|
||||
|
||||
if (SONG == null)
|
||||
SONG = Chart.parse('tutorial', 'normal');
|
||||
SONG = Chart.parse('tutorial', difficulty = 'normal', variation = null);
|
||||
|
||||
scrollSpeed = SONG.scrollSpeed;
|
||||
|
||||
@@ -1052,14 +1060,22 @@ class PlayState extends MusicBeatState
|
||||
}
|
||||
|
||||
public override function destroy() {
|
||||
var notNull = stage != null;
|
||||
if (notNull) PlayState.instance.gameAndCharsCall("onStageDestroy", [stage]);
|
||||
scripts.call("destroy");
|
||||
for(g in __cachedGraphics)
|
||||
g.useCount--;
|
||||
|
||||
for (g in __cachedGraphics) g.useCount--;
|
||||
@:privateAccess {
|
||||
for (strumLine in strumLines.members) FlxG.sound.destroySound(strumLine.vocals);
|
||||
if (FlxG.sound.music != inst) FlxG.sound.destroySound(inst);
|
||||
FlxG.sound.destroySound(vocals);
|
||||
}
|
||||
|
||||
if (notNull) {
|
||||
stage.destroySilently();
|
||||
remove(stage, true);
|
||||
}
|
||||
|
||||
scripts = FlxDestroyUtil.destroy(scripts);
|
||||
|
||||
super.destroy();
|
||||
@@ -1352,7 +1368,7 @@ class PlayState extends MusicBeatState
|
||||
updateRatingStuff();
|
||||
|
||||
if (canAccessDebugMenus && chartingMode && controls.DEV_ACCESS)
|
||||
FlxG.switchState(new funkin.editors.charter.Charter(SONG.meta.name, difficulty, false));
|
||||
FlxG.switchState(new funkin.editors.charter.Charter(SONG.meta.name, difficulty, variation, false));
|
||||
|
||||
if (Options.camZoomOnBeat && camZooming) {
|
||||
var beat = Conductor.getBeats(camZoomingEvery, camZoomingInterval, camZoomingOffset);
|
||||
@@ -1448,7 +1464,7 @@ class PlayState extends MusicBeatState
|
||||
public function moveCamera() if (strumLines.members[curCameraTarget] != null) {
|
||||
var data:CamPosData = getStrumlineCamPos(curCameraTarget);
|
||||
if (data.amount > 0) {
|
||||
var event = scripts.event("onCameraMove", EventManager.get(CamMoveEvent).recycle(data.pos, strumLines.members[curCameraTarget], data.amount));
|
||||
var event = gameAndCharsEvent("onCameraMove", EventManager.get(CamMoveEvent).recycle(data.pos, strumLines.members[curCameraTarget], data.amount));
|
||||
if (!event.cancelled)
|
||||
camFollow.setPosition(event.position.x, event.position.y);
|
||||
}
|
||||
@@ -1571,7 +1587,12 @@ class PlayState extends MusicBeatState
|
||||
var camera:FlxCamera = event.params[1] == "camHUD" ? camHUD : camGame;
|
||||
camera.zoom += event.params[0];
|
||||
case "Camera Bop":
|
||||
camZoomingMult += event.params[0];
|
||||
if (useCamZoomMult) {
|
||||
camZoomingMult += event.params[0];
|
||||
} else {
|
||||
FlxG.camera.zoom += event.params[0] * camZoomingStrength;
|
||||
camHUD.zoom += event.params[0] * camZoomingStrength;
|
||||
}
|
||||
case "Camera Zoom":
|
||||
var cam = event.params[2] == "camHUD" ? camHUD : camGame;
|
||||
var name = (event.params[2] == "camHUD" ? "camHUD" : "camGame") + ".zoom"; // avoiding having different values from these 2 - Nex
|
||||
@@ -1632,7 +1653,7 @@ class PlayState extends MusicBeatState
|
||||
case "Play Animation":
|
||||
if (strumLines.members[event.params[0]] != null && strumLines.members[event.params[0]].characters != null)
|
||||
for (char in strumLines.members[event.params[0]].characters)
|
||||
if (char != null) 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
|
||||
}
|
||||
}
|
||||
@@ -1687,8 +1708,8 @@ class PlayState extends MusicBeatState
|
||||
*/
|
||||
public function endSong():Void
|
||||
{
|
||||
if (gameAndCharsEvent("onSongEnd", new CancellableEvent()).cancelled) return;
|
||||
endingSong = true;
|
||||
gameAndCharsCall("onSongEnd");
|
||||
canPause = false;
|
||||
|
||||
for (strumLine in strumLines.members) strumLine.vocals.stop();
|
||||
@@ -1697,7 +1718,7 @@ class PlayState extends MusicBeatState
|
||||
|
||||
if (validScore) {
|
||||
#if !switch
|
||||
FunkinSave.setSongHighscore(SONG.meta.name, difficulty, {
|
||||
FunkinSave.setSongHighscore(SONG.meta.name, difficulty, variation, {
|
||||
score: songScore,
|
||||
misses: misses,
|
||||
accuracy: accuracy,
|
||||
@@ -1729,6 +1750,7 @@ class PlayState extends MusicBeatState
|
||||
campaignAccuracyTotal += accuracy;
|
||||
campaignAccuracyCount++;
|
||||
storyPlaylist.shift();
|
||||
storyVariations.shift();
|
||||
|
||||
if (storyPlaylist.length <= 0) {
|
||||
FlxG.switchState(new StoryMenuState());
|
||||
@@ -1748,16 +1770,16 @@ class PlayState extends MusicBeatState
|
||||
FlxG.save.flush();
|
||||
}
|
||||
else {
|
||||
Logs.infos('Loading next song (${storyPlaylist[0].toLowerCase()}/$difficulty)', "PlayState");
|
||||
Logs.infos('Loading next song (${storyPlaylist[0].toLowerCase()}/$difficulty/${storyVariations[0]})', "PlayState");
|
||||
|
||||
registerSmoothTransition();
|
||||
|
||||
__loadSong(storyPlaylist[0], difficulty);
|
||||
__loadSong(storyPlaylist[0], difficulty, storyVariations[0]);
|
||||
FlxG.switchState(new PlayState());
|
||||
}
|
||||
}
|
||||
else if (chartingMode)
|
||||
FlxG.switchState(new funkin.editors.charter.Charter(SONG.meta.name, difficulty, false));
|
||||
FlxG.switchState(new funkin.editors.charter.Charter(SONG.meta.name, difficulty, variation, false));
|
||||
else
|
||||
FlxG.switchState(new FreeplayState());
|
||||
}
|
||||
@@ -1796,7 +1818,10 @@ class PlayState extends MusicBeatState
|
||||
|
||||
var event:NoteMissEvent = gameAndCharsEvent("onPlayerMiss", EventManager.get(NoteMissEvent).recycle(note, -10, 1, muteVocalsOnMiss, note != null ? -0.0475 : -0.04, Paths.sound(FlxG.random.getObject(Flags.DEFAULT_MISS_SOUNDS)), FlxG.random.float(0.1, 0.2), note == null, combo > 5, "sad", true, true, "miss", strumLines.members[playerID].characters, playerID, note != null ? note.noteType : null, directionID, 0));
|
||||
strumLine.onMiss.dispatch(event);
|
||||
if (event.cancelled) return;
|
||||
if (event.cancelled) {
|
||||
gameAndCharsEvent("onPostPlayerMiss", event);
|
||||
return;
|
||||
}
|
||||
|
||||
if (strumLine != null) strumLine.addHealth(event.healthGain);
|
||||
if (gf != null && event.gfSad && gf.hasAnimation(event.gfSadAnim))
|
||||
@@ -1832,6 +1857,8 @@ class PlayState extends MusicBeatState
|
||||
|
||||
if (event.deleteNote && strumLine != null && note != null)
|
||||
strumLine.deleteNote(note);
|
||||
|
||||
gameAndCharsEvent("onPostPlayerMiss", event);
|
||||
}
|
||||
|
||||
@:dox(hide)
|
||||
@@ -1941,7 +1968,7 @@ class PlayState extends MusicBeatState
|
||||
var suf:String = hasEvent ? evt.ratingSuffix : "";
|
||||
|
||||
var rating:FlxSprite = comboGroup.recycleLoop(FlxSprite);
|
||||
rating.resetSprite(comboGroup.x + -40, comboGroup.y + -60);
|
||||
CoolUtil.resetSprite(rating, comboGroup.x + -40, comboGroup.y + -60);
|
||||
rating.loadAnimatedGraphic(Paths.image('${pre}${myRating}${suf}'));
|
||||
rating.acceleration.y = 550;
|
||||
rating.velocity.y -= FlxG.random.int(140, 175);
|
||||
@@ -1968,7 +1995,7 @@ class PlayState extends MusicBeatState
|
||||
|
||||
if (evt.displayCombo) {
|
||||
var comboSpr:FlxSprite = comboGroup.recycleLoop(FlxSprite).loadAnimatedGraphic(Paths.image('${pre}combo${suf}'));
|
||||
comboSpr.resetSprite(comboGroup.x, comboGroup.y);
|
||||
CoolUtil.resetSprite(comboSpr, comboGroup.x, comboGroup.y);
|
||||
comboSpr.acceleration.y = 600;
|
||||
comboSpr.velocity.y -= 150;
|
||||
comboSpr.velocity.x += FlxG.random.int(1, 10);
|
||||
@@ -1992,7 +2019,7 @@ class PlayState extends MusicBeatState
|
||||
for (i in 0...separatedScore.length)
|
||||
{
|
||||
var numScore:FlxSprite = comboGroup.recycleLoop(FlxSprite).loadAnimatedGraphic(Paths.image('${pre}num${separatedScore.charAt(i)}${suf}'));
|
||||
numScore.resetSprite(comboGroup.x + (43 * i) - 90, comboGroup.y + 80);
|
||||
CoolUtil.resetSprite(numScore, comboGroup.x + (43 * i) - 90, comboGroup.y + 80);
|
||||
if (hasEvent) {
|
||||
numScore.antialiasing = evt.numAntialiasing;
|
||||
numScore.scale.set(evt.numScale, evt.numScale);
|
||||
@@ -2132,43 +2159,51 @@ class PlayState extends MusicBeatState
|
||||
if (difficulty == null) difficulty = Flags.DEFAULT_DIFFICULTY;
|
||||
storyWeek = weekData;
|
||||
storyPlaylist = [for (e in weekData.songs) e.name];
|
||||
storyVariations = [for (e in weekData.songs) e.variation];
|
||||
isStoryMode = true;
|
||||
campaignScore = 0;
|
||||
campaignMisses = 0;
|
||||
campaignAccuracyTotal = 0;
|
||||
campaignAccuracyCount = 0;
|
||||
chartingMode = false;
|
||||
opponentMode = coopMode = false;
|
||||
__loadSong(storyPlaylist[0], difficulty);
|
||||
chartingMode = coopMode = opponentMode = false;
|
||||
__loadSong(storyPlaylist[0], difficulty, storyVariations[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads a song into PlayState
|
||||
* @param name Song name
|
||||
* @param difficulty Chart difficulty (if invalid, will load an empty chart)
|
||||
* @param variation Song Variation
|
||||
* @param opponentMode Whenever opponent mode is on
|
||||
* @param coopMode Whenever co-op mode is on.
|
||||
*/
|
||||
public static function loadSong(_name:String, ?_difficulty:String, _opponentMode:Bool = false, _coopMode:Bool = false) {
|
||||
public static function loadSong(_name:String, ?_difficulty:String, ?_variation:Dynamic, _opponentMode:Bool = false, _coopMode:Bool = false) {
|
||||
if (_difficulty == null) difficulty = Flags.DEFAULT_DIFFICULTY;
|
||||
isStoryMode = false;
|
||||
if (_variation is Bool) { // vackward cumpatibshit
|
||||
_coopMode = _opponentMode;
|
||||
_opponentMode = cast _variation;
|
||||
_variation = null;
|
||||
}
|
||||
else if (!(_variation is String)) _variation = null;
|
||||
opponentMode = _opponentMode;
|
||||
chartingMode = false;
|
||||
coopMode = _coopMode;
|
||||
__loadSong(_name, _difficulty);
|
||||
isStoryMode = chartingMode = false;
|
||||
__loadSong(_name, _difficulty, cast _variation);
|
||||
}
|
||||
|
||||
/**
|
||||
* (INTERNAL) Loads a song without resetting story mode/opponent mode/coop mode values.
|
||||
* @param name Song name
|
||||
* @param difficulty Song difficulty
|
||||
* @param difficulty Chart difficulty
|
||||
* @param variation Song Variation
|
||||
*/
|
||||
public static function __loadSong(_name:String, _difficulty:String) {
|
||||
public static function __loadSong(_name:String, _difficulty:String, _variation:String) {
|
||||
difficulty = _difficulty;
|
||||
variation = _variation;
|
||||
seenCutscene = false;
|
||||
deathCounter = 0;
|
||||
|
||||
SONG = Chart.parse(_name, _difficulty);
|
||||
SONG = Chart.parse(_name, _difficulty, _variation);
|
||||
fromMods = SONG.fromMods;
|
||||
}
|
||||
}
|
||||
@@ -2219,4 +2254,4 @@ class CamPosData {
|
||||
pos.put();
|
||||
pos = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -206,7 +206,7 @@ class Stage extends FlxBasic implements IBeatReceiver {
|
||||
}
|
||||
|
||||
// idk lemme check anyways just in case scripts did smth - Nex
|
||||
if (event != null) PlayState.instance.scripts.event("onPostStageCreation", event);
|
||||
if (event != null) PlayState.instance.gameAndCharsEvent("onPostStageCreation", event);
|
||||
|
||||
// shortlived scripts destroy when the stage finishes setting up - Nex
|
||||
for (info in xmlImportedScripts) if (info.shortLived) {
|
||||
@@ -349,17 +349,37 @@ class Stage extends FlxBasic implements IBeatReceiver {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Same of destroy, but doesn't call the various script events.
|
||||
* @param destroySprites Whether the stage sprites should be destroyed
|
||||
* @param destroyScript Whether the stage script should be destroyed
|
||||
**/
|
||||
public function destroySilently(destroySprites:Bool = true, destroyScript:Bool = true) {
|
||||
if (destroyScript && stageScript != null) {
|
||||
if (PlayState.instance == state && PlayState.instance.scripts != null) PlayState.instance.scripts.remove(stageScript);
|
||||
stageScript.destroy();
|
||||
}
|
||||
|
||||
if (destroySprites)
|
||||
for (e in stageSprites)
|
||||
e?.destroy();
|
||||
|
||||
startCam.put();
|
||||
super.destroy();
|
||||
}
|
||||
|
||||
public override function destroy() {
|
||||
if (PlayState.instance == state && PlayState.instance.scripts != null) PlayState.instance.gameAndCharsCall("onStageDestroy", [this]);
|
||||
stageScript?.call("destroy");
|
||||
destroySilently();
|
||||
}
|
||||
|
||||
public function beatHit(curBeat:Int) {}
|
||||
|
||||
public function stepHit(curStep:Int) {}
|
||||
|
||||
public function measureHit(curMeasure:Int) {}
|
||||
|
||||
public override function destroy() {
|
||||
startCam.put();
|
||||
super.destroy();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a list of stages that are available to be used.
|
||||
* @param mods Whenever only the mods folder should be checked
|
||||
|
||||
@@ -25,9 +25,14 @@ class FreeplayState extends MusicBeatState
|
||||
public var curSong:Null<ChartMetaData>;
|
||||
|
||||
/**
|
||||
* Current song metadata difficulty
|
||||
* Current song difficulties
|
||||
*/
|
||||
public var curSongDifficulty:Null<String>;
|
||||
public var curDifficulties:Array<String>;
|
||||
|
||||
/**
|
||||
* songs[curSelected].metas.get(curDiffMetaIndices[curDifficulty])
|
||||
*/
|
||||
public var curDiffMetaKeys:Array<String> = [];
|
||||
|
||||
/**
|
||||
* Currently selected song
|
||||
@@ -117,16 +122,15 @@ class FreeplayState extends MusicBeatState
|
||||
curSelected = k;
|
||||
}
|
||||
}
|
||||
updateCurSongMeta();
|
||||
|
||||
if (curSong != null) {
|
||||
for(k=>diff in songs[curSelected].difficulties) {
|
||||
if (diff == Options.freeplayLastDifficulty) {
|
||||
curDifficulty = k;
|
||||
}
|
||||
}
|
||||
updateCurDifficulties();
|
||||
for(i=>diff in curDifficulties) {
|
||||
if (curDiffMetaKeys[i] == Options.freeplayLastVariation && diff == Options.freeplayLastDifficulty)
|
||||
curDifficulty = i;
|
||||
}
|
||||
|
||||
updateCurSong();
|
||||
|
||||
DiscordUtil.call("onMenuLoaded", ["Freeplay"]);
|
||||
|
||||
super.create();
|
||||
@@ -151,8 +155,7 @@ class FreeplayState extends MusicBeatState
|
||||
|
||||
var icon:HealthIcon = new HealthIcon(songs[i].icon);
|
||||
icon.sprTracker = songText;
|
||||
icon.setUnstretchedGraphicSize(150, 150, true);
|
||||
icon.updateHitbox();
|
||||
if (Math.max(icon.width, icon.height) > 150) icon.setUnstretchedGraphicSize(150, 150);
|
||||
|
||||
// using a FlxGroup is too much fuss!
|
||||
iconArray.push(icon);
|
||||
@@ -181,7 +184,6 @@ class FreeplayState extends MusicBeatState
|
||||
add(scoreText);
|
||||
|
||||
changeSelection(0, true);
|
||||
changeDiff(0, true);
|
||||
changeCoopMode(0, true);
|
||||
|
||||
interpColor = new FlxInterpolateColor(bg.color);
|
||||
@@ -257,7 +259,7 @@ class FreeplayState extends MusicBeatState
|
||||
var dontPlaySongThisFrame = false;
|
||||
autoplayElapsed += elapsed;
|
||||
if (!disableAutoPlay && !songInstPlaying && (autoplayElapsed > timeUntilAutoplay)) {
|
||||
if (curPlayingInst != (curPlayingInst = Paths.inst(curSong.name, curSongDifficulty, curSong.instSuffix))) {
|
||||
if (curPlayingInst != (curPlayingInst = Paths.inst(curSong.name, curDifficulties[curDifficulty], curSong.instSuffix))) {
|
||||
var streamed = false;
|
||||
if (Options.streamedMusic) {
|
||||
var sound = Assets.getMusic(curPlayingInst, true, false);
|
||||
@@ -330,9 +332,9 @@ class FreeplayState extends MusicBeatState
|
||||
public function select() {
|
||||
updateCoopModes();
|
||||
|
||||
if (songs[curSelected].difficulties.length <= 0) return;
|
||||
if (curDifficulties.length == 0) return;
|
||||
|
||||
var event = event("onSelect", EventManager.get(FreeplaySongSelectEvent).recycle(curSong.name, curSongDifficulty, __opponentMode, __coopMode));
|
||||
var event = event("onSelect", EventManager.get(FreeplaySongSelectEvent).recycle(curSong.name, curDifficulties[curDifficulty], curSong.variant, __opponentMode, __coopMode));
|
||||
|
||||
if (event.cancelled) return;
|
||||
|
||||
@@ -341,16 +343,17 @@ class FreeplayState extends MusicBeatState
|
||||
#end
|
||||
|
||||
Options.freeplayLastSong = curSong.name;
|
||||
Options.freeplayLastDifficulty = curSongDifficulty;
|
||||
Options.freeplayLastDifficulty = curDifficulties[curDifficulty];
|
||||
Options.freeplayLastVariation = curSong.variant;
|
||||
|
||||
PlayState.loadSong(event.song, event.difficulty, event.opponentMode, event.coopMode);
|
||||
PlayState.loadSong(event.song, event.difficulty, event.variant, event.opponentMode, event.coopMode);
|
||||
FlxG.switchState(new PlayState());
|
||||
}
|
||||
|
||||
public function convertChart() {
|
||||
trace('Converting ${curSong.name} (${curSongDifficulty}) to Codename format...');
|
||||
var chart = Chart.parse(curSong.name, curSongDifficulty);
|
||||
Chart.save('${Main.pathBack}assets/songs/${curSong.name}', chart, curSongDifficulty);
|
||||
trace('Converting ${curSong.name} ${curDifficulties[curDifficulty]} ${curSong.variant} to Codename format...');
|
||||
var chart = Chart.parse(curSong.name, curDifficulties[curDifficulty], curSong.variant);
|
||||
Chart.save(chart, curDifficulties[curDifficulty], curSong.variant);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -358,39 +361,35 @@ class FreeplayState extends MusicBeatState
|
||||
* @param change How much to change.
|
||||
* @param force Force the change if `change` is equal to 0
|
||||
*/
|
||||
public function changeDiff(change:Int = 0, force:Bool = false)
|
||||
{
|
||||
public function changeDiff(change:Int = 0, force:Bool = false) {
|
||||
if (change == 0 && !force) return;
|
||||
|
||||
var song = songs[curSelected];
|
||||
var validDifficulties = song.difficulties.length > 0;
|
||||
var event = event("onChangeDiff", EventManager.get(MenuChangeEvent).recycle(curDifficulty, validDifficulties ? FlxMath.wrap(curDifficulty + change, 0, song.difficulties.length-1) : 0, change));
|
||||
var validDifficulties = curDifficulties.length > 0;
|
||||
var event = event("onChangeDiff", EventManager.get(MenuChangeEvent).recycle(curDifficulty, validDifficulties ? FlxMath.wrap(curDifficulty + change, 0, curDifficulties.length-1) : 0, change));
|
||||
|
||||
if (event.cancelled) {
|
||||
if (force) updateCurSongMeta();
|
||||
if (force) updateCurSong();
|
||||
return;
|
||||
}
|
||||
|
||||
var prevInstSuffix = curSong.instSuffix;
|
||||
var prevSong = curSong;
|
||||
curDifficulty = event.value;
|
||||
updateCurSongMeta();
|
||||
updateCurSong();
|
||||
updateScore();
|
||||
|
||||
#if PRELOAD_ALL
|
||||
if (curSong.instSuffix != prevInstSuffix) {
|
||||
if (curSong != prevSong) {
|
||||
autoplayElapsed = 0;
|
||||
songInstPlaying = false;
|
||||
}
|
||||
#end
|
||||
|
||||
if (song.difficulties.length > 1)
|
||||
diffText.text = '< ${song.difficulties[curDifficulty].toUpperCase()} >';
|
||||
else
|
||||
diffText.text = validDifficulties ? song.difficulties[curDifficulty].toUpperCase() : "-";
|
||||
var text = validDifficulties ? curDifficulties[curDifficulty].toUpperCase() + (curSong != songs[curSelected] ? ' (${curSong.variant.toUpperCase()})' : '') : '-';
|
||||
diffText.text = curDifficulties.length > 1 ? '< $text >' : text;
|
||||
}
|
||||
|
||||
function updateScore() {
|
||||
if (songs[curSelected].difficulties.length <= 0) {
|
||||
if (curDifficulties.length == 0) {
|
||||
intendedScore = 0;
|
||||
return;
|
||||
}
|
||||
@@ -398,7 +397,7 @@ class FreeplayState extends MusicBeatState
|
||||
var changes:Array<HighscoreChange> = [];
|
||||
if (__coopMode) changes.push(CCoopMode);
|
||||
if (__opponentMode) changes.push(COpponentMode);
|
||||
var saveData = FunkinSave.getSongHighscore(curSong.name, curSongDifficulty, changes);
|
||||
var saveData = FunkinSave.getSongHighscore(curSong.name, curDifficulties[curDifficulty], curSong.variant, changes);
|
||||
intendedScore = saveData.score;
|
||||
}
|
||||
|
||||
@@ -448,8 +447,7 @@ class FreeplayState extends MusicBeatState
|
||||
* @param change How much to change
|
||||
* @param force Force the change, even if `change` is equal to 0.
|
||||
*/
|
||||
public function changeSelection(change:Int = 0, force:Bool = false)
|
||||
{
|
||||
public function changeSelection(change:Int = 0, force:Bool = false) {
|
||||
if (change == 0 && !force) return;
|
||||
|
||||
var event = event("onChangeSelection", EventManager.get(MenuChangeEvent).recycle(curSelected, FlxMath.wrap(curSelected + change, 0, songs.length-1), change));
|
||||
@@ -458,6 +456,14 @@ class FreeplayState extends MusicBeatState
|
||||
curSelected = event.value;
|
||||
if (event.playMenuSFX) CoolUtil.playMenuSFX(SCROLL, 0.7);
|
||||
|
||||
var prevDiff = curDifficulties[curDifficulty], prevVariant = curDiffMetaKeys[curDifficulty];
|
||||
updateCurDifficulties();
|
||||
|
||||
for (i => diff in curDifficulties) if (diff == prevDiff && curDiffMetaKeys[i] == prevVariant) {
|
||||
curDifficulty = i;
|
||||
break;
|
||||
}
|
||||
|
||||
changeDiff(0, true);
|
||||
|
||||
#if PRELOAD_ALL
|
||||
@@ -491,13 +497,24 @@ class FreeplayState extends MusicBeatState
|
||||
}
|
||||
}
|
||||
|
||||
function updateCurSongMeta() {
|
||||
var song = songs[curSelected];
|
||||
if (song == null) {
|
||||
curSong = null;
|
||||
curSongDifficulty = null;
|
||||
function updateCurDifficulties() {
|
||||
curDiffMetaKeys.resize(0);
|
||||
curDifficulties = songs[curSelected].difficulties.copy();
|
||||
for (i in 0...curDifficulties.length) curDiffMetaKeys.push(null);
|
||||
|
||||
if (songs[curSelected].variants != null) {
|
||||
var meta:ChartMetaData;
|
||||
for (variant in songs[curSelected].variants) if ((meta = songs[curSelected].metas.get(variant)) != null) {
|
||||
curDifficulties = curDifficulties.concat(meta.difficulties);
|
||||
for (i in 0...meta.difficulties.length) curDiffMetaKeys.push(variant);
|
||||
}
|
||||
}
|
||||
else if ((curSong = song.metas.get(curSongDifficulty = song.difficulties[curDifficulty])) == null)
|
||||
}
|
||||
|
||||
function updateCurSong() {
|
||||
var song = songs[curSelected];
|
||||
if (song == null) curSong = null;
|
||||
else if ((curSong = song.metas.get(curDiffMetaKeys[curDifficulty])) == null)
|
||||
curSong = song;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,10 +65,12 @@ class PauseSubState extends MusicBeatSubstate
|
||||
|
||||
menuItems = event.options;
|
||||
|
||||
pauseMusic = FlxG.sound.load(Assets.getMusic(Paths.music(event.music)), 0, true);
|
||||
pauseMusic.persist = false;
|
||||
pauseMusic.group = FlxG.sound.defaultMusicGroup;
|
||||
pauseMusic.play(false, FlxG.random.int(0, Std.int(pauseMusic.length / 2)));
|
||||
if (Assets.exists(Paths.music(event.music))) {
|
||||
pauseMusic = FlxG.sound.load(Assets.getMusic(Paths.music(event.music)), 0, true);
|
||||
pauseMusic.persist = false;
|
||||
pauseMusic.group = FlxG.sound.defaultMusicGroup;
|
||||
pauseMusic.play(false, FlxG.random.int(0, Std.int(pauseMusic.length / 2)));
|
||||
}
|
||||
|
||||
if (__cancelDefault = event.cancelled) return;
|
||||
|
||||
@@ -119,9 +121,11 @@ class PauseSubState extends MusicBeatSubstate
|
||||
camera = new FlxCamera();
|
||||
camera.bgColor = 0;
|
||||
FlxG.cameras.add(camera, false);
|
||||
}
|
||||
|
||||
override function createPost() {
|
||||
super.createPost();
|
||||
pauseScript.call("postCreate");
|
||||
|
||||
game.updateDiscordPresence();
|
||||
}
|
||||
|
||||
@@ -129,7 +133,7 @@ class PauseSubState extends MusicBeatSubstate
|
||||
{
|
||||
super.update(elapsed);
|
||||
|
||||
if (pauseMusic.volume < 0.5)
|
||||
if (pauseMusic != null && pauseMusic.volume < 0.5)
|
||||
pauseMusic.volume += 0.01 * elapsed;
|
||||
|
||||
pauseScript.call("update", [elapsed]);
|
||||
@@ -167,7 +171,7 @@ class PauseSubState extends MusicBeatSubstate
|
||||
case "Change Options":
|
||||
FlxG.switchState(new OptionsMenu((_) -> FlxG.switchState(new PlayState())));
|
||||
case "Exit to charter":
|
||||
FlxG.switchState(new Charter(PlayState.SONG.meta.name, PlayState.difficulty, false));
|
||||
FlxG.switchState(new Charter(PlayState.SONG.meta.name, PlayState.difficulty, PlayState.variation, false));
|
||||
case "Exit to menu":
|
||||
if (PlayState.chartingMode && Charter.undos.unsaved)
|
||||
game.saveWarn(false);
|
||||
|
||||
@@ -36,7 +36,7 @@ final class AlphabetComponent {
|
||||
public var cos:Float;
|
||||
public var scaleX:Float;
|
||||
public var scaleY:Float;
|
||||
|
||||
|
||||
public var flipX:Bool;
|
||||
public var flipY:Bool;
|
||||
|
||||
@@ -163,7 +163,7 @@ class Alphabet extends FlxSprite {
|
||||
};
|
||||
var manualLetters:Array<String> = [];
|
||||
var failedLetters:Array<String> = [];
|
||||
var failedOutlines:Array<String> = [];
|
||||
var sheets:Array<String> = [];
|
||||
|
||||
public var renderMode:AlphabetRenderMode = DEFAULT;
|
||||
|
||||
@@ -321,7 +321,7 @@ class Alphabet extends FlxSprite {
|
||||
if (!isOnScreen(camera)) {
|
||||
frameOffset.y -= offsetY;
|
||||
frameOffset.x -= offsetX;
|
||||
break;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (__component.hasColorMode)
|
||||
@@ -436,10 +436,8 @@ class Alphabet extends FlxSprite {
|
||||
if (anim == null)
|
||||
return defaultAdvance;
|
||||
|
||||
if (data.advanceEmpty && !data.isDefault) {
|
||||
data.advanceEmpty = false;
|
||||
if (data.advanceEmpty && !data.isDefault)
|
||||
data.advance = frames.frames[anim.frames[0]].sourceSize.x;
|
||||
}
|
||||
return (data.isDefault) ? frames.frames[anim.frames[0]].sourceSize.x : data.advance;
|
||||
}
|
||||
|
||||
@@ -514,28 +512,17 @@ class Alphabet extends FlxSprite {
|
||||
return animation.getByName(name);
|
||||
}
|
||||
|
||||
/*function getLetterOutline(char:String, component:AlphabetComponent, index:Int) {
|
||||
var name = char + "Outline" + Std.string(index);
|
||||
if (failedOutlines.contains(name)) return null;
|
||||
if (animation.exists(name)) return animation.getByName(name);
|
||||
|
||||
animation.addByPrefix(name, component.outline.anim, fps);
|
||||
if (!animation.exists(name)) {
|
||||
failedOutlines.push(name);
|
||||
return null;
|
||||
}
|
||||
return animation.getByName(name);
|
||||
}*/
|
||||
|
||||
function checkNode(node:Xml):Void {
|
||||
switch (node.nodeName) {
|
||||
case "spritesheet":
|
||||
final sheet = node.firstChild().nodeValue.trim();
|
||||
if (frames == null)
|
||||
frames = Paths.getFrames(node.firstChild().nodeValue);
|
||||
frames = Paths.getFrames(sheet);
|
||||
else {
|
||||
for (frame in Paths.getFrames(node.firstChild().nodeValue).frames)
|
||||
for (frame in Paths.getFrames(sheet).frames)
|
||||
frames.pushFrame(frame);
|
||||
}
|
||||
sheets.push(sheet);
|
||||
case "defaultAnim":
|
||||
var idx = ["UPPER", "LOWER"].indexOf(node.get("casing").toUpperCase()) + 1;
|
||||
|
||||
@@ -549,7 +536,7 @@ class Alphabet extends FlxSprite {
|
||||
advance: 0.0,
|
||||
advanceEmpty: true,
|
||||
components: [{
|
||||
anim: node.firstChild().nodeValue,
|
||||
anim: node.firstChild().nodeValue.trim(),
|
||||
|
||||
x: 0.0,
|
||||
y: 0.0,
|
||||
@@ -560,7 +547,7 @@ class Alphabet extends FlxSprite {
|
||||
angle: angle,
|
||||
cos: angleCos,
|
||||
sin: angleSin,
|
||||
|
||||
|
||||
flipX: node.get("flipX") == "true",
|
||||
flipY: node.get("flipY") == "true",
|
||||
|
||||
@@ -616,7 +603,7 @@ class Alphabet extends FlxSprite {
|
||||
angle: angle,
|
||||
cos: angleCos,
|
||||
sin: angleSin,
|
||||
|
||||
|
||||
flipX: xFlip,
|
||||
flipY: yFlip,
|
||||
|
||||
@@ -639,7 +626,7 @@ class Alphabet extends FlxSprite {
|
||||
angle: angle,
|
||||
cos: angleCos,
|
||||
sin: angleSin,
|
||||
|
||||
|
||||
flipX: xFlip,
|
||||
flipY: yFlip,
|
||||
|
||||
@@ -673,7 +660,7 @@ class Alphabet extends FlxSprite {
|
||||
var xScale:Float = Std.parseFloat(node.get("scaleX")).getDefaultFloat(1.0);
|
||||
var yScale:Float = Std.parseFloat(node.get("scaleY")).getDefaultFloat(1.0);
|
||||
var advance:Float = Std.parseFloat(node.get("advance"));
|
||||
|
||||
|
||||
var xFlip = node.get("flipX") == "true";
|
||||
var yFlip = node.get("flipY") == "true";
|
||||
|
||||
@@ -694,7 +681,7 @@ class Alphabet extends FlxSprite {
|
||||
angle: angle,
|
||||
cos: angleCos,
|
||||
sin: angleSin,
|
||||
|
||||
|
||||
flipX: xFlip,
|
||||
flipY: yFlip,
|
||||
|
||||
@@ -705,7 +692,7 @@ class Alphabet extends FlxSprite {
|
||||
|
||||
components.push({
|
||||
outIndex: (node.get("hasOutline") == "true") ? 0 : null,
|
||||
anim: node.firstChild().nodeValue,
|
||||
anim: node.firstChild().nodeValue.trim(),
|
||||
|
||||
x: xOff,
|
||||
y: yOff,
|
||||
@@ -766,6 +753,8 @@ class Alphabet extends FlxSprite {
|
||||
v[2] = [];
|
||||
v;
|
||||
}
|
||||
sheets = [];
|
||||
manualLetters = [];
|
||||
failedLetters = [" "];
|
||||
|
||||
defaultAdvance = Std.parseFloat(xml.get("advance")).getDefaultFloat(40.0);
|
||||
@@ -781,34 +770,102 @@ class Alphabet extends FlxSprite {
|
||||
checkNode(node);
|
||||
}
|
||||
|
||||
private static var alphabetProperties:Array<String> = ["fps", "advance", "lineGap", "forceCasing", "useColorOffsets", "antialiasing"];
|
||||
private static var componentProperties:Array<String> = ["name", "anim", "x", "y", "scaleX", "scaleY", "angle", "offsetX", "offsetY", "flipX", "flipY"];
|
||||
private static var alphabetProperties:Array<String> = ["fps", "advance", "lineGap", "forceCasing", "colorMode", "antialiasing"];
|
||||
private static var componentProperties:Array<String> = ["char", "advance", "anim", "x", "y", "scaleX", "scaleY", "flipX", "flipY", "angle", "colorMode", "hasOutline", "outline", "outlineX", "outlineY"];
|
||||
|
||||
public function buildXML():Xml {
|
||||
var xml = Xml.createElement("alphabet");
|
||||
var xml = Xml.createElement("alphabetFont");
|
||||
xml.set("fps", Std.string(fps));
|
||||
xml.set("advance", Std.string(defaultAdvance));
|
||||
xml.set("lineGap", Std.string(lineGap));
|
||||
xml.set("forceCasing", ["none", "upper", "lower"][forceCase]);
|
||||
xml.set("useColorOffsets", ["tint", "offsets", "none"][colorMode]);
|
||||
xml.set("colorMode", ["tint", "offsets", "none"][colorMode]);
|
||||
xml.set("antialiasing", antialiasing ? "true" : "false");
|
||||
|
||||
xml.attributeOrder = alphabetProperties;
|
||||
|
||||
/*for (component in components) {
|
||||
var componentXml = Xml.createElement("component");
|
||||
componentXml.attributeOrder = componentProperties;
|
||||
componentXml.set("name", component.name);
|
||||
componentXml.set("anim", component.anim);
|
||||
componentXml.set("x", Std.string(component.x));
|
||||
componentXml.set("y", Std.string(component.y));
|
||||
if(component.scaleX != 1) componentXml.set("scaleX", Std.string(component.scaleX));
|
||||
if(component.scaleY != 1) componentXml.set("scaleY", Std.string(component.scaleY));
|
||||
if(component.angle != 0) componentXml.set("angle", Std.string(component.angle));
|
||||
if(component.offsetX != 0) componentXml.set("offsetX", Std.string(component.offsetX));
|
||||
if(component.offsetY != 0) componentXml.set("offsetY", Std.string(component.offsetY));
|
||||
xml.addChild(componentXml);
|
||||
}*/
|
||||
for (sheet in sheets) {
|
||||
var sheetNode = Xml.createElement("spritesheet");
|
||||
sheetNode.addChild(Xml.createPCData(sheet));
|
||||
xml.addChild(sheetNode);
|
||||
}
|
||||
|
||||
for (i in 0...3) {
|
||||
if (defaults[i] == null) continue;
|
||||
|
||||
var compon = defaults[i].components[0];
|
||||
var node = Xml.createElement("defaultAnim");
|
||||
node.addChild(Xml.createPCData(compon.anim));
|
||||
if (i != 0)
|
||||
node.set("casing", ["upper", "lower"][i - 1]);
|
||||
|
||||
if (compon.scaleX != 1.0 || compon.scaleY != 1.0) {
|
||||
node.set("scaleX", Std.string(compon.scaleX));
|
||||
node.set("scaleY", Std.string(compon.scaleY));
|
||||
}
|
||||
if (compon.flipX || compon.flipY) {
|
||||
node.set("flipX", Std.string(compon.flipX));
|
||||
node.set("flipY", Std.string(compon.flipY));
|
||||
}
|
||||
if (compon.angle != 0.0)
|
||||
node.set("angle", Std.string(compon.angle));
|
||||
|
||||
node.attributeOrder = componentProperties;
|
||||
xml.addChild(node);
|
||||
}
|
||||
|
||||
for (let in manualLetters) {
|
||||
var data = fastGetData(let);
|
||||
var node = Xml.createElement(data.components.length - data.startIndex > 1 ? "composite" : "anim");
|
||||
node.set("char", let);
|
||||
if (!data.advanceEmpty)
|
||||
node.set("advance", Std.string(data.advance));
|
||||
|
||||
for (i in data.startIndex...data.components.length) {
|
||||
var compon = data.components[i];
|
||||
var cNode:Xml = node;
|
||||
|
||||
if (data.components.length - data.startIndex > 1) {
|
||||
cNode = Xml.createElement("component");
|
||||
cNode.set("anim", compon.anim);
|
||||
node.addChild(cNode);
|
||||
} else
|
||||
cNode.addChild(Xml.createPCData(compon.anim));
|
||||
|
||||
if (compon.x != 0.0 || compon.y != 0.0) {
|
||||
cNode.set("x", Std.string(-compon.x));
|
||||
cNode.set("y", Std.string(compon.y));
|
||||
}
|
||||
if (compon.scaleX != 1.0 || compon.scaleY != 1.0) {
|
||||
cNode.set("scaleX", Std.string(compon.scaleX));
|
||||
cNode.set("scaleY", Std.string(compon.scaleY));
|
||||
}
|
||||
if (compon.flipX || compon.flipY) {
|
||||
cNode.set("flipX", Std.string(compon.flipX));
|
||||
cNode.set("flipY", Std.string(compon.flipY));
|
||||
}
|
||||
if (compon.angle != 0.0)
|
||||
cNode.set("angle", Std.string(compon.angle));
|
||||
if (compon.hasColorMode)
|
||||
cNode.set("colorMode", ["tint", "offsets", "none"][compon.colorMode]);
|
||||
|
||||
if (compon.outIndex != null) {
|
||||
var outline = data.components[compon.outIndex];
|
||||
|
||||
cNode.set("hasOutline", "true");
|
||||
cNode.set("outline", outline.anim);
|
||||
if (outline.x != 0.0 || outline.y != 0.0) {
|
||||
cNode.set("outlineX", Std.string(outline.x));
|
||||
cNode.set("outlineY", Std.string(outline.y));
|
||||
}
|
||||
}
|
||||
|
||||
cNode.attributeOrder = componentProperties;
|
||||
}
|
||||
|
||||
node.attributeOrder = componentProperties;
|
||||
xml.addChild(node);
|
||||
}
|
||||
|
||||
return xml;
|
||||
}
|
||||
@@ -828,9 +885,9 @@ class Alphabet extends FlxSprite {
|
||||
this.letterData = from.letterData;
|
||||
this.defaults = from.defaults;
|
||||
this.loaded = from.loaded;
|
||||
this.sheets = from.sheets;
|
||||
this.manualLetters = from.manualLetters;
|
||||
this.failedLetters = from.failedLetters;
|
||||
this.failedOutlines = from.failedOutlines;
|
||||
}
|
||||
|
||||
override function destroy():Void {
|
||||
@@ -843,7 +900,7 @@ class Alphabet extends FlxSprite {
|
||||
defaults = null;
|
||||
manualLetters = null;
|
||||
failedLetters = null;
|
||||
failedOutlines = null;
|
||||
sheets = null;
|
||||
super.destroy();
|
||||
}
|
||||
|
||||
|
||||
@@ -73,6 +73,7 @@ class Options
|
||||
*/
|
||||
public static var freeplayLastSong:String = null;
|
||||
public static var freeplayLastDifficulty:String = "normal";
|
||||
public static var freeplayLastVariation:String = null;
|
||||
public static var contributors:Array<funkin.backend.system.github.GitHubContributor.CreditsGitHubContributor> = [];
|
||||
public static var mainDevs:Array<Int> = []; // IDs
|
||||
public static var lastUpdated:Null<Float>;
|
||||
|
||||
@@ -151,6 +151,11 @@ class OptionsMenu extends TreeMenu {
|
||||
var options:Array<FlxSprite> = [];
|
||||
|
||||
for(node in xml.elements) {
|
||||
switch(node.name) {
|
||||
case "separator":
|
||||
options.push(new Separator(node.has.height ? Std.parseFloat(node.att.height) : 67));
|
||||
}
|
||||
|
||||
if (!node.has.name) {
|
||||
Logs.warn("An option node requires a name attribute.");
|
||||
continue;
|
||||
@@ -165,7 +170,6 @@ class OptionsMenu extends TreeMenu {
|
||||
continue;
|
||||
}
|
||||
options.push(new Checkbox(name, desc, node.att.id, null, FlxG.save.data));
|
||||
|
||||
case "number":
|
||||
if (!node.has.id) {
|
||||
Logs.warn("A number option requires an \"id\" for option saving.");
|
||||
@@ -195,7 +199,7 @@ class OptionsMenu extends TreeMenu {
|
||||
continue;
|
||||
}
|
||||
var v:Dynamic = 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.att.forId));
|
||||
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));
|
||||
case 'slider':
|
||||
if (!node.has.id) {
|
||||
Logs.warn("A slider option requires an \"id\" for option saving.");
|
||||
@@ -204,10 +208,6 @@ class OptionsMenu extends TreeMenu {
|
||||
var step = node.has.change ? Std.parseFloat(node.att.change) : (node.has.step ? Std.parseFloat(node.att.step) : null);
|
||||
var segments = node.has.segments ? Std.parseInt(node.att.segments) : 5;
|
||||
options.push(new SliderOption(name, desc, Std.parseFloat(node.att.min), Std.parseFloat(node.att.max), step, segments, node.att.id, Std.parseInt(node.att.barWidth), null, FlxG.save.data));
|
||||
|
||||
case 'separator':
|
||||
options.push(new Separator(Std.parseInt(node.att.height)));
|
||||
|
||||
case "menu":
|
||||
options.push(new TextOption(name, desc, ' >', () -> {
|
||||
var screen = new TreeMenuScreen(name, desc);
|
||||
|
||||
@@ -128,11 +128,12 @@ class TreeMenuScreen extends FlxSpriteGroup {
|
||||
var i = curSelected, y = initY, object:FlxSprite = null, itemHeight:Float = 0;
|
||||
|
||||
inline function updateItem() {
|
||||
object.y = CoolUtil.fpsLerp(object.y, y - (itemHeight = object.height) * 0.5, r);
|
||||
object.y = CoolUtil.fpsLerp(object.y, y - itemHeight * 0.5, r);
|
||||
object.x = x + 100 - Math.pow(Math.abs((object.y - (FlxG.height - itemHeight) * 0.5) / itemHeight / FlxG.height * FlxG.initialHeight), 1.6) * 15;
|
||||
}
|
||||
|
||||
while (i < length) if ((object = members[i++]) != null) {
|
||||
itemHeight = object.height;
|
||||
updateItem();
|
||||
y += itemHeight;
|
||||
}
|
||||
@@ -140,7 +141,7 @@ class TreeMenuScreen extends FlxSpriteGroup {
|
||||
y = initY;
|
||||
i = curSelected;
|
||||
while (i-- > 0) if ((object = members[i]) != null) {
|
||||
y -= itemHeight;
|
||||
y -= (itemHeight = object.height);
|
||||
updateItem();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -60,4 +60,4 @@ class AdvancedAppearanceOptions extends TreeMenuScreen {
|
||||
private function __changeAntialiasing() {
|
||||
FlxG.game.stage.quality = (FlxG.enableAntialiasing = Options.antialiasing) ? BEST : LOW;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,10 +16,9 @@ class IconOption extends TextOption {
|
||||
|
||||
iconSpr = new HealthIcon(icon, false);
|
||||
iconSpr.setPosition(90 - iconSpr.width, (__text.height - iconSpr.height) / 2);
|
||||
iconSpr.setUnstretchedGraphicSize(150, 150, true);
|
||||
iconSpr.updateHitbox();
|
||||
iconSpr.sprTracker = __text;
|
||||
iconSpr.sprTrackerAlignment = LEFT;
|
||||
if (Math.max(iconSpr.width, iconSpr.height) > 150) iconSpr.setUnstretchedGraphicSize(150, 150);
|
||||
add(iconSpr);
|
||||
}
|
||||
}
|
||||
@@ -10,7 +10,7 @@ class NewOption extends TextOption {
|
||||
|
||||
public function new(name:String, desc:String, callback:Void->Void) {
|
||||
super(name, desc, callback);
|
||||
itemHeight = 160;
|
||||
itemHeight = 150;
|
||||
|
||||
__text.color = FlxColor.LIME;
|
||||
__text.x = 100;
|
||||
|
||||
@@ -6,7 +6,7 @@ import flixel.FlxBasic;
|
||||
|
||||
class Separator extends FlxSprite {
|
||||
var separatorHeight:Float;
|
||||
public function new(height = 67) {
|
||||
public function new(height = 67.0) {
|
||||
super();
|
||||
separatorHeight = height;
|
||||
}
|
||||
|
||||
@@ -3,25 +3,24 @@ package funkin.savedata;
|
||||
import flixel.util.FlxSave;
|
||||
import lime.app.Application;
|
||||
import openfl.Lib;
|
||||
import haxe.Serializer;
|
||||
import haxe.Unserializer;
|
||||
|
||||
/**
|
||||
* Class used for saves WITHOUT going through the struggle of type checks
|
||||
* Just add your save variables the way you would do in the Options.hx file.
|
||||
* The macro will automatically generate the `flush` and `load` functions.
|
||||
*/
|
||||
@:build(funkin.backend.system.macros.FunkinSaveMacro.build("save", "flush", "load"))
|
||||
@:build(funkin.backend.system.macros.FunkinSaveMacro.build("save", "__flush", "__load"))
|
||||
class FunkinSave {
|
||||
public static var highscores:Map<HighscoreEntry, SongScore> = [];
|
||||
|
||||
@:doNotSave public static var highscores:Map<HighscoreEntry, SongScore> = [];
|
||||
|
||||
/**
|
||||
* ONLY OPEN IF YOU WANT TO EDIT FUNCTIONS RELATED TO SAVING, LOADING OR HIGHSCORES.
|
||||
*/
|
||||
#if REGION
|
||||
@:dox(hide) @:doNotSave
|
||||
private static var __eventAdded = false;
|
||||
@:doNotSave
|
||||
public static var save:FlxSave;
|
||||
@:dox(hide) @:doNotSave private static var __eventAdded = false;
|
||||
@:doNotSave public static var save:FlxSave;
|
||||
|
||||
public static function init() {
|
||||
var path = Flags.SAVE_PATH, name = Flags.SAVE_NAME;
|
||||
@@ -46,20 +45,64 @@ class FunkinSave {
|
||||
}
|
||||
}
|
||||
|
||||
public static function load() {
|
||||
__load();
|
||||
if (save.data.highscores != null) {
|
||||
var temp;
|
||||
for (entryData in Reflect.fields(save.data.highscores))
|
||||
if ((temp = __getHighscoreEntry(entryData)) != null && Reflect.field(save.data.highscores, entryData) != null)
|
||||
highscores.set(temp, Reflect.field(save.data.highscores, entryData));
|
||||
}
|
||||
}
|
||||
|
||||
public static function flush() {
|
||||
if (save.data.highscores == null) save.data.highscores = {};
|
||||
for (entry => score in highscores) Reflect.setField(save.data.highscores, __formatHighscoreEntry(entry), score);
|
||||
__flush();
|
||||
}
|
||||
|
||||
static function __getHighscoreEntry(data:String):HighscoreEntry {
|
||||
try {
|
||||
var d = Unserializer.run(data);
|
||||
if (d.song is String)
|
||||
return HSongEntry(d.song, d.diff, d.variation, d.changes);
|
||||
else if (d.week is String)
|
||||
return HWeekEntry(d.week, d.diff);
|
||||
}
|
||||
catch (e) {}
|
||||
return null;
|
||||
}
|
||||
|
||||
static function __formatHighscoreEntry(entry:HighscoreEntry):String {
|
||||
switch (entry) {
|
||||
case HWeekEntry(weekName, difficulty):
|
||||
return Serializer.run({week: weekName, diff: difficulty});
|
||||
case HSongEntry(songName, difficulty, variation, changes):
|
||||
var d:Dynamic = {
|
||||
song: songName,
|
||||
diff: difficulty,
|
||||
changes: changes
|
||||
};
|
||||
if (variation != null && variation != '') d.variation = variation;
|
||||
return Serializer.run(d);
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the high-score for a song.
|
||||
* @param name Song name
|
||||
* @param diff Song difficulty
|
||||
* @param changes Changes made to that song in freeplay.
|
||||
*/
|
||||
public static inline function getSongHighscore(name:String, diff:String, ?changes:Array<HighscoreChange>) {
|
||||
public static inline function getSongHighscore(name:String, diff:String, ?variation:String, ?changes:Array<HighscoreChange>) {
|
||||
if (changes == null) changes = [];
|
||||
return safeGetHighscore(HSongEntry(name.toLowerCase(), diff.toLowerCase(), changes));
|
||||
return safeGetHighscore(HSongEntry(name.toLowerCase(), diff.toLowerCase(), variation, changes));
|
||||
}
|
||||
|
||||
public static inline function setSongHighscore(name:String, diff:String, highscore:SongScore, ?changes:Array<HighscoreChange>) {
|
||||
public static inline function setSongHighscore(name:String, diff:String, ?variation:String, highscore:SongScore, ?changes:Array<HighscoreChange>) {
|
||||
if (changes == null) changes = [];
|
||||
if (safeRegisterHighscore(HSongEntry(name.toLowerCase(), diff.toLowerCase(), changes), highscore)) {
|
||||
if (safeRegisterHighscore(HSongEntry(name.toLowerCase(), diff.toLowerCase(), variation, changes), highscore)) {
|
||||
flush();
|
||||
return true;
|
||||
}
|
||||
@@ -103,7 +146,7 @@ class FunkinSave {
|
||||
|
||||
enum HighscoreEntry {
|
||||
HWeekEntry(weekName:String, difficulty:String);
|
||||
HSongEntry(songName:String, difficulty:String, changes:Array<HighscoreChange>);
|
||||
HSongEntry(songName:String, difficulty:String, variation:Null<String>, changes:Array<HighscoreChange>);
|
||||
}
|
||||
|
||||
enum HighscoreChange {
|
||||
|
||||
@@ -7,6 +7,10 @@ class Config {
|
||||
"flixel",
|
||||
|
||||
"funkin",
|
||||
#if MODCHARTING_FEATURES
|
||||
"modchart.engine",
|
||||
"modchart.backend.standalone",
|
||||
#end
|
||||
#end
|
||||
];
|
||||
|
||||
|
||||
@@ -161,9 +161,9 @@ class NativeAudioSource {
|
||||
}
|
||||
|
||||
private function complete() {
|
||||
completed = true;
|
||||
if (!completed) parent.onComplete.dispatch();
|
||||
stop();
|
||||
parent.onComplete.dispatch();
|
||||
completed = true;
|
||||
}
|
||||
|
||||
// Streaming, atleast for vorbis for now.
|
||||
|
||||
Reference in New Issue
Block a user